Serial communication between RPi and Arduino using C++ - raspberry-pi

I've written two pieces of code, to create a serial communication between Arduino and a Raspberry Pi using C++. The codes are:
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 baud
}
void loop() {
Serial.println("Hello from arduino");
delay(500);
}
And the C++ code in Raspberry is :
#include <iostream>
#include <wiringPi.h>
#include <wiringSerial.h>
using namespace std ;
int serialDeviceId=0;
int main(void)
{
int pin=7;
serialDeviceId= serialOpen("/dev/ttyACM1",9600);
if(serialDeviceId==-1)
{
cout<<"Unable to open serial device"<<endl;
return 1;
}
if(wiringPiSetup()==-1)
{
return 0 ;
}
pinMode(pin,OUTPUT); // designing pin as an output
while(1)
{
digitalWrite(pin,0);
delay(500);
digitalWrite(pin,1);
delay(500);
}
return 0;
}
So now I would like to read the data from the serial port using always that wiringpi and I've found that I can use SerialGetchar, but I don't know exactly how to use it. I just need to need this part in my code so that I can receive that "Hello from from arduino" written in the serial, from my Arduino code.

This code should work for you on the Raspberry Pi. It is extremely simple! Make sure you get the correct device special file by running:
dmesg
and looking for line like this:
[610106.464745] usb 1-1.4: new full-speed USB device number 4 using dwc_otg
[610106.608642] usb 1-1.4: New USB device found, idVendor=2341, idProduct=0043
[610106.608655] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=220
[610106.608663] usb 1-1.4: Manufacturer: Arduino (www.arduino.cc)
[610106.608671] usb 1-1.4: SerialNumber: 55731323536351E002E1
[610106.686193] cdc_acm 1-1.4:1.0: ttyACM0: USB ACM device
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringSerial.h>
int main ()
{
int fd ;
if((fd=serialOpen("/dev/ttyACM0",9600))<0){
fprintf(stderr,"Unable to open serial device: %s\n",strerror(errno));
return 1;
}
for (;;){
putchar(serialGetchar(fd));
fflush(stdout);
}
}
I assume you have a USB cable connecting one of the RaspberryPi USB ports to the USB port on the Arduino.

Related

Cant't send a data from my cell phone(android) to HM10

I am using HM10(Bluetooth module) and the NUCLEO board.
I am trying to send data (like A, B... just characters) from my android phone using "Serial Bluetooth terminal" app. I succeeded in connecting the phone and HM10, but data is not sent to HM10. I never know what is problem. Plz, give me some advice.
#include "mbed.h"
// set up the HM10 Serial connection
BufferedSerial hm10(D10,D2,9600); //TX, RX
BufferedSerial pc(CONSOLE_TX,CONSOLE_RX,9600);
DigitalOut led1(D3);
DigitalOut led2(D4);
char buf[80];
int main(){
sprintf(buf,"\r\nHello New Serial Function in mbed-os v.%.1f\r\n",6.0);
pc.write(buf, strlen(buf));
while(true) {
sprintf(buf,"waiting for data");
pc.write(buf, strlen(buf));
int num = hm10.read(buf,sizeof(buf));
led1=!led1; // for debugging
pc.write(buf,num);
//memset(buf,0,sizeof(buf));
}
}

ESP32 ModBus master half duplex read coil input registers

I'm trying to read a MODBUS sensor via an ESP32.
I'm using the following library: https://github.com/emelianov/modbus-esp8266
I have the following code:
#include <ModbusRTU.h>
#include <SoftwareSerial.h>
SoftwareSerial modBusSerial;
ModbusRTU modbus;
#define startReg 100
#define endReg 123
uint16_t res[endReg - startReg + 1];
// Callback to monitor errors in the modbus
bool cb(Modbus::ResultCode event, uint16_t transactionId, void* data) {
if (event != Modbus::EX_SUCCESS) {
Serial.print("Request result: 0x");
Serial.print(event, HEX);
}
return true;
}
void setup() {
Serial.begin(115200); // Default serial port (Hardware serial)
modBusSerial.begin(9600, SWSERIAL_8E1, MB_RX, MB_TX); // modbus configuration SWSERIAL_8E1 = 8 bits data, even parity and 1 stop-bit
modbus.begin(&modBusSerial);
modbus.master();
Serial.println("starting modbus...");
while (true) {
Serial.println(modBusSerial.read());
res[endReg - startReg] = 0; // string terminator to allow to use res as char*
if (!modbus.slave()) {
modbus.readIreg(16, startReg, res, endReg - startReg, cb);
}
modbus.task();
Serial.print("result: ");
Serial.println((char*) res);
delay(1000); // every second
}
}
Response I get;
When I do the exact same in QModMaster, I do get the correct output. Anyone any idea what I'm doing wrong here?
These are the settings I use;
I am aware of the "wrong" address in my code. I have 2 identical sensors but one is connected to my computer while the other one is connected to my ESP32.
Thanks in advance!

Unrecognizable characters received over UART

I have compiled code to transmit data from an STM32 board to the Arduino Uno and print it on the serial terminal. I have previously written code, similar to this and it worked as expected.
However, when I try transmitting a string from the STM32 this time, the TX-Led of the Arduino blinks, which is strange.
I have checked the baud rate of both devices and they match. On the serial terminal of the Arduino, backward question marks are printed when I am transmitting a short string "Test".
Please could someone help me identify any potential problems with what I have done.
The code for the STM32 UART settings was generated by cubeMX:
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;`
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
The string and HAL_UART instruction to transmit the data:
char let[30] = "Test\r\n";
HAL_UART_Transmit(&huart1, (uint8_t*)let, strlen(let), 1000);
All necessary functions (MX_USART1_UART_Init()) have been called and the HAL_UART_Transmit() is in the while loop, situated in the main loop, as I have cross-checked that.
My arduino program:
void setup() {
Serial.begin(115200);
// Define the LED pin as Output
pinMode (13, OUTPUT);
Serial.println("Arduino UART Receiver");
Serial.println("-----------------------------");
}
void loop() {
digitalWrite(13, LOW);
//wait until something is received
while(! Serial.available());
digitalWrite(13, HIGH);
//read the data
char in_read=Serial.read();
//print the data
Serial.print(in_read);
}
Arduino Uno has only one USART hardware, and it's connected to a USART-USB converter chip. This bus is point-to-point and can't be shared by another device when there is an active connection between Arduino and PC.
The RX pin of the Arduino is driven by two devices: STM32 and the converter chip. Converter tries to keep that line at logic high (because the TX coming from the PC is idle) while STM32 tries to drive that line with its own TX. Anything can happen there... Arduino is probably getting junk from its RX line.
If you can somehow disconnect Arduino RX from the converter chip (cutting the trace for example) it will probably work. But then you won't be able to program Arduino again.
You may use a software serial pin instead of the hardware RX pin. I don't have much experience with Arduino but I'm sure there must be software serial libraries out there.

UDP Socket communication using different ports between two hosts

I have a device that listen to UDP packets on port IN_PORT and echo the message on port OUT_PORT. I can communicate with it using a test software like Packet Sender.
I have to write a C++ library (Win32 at the moment) to communicate with the device. I made several tests but I still wasn't able to communicate. My guess is to use this workflow:
create socket
fill sockaddr_in structure with the device address, AF_INET family and the listeng port (OUT_PORT)
bind the socket
change sockaddr_in.sin_port with IN_PORT and send a packet (using sendto)
wait for an answer (using recvfrom)
repeat from 4
This works if I simulate the device with the Packet Sender utility working locally (device address = 127.0.0.1). I can't use the same workflow to connect to a remote address, even in the same subnet (e.g. my PC address: 192.168.1.2, remote PC address 192.168.1.5), since I get WSAEADDRNOTAVAIL error.
I've tested several different workflows, and read several discussions on the topic here and there, but none works, awfully.
Can someone give me some hints on the subject.
Thanks!
MIX
Your work flow is slightly wrong. It should be more like this instead:
create socket
fill sockaddr_in structure with the address of the local network adapter that is communicating with the device, AF_INET family, and the listenig port (OUT_PORT)
bind the socket
change sockaddr.sin_addr with device address, and sockaddr_in.sin_port with IN_PORT, and send a packet (using sendto)
wait for an answer (using recvfrom)
repeat from 4
I changed my code following Remy Lebeau hints. It works now. If someone will like to have a look and spot some weak points, or suggest improvements, I'll be glad (a code that "just works" is never enough; it must also "shine"!). Comments mark the previous (wrong) version of the code.
#pragma comment (lib, "Ws2_32.lib")
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <STRING>
#define IN_PORT 18
#define OUT_PORT 17
#define LOCAL_IP "10.0.10.108"
#define DEVICE_IP "10.0.10.104"
#define DEFAULT_BUFLEN 1024
int main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET sck;
struct sockaddr_in sckAddrInfo;
bool terminate;
char dataBuffer[DEFAULT_BUFLEN];
int rcvDataLength;
int sckAddrInfoLength;
WSAStartup(MAKEWORD(2,2), &wsaData);
sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset((&sckAddrInfo), 0, sizeof(sckAddrInfo));
sckAddrInfo.sin_family = AF_INET;
sckAddrInfo.sin_port = htons(IN_PORT);
//sckAddrInfo.sin_addr.s_addr = inet_addr(DEVICE_IP); // WRONG! Must bind local address
sckAddrInfo.sin_addr.s_addr = inet_addr(LOCAL_IP);
bind(sck, (struct sockaddr*)(&sckAddrInfo), sizeof(sckAddrInfo));
terminate = false;
sckAddrInfoLength = sizeof(sckAddrInfo);
while(!terminate)
{
printf("Write echo request: ");
gets(dataBuffer);
sckAddrInfo.sin_addr.s_addr = inet_addr(DEVICE_IP); // Must set device address, too, not just output port
sckAddrInfo.sin_port = htons(OUT_PORT);
sendto(sck, dataBuffer, strlen(dataBuffer), 0, (struct sockaddr*)(&sckAddrInfo), sizeof(sckAddrInfo));
memset(dataBuffer, '\0', DEFAULT_BUFLEN);
rcvDataLength = recvfrom(sck, dataBuffer, DEFAULT_BUFLEN, 0, (struct sockaddr*)(&sckAddrInfo), &sckAddrInfoLength);
printf("Device answer: %s\n", dataBuffer);
if(strcmp(dataBuffer, "quit") == 0)
terminate = true;
}
closesocket(sck);
WSACleanup();
return 0;
}

Using multicast addresses and groups

For a week or so I have been researching methods to send datagrams to multiple clients from a single source, and found that the IP supports multicasting over the range of 224.0.0.0 and 234.255.255.255. I have read a few documents that describe the technology, but am finding nothing that has helped me understand how to use them.
From what I have gathered, it seems that a program asks the OS kernel to join a non-associated multicast group, then starts sending data over a socket via UDP to the multicast address. Everything else is handled by WAN without needing anything something physically at the address being sent to.
This line of thinking has been vaguely supported by what I've read, but has not been confirmed at all. Is this thinking correct? What is mistaken if there are issues with it?
This is essentially correct.
On the receiver side, you first open up a socket listening on a particular port. Then you join a multicast address on a given network interface. Doing so causes the OS to send out IGMP messages to the network informing routers that is joining a group.
On the sender side, you open a socket, then configure the outgoing network interface for multicast. Once you do that, you can send packets to any multicast address.
Here's an example sender in C:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
struct sockaddr_in sin;
struct in_addr out_addr;
char mes[255], ttl;
int sock;
printf("Enter message: ");
fgets(mes, sizeof(mes), stdin);
bzero(&sin,sizeof(sin));
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=inet_addr(argv[1]);
sin.sin_port=htons(atoi(argv[2]));
if ((sock=socket(AF_INET,SOCK_DGRAM,0))==-1) {
perror("Error creating socket");
exit(1);
}
out_addr.s_addr=inet_addr(argv[3]);
if (setsockopt(sock,IPPROTO_IP,IP_MULTICAST_IF,(char *)&out_addr,sizeof(out_addr))== -1) {
perror("Error setting outgoing interface");
close(sock);
exit(1);
}
if (sendto(sock,mes,strlen(mes),0,(struct sockaddr *)&sin,sizeof(sin))==-1) {
close(sock);
perror("Send error");
}
close(sock);
}
And here's a sample receiver in C:
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int addr_len;
struct sockaddr_in sin,sin_recv;
struct ip_mreq multi;
char mes[255];
int sock;
bzero(&sin,sizeof(sin));
multi.imr_multiaddr.s_addr=inet_addr(argv[1]);
multi.imr_interface.s_addr=inet_addr(argv[2]);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(atoi(argv[3]));
if ((sock=socket(AF_INET,SOCK_DGRAM,0))==-1) {
perror("Error creating socket");
exit(1);
}
if (setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&multi,sizeof(multi))== -1) {
perror("Error joining multicast group");
close(sock);
exit(1);
}
if (bind(sock,(struct sockaddr *)&sin,sizeof(sin))==-1) {
perror("Error binding socket");
close(sock);
exit(1);
}
while (1) {
bzero(mes,sizeof(mes));
bzero(&sin_recv,sizeof(sin_recv));
addr_len=sizeof(sin_recv);
printf("Waiting for packet...\n");
if (recvfrom(sock,mes,sizeof(mes),0,(struct sockaddr *)&sin_recv,&addr_len)==-1) {
perror("error recving socket");
close(sock);
exit(1);
}
printf("Got packet\n");
printf("Origin: %s port %d\n",inet_ntoa(sin_recv.sin_addr),sin_recv.sin_port);
printf("Message: %s\n",mes);
}
}