I have some problems with a program in which I want to send via UART a variable that is a counter.
The goal is to see this counter on Matlab Simulink.
Actually what I'm able to see on Matlab is not what i want to see, because I just see the values of the Characters in ASCII (I mean the characters of the printf...see the code then).
while(1){
HAL_UART_Receive_IT(&huart2, &bufferRX, 1);
//Serial Stream Routine
if(streamActive == 1 && counter < MAX_VALUE) //RUNNING state: we start the counter and the transmission begin
{
if (dataReady == 1)
{
printf("The actual counter value is: %d \r\n", counter);
counter++;
dataReady = 0;
}
}
else
if(streamActive == 1 && counter >= MAX_VALUE){
counter = 0;
}
So, if I want to transmit and visualize on simulink just the actual value of the counter, what I have to write here?
I also implemented these functions in order to use the UART:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart2, &bufferRX, 1);
}
And this is for the printf:
int __io_putchar(int ch)
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, sizeof(ch), HAL_MAX_DELAY);
/* Loop until the end of transmission */
while (HAL_UART_GetState(&huart2) == HAL_UART_STATE_RESET) {
}
return ch;
}
Related
I am currently working on a project where i want to communicate with ESP8266 module using usart-1 and have another usart-2 which could be used in putty. My question is if there is any possibility to achieve this goal with HAL_UART_RxCpltCallback function? So far my all attempts to do so failed miserably and the best i could is creating communication where data can be send to esp but no answer can be captured. All my other attempts ended in creating a loop between usarts. Thank you in advance
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
uint8_t Data[50];
uint16_t size = 0;
size = sprintf(Data, "%c", Received);
if(Received != '\r' && Received != '\n')
{
RingBuffer_PutChar(&USART_RingBuffer_Tx, Received);
HAL_UART_Transmit_IT(&huart1, Data, size);
HAL_UART_Receive_IT(&huart1, &Received, 1);
}
else
{
if(Received == '\n')
{
//size = sprintf(Data, "\n\r", 2);
HAL_UART_Transmit_IT(&huart1,(uint8_t*) "\n\r", 2);
HAL_UART_Receive_IT(&huart1, &Received, 1);
}
if(Received == '\r')
{
if(!RingBuffer_IsEmpty(&USART_RingBuffer_Tx))
{
RingBuffer_PutChar(&USART_RingBuffer_Tx, '\r');
RingBuffer_PutChar(&USART_RingBuffer_Tx, '\n');
HAL_UART_Transmit_IT(&huart6, (uint8_t*) RingBufferData_Tx, sizeof(RingBufferData_Tx));
HAL_UART_Transmit_IT(&huart1, "\nSent\n\r", 12);
HAL_UART_Receive_IT(&huart6, &Received1, 1);
HAL_UART_Receive_IT(&huart1, &Received, 1);
RingBuffer_Clear(&USART_RingBuffer_Tx);
}
else
{
HAL_UART_Transmit_IT(&huart1,(uint8_t*) "Buffer is empty\n\r", 17);
HAL_UART_Receive_IT(&huart1, &Received, 1);
}
}
}
}
The HAL_UART_RxCpltCallback function has a parameter UART_HandleTypeDef *huart, so you can check which UART instance called this Callback.
You might check it whether it is usart-1 or usart-2 and execute the code according to this.
I am trying to figure out a nice solution to reading serial data, and what to do when a read() is done but it contains an incomplete message.
The expected messages between devices have a defined start and end byte so its easy to see when a message starts and ends.
I can open a serial port fine and read from the serial port. But I am encountering the computer is reading faster than data coming through and I get an incomplete message.
For this example, lets say the message expected is
0x10 0xFF 0xFF 0xFF 0xFF 0x11
With 0x10 the start, 0x11 the end, and 0xFF is the data bytes
I am new to C so I may be missing something obvious,
My current solution
int main() {
/* Ommited serial port opening and checking*/
char read_buffer[80];
char message_buffer[80];
int message_buffer_index = 0;
int start_index = -1;
int end_index = -1;
int read_bytes;
read_bytes = read(serial_port, read_buffer, sizeof(read_buffer) - 1);
/* Now lets say read_bytes returns 3 and read buffer is {0x10, 0xFF, 0xFF} */
/* What should I do with the read_buffer? Currently appending to message buffer*/
memcpy(&message_buffer[message_buffer_index], &read_buffer[0], read_bytes);
/* Now check the message buffer for a full message */
for (int i = 0; i < 80; i++) {
if (message_buffer[i] = 0x10) {
start_index = i;
continue;
}
if (message_buffer[i] = 0x11) {
end_index = i;
}
if (start_index != -1 && end_index != -1) {
/* Found a message, do something with it, not super important here */
process_message();
/* Now how to erase the full message from the
buffer and push any non processed data to the
front? */
remove_message();
}
}
}
int process_message();
int remove_message();
To minimize the overhead of making many read() syscalls of small byte counts (e.g. the misguided solution of reading a byte at a time), use an intermediate buffer in your code.
The read() of the serial terminal should be in blocking mode to avoid a return code of zero bytes.
#define BLEN 1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;
/* get a byte from intermediate buffer of serial terminal */
static unsigned char getbyte(void)
{
if ((rp - rbuf) >= bufcnt) {
/* buffer needs refill */
bufcnt = read(fd, rbuf, BLEN);
if (bufcnt <= 0) {
/* report error, then abort */
}
rp = rbuf;
}
return *rp++;
}
For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value or at least the length of longest expected message, and a VTIME of 1.
Now you can conveniently access the received data a byte at a time with minimal performance penalty.
#define MLEN 1024 /* choose appropriate value for message protocol */
int main()
{
unsigned char mesg[MLEN];
...
while (1) {
while (getbyte() != 0x10)
/* discard data until start found */ ;
length = 0;
while ((mesg[length] = getbyte()) != 0x11) {
/* accumulate data until end found */
length++;
}
/* process the message */
...
} /* loop for next message */
...
}
Note that your detection for a message frame is not robust.
If the data is binary and therefore can use the same values as these start and end bytes, then this parsing of the received data is prone to misaligned message frames.
See this answer for a description of a proper alogrithm.
You need circular buffer. Place data in the buffer and the process takes them when for example there is enough data or in any convenient moment.
Wikipedia has excellent article about it https://en.wikipedia.org/wiki/Circular_buffer
Better use stdio for reading, something like this:
FILE *fp = fdopen(serial_port, "r");
while (blabla) {
while (fgetc(fp) != 0x10)
; // wait until start
while ((c = fgetc(fp)) != 0x11)
message_buffer[message_buffer_index++] = c;
// here you have a complete message
}
Insert checks for EOF and errors if needed
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Greetins,
I recently bought a temperature & humidity sensor (aosong am2302). I hooked it to a rasp pi 3 and it works like charm with the adafruit library. The problem comes when i try to make it work on another board (described here). I used this library for gpio reading. I modified the file of beaglebone for gpio mapping and that's it. I run the tests and they work, so basically the lib looks like it works. So after that, I code the sensor reader and it doesnt work and I dont know why.
After I run the sensor reader, If I check the file system, the gpio is exported.
The sensor is installed like this:
-Power to 5V (also tried with 3.3v)
-VCC to gpio
-Ground to GND.
and here the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/wait.h>
#include <sys/time.h>
#include "libsoc_gpio.h" //library for gpio reading
#define MAXTIMINGS 10
#define SILENT 0
int bits[MAXTIMINGS+1],data[5];
int readDHT(int pin,int allowRetry);
int
main(int argc, char **argv)
{ int dhtpin;
if (argc>1)dhtpin=atoi(argv[1]);
else printf("Introduce pin");
if( SILENT < 1 ) {
printf("Using pin #%d\n", dhtpin);
}
readDHT(dhtpin,5);
return 0;
}
int
readDHT(int pin, int allowRetry)
{
int bitidx=0;
int counter = 0;
int i=0,j=0;
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
gpio *gpio_output = libsoc_gpio_request(pin, LS_SHARED); //export GPIO
if (gpio_output == NULL)
{
fprintf(stderr, "Failed to open GPIO %d\n", pin);
return -1;
}
libsoc_gpio_set_direction(gpio_output, OUTPUT);
if (libsoc_gpio_get_direction(gpio_output) != OUTPUT)
{
fprintf(stderr, "Failed to set direction to OUTPUT\n");
if (gpio_output)
{
libsoc_gpio_free(gpio_output);
}
return -1;
}
libsoc_gpio_set_level(gpio_output, LOW);
libsoc_gpio_set_level(gpio_output, HIGH);
libsoc_gpio_set_direction(gpio_output, INPUT);
/* Wait for pin to drop */
while (libsoc_gpio_get_level(gpio_output) == HIGH)
{
if(counter++>10000){
printf("ERROR: Pin never dropped\n");
return 1;
}
}
if (i<= MAXTIMINGS)
{
counter =0;
while (libsoc_gpio_get_level(gpio_output) == LOW){
if(counter++ == 1000)
break;
}
counter =0;
while(libsoc_gpio_get_level(gpio_output) == HIGH){
if (counter++==1000)
break;
}
bits[bitidx++] = counter;
i++;
}
/* read data */
for (i = 1; i < bitidx; i++) {
data[j / 8] <<= 1;
if(bits[i]>200){
data[j/8] |= 1;
}
j++;
}
if( SILENT < 1 ) {
printf("Data (%d): 0x%x 0x%x 0x%x 0x%x 0x%x\n", j, data[0], data[1], data[2], data[3], data[4]);
}
if ((j >= 39) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
float f, h;
h = data[0] * 256 + data[1];
h /= 10;
f = (data[2] & 0x7F)* 256 + data[3];
f /= 10.0;
if (data[2] & 0x80) f *= -1;
printf("CTemp: %.1f\nFTemp: %.1f\nHum: %.1f%\n", f, ((f*9)/5)+32, h);
} else if( allowRetry > 0 ) {
sleep(1);
if( SILENT < 1 ) {
printf( "Error getting information. Retrying\n" );
}
return readDHT(pin, --allowRetry );
} else {
if( SILENT < 1 ) {
printf( "Error getting information. Retries exhausted.\n" );
}
return 1;
}
return 0;
if (gpio_output)
{
libsoc_gpio_free(gpio_output);
}
/* Check we got all the data and checksum matches */
}
With this code I get "Pin never dropped", so pin never goes to 0 so it doesnt report data. So i decided to try with bash and see if pin drops to 0. I coded the same as on the previous code but in bash and see the value of the pin (always 1, not dropping). Comming to this point, I run out of options, the sensor works (it's not broken), the library works but the sensor on this machine no. Any clue or idea on how to approach to find a solution?
Thanks :)
Some things to try that might get you going....
First increase the counter "counter++>10000" to something much larger, It could be that the new processor you are running increments the counter at a much faster rate and you just timeout before the pin drops.
If that doesn't work remove the timeout counter and loop forever in your source, also remove the sensor, then physically pull the data line to ground with a piece of wire and see if your code/new processor catches the signal change, at least then you know your source/hardware is configured correctly so you can focus your efforts elsewhere.
Double check the voltage compatibility between your new processor 'high' level and what the sensors 'high' threshold is to ensure it is catching a 'one' on the data line.
Lettus know how you go!
Tony
this program is to receive and then send data through serial port.
After setting up serial, read a byte from serial(i'm using a tool called putty to send chars), if it is a 'a', read 16byte from a file and then send to serial, and then reads a 'b', and goes on to lettle 'p'. total 16 loops.
but now, i can have the first two loops work, when it comes to the third loop, after readfile(), the readBuff is 50h, while it is what it reads from serial for the first 2 loops, like 'a', 'b'.
it always fails at the 3rd loop.
it is weird, does someone have a clue?
hSerial = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
);
if(hSerial==INVALID_HANDLE_VALUE){
if(GetLastError()==ERROR_FILE_NOT_FOUND){
printf("create serial handle file failed!-1");
return 0;
}
printf("create serial handle file failed!-2");
return 0;
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
dcbSerialParams.fBinary = TRUE;
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams)){
printf("set serial state failed");
return 0;
}
COMMTIMEOUTS cmt;
cmt.ReadIntervalTimeout = 1;
cmt.ReadTotalTimeoutMultiplier = 100000000;
cmt.ReadTotalTimeoutConstant = 100000000;
cmt.WriteTotalTimeoutConstant = 10;
cmt.WriteTotalTimeoutConstant = 10;
if(!SetCommTimeouts(hSerial, &cmt)){
printf("set timeout failed");
return 0;
}
char readBuff; //read 1 byte from serial which indicate the send loop
DWORD dwBytesRead; //number of bytes read from binary
char writeBuff[16]; /*read 16bytes from spd binary to write to serial */
DWORD dwBytesWrite; /*stores actual number of bytes writen*/
for(int i = 0; i<=15; i++){
//initial the variables to 0 incase some weird behavior
readBuff = 0;
dwBytesRead = 0;
dwBytesWrite = 0;
for(int j=0; j<=15; j++)
writeBuff[j] = 0;
if(!ReadFile(hSerial, &readBuff, 1 , &dwBytesRead, NULL)){
if(dwBytesRead != 1){
printf("read failed, please check!\n");
return 0;
}
}
//when it comes to the 3rd loop, readfile() reads a 50h, even if i didn't send anything to serial line.
if(readBuff != ('a' + i)){
printf("failed the %dth loop\n", i);
return 0;
}
else{
//read spd binary then puts to serial
if(fread(writeBuff, 1, 16, file) != 16){
printf("read binary failed, please check!\n");
return 0;
}
//send to serial
if(!WriteFile(hSerial, writeBuff, 16, &dwBytesWrite, NULL)){
if(dwBytesWrite != 16){
printf("write to serial failed, please check!\n");
return 0;
}
}
printf("%c", readBuff);
}
}//end of for loop
If ReadFile fails you need to read again until you have found some valid data. But instead, you check dwBytesRead and makes the decision to continue based on what's in that variable. When ReadFile fails, I wouldn't trust dwBytesRead to contain a valid value. Suppose the UART read 1 byte but got an overrun/framing error?
Change the program to
while(!ReadFile(...))
;
Am I not leaving my signal handler function in the correct way? It does not seem to return to the program normally. Instead it goes into the loop and where it should wait for user input, it skips and reads the length of the "user input" to -1 and errors out. (Will make more sense in code.)
void handle_SIGINT() {
int k = recent;
int count = 0;
int stop;
if (stringSize >= 10) {
stop = 10;
}
else {
stop = p;
}
printf("\nCommand History:\n");
for (count = 0; count < stop; count++) {
if (k < 0) {
k += 10;
}
printf("%s", string[abs(k)]);
k -= 1;
}
}
void setup(char inputBuffer[], char *args[],int *background)
{
//char inputBuffer[MAX_LINE];
int length, /* # of characters in the command line */
i, /* loop index for accessing inputBuffer array */
start, /* index where beginning of next command parameter is */
ct; /* index of where to place the next parameter into args[] */
int add = 1;
ct = 0;
/* read what the user enters on the command line */
length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
printf("%i",length);
start = -1;
if (length == 0)
exit(0); /* ^d was entered, end of user command stream */
if (length < 0){
perror("error reading the commanddddddddd");
exit(-1); /* terminate with error code of -1 */
}
}
int main(void)
{
char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
int background; /* equals 1 if a command is followed by '&' */
char *args[MAX_LINE/2+1];/* command line (of 80) has max of 40 arguments */
FILE *inFile = fopen("pateljay.history", "r");
if (inFile != NULL) {
int count = 0;
char line[MAX_LINE];
while (fgets(line,sizeof line, inFile) != NULL) {
string[count] = strdup(line);
//string[count][strlen(line)] = '\n';
//string[count][strlen(line) + 1] = '\0';
printf("%s", string[count]);
count++;
stringSize++;
}
p = count % 10;
recent = abs(p - 1);
}
fclose(inFile);
/* set up the signal handler */
struct sigaction handler;
handler.sa_handler = handle_SIGINT;
sigaction(SIGINT, &handler, NULL);
while (1) {/* Program terminates normally inside setup */
background = 0;
printf("COMMAND->");
fflush(0);
setup(inputBuffer, args, &background);/* get next command */
}
}
So when ctrl+c is entered it should catch the signal and handle it. Once it returns back to main, it goes into setup and completely skips the read function and makes length equal to -1. This in turn errors out the program. I think the code inside handle_SIGINT is irrelevant as it is right now. Does anyone know any reason why it would be skipping the read function in setup?
read is blocking, waiting for input. SIGINT arrives. The kernel calls your signal handler. When your signal handler returns, the kernel makes read return -1 and set errno to EINTR. You need to check for this case and handle it by calling read again:
do {
length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
} while (length == -1 && errno == EINTR);
The signal handler is supposed to take an int argument:
void handle_sigint(int signum) {}