I have interfaced a programmable xbee with a 16x2 character LCD. I transmit wireless frames with the the help of another xbee and display it on the recieving xbee.
The problem arises when I send two wireless frames one after another.
Consider that I send 24 characters in the first frame, that will be displayed normally as it should be(with a random extra character at the end of the display which I dont know why)
The problem arises when I send a second frame which is smaller than the first frame for eg. of 6 characters. The LCD displays the the 6 characters but adds further 18 characters that were there in the first frame after the 6 characters.
The display looks likes this:
Frame1 display : This is a check message.
Frame2 display : Hello!s a check message. (original message : Hello!)
I tried clearall() lcd function between frames at different positions but it does not work. I also different things you see in the code but they dont work.
The code currently looks like this;
enter code here
#include <xbee_config.h>
#include <types.h>
#include <string.h>
#include <ctype.h>
#define char_lcd_writ_str(a) char_lcd_writ(a, strlen(a))
static uint8_t test_stage = 0;
static uint8_t test_stage_done = 0;
static const char str[] = "abcdefghijklmnopqrstuvwxyz012345";
#if defined(RTC_ENABLE_PERIODIC_TASK)
void rtc_periodic_task(void)
{
test_stage++;
if (test_stage == 8)
test_stage = 0;
test_stage_done = 0;
}
#endif
#ifdef ENABLE_XBEE_HANDLE_RX
int xbee_transparent_rx(const wpan_envelope_t FAR *envelope, void FAR *context)
{
int c=0;
char addrbuf[ADDR64_STRING_LENGTH];
char_lcd_init(CHAR_LCD_CFG);
char_lcd_clear();
addr64_format(addrbuf, &envelope->ieee_address);
sys_watchdog_reset();
while (c<4)
{
char_lcd_writ_str(envelope->payload);
delay_ticks(2*HZ);
char_lcd_clear();
char_lcd_goto_xy(0, 0);
c++;
}
}
#endif
void main(void)
{
uint8_t i, j;
sys_hw_init();
sys_xbee_init();
sys_app_banner();
char_lcd_init(CHAR_LCD_CFG);
for (;;) {
if (!test_stage_done) {
switch (test_stage) {
case 0:
char_lcd_goto_xy(0, 0);
char_lcd_writ_str("All working fine");
break;
}
test_stage_done = 1;
}
sys_watchdog_reset();
sys_xbee_tick();
}
}
ssize_t char_lcd_writ(const uint8_t *data, size_t len)
{
size_t written = 0;
while (written < len) {
char_lcd_putchar(*data++);
written++;
if ( written == 32 || written == 64 || written == 96 || written == 128 || written == 160 || written == 192 )
{
delay_ticks(2*HZ);
char_lcd_clear();
char_lcd_goto_xy(0, 0);
}
}
while (written < len) {
written = 0;
memset(*data++, '\0', len);
written++;
}
return (ssize_t)written;
}
Could be as simple as envelope->payload not being null-terminated and actually containing those extra characters if you go beyond the payload length specified in the envelope. Try using your char_lcd_writ() function with the payload's length instead of char_lcd_writ_str() which will use strlen() to find the length.
Related
I am successfully receiving data over RF on a second Arduino. However I am trying to compare the incoming string so that I can call a method when there is a match. The "if" block is never executed. I am just trying to compare the strings that are incoming. It's printing the correct values to the serial monitor but the block is never executed. Maybe because this is using a pointer to a string (don't shoot me)? I am not that familiar with C or C++. I have tried several of the string comparison methods in the Arduino docs but no joy? Any reccomendations?
void loop()
{
// Set buffer to size of expected message
uint8_t buf[7];
uint8_t buflen = sizeof(buf);
// Check if received packet is correct size
if (rf_driver.recv(buf, &buflen))
{
// Message received with valid checksum
Serial.print("Message Received: ");
String str_out = String((char*)buf);
Serial.println(str_out); /
if (str_out == "plasma1") { // this is never executed wtf!!!
plasmaSequenceOne();
} else if (str_out == "plasma2") {
plasmaSequenceTwo();
} else if (str_out == "plasma3") {
plasmaSequenceThree();
} else if (str_out == "plasma4") {
plasmaSequenceFour();
}
}
}
Making Alex' self-response easier readable, and avoiding unnecessary String objects:
uint8_t buf[8];
uint8_t buflen = sizeof(buf)-1; // leave space for terminating 0
if (rf_driver.recv(buf, &buflen)) {
buf[buflen] = 0;
char* str_out = (char*)buf;
Serial.println (str_out);
if (strcmp(str_out, "plasma1")==0) plasmaSequenceOne();
...
}
This worked, thanks to #Remy Lebeau.
Large strings sent over serial are not correctly read using an Arduino Uno and the Arduino IDE. When the typed command is too long, not the whole data is returned and sometimes is is even random numbers.
99,3,0,1,0,0,0 Results correctly in (not sure why there is an ending , tho):
receivedValues are: 99,3,0,1,0,0,0,
99,3,0,0,0,0,0 Results correctly in: receivedValues are: 99,3,0,0,0,0,0,
Where is starts to go wrong:
99,3,0,100,200,300,400 Results in: receivedValues are: 99,3,0,100,200,44,144,
99,123456789 Results in: receivedValues are: 99,21,0,1,200,200,244,
99,3,0,1,200,200,2000 Results in: receivedValues are: 99,3,0,1,200,200,208,
Here is the part of my code that is relevant:
uint8_t receivedValues[7] = {0, 0, 0, 0, 0, 0, 0};
#define HEADER 0 // 99
#define CMD 1 // LICHT (2) || GEUR (3)
#define DATA0 2 // KLEUR INDEX || GEUR INDEX
#define DATA1 3 // H || ON / OFF
#define DATA2 4 // S
#define DATA3 5 // V
#define DATA4 6 // BlendTime
#define CHECK 99
#define ON 1
#define OFF 0
bool messageReceived = false;
bool startBlending = false;
void setup()
{
Serial.begin(9600);
}
void loop()
{
ParseSerial();
if (messageReceived)
{
printMessage();
// CheckCommand();
messageReceived = false;
}
}
void ParseSerial()
{
int serialIndex = 0;
if (Serial.available() > 8)
{
while (0 < Serial.available())
{
String bufferString;
int bufferInt;
bufferString = Serial.readStringUntil(',');
bufferInt = bufferString.toInt();
receivedValues[serialIndex] = bufferInt;
serialIndex++;
}
if (receivedValues[HEADER] == CHECK)
{
Serial.print("receivedValues[0]: ");
Serial.println(receivedValues[0]);
messageReceived = true;
}
if (receivedValues[HEADER] != CHECK)
{
Serial.println("not a good package");
}
Serial.flush();
}
else
{
Serial.flush();
}
}
void printMessage()
{
Serial.print("receivedValues are: ");
for (int i = 0; i < 7; i++)
{
Serial.print(receivedValues[i]);
Serial.print(",");
}
Serial.println();
}
If the header of the message does not start with 99 it will write not a good package. What is noticeable it that when I do enter a command with 99 at the beginning ONCE, it will write not a good package twice most of the time.
receivedValues is declared as uint8_t receivedValues[7]. The maximum value for uint8_t is 255. If you try to store a larger number, it will be truncated.
If you want to store larger numbers, you need to pick a wider integer type for your array, e.g.
uint32_t receivedValues[7] = {0, 0, 0, 0, 0, 0, 0};
Which will work up to UINT32_MAX, which is 0xFFFFFFFF (4294967295)
I found the solution to this problem. Changing uint8_t was not the answer.
A byte of 8 binary bits can represent 28 = 256 numbers: 0 - 255. The
serial connection sends data byte by byte, so if you want to send a
number larger than 255, you'll have to send multiple bytes
Link to source:
https://forum.arduino.cc/index.php?topic=492055.0
I ended up sending a smaller number (minutes) than 255, and then in the Arduino code multiply it again (to seconds).
I'm using structure to process NMEA messages, but I don't know what, something goes wrong when processing it. So, I have NMEA_parse.h:
/* GPRMC */
#define TIME 2U
#define LAT 4U
#define LON 6U
#define SPD 8U
#define ANG 9U
#define DATE 10U
extern struct gprmc{
char time[10];
char latitude[10];
char longitude[10];
char speed[10];
char angle[10];
char date[10];
}gprmc_datas;
NMEA_parse.c:
#include "NMEA_parse.h"
struct gprmc gprmc_datas;
static void fill_data (char* param_in)
{
uint8_t i = 0U;
char* trunk;
char trunk_datas[20U][10U];
trunk = strtok(param_in, ",");
while(trunk != NULL)
{
i++;
if(i > 20) { i = 0; }
strcpy(trunk_datas[i],trunk);
trunk = strtok (NULL, ",");
}
if(memcmp(trunk_datas[1U],"GPRMC",6U) == 0U)
{
strcpy(gprmc_datas.time,trunk_datas[TIME]);
strcpy(gprmc_datas.latitude,trunk_datas[LAT]);
strcpy(gprmc_datas.longitude,trunk_datas[LON]);
strcpy(gprmc_datas.date,trunk_datas[DATE]);
strcpy(gprmc_datas.time,trunk_datas[TIME]);
}
}
main.c:
#include <stdio.h>
#include "NMEA_parse.h"
int main(void)
{
char *message = "$GPRMC,182127.00,A,4753.47678,N,02022.20259,E,0.837,,161019,,,A*7C\r\n";
char *mes = "$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A";
proc_sentence(message);
printf("\ntime: %s\n", gprmc_datas.time);
printf("latitude: %s\n", gprmc_datas.latitude);
printf("longitude: %s\n", gprmc_datas.longitude);
}
proc_sentence function pass the data to fill_data(), if the message valid (checksum, etc)
When I'm using the mes as input, everything is correct, but when I switch to message, some abnormality is shown, because the result is the following:
time: 182127.00
latitude: 4753.4767802022.2025E
longitude: 02022.2025E
Do you have any idea what goes wrong?
If you change latitude[10] in the struct into latitude [12], the string "message" can also be used.
Unlike almost every other SO question about the use of scanf, yours is actually a problem that cries out for it. After all, if a machine wrote it, a machine can read it, right?
Using C's concatenation of string literals, I got pretty close to filling the struct with a single function:
int n = sscanf( message,
"%[^,],"
"%[^,],"
"%*[^,],%[^,],"
"%*[^,],%[^,],"
"%*[^,],%[^,],"
"%[^,],"
"%[^,],",
label,
gprmc.time,
gprmc.latitude,
gprmc.longitude,
gprmc.speed,
gprmc.angle,
gprmc.date );
This makes use of the little-used regex specifier, where we look for non-commas %[^] separated by commas. The %*[^] specifies to skip the field.
New to coding! I am trying to get text on my LED Matrix through serial data that is being sent in from processing.
My code works but the only problem is that though the serial data on processing is constant, the arduino code only reads the number once. This makes it so that the text will not scroll all the way through. How do I loop a serial read on arduino?
Here is the relevant portion of my code:
void loop()
{
if (Serial.available() > 0)
{
int matrixPinState = Serial.read();
// stage = Serial.read();
// analogWrite(matrixPin, stage);
if (matrixPinState == 1)
{
matrix.fillScreen(0);
matrix.setCursor(x, 0);
matrix.print(F("Im kind"));
if (--x < -30)
{
x = matrix.width();
if (++pass >= 8) pass = 0;
matrix.setTextColor(colors[pass]);
}
matrix.show();
delay(30);
}
}
}
When a byte(or you call it character, a data that is 8 bit long) is fetched by uart block(the hardware), it is buffered to input buffer so that programmer can read and process it.
In your case, when you send a character, it is fetched and put to the buffer and when you read it there is no more byte available to read unless you send to new one.
In short, read the pin state once. You can do something like:
int matrixPinState = 0
void setup() {
// do all your setup settings first
while (Serial.available() < 0) {
// wait here for the input
delay(30);
}
// got your input, read it
matrixPinState = Serial.read();
}
void loop()
{
if (matrixPinState == 1)
{
matrix.fillScreen(0);
matrix.setCursor(x, 0);
matrix.print(F("Im kind"));
if (--x < -30)
{
x = matrix.width();
if (++pass >= 8) pass = 0;
matrix.setTextColor(colors[pass]);
}
matrix.show();
delay(30);
}
}
I am trying to read complete messages from my GPS via serial port.
The message I am looking for starts with:
0xB5 0x62 0x02 0x13
So I read from the serial port like so
while (running !=0)
{
int n = read (fd, input_buffer, sizeof input_buffer);
for (int i=0; i<BUFFER_SIZE; i++)
{
if (input_buffer[i]==0xB5 && input_buffer[i+1]== 0x62 && input_buffer[i+2]== 0x02 && input_buffer[i+3]== 0x13 && i<(BUFFER_SIZE-1) )
{
// process the message.
}
}
The problem I am having is that I need to get a complete message. Half of a message could be in the buffer one iteration. And the other half could come into the message the next iteration.
Somebody suggested that free the buffer up from the complete message. And then I move the rest of data in the buffer to the beginning of the buffer.
How do I do that or any other way that make sure I get every complete selected message that comes in?
edit//
I want a particular class and ID. But I can also read in the length
To minimize the overhead of making many read() syscalls of small byte counts, use an intermediate buffer in your code.
The read()s 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;
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.
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 */
unsigned char mesg[MLEN];
while (1) {
while (getbyte() != 0xB5)
/* hunt for 1st sync */ ;
retry_sync:
if ((sync = getbyte()) != 0x62) {
if (sync == 0xB5)
goto retry_sync;
else
continue; /* restart sync hunt */
}
class = getbyte();
id = getbyte();
length = getbyte();
length += getbyte() << 8;
if (length > MLEN) {
/* report error, then restart sync hunt */
continue;
}
for (i = 0; i < length; i++) {
mesg[i] = getbyte();
/* accumulate checksum */
}
chka = getbyte();
chkb = getbyte();
if ( /* valid checksum */ )
break; /* verified message */
/* report error, and restart sync hunt */
}
/* process the message */
switch (class) {
case 0x02:
if (id == 0x13) {
...
...
You can break the read into three parts. Find the start of a message. Then get the LENGTH. Then read the rest of the message.
// Should probably clear these in case data left over from a previous read
input_buffer[0] = input_buffer[1] = 0;
// First make sure first char is 0xB5
do {
n = read(fd, input_buffer, 1);
} while (0xB5 != input_buffer[0]);
// Check for 2nd sync char
n = read(fd, &input_buffer[1], 1);
if (input_buffer[1] != 0x62) {
// Error
return;
}
// Read up to LENGTH
n = read(fd, &input_buffer[2], 4);
// Parse length
//int length = *((int *)&input_buffer[4]);
// Since I don't know what size an int is on your system, this way is better
int length = input_buffer[4] | (input_buffer[5] << 8);
// Read rest of message
n = read(fd, &input_buffer[6], length);
// input_buffer should now have a complete message
You should add error checking...