如何通过HAL_UART接收数据?

时间:2019-05-30 19:03:37

标签: c uart stm32f4discovery hal

我正在学习STM32。我想通过UART逐字节接收数据并中断。

HAL_UART_Receive_IT(&huart1, buffer, length)

&huart1是我的uart门,其中buffer是输入存储,而length是输入字节数。我使用以下功能读取数据

static requestRead(void *buffer, uint16_t length)
{
    uint8_t teste;
    while (HAL_UART_Receive_IT(&huart1, buffer, length) != HAL_OK) osDelay(1);
    //HAL_UART_RxCpltCallback
}

我将数据存储在:

void StartDefaultTask(void const *argument)
{
    char sender[] = "Alaska Sending\n";
    uint8_t receive[10];
    uint8_t data[30];

    for (;;)
    {
        uint8_t i = 0;
        memset(data, 0, 30);

        requestRead(&receive, 1);
        data[i++] = receive;

        while (data != '\r')
        {
            requestRead(&receive, 1);
            data[i++] = receive;
        }

        //HAL_UART_Transmit(&huart1, data, i, HAL_MAX_DELAY);

    }
    /* USER CODE END StartDefaultTask */
}

我的问题是值的接收和存储。当我通过串行方式发送字符串 Welcome to Alaska \ n (欢迎来到阿拉斯加\ n )时,只读取并存储了W,那么我需要再次发送缓冲区并再次仅存储W。如何解决此问题?

1 个答案:

答案 0 :(得分:0)

好吧,这里有几个问题。

数组及其内容

data[i++] = receive;

receive缓冲区的地址(内存指针值)存储到data数组中。那当然不是你想要的。由于这是一个非常基本的C编程范例,因此建议您回顾一下good C textbook中有关数组和指针的章节。

您发送的内容和期望的内容

while (data != '\r')

即使正确获得数组地址及其值(请参见上文),您也将发送以'\n'结尾的字符串,并检查一个'\r'字符,因此请更改一个或其他人来获得比赛。

缺少volatile

uint8_t receive[10];

应将接收缓冲区声明为volatile,因为它会被中断处理程序访问。否则,即使主程序已经检查了接收是否完成(请参阅下文),也会丢失对缓冲区的写操作。

实时处理硬件

while (HAL_UART_Receive_IT(&huart1, buffer, length) != HAL_OK) osDelay(1);

这将使UART接收(和错误处理)中断能够接收一个字节。到目前为止还可以,但是函数在接收到字节之前返回 ,并且立即再次调用它,它将第二次返回HAL_BUSY并等待毫秒,然后再尝试。在那毫秒内,它将丢失其余的大部分传输,因为字节到达的速度快于此,并且您的程序对此无能为力。

此外,主程序不检查接收是否完成,可能在中断处理程序将值放入缓冲区之前访问缓冲区。

如果使用中断接收数据,则必须在中断处理程序中对该数据进行某些处理。 (如果您不使用中断,而是使用 polling 进行数据访问,请确保您已达到界面速度所规定的期限)。

HAL不适合此类任务

HAL没有接口来接收以特定值结尾的未知长度的数据。当然,主程序可以一次轮询接收者一个字节,但是它必须确保轮询发生的速度比数据传入的速度快。换句话说,该程序在等待传输时可以做很少的事情。

有一些变通办法,但是我现在什至不予暗示,因为它们会在RTOS环境中导致deadlocks,这往往在最不方便的时间发生,并且很难调查和解决。适当避免。

改为编写您的中断处理程序

(所有详细信息在您的控制器的参考手册中)

  • 设置UART中断优先级NVIC_SetPriority()
  • 使用NVIC_EnableIRQ()启用中断
  • USART_CR1_RXNEIE位设置为1

在中断处理程序中,

  • 阅读SR寄存器
  • 如果设置了RXNE位,
    • 从数据寄存器中读取数据
    • 将其存储在缓冲区中
    • 设置与结束符匹配的全局标志
    • 如果程序在处理第一行时需要更多数据,请切换到另一个缓冲区。

别忘了声明将中断处理程序接触的所有变量都声明为volatile