Home > database >  String parsing, turn LED on/off based on received serial data
String parsing, turn LED on/off based on received serial data

Time:02-01

I am receiving in the serial port from python a string in this format (0,77,88,55). I have the first number randomized to either be 0 or 1, the rest are fixed.

import random
import serial
import time

last_time = 0
test_list = [0,1]

serialSTM32 = serial.Serial('COM22',9600,writeTimeout=0)

while True:
    if (time.time() - last_time) > 2:
        random_num = random.choice(test_list)
        #string = str(random_num)
        string = "("   str(random_num)   ","   "77"   ","   "88"   ","   "55"   ")"
        serialSTM32.write(string.encode('utf-8'))
        print(string)
        last_time = time.time()
        serialSTM32.flushInput()

The STM32 MCU is receiving through the virtual serial COM port the data through a variable in the "usbd_cdc_if.c" file:

uint8_t bufferVariable = 0;

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  bufferVariable = Buf[0];
  return (USBD_OK);
}

The bufferVariable is passed to the "main.c" file using:

extern uint8_t bufferVariable;

The "main.c" is then parsing the data, splitting the data and placing the first number which is '0' or '1' in a variable named "first", the second number which is '77' in a variable named "second" etc. I am taking the "first" variable to see if it is '1' to turn on the LED, but if it is '0' to turn off the LED. Program waits for start market "(" and keeps reading until it reaches end marker ")", then parses the data in between the two. **Works well on Arduino from parsing tutorial a while back, i converted everything to work on STM32 MCU....

**For this STM32 controller, previously, I tested without the parsing, only receiving '1' or '0' through serial to turn on/off the LED which works.....but now I am using the format (0,77,88,55) which includes parsing the data then getting the value extracted from that format. **This part is not working....LED does not turn on or off.

"main.c" file code:

#define buffer_size 40

char input_buffer[buffer_size];
const char start_marker = '(';
const char end_marker = ')';
uint8_t bytes_received = 0;
uint8_t read_in_progress = 0;

char* grab_value(char *data, char separator, int index) {
    int found = 0;
    int string_index[] = { 0, -1 };
    int maximum_index = strlen(data) - 1;

    for (int i = 0; i <= maximum_index && found <= index; i  ) {
        if (data[i] == separator || i == maximum_index) {
            found  ;
            string_index[0] = string_index[1]   1;
            string_index[1] = (i == maximum_index) ? i   1 : i;
        }
    }

    if (found > index) {
        data[string_index[1]] = '\0';
        return &data[string_index[0]];
    } else {
        return NULL;
    }
}

int first, second, third, fourth;

extern uint8_t bufferVariable;

int main(void) {

    while (1) {

        if (bufferVariable == end_marker) {
            read_in_progress = 0;
            input_buffer[bytes_received] = '\0';
        }

        if (read_in_progress) {
            input_buffer[bytes_received  ] = bufferVariable;
            if (bytes_received == buffer_size) {
                bytes_received = buffer_size - 1;
            }
        }

        if (bufferVariable == start_marker) {
            bytes_received = 0;
            read_in_progress = 1;
        }
        char *str_first = grab_value(input_buffer, ',', 0);
        char *str_second = grab_value(input_buffer, ',', 1);
        char *str_third = grab_value(input_buffer, ',', 2);
        char *str_fourth = grab_value(input_buffer, ',', 3);

        if (str_first) {
            first = atoi(str_first);
        }
        if (str_second) {
            second = atoi(str_second);
        }
        if (str_third) {
            third = atoi(str_third);
        }
        if (str_fourth) {
            fourth = atoi(str_fourth);
        }
        printf("first: %d\n", first);

        if (first == '0') {
            HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
        } else if (first == '1') {
            HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
        }

    }
    
}

CodePudding user response:

Disclaimer, this is my personal preference:

For embedded, you should never use blocking I/O, always buffered, interrupt-driven I/O. I cannot say a single thing in favor of blocking I/O except it's simpler.

You say the problem is, that the LED doesn't toggle.

Let's look at the facts.

This check controls whether or not to toggle the LED:

if (first == '0') {
    HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
} else if (first == '1') {
    HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
}

I notice that you're comparing an integer with the char-values for 0 and 1 and not the integer values. You're essentially checking if first == 48/49 instead of 0/1 (see integer values https://www.asciitable.com/)

At the same time, you're converting the received string to an integer by doing

first = atoi(str_first);

Compare first against 0 or 1 instead of '0' and '1' (which are 48 and 49 respectively).

CodePudding user response:

first == '0'

It is completely wrong. '0' is not zero integer value only 48 in ASCII representing the character '0'.

Do not reinvent the wheel.

After the whole sting reception simply:

if(sscanf(inputBuffer, "(%d,%d,%d,%d)", &first, &second, &third, &fourth) == 4)
{
    if(!first) HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_SET);
    else HAL_GPIO_WritePin(GPIOK, GPIO_PIN_3, GPIO_PIN_RESET);
}

STM32 uCs have much more resources than AVR uCs used in Arduino and you do not need any "tricks" Only make sure that inputBuffer is null character terminated

  • Related