如何在阵列中使用UART接收未知长度的数据并存储并接收下一组数据,而又不删除第一个寄存器中的内容?

时间:2019-12-16 07:03:30

标签: c stm32 uart

我必须从UART中断串行通信接收未知长度的数据。我已经初始化了一个数组,以存储数据。现在,当我收到数据并逐字节存储直到用户输入\ n时,应该存储数据,并且在输入一组新数据时不会覆盖该数据。为此,我想到了在有时间时初始化一个计数器如果接收到数据,则计数器应递增,并且要存储在下一个寄存器中的数据。由于我是编程新手,因此需要为STM32编写C语言,该怎么做?

uint8_t rx_data [200];
int count = 0;
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

    HAL_UART_Receive_IT (&huart2, rx_data);
    count ++;
}

1 个答案:

答案 0 :(得分:1)

嗯,最好的方法是两个缓冲区和FreeRTOS。 问题是您可能不会一一收到,但一次可以获取字节数。因此,您需要两个缓冲区:“接收缓冲区”和“数据缓冲区”。另外,您可能需要某种“清除缓冲区”来清空其他缓冲区。这样比循环中的空缓冲区快。

所以,让我们看看。我为STM32F303编写示例。首先,在CubeMX中为FreeRTOS创建一个任务,将其设为 consoleTaskHandle 。然后在 stm32f3xx_it.c 中添加或编辑:

/* Private includes -----------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h"
/* USER CODE END Includes */

//........................
//........................

/* USER CODE BEGIN EV */
extern osThreadId consoleTaskHandle;
/* USER CODE END EV */

//........................
//........................

/**
* @brief This function handles USART2 global interrupt
*/
void USART2_IRQHandler(void) {
    /* USER CODE BEGIN USART2_IRQn 0 */
    BaseType_t xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;

    vTaskNotifyGiveFromISR(consoleTaskHandle, &xHigherPriorityTaskWoken);

    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    /* USER CODE END USART2_IRQn 0 */
    HAL_UART_IRQHandler(&huart2);
    /* USER CODE BEGIN USART2_IRQn 1 */

    /* USER CODE END USART2_IRQn 1 */
}

这意味着,每次IT执行时,我们都会向FreeRTOS任务发送通知。

现在,让我们编写任务以处理接收到的数据。所以 main.c

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
/* USER CODE END Includes */

//........................
//........................

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USART */
#define USART_CONSOLE_BUFFER_SIZE ((uint8_t)64)
/* USER CODE END PD */

//........................
//........................

/* USER CODE BEGIN PV */
/* USART */
static const char emptyBuffer[USART_CONSOLE_BUFFER_SIZE] = {0x00};
char consoleRxBuffer[USART_CONSOLE_BUFFER_SIZE] = {0x00};
char consoleTxBuffer[USART_CONSOLE_BUFFER_SIZE] = {0x00};
/* USER CODE END PV */

//........................
//........................

/* USER CODE BEGIN Header_StartConsoleTask */
/**
* @brief Function implementing the consoleTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartConsoleTask */
void StartConsoleTask(void const * argument) {
    /* USER CODE BEGIN StartConsoleTask */
    uint32_t ulNotifiedValue     = 0;
    static uint8_t rxBufferLen   = 0; /*!< Current RX buffer length */ 
    static uint8_t txBufferLen   = 0; /*!< Current TX buffer length */
    static uint8_t lastBufferLen = 0; /*!< Last RX buffer length */


    static bool gotCommand = false;  /*!< Recieved command flag */

    char command[USART_CONSOLE_BUFFER_SIZE] = {0x00}; /*!< Command buffer */

    if (HAL_UART_Receive_IT(&huart2, (uint8_t *)consoleRxBuffer, USART_CONSOLE_BUFFER_SIZE) != HAL_OK) {
        // Uart error handle
    }

    for (;;) {
        ulNotifiedValue = ulTaskNotifyTake(pdFALSE, (TickType_t) ULONG_MAX);

        // Got notification from IT
        if (ulNotifiedValue > 0) {
            // Let's check the RX buffer first
            rxBufferLen = strlen(consoleRxBuffer);

            if (rxBufferLen > 0) {
                // Let's send data back to console
                // or we gonna print data blindly
                if (rxBufferLen > lastBufferLen) {
                    /*
                        If the last symbol is '\r', then:
                            - Stop RX
                            - Send '\n' next
                            - Copy RX buffer to command buffer
                            - Empty RX buffer and start IT again
                            - Set 'GotCommand flag'
                        ELSE
                            - Simply send data back to cosole
                     */

                    // Count ammount of data to send back
                    txBufferLen = rxBufferLen - lastBufferLen;

                    // Copy data from RX buffer to TX buffer
                    strncpy(consoleTxBuffer, &consoleRxBuffer[lastBufferLen], txBufferLen);
                    consoleTxBuffer[txBufferLen] = '\0';

                    if (consoleRxBuffer[rxBufferLen - 1] == '\r') {
                        gotCommand = true;

                        HAL_UART_AbortReceive_IT(&huart2);

                        consoleTxBuffer[txBufferLen] = '\n';
                        consoleTxBuffer[txBufferLen + 1] = '\0';

                        /* Copy command from RX buffer to command buffer */
                        // Let's trim spaces from the beginning
                        uint8_t commandStartPos = 0;

                        for (int i = 0; i < USART_CONSOLE_BUFFER_SIZE; ++i) {
                            if (consoleRxBuffer[0] == ' ') {
                                commandStartPos++;
                            } else {
                                break;
                            }
                        }

                        strncpy(command, &consoleRxBuffer[commandStartPos], strlen(consoleRxBuffer) - commandStartPos + 1);

                        /*
                            Empty RX buffer
                            I clean it by copying empty buffer to RX. That increases memory 
                            consumption, but works faster. You can do it in cycle.
                         */
                        strncpy(consoleRxBuffer, emptyBuffer, USART_CONSOLE_BUFFER_SIZE);

                        lastBufferLen = 0;

                        // Start the UART IT again
                        if (HAL_UART_Receive_IT(&huart2, (uint8_t *)consoleRxBuffer, USART_CONSOLE_BUFFER_SIZE) != HAL_OK) {
                            // Uart error handle
                        }

                    } else {
                        lastBufferLen = rxBufferLen;
                    }

                    // Send data back to console through UART DMA (you must turn it on in settings)
                    if (HAL_UART_Transmit_DMA(&huart2, (uint8_t *)consoleTxBuffer, strlen(consoleTxBuffer)) != HAL_OK) {
                        // Uart error handle
                    }

                    while (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC) == RESET) {
                        vTaskDelay(1);
                    }
                }

                /* If we got command in last condition */
                if (gotCommand == true) {
                    gotCommand = false; // Reset flag

                    // Do some work with recieved command/data
                }
            }
        }
    }
}