How to receive a string properly from UART - c

I sending a string like this:
$13,-14,283,4,-4,17,6,-240,-180#
But is not showing up because the buffer is 'overloading', how can I receive the whole string or how can I clear it after each byte read?
// get a character string
char *getsU2(char *s, int len) {
char *p = s; // copy the buffer pointer
do {
*s = getU2(); // get a new character
if (( *s=='\r') || (*s=='\n')) // end of line...
break; // end the loop s++;
// increment the buffer pointer
len--;
} while (len>1); // until buffer is full
*s = '\0'; // null terminate the string
return p; // return buffer pointer
}
// get a character string
char *getsU2(char *s, int len) {
char *p = s; // copy the buffer pointer
do {
*s = getU2(); // get a new character
if (( *s=='\r') || (*s=='\n')) // end of line...
break; // end the loop
s++;
// increment the buffer pointer
len--;
} while (len>1); // until buffer is full
*s = '\0'; // null terminate the string
return p; // return buffer pointer
}
char getU2(void) {
if(U2STAbits.OERR == 1)
{ U2STAbits.OERR = 0; }
while (!U2STAbits.URXDA); // wait for new character to arrive return U2RXREG;
// read character from the receive buffer }
getsU2(buffer,sizeof(buffer));

Try using the UART receive interrupt. Code below is for a PIC24H; modify appropriately.
In your init function:
IFS0bits.U1RXIF = 0; // clear rx interrupt flag
IFS0bits.U1TXIF = 0; // clear tx interrupt flag
IEC0bits.U1RXIE = 1; // enable Rx interrupts
IPC2bits.U1RXIP = 1;
IEC0bits.U1TXIE = 1; // enable tx interrupts
IPC3bits.U1TXIP = 1;
Create an interrupt handler that places the bytes into a buffer or queue:
void __attribute__((__interrupt__, auto_psv)) _U1RXInterrupt(void)
{
char bReceived;
// Receive Data Ready
// there is a 4 byte hardware Rx fifo, so we must be sure to get all read bytes
while (U1STAbits.URXDA)
{
bReceived = U1RXREG;
// only usethe data if there was no error
if ((U1STAbits.PERR == 0) && (U1STAbits.FERR == 0))
{
// Put your data into a queue
FIFOPut(bReceived);
}
}
IFS0bits.U1RXIF = 0; // clear rx interrupt flag
}
Your queue code is along these lines:
#define FIFO_SIZE 64
char pbBuffer[FIFO_SIZE];
char *pbPut;
char *pbGet;
void FIFOInit(void)
{
pbPut = pbBuffer;
pbGet = pbBuffer;
}
void FIFOPut(char bInput)
{
*pbPut = bInput;
pbPut++;
if (pbPut >= (pbBuffer + FIFO_SIZE))
pbPut = pbBuffer;
}
char FIFOGet(void)
{
char bReturn;
bReturn = *pbGet;
pbGet++;
if (pbGet>= (pbBuffer + FIFO_SIZE))
pbGet= pbBuffer;
}
Obviously, one should beef up the FIFO functions to prevent overflow, return errors on an empty queue, etc.

Related

How to send and receive data through UART between two Arduino Unos

I have been working through this problem for quite some time now and have succeeded in getting a partial mark. I would like to know what is wrong with the code that I have, that is preventing me from succeeding under certain conditions
I need one arduino to communicate with another one by sending a string of characters. So far I have succeeded in sending and receiving some data but think that I may be having an issue with the buffer I have set up in my uart_receive_string() function. I will provide all of the necessary information and code needed in order to test this, just let me know if any more info is required and Ill be happy to provide.
Here is a link to the tinkercad driver: https://www.tinkercad.com/things/eUZqkaIHp6J
Just click "Copy and Tinker" and hit the code button up top in order to paste the below code into it. You will need to paste the code into both ardunios by selecting them via the drop down box.
This is the criteria for the question I am working on:
This is the output I should receive in the test driver provided:
Here is the current code that I have implemented:
It is what needs to be copied into tinkercad for both arduino's
#include <stdint.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void uart_putbyte(unsigned char data);
int uart_getbyte(unsigned char *buffer);
/*
** Define a function named uart_send_string which transmits the contents of
** a standard C string (i.e. a null-terminated char array) over UART. The
** function should iterate over the characters in the array, using a cast to
** convert each to an unsigned char, and transmitting the resulting byte via
** uart_putbyte. The end of the string should be signalled by sending a single
** null byte. That is, the number 0, not the character '0'.
**
** Param: str - string to be transmitted.
**
** Returns: Nothing.
*/
// vvvvvvv I need help with this vvvvvvv
void uart_send_string(char str[])
{
int i = 0;
char ch;
do{
ch = str[i];
uart_putbyte(ch);
i++;
}while(ch != '\0');
}
/*
** Define a function named uart_receive_string which uses uart_getbyte to fetch
** the contents of a standard C string (i.e. a null-terminated char array)
** from UART. The function should wait for characters, and must not return
** until a complete string has been retrieved.
**
** Note that uart_getbyte will return 1 if a byte is available, and zero
** otherwise. Therefore, to fetch a byte and store it in a variable named x,
** you will need to use a construct of the form:
** unsigned char x;
** while (! uart_getbyte(&x)) {
** // Do nothing.
** }
**
** Param: buffer - a char array which has capacity to store a string
** containing at most (buff_len-1) characters. If more than (buff_len-1)
** characters are received, the first (buff_len-1) of them should be
** stored consecutively in the buffer, and any others discarded. The
** string must be terminated correctly with a null terminator in all
** circumstances.
**
** Param: buff_len - an int which specifies the capacity of the buffer.
**
** Returns: Nothing. However, up to buff_len elements of buffer may have been
** overwritten by incoming data.
*/
//vvvvvvv I need help with this vvvvvvv
void uart_receive_string(char buffer[], int buff_len)
{
int i = 0;
unsigned char ch;
while(!uart_getbyte(&ch))
{
if(ch == 0)
{
break;
}
if(i < buff_len-1)
{
ch = buffer[i];
uart_putbyte(ch);
i++;
}
}
buffer[i]=0;
}
/*
***************************************************************************
** Initialise UART.
***************************************************************************
*/
void uart_init(void) {
UBRR0 = F_CPU / 16 / 9600 - 1;
UCSR0A = 0;
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (3 << UCSZ00);
}
/*
**************************************************************************
** Send one byte, protecting against overrun in the transmit buffer.
**
** Param: data - a byte to be transmitted.
**
** Returns: Nothing.
***************************************************************************
*/
#ifndef __AMS__
void uart_putbyte(unsigned char data) {
// Wait for empty transmit buffer
while (!(UCSR0A & (1 << UDRE0)));
// Send data by assigning into UDR0
UDR0 = data;
}
#endif
/*
***************************************************************************
** Attempt to receive one byte, returning immediately to sender.
**
** Param: buffer - the address of a byte in which a result may be stored.
**
** Returns: If a byte is available returns 1 and stores the incoming byte in
** location referenced by buffer. Otherwise returns 0 and makes no other
** change to the state.
***************************************************************************
*/
#ifndef __AMS__
int uart_getbyte(unsigned char *buffer) {
// If receive buffer contains data...
if (UCSR0A & (1 << RXC0)) {
// Copy received byte from UDR0 into memory location (*buffer)
*buffer = UDR0;
//
return 1;
}
else {
return 0;
}
}
#endif
/*
***************************************************************************
** Implement main event loop.
***************************************************************************
*/
void process() {
// Use two devices, as indicated in the supplied TinkerCad model. One
// device acts as the sender (is_sender = 1), the other as receiver
// (is_sender = 0). Change this to set the role accordingly.
const int is_sender = 1;
if (is_sender) {
static char * messages_to_send[] = {
"", // Empty string
"A", // String with one symbol.
"Hello from CAB202!", // Multiple symbols
"1234567890abcdefghijklmnopqrstuvwxyz", // Longer than buffer size.
NULL, // End of list
};
static int next_message = 0;
uart_send_string(messages_to_send[next_message]);
next_message ++;
if (messages_to_send[next_message] == NULL) next_message = 0;
_delay_ms(300);
}
else {
#define BUFF_SIZE 20
char buffer[BUFF_SIZE];
uart_receive_string(buffer, BUFF_SIZE);
uart_send_string(buffer);
uart_putbyte('\r');
uart_putbyte('\n');
}
}
int main(void) {
uart_init();
while (1) {
process();
}
return 0;
}
The areas of this code that I am required to work on are these:
This is needed to send the data:
void uart_send_string(char str[])
{
int i = 0;
char ch;
do{
ch = str[i];
uart_putbyte(ch);
i++;
}while(ch != '\0');
}
This is needed to receive the data:
void uart_receive_string(char buffer[], int buff_len)
{
int i = 0;
unsigned char ch;
while(!uart_getbyte(&ch))
{
if(ch == 0)
{
break;
}
if(i < buff_len-1)
{
ch = buffer[i];
uart_putbyte(ch);
i++;
}
}
buffer[i]=0;
}
I am really sorry if this is hard to understand. Ill do my best to clarify any additional information that is needed. I just need to figure out what I am doing incorrectly.

Crash when reading const* in c on ESP8266

I'm making a system that reads sensor value from Arduino Uno through SoftwareSerial and publishes it via MQTT. However, the problem I'm facing I think is more general, I must admit I am new to c.
I'm reading the data, and splitting it into two const* variables that are defined on the top of my program.
When I read back the saved "data" and "topic" variable that I have parsed from the Serial connection, I only get garbage output, and usually a crash that restarts the device.
It prints them successfully inside the read-from-serial function, but it can't be correctly read later. Can it have something to do with how the data is saved? Can I explicitly allocate some memory for the variables?
I'm using a ESP8266 (ESP07) chip with lowered baud rate and proper voltage supply. It seems to be running well and stable.
#include <StringSplitter.h>
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <time.h>
//const char* ssid = "xxxx";
//const char* password = "xxxx";
const char* ssid = "xxxx";
const char* password = "xxxx";
const char* mqttServer = "xxxx;
const int mqttPort = xxxx;
const char* mqttUser = "xxxx";
const char* mqttPassword = "xxxx";
int timezone = 1;
int dst = 0;
The data is stored here:
char* data;
char* topic;
boolean newData = false;
boolean unpublishedData = false;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(19200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
configTime(timezone * 3600, dst * 0, "pool.ntp.org", "time.nist.gov");
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
while (!client.connected()) {
Serial.println("Connecting to MQTT...");
if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
// wait and determine if we have a valid time from the network.
time_t now = time(nullptr);
Serial.print("Waiting for network time.");
while (now <= 1500000000) {
Serial.print(".");
delay(300); // allow a few seconds to connect to network time.
now = time(nullptr);
}
}
Serial.println("");
time_t now = time(nullptr);
Serial.println(ctime(&now));
String datatext = "val: ";
String timetext = ", time: ";
String dataToBeSent = "test";
String timeToBeSent = ctime(&now);
String publishString = datatext + dataToBeSent + timetext + timeToBeSent;
Serial.println("Attempting to publish: " + publishString);
client.publish("trykk/sensor0", (char*) publishString.c_str());
client.subscribe("trykk/sensor0");
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void loop() {
client.loop();
recvWithStartEndMarkers();
showNewData();
publishReceived();
}
void publishReceived() {
if (unpublishedData) {
Serial.println("Hello from inside the publisher loop!");
time_t now = time(nullptr);
char* timeNow = ctime(&now);
It fails here, reading the data:
char publishText[30]; //TODO: make it JSON
strcpy( publishText, data );
strcat( publishText, " " );
strcat( publishText, timeNow );
Serial.print("publishText: ");
Serial.println(publishText);
Serial.print("topic: ");
Serial.println(topic);
client.publish(topic, publishText);
client.subscribe(topic);
unpublishedData = false;
} else if (!data) {
Serial.println("No data saved to array.");
} else if (!topic) {
Serial.println("No topic saved to array.");
}
}
void recvWithStartEndMarkers() {
int numChars = 32;
char receivedChars[numChars];
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
if (Serial.available() > 0) {
Serial.println("Hello from inside the receive loop!");
delay(100);
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
Serial.println("Reading from data line.");
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
Serial.println("Found the end marker.");
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
unpublishedData = true;
This part prints the values correctly back to me:
//Split the string
Serial.print("ESP debug: read: ");
Serial.println(receivedChars);
const char s[2] = ":";
*data = strtok(receivedChars, s);
Serial.print(data);
Serial.print(" ");
*topic = strtok(NULL, s);
Serial.println(topic);
}
}
else if (rc == startMarker) {
recvInProgress = true;
Serial.println("Found start marker");
}
}
}
}
//This is gutted as it gave me problems reading the variables
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.print("Topic: ");
Serial.print("stuff");
Serial.print(", data: ");
Serial.println("more stuff");
newData = false;
}
}
From your code :
char* data;
...
*data = strtok(receivedChars, s);
strtok return a char* but you do *data = strtok(...) while data is itself a (non initialized) char *, this is non consistent, and you have a first 'chance' to have a crash because you write at a random address.
If you do not have the crash and your program can continue data is not modified by itself and stay uninitialized.
In
strcpy( publishText, data );
...
Serial.print(data);
When you use data as a char* doing Serial.print(data); and strcpy( publishText, data ); you read from a random (and certainly invalid) address, producing your crash.
To correct just replace *data = strtok(receivedChars, s); by data = strtok(receivedChars, s);
After fixing the assignment of strtok's result to data as shown in bruno's answer there is another bug that can lead to a crash.
Your function loop() calls recvWithStartEndMarkers() first, then publishReceived().
void loop() {
client.loop();
recvWithStartEndMarkers();
showNewData();
publishReceived();
}
In function recvWithStartEndMarkers you read some data into a local array receivedChars, feed this into strtok and write a pointer returned from strtok to a global variable data.
void recvWithStartEndMarkers() {
int numChars = 32;
char receivedChars[numChars]; /* this is a local variable with automatic storage */
/* ... */
while (Serial.available() > 0 && newData == false) {
/* ... */
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
/* ... */
receivedChars[ndx] = '\0'; // terminate the string
/* Now there is a terminated string in the local variable */
/* ... */
//Split the string
/* ... */
const char s[2] = ":";
data = strtok(receivedChars, s); /* strtok modifies the input in receivedChars and returns a pointer to parts of this array. */
/* ... */
}
After leaving the function the memory that was receivedChars is no longer valid. This means data will point to this invalid memory on the stack.
Later you want to access the global variable data in a function publishReceived(). Accessing this memory is is unspecified behavior. You may still get the data, you may get something else or your program may crash.
void publishReceived() {
/* ... */
char publishText[30]; //TODO: make it JSON
strcpy( publishText, data ); /* This will try to copy whatever is now in the memory that was part of receivedChars inside recvWithStartEndMarkers() but may now contain something else, e.g. local data of function publishReceived(). */
/* ... */
To fix this you could use strdup in recvWithStartEndMarkers():
data = strtok(receivedChars, s);
if(data != NULL) data = strdup(data);
Then you have to free(data) somewhere when you no longer need the data or before calling recvWithStartEndMarkers() again.
Or make data an array and use strncpy in recvWithStartEndMarkers().

recv all socket (until the message end symbol), C

I want to write a recvall function for socket in C. I assume, that every message in my protocol ends with \r\n. I wrote something like this below:
int recvall (int socket, char *buffer, int numBytes)
{
int bytesRcvd = 0;
numBytes = numBytes - 1;
while(bytesRcvd < numBytes)
{
int chunk = recv(socket, buffer + bytesRcvd, numBytes - bytesRcvd, 0);
if (chunk == 0 || chunk == -1)
break;
if(strstr(buffer, "\r\n"))
break;
bytesRcvd += (chunk);
}
buffer[bytesRcvd] = '\0';
return bytesRcvd;
}
But it shows me that it returns and reads 0 bytes. On the other hand, when I remove:
if(strstr(buffer, "\r\n"))
break;
it hangs. How to improve it?
One mistake here is that strstr expects a zero-terminated string. A fix:
buffer[chunk] = 0;
if(strstr(buffer, "\r\n"))
break;
However, there may be more data following "\r\n", and that data gets lost here.
A common design pattern for receiving data is:
Have a class that maintains a connection with send/receive buffers.
When it has received data into the receive buffer, it calls a message parsing callback passing buffer and buffer_size.
The message parsing callback consumes all available complete messages in the buffer and returns the number of bytes consumed (as you do).
The message parsing callback calls another callback, passing a complete message to it.
Something like this:
typedef struct
{
int socket;
// Message-parsing callback.
size_t(*on_recv_cb)(void*, void*, size_t);
void* on_recv_cb_data;
unsigned char recv_buffer[256 * 1024];
size_t recv_buffer_size; // Initialized with 0;
} Connection;
void Connection_on_socket_ready_for_read(Connection* self) {
// Assumes a non-blocking socket. Read once to avoid starvation of other sockets.
ssize_t received = read(self->socket, self->recv_buffer + self->recv_buffer_size, sizeof self->recv_buffer - self->recv_buffer_size);
if(received > 0) {
self->recv_buffer_size += received;
size_t consumed = self->on_recv_cb(self->on_recv_cb_data, self->recv_buffer, self->recv_buffer_size);
self->recv_buffer_size -= consumed;
memmove(self->on_recv_cb_data, self->recv_buffer + consumed, self->recv_buffer_size);
}
else if(received < 0) {
if(EAGAIN == errno)
return;
perror("error");
// Handle error.
}
else {
// Handle EOF.
}
}
typedef struct {
// Message callback.
void(*on_message_cb)(void*, char*, size_t);
void* on_message_cb_data;
} MessageParserCrLf;
size_t MessageParserCrLf_on_recv(void* cb_data, void* data, size_t data_size) {
MessageParserCrLf* self = cb_data;
char* message_begin = data;
char* message_end = data;
while(data_size - (message_end - (char*)data) >= 2) {
if(message_end[0] == '\r' && message_end[1] == '\n') {
message_end += 2;
self->on_message_cb(self->on_message_cb_data, message_begin, message_end - message_begin);
message_begin = message_end;
}
else {
++message_end;
}
}
return message_begin - (char*)data;
}
void on_message(void* cb_data, char* message, size_t message_size) {
(void)cb_data; // Unused here.
printf("on_message: %.*s\n", (int)message_size, message);
}
int main() {
MessageParserCrLf message_parser = {on_message, NULL};
Connection connection = {0, MessageParserCrLf_on_recv, &message_parser, {}, 0};
Connection_on_socket_ready_for_read(&connection);
}
Outputs:
[~/src/test]$ cat lines.txt
abc
def
end
[~/src/test]$ ./test < lines.txt
on_message: abc
on_message: def
on_message: end
If there is "\r\n" in the received buffer, the following line will break and end the while loop,
if(strstr(buffer, "\r\n")) break;
but bytesRcvd hasn't increased, so the function will return with bytesRcvd=0.
Try to put bytesRcvd increase before judging like this,
bytesRcvd += (chunk);
if(strstr(buffer, "\r\n"))
break;

Array of Chars as Queue in C

I'm coding a piece of code for AVR. I want to build a queue that can push and pop, and this queue is an array of chars (string). So when I push 'a':
['b', 'c', 'd', 'e', 'f']
becomes:
['a','b', 'c', 'd', 'e', 'f']
and when I pop, f comes out. I've written this code, but it only pushes 1 char to the queue, as if it removes the whole queue. Here's my code for the queue:
char queue[50] = "";
char* queue_tail = &queue[0];
char* queue_head = &queue[0];
void queue_push(char l_item)
{
if(queue_head != &queue[strlen(queue) - 1]) //if queue is not full, do the job
{
//Push all elements one step further
char* traveler = queue_head;
for(; traveler != queue_tail; --traveler)
{
*(traveler+1) = *traveler;
*traveler = '';
}
++queue_head;
*queue_tail = l_item;
}
}
char queue_pop()
{
char temp = *queue_head;
*queue_head = '';
--queue_head;
return temp;
}
This is my main function:
#include <mega32.h>
#include <alcd.h>
#include <delay.h>
#include <string.h>
void main(void)
{
const char text[] = "Hello world!";
int col_counter = 0;
char* p_head = '';
lcd_init(32);
p_head = &text[12];
while(1)
{
lcd_clear();
if(col_counter + strlen(text) > 32)
{
queue_push(*p_head);
--p_head;
}
lcd_gotoxy(col_counter, 0);
lcd_puts(text);
lcd_gotoxy(0,0);
lcd_puts(queue);
delay_ms(200);
++col_counter;
}
}
Any help would be appreciated. Thanks in advance.
I changed the meaning of queue_head from the last element to one past the last element in the queue, and adjusted the code.
Here is a corrected code (main() in this code is a test code for usual PC):
#include <stdio.h>
char queue[50] = "";
char* queue_tail = &queue[0];
char* queue_head = &queue[0];
void queue_push(char l_item)
{
if(queue_head != queue + sizeof(queue)/sizeof(*queue)) //if queue is not full, do the job
{
//Push all elements one step further
char* traveler = queue_head;
for(; traveler != queue_tail; --traveler)
{
*traveler = *(traveler - 1);
}
++queue_head;
*queue_tail = l_item;
}
}
char queue_pop(void)
{
char temp;
if (queue_head == queue_tail) return '\0'; // the queue is empty
--queue_head;
temp = *queue_head;
*queue_head = '\0';
return temp;
}
int main(void) {
queue_push(100);
queue_push(110);
printf("%d\n",queue_pop());
printf("%d\n",queue_pop());
return 0;
}
Proposal for a circular buffer implementation (obviating the need to copy the buffer's content to and fro):
char queue[50] = "";
char* queue_tail = &queue[0];
char* queue_head = &queue[0];
#define END_OF_QUEUE (&queue[sizeof(queue)/sizeof(*queue)]) // The first element _after_ the buffer.
#define QUEUE_NOT_FULL 0
#define QUEUE_IS_FULL 1
uint8_t queueState;
void queue_push(const char l_item)
{
// 0) Addition is always modulus buffer size (50)
// 1) head points to the next empty location which can store an incoming byte
// 2) tail points to the next location from where a byte may be read
// 3) Queue is empty iff tail == head && queueState == QUEUE_NOT_FULL
// 4) Queue is full iff tail == head && queueState == QUEUE_IS_FULL
if ( queueState == QUEUE_NOT_FULL ) {
// Store item to the current head:
*queue_head = l_item;
// Advance head by one:
queue_head++;
if ( queue_head == END_OF_QUEUE ) {
// head passed the end of buffer -> continue at the start:
queue_head = &queue[0];
}
// If head meets tail after appending the new element, the buffer is now full.
if ( queue_head == queue_tail ) {
queueState = QUEUE_IS_FULL;
}
} else {
// Buffer overflow! - Options: Ignore new data, overwrite old data, wait until not full, signal an error somehow.
}
}
char queue_pop()
{
if ( (queue_tail == queue_head) && (queueState == QUEUE_NOT_FULL) ) {
// Queue is empty. "Buffer underflow." - Options: Return dummy value, wait until data available, signal an error somehow.
return '\0';
} else {
const char result = *queue_tail;
queue_tail++;
if ( queue_tail == END_OF_QUEUE ) {
// tail passed the end of buffer -> continue at the start:
queue_tail = &queue[0];
}
// We just removed an element from the queue, so the queue cannot be full now even if it was full a moment ago.
queueState = QUEUE_NOT_FULL;
return result;
}
}
(Note that, without further synchronization elements, this code will not work correctly when running concurrently, i.e. when accessing the buffer (read or write) from within an ISR.)

comparing array of strings

#include<reg51.h>
#include<string.h>
#include"_LCD_R8C.c"
unsigned char c[12];
unsigned char chr[11];
void serial_int (void) interrupt 4
{
if (RI==1)
{
chr[11] = SBUF;
RI = 0;
TI = 0;
}
}
int main()
{
unsigned char a[2][11]={"$0016221826","$0123456789"};
int i,j;
lcd_init();
lcd_clear();
SCON = 0x50;
TMOD = 0x20;
TH1 = 0xFD;
ET0 = 0;
TR1 = 1;
RI = 1;
ES = 1;
EA = 1;
for(j=0;j<1;j++)
{
for(i=0;i<=10;i++)
{
c[i]=chr[i];
}
c[11]='\0';
}
for(i=0;i<=1;i++)
{
j=strcmp(a[i],c); /* !!! Here is the problem !!! */
if(j==0)
{
lcd_printxy(1,1,"yes");
}
else
{
lcd_printxy(1,6,"no");
}
}
}
I am getting the display as "no", please let me know what is the problem?
the problem might be
1) the received array of characters are not converted to string, or
2) the received array of characters are converted to string but not able to compare with the available string..
please go through the program
One obvious bug for starters - change:
unsigned char a[2][11]={"$0016221826","$0123456789"};
to:
unsigned char a[2][12]={"$0016221826","$0123456789"};
(You need to allow room for the terminating '\0' in each string - I'm surprised your compiler didn't complain about this ?)
Also, this line in your interrupt handler is wrong:
chr[11] = SBUF;
Several problems with this - char only has storage for 11 chars, not 12, and you probably want to be accumulating characters from index 0 and then bumping the index, otherwise you're just overwriting the same character each time.
Looking at the rest of the code there are so many other problems that I think you may need to take a step back here and start with a simpler program - get that working first and then add to it in stages.
You might also want to get a decent introductory book on C and study it as there are lots of very basic mistakes in the code, so you might benefit from a better understanding of the language itself.
You only assign a value to chr[11], the rest of the array is uninitialized and will contain random data. You then copy this array containing random data to c (you could use e.g. memcpy here instead of looping yourself), and finally you compare the complete contents of c (which is random data) with one of the entries in a. So it's kind of natural that the result of that comparison will be that the strings are not equal.
Edit: A redesign of the program in the question
Your program has too many problems to be easily fixed, so I decided to try and rewrite it:
#include <reg51.h>
#include <string.h>
#include "_LCD_R8C.c"
#define INPUT_LENGTH 11
#define ACCEPTABLE_INPUT_COUNT 2
char input[INPUT_LENGTH]; /* The input from the serial port */
int input_pos = 0; /* Current position to write in the input buffer */
int input_done = 0; /* 0 = not done yet, 1 = all input read */
void serial_int (void) interrupt 4
{
if (!input_done && RI == 1)
{
/* Put the input at next position in the input buffer */
/* Then increase the position */
input[input_pos++] = SBUF;
RI = 0;
TI = 0;
/* Check if we have received all input yet */
if (input_pos >= INPUT_LENGTH)
input_done = 1;
}
}
int main()
{
/* Array of data that this programs thinks is acceptable */
/* +1 to the input length, to fit the terminating '\0' character */
char acceptable_inputs[ACCEPTABLE_INPUT_COUNT][INPUT_LENGTH + 1] = {
"$0016221826", "$0123456789"
};
iny acceptable_found = 0; /* Acceptable input found? */
/* Initialization */
lcd_init();
lcd_clear();
SCON = 0x50;
TMOD = 0x20;
TH1 = 0xFD;
ET0 = 0;
TR1 = 1;
RI = 1;
ES = 1;
EA = 1;
/* Wait until we have received all input */
while (!input_done)
; /* Do nothing */
/* Check the received input for something we accept */
for (int i = 0; i < ACCEPTABLE_INPUT_COUNT; i++)
{
if (memcmp(acceptable_inputs[i], input, INPUT_LENGTH) == 0)
{
/* Yes, the data received is acceptable */
acceptable_found = 1;
break; /* Don't have to check any more */
}
}
if (acceptable_found)
lcd_printxy(1, 1, "Yes");
else
lcd_printxy(1, 1, "No");
return 0;
}

Resources