经验——USART1__HAL接收数据

MCU:stm32f407vet6

外设:LD3320,其他同理

一、基本流程

        思路:先配置好USART1,再配置中断,然后对串口发送的数据进行处理

        接线:外设的TXDRXD分别接MCU的RXDTXD,交叉相连

        流程:外设向串口发送数据,MCU接收缓冲区非空,从而触发中断接收数据,接收数据后进入中断回调函数,在中断回调函数里进行数据处理或是发送数据处理的标志由主循环的函数执行

二、代码

        重点是先理解原理,然后就可以自由发挥

1,配置  

      配置USART1的模式,以及TXD、RXD的GPIO引脚,重点是配置波特率GPIO引脚

uint8_t usartBuffer[USART_RX_BUFFER_SIZE];// 定义接收缓冲区,里面是宏定义
uint16_t bufferIndex = 0;// 缓冲区索引
UART_HandleTypeDef huart1;


void LD_USART1_UART_Init()
{
    __HAL_RCC_USART1_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 9600;//波特率
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        Error_Handler();
    }
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
     PA9     ------> USART1_TX
     PA10     ------> USART1_RX
  */
    GPIO_InitStruct.Pin = TXD | RXD;//引脚已经宏定义过了
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);//我这里是中断分组4,你可以按照你自己的中断分组来配,比如2,2,
    HAL_NVIC_EnableIRQ(USART1_IRQn);

}

配置ISR(这里没有把它放在中断步骤里,是为了让代码的配置流程更顺畅一点)

void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart1);
}

2,初始化

        在合适的位置放上初始化函数。下面那个接收中断的函数HAL_UART_Receive_IT其实就是激活接收非空中断,简单来说就是外设向串口发送数据,接收缓冲区就非空了,于是触发中断,进入中断回调函数了。

        不过这个函数有个特点,就是你调用这个函数后,它会一直等待接收缓冲区非空,直至非空触发中断,然后就没了,不会再接收数据了。也就是说如果你想一直接收数据的话,那么必须在中断回调函数里也调用这个函数。

        这个函数里的形参,第一个不陌生,第二个是自己定义的缓冲区数组,在前面的【配置】里定义过了。第三个参数是传递的字节长度n,当接收缓冲区非空,这个函数会把缓冲区的n个字节长度的数据复制到你填的缓冲区数组里。

        字节长度填1是因为接收的数据是不定长的并且中英数字混合,同时还有结束标志,所以需要一个一个字节地传输以便判断接收是否完成。一般都填1,除非你确定数据是定长的

    LD_USART1_UART_Init();

    if (HAL_UART_Receive_IT(&huart1, usartBuffer, 1) != HAL_OK) /*激活传输*/
        Error_Handler();

3,中断     

        配置中断回调函数(我这里开启了预编译指令,不用在意),正如前面所言,我需要接收含结束标志的不定长数据,这里的结束标志为“\r\n”。

        所以第①步就是,先检验一下数据的末尾是否是结束标志,从而决定是否处理数据。这里使用ifelse ifelse的三个分支流程,分别对应【传输完成】、【传输错误】、【正在传输】

        需要说明的是最后一句bufferIndex++放在前面是因为

  bufferIndex++;
  HAL_UART_Receive_IT(&huart1, usartBuffer + bufferIndex, 1);

初始化步骤时,就已经开启了接收中断,所以接收完之后的,缓冲区数组的第0个位置已经有了数据,为了不被覆盖,需要在接收下一个之前先让索引自增

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
#if LD_USART1_USE
    if (huart->Instance == USART1)
    {
        // 检查是否收到了完整的 "\r\n"
        if (bufferIndex >= 2 && usartBuffer[bufferIndex - 1] == '\r' && usartBuffer[bufferIndex] == '\n')
        {
            bufferIndex -= 2;// 移除结束标志

            /**解锁处理任务,你可以换成自己的数据处理代码,或者是把处理数据的标志置1,在主循环里识别标志并处理*/
            BaseType_t xHigherPriorityTaskWoken = pdFALSE;
            xSemaphoreGiveFromISR(usartBinarySemHandle, &xHigherPriorityTaskWoken);
            if (xHigherPriorityTaskWoken == pdTRUE)
            {
                portYIELD_FROM_ISR(xHigherPriorityTaskWoken);// 请求上下文切换
            }
            /**上面是解锁处理任务*/

        }
        else if (bufferIndex == USART_RX_BUFFER_SIZE - 1)// 缓冲区满但未找到结束符,处理错误
        {
            bufferIndex = 0;// 或者其他适当的错误处理
            memset(usartBuffer, 0, USART_RX_BUFFER_SIZE);
        }
        else// 继续接收下一个字符
        {
            bufferIndex++;
            HAL_UART_Receive_IT(&huart1, usartBuffer + bufferIndex, 1);
        }
    }

#endif
}

  

4,数据处理

        函数名或者任务名我就不写了,这里只写大概的执行过程。这一步的前提就是先判断是否需要进行数据处理,如果需要的话再执行下面代码。

        先是处理相关数据,再是重置缓冲区,防止数据不断追加。最后是再启动接收数据中断,等待接收缓冲区非空,即等待外设向串口发送数据。

       /**处理相关数据*/

        // 重置缓冲区索引,准备接收下一条数据
        bufferIndex = 0;
        memset(usartBuffer, 0, USART_RX_BUFFER_SIZE);
        // 继续接收新的数据
        HAL_UART_Receive_IT(&huart1, usartBuffer, 1);

  • 27
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USART2_IRQn是一个中断号,代表USART2的中断。在HAL库中,中断句柄是用于管理中断的结构体,其中包含了中断的配置信息、状态信息、中断回调函数等。USART2_IRQn并不是一个中断句柄,它只是一个中断号,用于标识USART2中断在中断向量表中的位置。在HAL库中,如果要使用USART2中断,需要先定义一个中断句柄,然后使用HAL库提供的函数进行初始化、配置和启用中断等操作。以下是一个使用HAL库的USART2中断句柄的例子: ```c /* Define USART2 interrupt handler structure */ UART_HandleTypeDef huart2; /* Initialize USART2 interrupt handler */ void USART2_Init(void) { /* Configure USART2 parameters */ huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; /* Configure USART2 NVIC priority */ HAL_NVIC_SetPriority(USART2_IRQn, 0, 1); /* Enable USART2 interrupt */ HAL_NVIC_EnableIRQ(USART2_IRQn); /* Initialize USART2 */ HAL_UART_Init(&huart2); } /* USART2 interrupt callback function */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Handle USART2 receive interrupt */ } /* Main function */ int main(void) { /* Initialize USART2 */ USART2_Init(); /* Main loop */ while (1) { /* Do something */ } } ``` 在这个例子中,定义了一个名为huart2的UART_HandleTypeDef类型的变量,用于管理USART2的中断。在USART2_Init函数中,先配置了USART2的参数,然后使用HAL_NVIC_SetPriority函数设置了USART2的抢占优先级和响应优先级,接着使用HAL_NVIC_EnableIRQ函数使能USART2中断,并最终使用HAL_UART_Init函数初始化USART2。在USART2中断发生时,会自动调用HAL_UART_RxCpltCallback回调函数,由此处理USART2的接收数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值