Reading uart hex values ignores certain bytes/characters - c++

I'm new to C/C++ and I'm trying to make communication by uart using HEX values.
Device port: /dev/ttyS2. Baudrate: 38400
I'm using redis to subscribe the messages. And for testing I'm using "Termite", a RS232 terminal to simulate.
I found some guide that worked really fine, the problem is that when I try to read the message some bytes/characters mess with it.
Here is my code for the connection:
this->fd = open(device,O_RDWR | O_NOCTTY);
/*---------- Setting the Attributes of the serial port using termios structure --------- */
tcgetattr(this->fd, &SerialPortSettings); /* Get the current attributes of the Serial port */
/* Setting the Baud rate */
cfsetispeed(&SerialPortSettings,B38400); /* Set Read Speed as 38400 */
cfsetospeed(&SerialPortSettings,B38400); /* Set Write Speed as 38400 */
/* 8N1 Mode */
SerialPortSettings.c_cflag &= ~PARENB; /* Disables the Parity Enable bit(PARENB),So No Parity */
SerialPortSettings.c_cflag &= ~CSTOPB; /* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit */
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the mask for setting the data size */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /* No Hardware flow Control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF flow control both i/p and o/p */
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* Non Cannonical mode */
SerialPortSettings.c_oflag &= ~OPOST; /*No Output Processing*/
SerialPortSettings.c_oflag = 0;
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 1; /* Read at least X characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
tcflush(this->fd, TCIFLUSH);
if((tcsetattr(this->fd,TCSANOW,&SerialPortSettings)) != 0) { /* Set the attributes to the termios structure*/
printf("\n ERROR ! in Setting attributes");
}
else {
tcsetattr(fd, TCSANOW, &SerialPortSettings);
printf("\n BaudRate = 38400 \n StopBits = 1 \n Parity = none\n\n");
}
And here is the code for reading:
char read_buffer[32];
int bytes_read;
while(true) {
bytes_read = read(serialport.fd, &read_buffer, sizeof(read_buffer)); /* Read the data */
printf("bytes read: %d", bytes_read);
if (bytes_read < 0) {
printf("Error reading: %s", strerror(errno));
}
else if (bytes_read > 0) {
//read_buffer[bytes_read] = '\0';
printf("\n");
printf("HEX:");
for (int i=0; i<bytes_read; i++) { /*printing only the received characters*/
printf(" %02x",read_buffer[i]);
}
printf("\n");
printf("+----------------------------------+\n");
/*#if defined(MODULE_REDIS) || defined(MODULE_ALL)
//redis.publish("channel:uart:ack", read_buffer);
redis.publish("channel:uart:ack", vectorUint8toHex(read_data).c_str());
#endif*/
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
When I send the message 0x2401010203040506070809af23, it only shows 8 bytes. (the bytes 0x03 and 0x04 messes with the message)
OUTPUT:
bytes read: 0bytes read: 8
HEX: 05 06 07 08 09 af 23 0a
+----------------------------------+
But when I send 0x2401010200000506070809af23, it works fine
OUTPUT:
bytes read: 14
HEX: 24 01 01 02 00 00 05 06 07 08 09 af 23 0a
+----------------------------------+
What I'm doing wrong? And one more thing. Using Termite have to turn the "append LF" setting or else I can't read the message, but that adds "0a" to my message, is this related to the configurations of the serial port?

Ok, so the problem was that some bytes in binary were 0x03 and 0x04 that are in ASCII "end of text" and "end of transmission". And was missing this line on the configurations:
SerialPortSettings.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
Thanks to the comments, I searched for some missing configurations and found it.
There's another post for my problem that I didn't found at the time:
Binary serial port read missing bytes in c

Related

Read from USB until a special character ; with Ubuntu and Arduino

I have an Arduino code that outputs strings coming from some sensors over the USB.
These are the strings:
Sensor 1 F1 410nm : 0 F2 435nm : 290 F3 445nm : 0 F4 460nm : 211 F5 480nm : 0 F6 515nm : 0 F7 535nm : 262 F8 555nm : 0 F9 590nm : 0 F10 610nm : 263 F11 630nm : 0 F12 645nm : 262 F13 680nm : 0 F14 715nm : 181 F15 730nm : 201 F16 780nm : 0 F17 860nm : 262 F18 940nm : 211;
Sensor 0 F1 410nm : 0 F2 435nm : 171 F3 445nm : 0 F4 460nm : 213 F5 480nm : 0 F6 515nm : 0 F7 535nm : 228 F8 555nm : 0 F9 590nm : 0 F10 610nm : 150 F11 630nm : 0 F12 645nm : 200 F13 680nm : 0 F14 715nm : 159 F15 730nm : 204 F16 780nm : 0 F17 860nm : 213 F18 940nm : 228;
Each string is terminated by the character ";".
Now, I wrote a simple C++ program that runs on Ubuntu and reads from serial and outputs data.
Arduino is connected via USB to the computer where I have to run the C/C++ program.
The problem is that it prints characters are they arrive and randomly, like this:
Sensor 0 F1 410nm : 0 F2 435nm : 272 F3 445nm : [ INFO] [1652193464.896782509]: Sensor 0 F1 410nm : 0 F2 435nm : 272 F3 445nm :
0 F4 460nm : 178 F5 480nm : 0 F6 515nm : 0 F7 53[ INFO] [1652193464.900888273]: 0 F4 460nm : 178 F5 480nm : 0 F6 515nm : 0 F7 53
5nm : 298 F8 555nm : 0 F9 590nm : 0 F10 610nm : 170 F11 630nm : 0 F12 645nm : 237 F13 680nm : 0 F14 715nm : 297 F15 730nm : 289 F16 780nm : 0 F17 860nm : 178 F18 940nm : 298;
while I would like to read all the characters till the ";" and then print the full string.
How can I do this in a smart way?
I can also format the string from Arduino by adding a character before each string, for example:
:String1_with_values;
in order to be able to know when the string starts and when it finishes.
Do you think it would be a good solution to improve it?
This is my current full code:
#include "ros/ros.h"
#include "std_msgs/String.h"
// C library headers
#include <iostream>
#include <stdio.h>
#include <string.h>
// Linux headers
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()
int main(int argc,char **argv) {
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);
// Open the serial port. Change device path as needed (currently set to an standard FTDI USB-UART cable type device)
int serial_port = open("/dev/ttyACM0", O_RDWR);
// Create new termios struc, we call it 'tty' for convention
struct termios tty;
// Read in existing settings, and handle any error
if(tcgetattr(serial_port, &tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return 1;
}
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size
tty.c_cflag |= CS8; // 8 bits per byte (most common)
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO; // Disable echo
tty.c_lflag &= ~ECHOE; // Disable erasure
tty.c_lflag &= ~ECHONL; // Disable new-line echo
tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
// tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)
tty.c_cc[VTIME] = 10; // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
tty.c_cc[VMIN] = 0;
// Set in/out baud rate to be 9600
cfsetispeed(&tty, B115200);
cfsetospeed(&tty, B115200);
// Save tty settings, also checking for error
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return 1;
}
unsigned char read_buf[800];
int count = 0;
while (ros::ok())
{
int n = read(serial_port, read_buf, sizeof(read_buf) - 1);
if (n < 0) {
/* handle errno condition */
return -1;
}
read_buf[n] = '\0';
std::cout << read_buf ;
std_msgs::String msg;
std::stringstream ss;
ss << read_buf;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
close(serial_port);
return 0; // success
}
The comment on your source says:
"// Wait for up to 1s (10 deciseconds), returning as soon as any data is received."
Since a transmission over a serial line takes some time, you will in most cases receive the message in multiple parts. (Look up "baudrate" to learn about transmission times.) How many characters one part contains, depends on many factors, and commonly you cannot foresee it.
Change your reading algorithm to a simple finite state machine that collects received characters until the end-of-message marker is received. A primitive solution would scan for it.

Methodology to debug tcdrain() blocking indefinitely

I'm sending packets from an Ubuntu machine to an STM32 autopilot through a USB cable using write() and tcdrain():
int Serial_port::_write_port(char* buff, unsigned int len) {
const std::lock_guard<std::mutex> lock(_mutex_write_on_port);
const int bytes_written = static_cast<int>(write(_fd,buff, len));
if(bytes_written<0) {
printf("write to port failed with errno: %s\n", std::strerror(errno));
}
//wait until all data has been written to the port
tcdrain(_fd);
return bytes_written;
}
After a few thousands packets successfully sent, tcdrain() randomly blocks. I'm trying to understand why.
Any recommendations on how to debug this?
I've done some research but couldn't come across a good debug methodology.
Note: I've noticed if I run a simple python command in another terminal ser = serial.Serial('/dev/ttySAC0') this "unfreezes" my code about 75% of the time but I'm kind of at a loss to understand why.
If that helps, here is how I configure the port:
int Serial_port::_config_port() {
//Config based on following sources:
//https://github.com/mavlink/c_uart_interface_example
//https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/
struct termios config;
if(tcgetattr(_fd, &config) < 0) {
return -1;
}
// Input flags - Turn off input processing
// convert break to null byte, no CR to NL translation,
// no NL to CR translation, don't mark parity errors or breaks
// no input parity check, don't strip high bit off,
// no XON/XOFF software flow control
config.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ISTRIP | IXON);
// Output flags - Turn off output processing
// no CR to NL translation, no NL to CR-NL translation,
// no NL to CR translation, no column 0 CR suppression,
// no Ctrl-D suppression, no fill characters, no case mapping,
// no local output processing
config.c_oflag &= ~(OCRNL | ONLCR | ONLRET | ONOCR | OFILL | OPOST);
// No line processing:
// echo off, echo newline off, canonical mode off,
// extended input processing off, signal chars off
config.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
// Turn off character processing
// clear current char size mask, no parity checking,
// no output processing, force 8 bit input
config.c_cflag &= ~(CSIZE | PARENB | CSTOPB); //~CSTOPB to set only 1 stop bit for multiflex
config.c_cflag |= CS8;
// One input byte is enough to return from read()
// Inter-character timer off
config.c_cc[VMIN] = 0; //DEBUG: this is different from mavlink recommended setup. Confirm this is ok
config.c_cc[VTIME] = 10;
//baudrate
if(cfsetispeed(&config,_baudrate)<0) return -1; //input baudrate
if(cfsetospeed(&config,_baudrate)<0) return -1; //output baudrate
//write config to port
if(tcsetattr(_fd,TCSAFLUSH,&config) < 0) {
return -1;
}
std::cout<<"port "<<_uart_name<< " configured successfully"<<std::endl;
return 0;
}

Canonical serial reading using terminos fail?

I am trying to read lines of datas comming from my arduino using serial.
My arduino code look like that : Serial3.print(Z, 2);Serial3.print(F(";"));Serial3.println(F("END\n"));
And this is my code to read the data on ubuntu :
void setup(){
//set up serial
tcgetattr(dueSerial, &port_options); // Get the current attributes of the Serial port
dueSerial = open("/dev/ttyUSB0", O_RDWR | O_NONBLOCK | O_NOCTTY | O_NDELAY);
if (dueSerial == -1) {
reportFailure("Could not open Arduino");
} else {
port_options.c_cflag &= ~PARENB; // Disables the Parity Enable bit(PARENB),So No Parity
port_options.c_cflag &= ~CSTOPB; // CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit
port_options.c_cflag &= ~CSIZE; // Clears the mask for setting the data size
port_options.c_cflag |= CS8; // Set the data bits = 8
port_options.c_cflag &= ~CRTSCTS; // No Hardware flow Control
port_options.c_cflag |= (CREAD | CLOCAL); // Enable receiver,Ignore Modem Control lines
port_options.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable XON/XOFF flow control both input & output
port_options.c_lflag &= ~(ECHO | ECHONL | IEXTEN | ISIG); // no echo
port_options.c_iflag |= ICANON; //Enable canonical
port_options.c_iflag |= ICRNL; //map CR to NL
//port_options.c_oflag &= ~OPOST; // No Output Processing
//port_options.c_lflag = 0; // enable raw input instead of canonical,
/*
initialize all control characters
default values can be found in /usr/include/termios.h, and are given
in the comments, but we don't need them here
*/
port_options.c_cc[VINTR] = 0; /* Ctrl-c */
port_options.c_cc[VQUIT] = 0; /* Ctrl-\ */
port_options.c_cc[VERASE] = 0; /* del */
port_options.c_cc[VKILL] = 0; /* # */
port_options.c_cc[VEOF] = 4; /* Ctrl-d */
port_options.c_cc[VTIME] = 0; /* inter-character timer unused */
port_options.c_cc[VMIN] = 0; /* blocking read until 1 character arrives */
port_options.c_cc[VSWTC] = 0; /* '\0' */
port_options.c_cc[VSTART] = 0; /* Ctrl-q */
port_options.c_cc[VSTOP] = 0; /* Ctrl-s */
port_options.c_cc[VSUSP] = 0; /* Ctrl-z */
port_options.c_cc[VEOL] = 0; /* '\0' */
port_options.c_cc[VREPRINT] = 0; /* Ctrl-r */
port_options.c_cc[VDISCARD] = 0; /* Ctrl-u */
port_options.c_cc[VWERASE] = 0; /* Ctrl-w */
port_options.c_cc[VLNEXT] = 0; /* Ctrl-v */
port_options.c_cc[VEOL2] = 0; /* '\0' */
cfsetispeed( & port_options, BAUDRATE); // Set Read Speed
cfsetospeed( & port_options, BAUDRATE); // Set Write Speed
tcflush(dueSerial, TCIFLUSH);
tcflush(dueSerial, TCIOFLUSH);
int att = tcsetattr(dueSerial, TCSANOW, & port_options);
if (att != 0) {
reportFailure("ERROR in Setting Arduino port attributes");
} else {
LOG_INFO("SERIAL DUE Port Good to Go");
}
}
}
void UART::tick() {
//Arduino msg = "IMU;LAX;LAY;LAZ;AVX;AVY;AVZ;AY;AP;AR;END"
// rx_buffer[0] = '0';
memset(&rx_buffer, '\0', sizeof(rx_buffer));
// tcflush(dueSerial, TCIOFLUSH);
rx_length = read(dueSerial, &rx_buffer,255);
if (rx_length < 0) {
LOG_INFO("Error reading");
}else{
LOG_INFO("Read %i bytes. Received message: %s", rx_length, rx_buffer);
}
}
But when I try this code I get many lines at a time so my output look like this :
2020-11-15 09:13:09.491 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp#87: Read 0 bytes. Received message:
2020-11-15 09:13:09.496 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp#87: Read 255 bytes. Received message: 0.01;0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;0.03;0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;0.03;0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;-0.02;0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.00;0.02;-0.02;-0.00;0.00;0.00;0.00;0.00;
2020-11-15 09:13:09.501 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp#87: Read 241 bytes. Received message: 0.00;END
IMU;-0.01;-0.02;-0.01;-0.00;0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;-0.01;-0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;0.03;-0.00;-0.00;0.00;0.00;0.00;0.00;END
IMU;-0.01;-0.02;0.03;0.00;0.00;0.00;0.00;0.00;0.00;END
2020-11-15 09:13:09.506 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp#87: Read 0 bytes. Received message:
2020-11-15 09:13:09.511 INFO packages/skeleton_pose_estimation/apps/usb/UART.cpp#87: Read 0 bytes. Received message:
But I want it to read only one line per read() function call.
I believe that I either set a wrong parameter making the conanical mode unused or maybe it's ignoring my \n and \r but don't know why....
Please help me to find why.
Thank you a ton !
But I want it to read only one line per read() function call. I believe that I either set a wrong parameter making the conanical mode unused ...
Your program does not behave as expected because canonical mode is never actually set.
The statement
port_options.c_iflag |= ICANON; //Enable canonical
is incorrect. ICANON is in the c_lflag member, and not in c_iflag.
Your code has additional issues.
(1) The variable dueSerial is used uninitialized:
void setup(){
//set up serial
tcgetattr(dueSerial, &port_options); // Get the current attributes of the Serial port
dueSerial = open(...);
...
The file descriptor needs to be obtained and validated before it can be used in the tcgetattr() call.
The proper ordering of statements is:
void setup(){
//set up serial
dueSerial = open(...);
if (dueSerial == -1) {
/* abort */
}
tcgetattr(dueSerial, &port_options);
...
(2) Numerous input conversions are left unspecified in your termios initialization.
Canonical mode enables various options to convert certain input characters, and most of these options need to be disabled for reading by a program (versus an interactive terminal).
Typically INPCK (enable input parity checking), IUCLC (map uppercase characters to lowercase), and IMAXBEL (ring bell when input queue is full) are disabled.
You need to review whether you also want IGNCR (preserve or ignore carriage return), INLCR (translate newline to carriage return), and ICRNL (translate carriage return to newline unless IGNCR is set) to also be disabled.
(3) Use of nonblocking mode is questionable.
Since you want "to read only one line per read() function call", then blocking mode is the proper way to obtain that result.
If you insist on using nonblocking mode, then the read() syscall will always return "immediately" and may not return any data at all.

Read 0 bytes after writing to /dev/ttyS0

I have been trying to perform serial communication on linux via the /dev/ttyS devices but when I try to read from them after writing I read no data.
I have the following code
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int main() {
printf("hello world\n");
int n;
int fd;
char c;
int bytes;
char buffer[10];
char *bufptr;
int nbytes;
int tries;
int x;
struct termios options;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
if(fd == -1) {
perror("open_port: Unable to open:");
} else
tcgetattr(fd, &options);
// Set the baudrate, same speed for both I/O
cfsetispeed(&options, B150);
cfsetospeed(&options, B150);
// Enable reading
options.c_cflag |= (CLOCAL | CREAD);
// Set 'RAW' mode
cfmakeraw(&options);
// Set byte size
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Set parity
// options.c_cflag &= ~PARENB;
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
// Set StopBits, #Linux no OneHalf is supproted, so OneHalf and Two are the same
options.c_cflag &= ~CSTOPB;
// Set Handshake options
// options.c_iflag |= CRTSCTS;
// options.c_iflag &= ~CRTSCTS;
// options.c_cflag &= ~( IXON | IXOFF | IXANY );
options.c_cflag |= IXON | IXOFF | IXANY;
// Set Timeouts
options.c_cc[VMIN] = 0; // read() will return after receiving character
options.c_cc[VTIME] = 10; // == 0 - infinite timeout, != 0 - sets timeout in deciseconds
tcsetattr(fd, TCSANOW, &options);
tcflush(fd, TCIOFLUSH);
bytes = write(fd, "ATZ\r",4);
printf(" wrote %d bytes\n", bytes);
bufptr = buffer;
bytes = read(fd, bufptr, sizeof(buffer));
printf("number of bytes read is %d\n", bytes);
perror ("read error:");
for (x = 0; x < 10 ; x++) {
c = buffer[x];
printf("%d ",c);
}
tcflush(fd, TCIOFLUSH);
close(fd);
printf("\n");
return (0);
}
The program output is as follows
hello world
wrote 4 bytes
number of bytes read is 0
read error:: Success
0 0 0 0 0 0 0 0 0 0
Although I expected it to read the 4 characters I just wrote it seems that read reads 0 bytes. In case i put VTIME to 0 then read blocks forever. I have tried to do echo /dev/ttyS0 but no output comes out. Any idea what might cause this and how can it be fixed?
Your code apparently is ok, except for the following facts:
You call perror("read error"); after calling printf(3), and not right after read(2) so the possible error (if happened) is masked to the call to read(2) by the call to printf(3). If you want to print the number of read characters, save the value of errno and the returned value from read(2) before calling printf(3), and then, if the returned error is neg, then call perror(3).
Anyway. The c_cc[VTIME] = 10 imposes a one second timeout, and this is too sort for resetting a modem. Your line settings are:
CS8, Parity ODD, one STOP bit, and 150 baudrate
Normally, modems answer to ATZ\r command after resetting, which takes some time (frequently more than a second) and in the default modem speed (because you have reset it) and not at the speed at which you have send the AT command.
Resetting a modem is, for this reason, done blindly normally, and then you send a simple AT\r command, in order to ask for an \r\nOK\r\n response. The answer to AT\r command is normally immediate, not as the response to a reset command, and lets the modem adjust its communication settings according to the received chars.
Modems always adapt their speed when the A and T sequence is received, by sampling the square pulses received at a high sampling frequency, then they switch speed to the detected and normally do speed conversion (making it possible to talk to the modem at a different speed than the negotiated remotely)

How to read temp from DS18B20 using UART board

I bought board like this now i want to connect temperature sensor to this board.
How to read temperature from sensor in c or c++?
I tried to write some code but it won't work. I connect DS18B20 data cabel directly to TXD and RXD pins.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <cstring>
#include <inttypes.h>
#include <errno.h>
int
set_interface_attribs (int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
std::cout<<"error "<<errno<<" from tcgetattr";
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // ignore break signal
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
std::cout<<"error "<<errno<<" from tcsetattr";
return -1;
}
return 0;
}
void
set_blocking (int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
std::cout<<"error "<<errno<<" from tggetattr";
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
std::cout<<"error "<<errno<<" setting term attributes";
}
int main()
{
char *portname = "/dev/ttyUSB0";
int tty_fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (tty_fd < 0)
{
std::cout<<"error "<<errno<<" opening "<<portname<<": "<< strerror (errno);
return -1;
}
set_interface_attribs (tty_fd, B9600, 0); // set speed to 115,200 bps, 8n1 (no parity)
set_blocking (tty_fd, true);
unsigned char c = 0xCC;
if(!write(tty_fd, &c, sizeof(c)))
std::cout<<"Write error";
sleep(2);
unsigned char buffer[8];
int size;
if((size = read(tty_fd, &buffer, 8)) < 0)
std::cout<<"Error";
else
std::cout<<"CC("<<size<<")='"<<buffer<<"'";
std::cout<<"\n";
c = 0x44;
if(!write(tty_fd, &c, sizeof(c)))
std::cout<<"Write error2";
c = 0xBE;
if(!write(tty_fd, &c, sizeof(c)))
std::cout<<"Write error2";
sleep(2);
if((size = read(tty_fd, &buffer, 8)) < 0)
std::cout<<"Error";
else
std::cout<<"BE("<<size<<")='"<<buffer<<"'";
std::cout<<"\n######################\n";
close(tty_fd);
}
I got:
CC(1)='Č#'
BE(2)='#ž#'
######################
CC(1)='Č#'
BE(2)='#ž#'
######################
CC(1)='Č#'
BE(2)='#ž#'
######################
Can you help me?
You can't do this with any software. The DS18B20 is electrically incompatible with the board you have. The sensor uses a 1-wire, open-collector communication scheme that is completely different from the serial protocol normally used with this board. With great difficulty you might be able to do some bit-banging of the RTS/CTS signals but you need circuitry to combine them into a bidirectional open-collector signal.
You can hack the UART to communicate with 1 wire protocol.
Connect Rx to Tx and add 4.7 pull-up resistor
See the application note from maxim:
http://www.maximintegrated.com/en/app-notes/index.mvp/id/214
As pointed out by user3804701, it's indeed possible to communicate with a 1-Wire device using a UART interface, and the application note at https://www.maximintegrated.com/en/app-notes/index.mvp/id/214 contains all the information needed to make it work.
But the OP's code needs several fixes:
Each transaction with DS18B20 is made of 3 steps: initialization (also called reset), ROM command and function command, optionally followed by a data exchange
The initialization or reset step is performed by configuring the UART with 9600 bps baud rate, transmitting 0x0F, and receiving a dummy byte; then, the baud rate must be set to 115200 bps to perform the next steps
Following the reset step, data is sent to DS18B20 by writing to the UART a 0xFF byte for each data bit set to 1, and a 0x00 byte for each bit set to 0, starting from the least significant bit; for example, to send 0xAB (i.e. 10101011), one would write to the UART the sequence (FF FF 00 FF 00 FF 00 FF); for each byte written to the UART, there is a "return byte" that needs to be read from the UART and discarded
Data is received from DS18B20 by sending the 0xFF byte following the rules in the previous bullet point, but instead of discarding the "return bytes" reading from the UART a byte for each data bit, starting from the least significant bit: a 0xFF value means that the bit value is 1, otherwise the bit value is 0; for example, the sequence (00 FF FF 00 FF 00 00 FF) read from the UART means that DS18B20 sent 0x96 (i.e. 10010110)
If there is just one DS18B20 connected to the 1-Wire bus, all transactions can use "skip ROM" (byte value 0xCC) as ROM command
The first transaction to be performed is the one that triggers a temperature conversion from DS18B20, with function command 0x44
After waiting for the conversion to complete (which can take up to 750 ms), the host can perform a second transaction to read the DS18B20 scratchpad memory (function command 0xBE); the scratchpad memory is 9 bytes long and contains among other things the temperature value
So in summary the steps needed to get a temperature sample from DS18B20 are: reset, write 0xCC, write 0x44, wait for conversion, reset, write 0xCC, write 0xBE, read 9 bytes.
Example code that implements this stuff is available at https://github.com/dword1511/onewire-over-uart.