第四章、UART异步串行通信总线

第一节、同步通信与异步通信的概念:

1.异步通信:

即通信双方,均独立工作,即有各自的时钟源。

发送方发出数据后,不需要等待接收方即时反馈与确认,可以继续进行其他操作。

因为异步通信没有使用同步的时钟,所以通常需要额外的控制信息,如:起始位,停止位,校验位,来标识数据的开始和结束,确定数据的正确传输和解析。

常见于有两个有独立时钟源的设备间的通信。

如:UART就是一种异步通信方式。

2.同步通信:

即通信双方,在共享的同一时钟下工作,使用同一时钟源。

发送方发出数据后,会等待接收方确认或反馈,然后才能进行继续下一步操作。

因为同步通信使用同一时钟,所以收发双方需要严格按照约定好的时序进行操作。

常见于在同一MCU或MPU下与多个外设设备的通信。

如:I2C,SPI就是一种同步通信方式。

3.工作模式:全双工与半双工式:

全双工是指:在同一时刻即可发送数据,亦可接收数据。所以一般情况为有两条数据线,发送线与接收线。

半双工是指:在同一时刻只能发送数据或接收数据,所以只需要一条数据线即可。

UART串口是一个全双工的异步的通信接口.

第二节、UART串口

1. UART通信协议的时序:从低到高字节发(LSB -->MSB)

 

2.UART控制器硬件接口及内部框图:

2.1接口连接:

通过三个引脚与其他设备连接在一起(见图248)。

任何USART双向通信至少需要两个脚:接

收数据输入(RX)和发送数据输出(TX)。

RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。

TX:发送数据输出。

2.2UART控制器硬件框图: 

2.3使用CubMX快速配置UART硬件相关的寄存器: 

第三节、UART串口驱动的HAL库API: 

1. 阻塞版收发数据接口函数:

1.1阻塞版发送数据:

HAL_StatusTypeDef HAL_UART_Transmit (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size,
uint32_t Timeout)
功能:通过 UART(通用异步收发传输器)发送数据
参数:
UART_HandleTypeDef *huart:一个指向 UART_HandleTypeDef 结构体的指针,该结构体包含指定 UART 模块的配置信息。
这个结构体包括 UART 外设的实例,以及其配置和状态信息。
uint8_t *pData:一个指向数据缓冲区的指针,缓冲区中包含要发送的数据。
uint16_t Size:要发送的数据的字节数。
uint32_t Timeout:等待传输完成的超时时间(以毫秒为单位)。
如果在这个时间内传输没有完成,函数将返回超时错误。

返回值
该函数返回一个 HAL_StatusTypeDef 类型的值,可以是以下几种之一:
HAL_OK: 函数执行成功。
HAL_ERROR: 执行过程中发生错误。
HAL_BUSY: UART 当前正忙于之前的操作。
HAL_TIMEOUT: 在操作完成前函数超时。

 1.2阻塞版接收数据:

HAL_StatusTypeDef HAL_UART_Receive (UART_HandleTypeDef * huart, uint8_t * pData, uint16_t Size,
uint32_t Timeout)
函数功能:通过 UART(通用异步收发传输器)接收数据.
参数说明
UART_HandleTypeDef *huart:一个指向 UART_HandleTypeDef 结构体的指针,
该结构体包含指定 UART 模块的配置信息。这个结构体包括 UART 外设的实例,以及其配置和状态信息。
uint8_t *pData:一个指向数据缓冲区的指针,接收的数据将存储在这个缓冲区中。
uint16_t Size:要接收的数据的字节数。
uint32_t Timeout:等待接收完成的超时时间(以毫秒为单位)。
如果在这个时间内接收没有完成,函数将返回超时错误。
返回值
该函数返回一个 HAL_StatusTypeDef 类型的值,可以是以下几种之一:
HAL_OK: 函数执行成功。
HAL_ERROR: 执行过程中发生错误。
HAL_BUSY: UART 当前正忙于之前的操作。
HAL_TIMEOUT: 在操作完成前函数超时。

1.3阻塞版uart收发数据实例应用:

驱动:uart_driver.c:

#include "uart_driver.h"
#include <stdint.h>
#include "FreeRTOS.h"
#include "main.h"
#include "task.h"
#include "usart.h"
#include <stdbool.h>
extern UART_HandleTypeDef huart1;
//阻塞方式发送数据:
int uart_send_by_block(void* buf, int size)
{
    return HAL_UART_Transmit(&huart1,buf, size, portMAX_DELAY);
}
//阻塞方式接收数据:
int uart_recv_by_block(void* buf, int maxSize)
{
    HAL_StatusTypeDef status;
    char* ptr = (char*)buf;
    int len = 0;
    while(true)
    {
        status = HAL_UART_Receive(&huart1, (uint8_t*)ptr, 1, portMAX_DELAY);
        if(*ptr == '\0' || *ptr == '\n' || *ptr == '\r')
        {
            break;
        }
        ptr++;
        len++;
        if(len > maxSize - 1)//应该是len > maxSize -1 才对,有点疏忽了。
        {
            break;
        }
    }
    return status;    
}

应用测试:uart_app.c:

#include "uart_app.h"
#include "uart_driver.h"
#include <string.h>
#include <stdbool.h>

//uart测试任务回调函数:
void uart_task_function(void* arg)
{
    const char* str = "Welcome uart_test,Plase input CMD: \n";
    uart_send_by_block((void*)str,strlen(str));
    char buf[128] = {0};
    while (true)
    {
        /* 测试uart串口收发数据 */
        memset(buf, 0,sizeof(buf));
        uart_recv_by_block(buf,sizeof(buf)-1);
        //发给串口,在PC串口终端进行显示:
        uart_send_by_block(buf,strlen(buf));
    }
}

2.中断非阻塞版收发数据接口函数:

2.1中断非阻塞版发送数据:

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
功能:用于通过 UART(通用异步收发传输器)以中断方式发送数据。
参数说明
UART_HandleTypeDef *huart:一个指向 UART_HandleTypeDef 结构体的指针,
该结构体包含指定 UART 模块的配置信息。这个结构体包括 UART 外设的实例,以及其配置和状态信息。
uint8_t *pData:一个指向数据缓冲区的指针,缓冲区中包含要发送的数据。
uint16_t Size:要发送的数据的字节数。
返回值
该函数返回一个 HAL_StatusTypeDef 类型的值,可以是以下几种之一:
HAL_OK: 函数执行成功。
HAL_ERROR: 执行过程中发生错误。
HAL_BUSY: UART 当前正忙于之前的操作。

该函数是非阻塞的,数据传输将在后台进行。
函数调用后立即返回,传输过程由中断驱动,传输完成后会产生一个完成中断。
需要在相应的 UART 中断服务程序(ISR)中处理传输完成事件。
通常在串口中断会调用 HAL_UART_IRQHandler 句柄。在这个句柄中回调处理完成的中断ISR:
在传输完成后会调用 HAL_UART_TxCpltCallback 回调函数,用户可以在该回调函数中执行后续处理。

1.重新实现HAL_UART_TxCpltCallback 回调函数,处理完成后的逻辑:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) 
{    
// 传输完成后的处理代码
    if (huart->Instance == USART1)
     {        
         // UART1 传输完成后的处理
     }
}

发送Transmit_IT中断调用路径:

2.2中断非阻塞版接收数据:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
功能:用于通过 UART(通用异步收发传输器)以中断方式接收数据
参数说明
UART_HandleTypeDef *huart:一个指向 UART_HandleTypeDef 结构体的指针,该结构体包含指定 UART 模块的配置信息。这个结构体包括 UART 外设的实例,以及其配置和状态信息。
uint8_t *pData:一个指向数据缓冲区的指针,接收的数据将存储在这个缓冲区中。
uint16_t Size:要接收的数据的字节数。
返回值
该函数返回一个 HAL_StatusTypeDef 类型的值,可以是以下几种之一:
HAL_OK: 函数执行成功。
HAL_ERROR: 执行过程中发生错误。
HAL_BUSY: UART 当前正忙于之前的操作。
该函数是非阻塞的,传输过程由中断驱动,数据接收将在后台进行。
函数调用后立即返回,接收完成后会产生一个完成中断。
需要在相应的 UART 中断服务程序(ISR)中处理接收完成事件。通常在 ISR 中调用 HAL_UART_IRQHandler 函数来处理中断。
在接收完成后会调用 HAL_UART_RxCpltCallback 回调函数,用户可以在该回调函数中执行后续处理。

 1.重新实现HAL_UART_RxCpltCallback 回调函数,处理完成后的逻辑:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{    
f    // 接收完成后的处理代码
    if (huart->Instance == USART1)
     {        
         // UART1 接收完成后的处理
     }
}

接收非阻塞中断的调用路径:

2.3中断非阻塞版uart收发实例应用:

驱动:

//非阻塞方式发送数据:
//实现完整数据的同步:
SemaphoreHandle_t send_sem;
int uart_send_by_interrupt(void* buf, int size)
{
    HAL_StatusTypeDef status;
    send_sem = xSemaphoreCreateBinary();
    status = HAL_UART_Transmit_IT(&huart1, buf, size);
    
    //获取信号量:
    xSemaphoreTake(send_sem,portMAX_DELAY);
    //删除信号量:
    vSemaphoreDelete(send_sem);
    return status;
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    BaseType_t status;
    //归还信号量:
    xSemaphoreGiveFromISR(send_sem, &status);
    if(status == pdTRUE)
    {
        portYIELD_FROM_ISR(status);
    }
}


//非阻塞方式接收数据:
SemaphoreHandle_t recv_sem;
char* ptr = NULL;
int maxlen = 0;
int uart_recv_by_interrupt(void* buf, int maxSize)
{
    HAL_StatusTypeDef status;
    ptr = buf;
    maxlen = maxSize;
    //先申请信号量
    recv_sem = xSemaphoreCreateBinary();
    //再调用非阻塞中断接收函数:
    status = HAL_UART_Receive_IT(&huart1, buf, 1);
    
    //获取信号量:
    xSemaphoreTake(recv_sem, portMAX_DELAY);
    //删除信号量:
    vSemaphoreDelete(recv_sem);
    return status;
}

//接受中断中的完成时的中断回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    static int len = 0;
    BaseType_t status;
    if(*ptr == '\0' || *ptr == '\n' || *ptr == '\r' || len > maxlen - 1)
    {
        //归还信号量:
        xSemaphoreGiveFromISR(recv_sem, &status);
        if(status == pdTRUE)
        {
            portYIELD_FROM_ISR(status);
        }
        //len归0
        len  = 0;
        //一定要在此返回
        return;
    }
    len++;
    ptr++;
    HAL_UART_Receive_IT(&huart1, (uint8_t*)ptr, 1);
}

应用测试:

#include "uart_app.h"
#include "uart_driver.h"
#include <string.h>
#include <stdbool.h>

//uart测试任务回调函数:
void uart_task_function(void* arg)
{
    const char* str = "Welcome uart_test,Please input CMD: \n";
    uart_send_by_interrupt((void*)str,strlen(str));
    char buf[128] = {0};
    while (true)
    {
        /* 测试uart串口收发数据 */
        memset(buf, 0,sizeof(buf));
        uart_recv_by_interrupt(buf, sizeof(buf)-1);
        //发给串口,在PC串口终端进行显示:
        uart_send_by_interrupt(buf,strlen(buf));
    }
}

3.DMA版收发数据接口函数:

1. DMA简述:

1. 什么是DMA,作用是什么?

由于很多外设的数据都由CPU进行拷贝,为了提高CPU实时性,进行更加重要的数据逻辑的处理,对于数据拷贝的工作,交于一个专门进行定向内存拷贝工作的Soc内部组件,就是DMA.

F103这个MCU有两个DMA控制器,DMA1有7个通道,DMA2有5个通道。每个通道用来处理来自一个或多个外设对存储器的访问。

DMA的作用:对于代替CPU执行一些简单的数据拷贝工作,拷贝完成之后产生一个中断通知,不需要CPU介入传输的具体过程。

2.DMA框图:

 

2.DMA版串口收发数据:

2.1 DMA版发送数据:

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
功能:用于通过 UART(通用异步收发传输器)以 DMA(直接存储器访问)方式发送数据
参数说明
UART_HandleTypeDef *huart:一个指向 UART_HandleTypeDef 结构体的指针,该结构体包含指定 UART 模块的配置信息。这个结构体包括 UART 外设的实例,以及其配置和状态信息。
uint8_t *pData:一个指向数据缓冲区的指针,缓冲区中包含要发送的数据。
uint16_t Size:要发送的数据的字节数。
返回值
该函数返回一个 HAL_StatusTypeDef 类型的值,可以是以下几种之一:
HAL_OK: 函数执行成功。
HAL_ERROR: 执行过程中发生错误。
HAL_BUSY: UART 当前正忙于之前的操作。
该函数是非阻塞的,数据传输将在后台进行。函数调用后立即返回,传输完成后会产生一个 DMA 中断。
需要在相应的 UART 和 DMA 中断服务程序(ISR)中处理传输完成事件。通常在 ISR 中调用 HAL_UART_IRQHandler 函数来处理中断。
在传输完成后会调用 HAL_UART_TxCpltCallback 回调函数,用户可以在该回调函数中执行后续处理。
与中断版一样。也可以处理完成之后的回调函数。

 

在传输完成后会调用 :HAL_UART_TxCpltCallback 回调函数,用户可以在该回调函数中执行后续处理。

2.2 DMA版接收数据:

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
功能:用于通过 UART(通用异步收发传输器)以 DMA(直接存储器访问)方式接收数据
参数说明
UART_HandleTypeDef *huart
:一个指向 UART_HandleTypeDef 结构体的指针,该结构体包含指定 UART 模块的配置信息。这个结构体包括 UART 外设的实例,以及其配置和状态信息。
uint8_t *pData
:一个指向数据缓冲区的指针,接收的数据将存储在这个缓冲区中。
uint16_t Size
:要接收的数据的字节数。
返回值
该函数返回一个 HAL_StatusTypeDef 类型的值,可以是以下几种之一:
HAL_OK: 函数执行成功。
HAL_ERROR: 执行过程中发生错误。
HAL_BUSY: UART 当前正忙于之前的操作。
该函数是非阻塞的,数据接收将在后台进行。函数调用后立即返回,接收完成后会产生一个 DMA 中断。
需要在相应的 UART 和 DMA 中断服务程序(ISR)中处理接收完成事件。
通常在 ISR 中调用 HAL_UART_IRQHandler 函数来处理中断。

在接收完成后会调用 HAL_UART_RxCpltCallback 回调函数,用户可以在该回调函数中执行后续处理。

2.3调用路径:以发送为例:

2.4工程配置DMA: 

2.5 HAL库中的uart全局实例与dma全局实例之间的关系: 

2.6 DMA版uart收发应用实例:

驱动:

#include "uart_driver.h"
#include <string.h>
#include <stdio.h>
extern UART_HandleTypeDef huart1;
// 阻塞方式发送数据:
int uart_send_by_block(void *buf, int size)
{
    return HAL_UART_Transmit(&huart1, buf, size, portMAX_DELAY);
}

// 阻塞方式接收数据:
int uart_recv_by_block(void *buf, int maxSize)
{
    HAL_StatusTypeDef status;
    char *ptr = (char *)buf;
    int len = 0;
    while (true)
    {

        status = HAL_UART_Receive(&huart1, (uint8_t *)ptr, 1, portMAX_DELAY);
        if (*ptr == '\0' || *ptr == '\n' || *ptr == '\r')
        {
            break;
        }
        ptr++;
        len++;
        if (len > maxSize - 1)
        {
            break;
        }
    }
    return status;
}

// 非阻塞方式发送数据:
// 实现完整数据的同步:
SemaphoreHandle_t send_sem;
int uart_send_by_interrupt(void *buf, int size)
{
    HAL_StatusTypeDef status;
    send_sem = xSemaphoreCreateBinary();
    status = HAL_UART_Transmit_IT(&huart1, buf, size);

    // 获取信号量:
    xSemaphoreTake(send_sem, portMAX_DELAY);
    // 删除信号量:
    vSemaphoreDelete(send_sem);
    return status;
}

// 非阻塞方式接收数据:
SemaphoreHandle_t recv_sem;
char *ptr = NULL;
int maxlen = 0;
int uart_recv_by_interrupt(void *buf, int maxSize)
{
    HAL_StatusTypeDef status;
    ptr = buf;
    maxlen = maxSize;
    // 先申请信号量
    recv_sem = xSemaphoreCreateBinary();
    // 再调用非阻塞中断接收函数:
    status = HAL_UART_Receive_IT(&huart1, buf, 1);

    // 获取信号量:
    xSemaphoreTake(recv_sem, portMAX_DELAY);
    // 删除信号量:
    vSemaphoreDelete(recv_sem);
    return status;
}

// 5.非阻塞DMA方式的发送数据:
SemaphoreHandle_t send_dma_sem;
int uart_send_by_dma(void *buf, int size)
{
    HAL_StatusTypeDef status;
    // 先创建信号量:
    send_dma_sem = xSemaphoreCreateBinary();
    status = HAL_UART_Transmit_DMA(&huart1, buf, size);

    // 获取信号量:
    xSemaphoreTake(send_dma_sem, portMAX_DELAY);

    //删除信号量:
    vSemaphoreDelete(send_dma_sem);
    return status;
}

// 发送完成之后的中断回调函数:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    BaseType_t status;
    if (huart1.hdmatx != NULL)
    {
        // 归还信号量:
        xSemaphoreGiveFromISR(send_dma_sem, &status);
        if (status == pdTRUE)
        {
            portYIELD_FROM_ISR(status);
        }
    }
    else{
        // 归还信号量:
        xSemaphoreGiveFromISR(send_sem, &status);
        if (status == pdTRUE)
        {
            portYIELD_FROM_ISR(status);
        }
    }
}

// 6.非阻塞中断方式接收数据:
SemaphoreHandle_t recv_dma_sem;
int uart_recv_by_dma(void *buf, int maxSize)
{
    HAL_StatusTypeDef status;
    ptr = buf;
    maxlen = maxSize;
    // 先申请信号量
    recv_dma_sem = xSemaphoreCreateBinary();
    // 再调用非阻塞中断接收函数:
    status = HAL_UART_Receive_DMA(&huart1, buf, 1);

    // 获取信号量:
    xSemaphoreTake(recv_dma_sem, portMAX_DELAY);
    // 删除信号量:
    vSemaphoreDelete(recv_dma_sem);
    return status;
}

// 接受中断中的完成时的中断回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    static int len = 0;
    BaseType_t status;
    if (*ptr == '\0' || *ptr == '\n' || *ptr == '\r' || len > maxlen - 1)
    {
        // 归还信号量:
        if(huart->hdmarx != NULL)
        {
            xSemaphoreGiveFromISR(recv_dma_sem, &status);
        }else{
            xSemaphoreGiveFromISR(recv_sem, &status);
        }
        if (status == pdTRUE)
        {
            portYIELD_FROM_ISR(status);
        }
        // len归0
        len = 0;
        // 一定要在此返回
        return;
    }
    len++;
    ptr++;
    if(huart->hdmarx != NULL)
    {
        HAL_UART_Receive_DMA(&huart1, (uint8_t *)ptr, 1);
    }
    else{
        HAL_UART_Receive_IT(&huart1, (uint8_t *)ptr, 1);
    }
    
}

 应用测试:

#include "uart_app.h"
#include "uart_driver.h"
#include <string.h>
#include <stdbool.h>

//uart测试任务回调函数:
void uart_task_function(void* arg)
{
    const char* str = "Welcome uart_test,Please input CMD: \n";
    uart_send_by_dma((void*)str,strlen(str));
    char buf[128] = {0};
    while (true)
    {
        /* 测试uart串口收发数据 */
        memset(buf, 0,sizeof(buf));
        uart_recv_by_dma(buf, sizeof(buf)-1);
        //发给串口,在PC串口终端进行显示:
        uart_send_by_dma(buf,strlen(buf));
    }
}

第四节、UART空闲idle中断:

1.idle中断是什么?意义是什么?

1.1什么是idle中断?

idle,空闲的定义是:总线上在一个字节(一个完整帧即10个bit)的时间内没有再接收到数据。

问:UART 的 IDLE 中断何时发生呢?

RxD 引脚一开始就是空闲的啊,难道 IDLE 中断一直产生?

答:不是的。当我们使能 IDLE 中断后,它并不会立刻产生,而是:至少收到 1 个数据后,发现:在一个字节的时间里,都没有接收到新数据,才会产生 。

1.2 idle中断意义是什么?

idle的意义:有了idle中断,我们对完整的数据边界就有了更好的判断,而不需要CPU参与到数据的判断中来,大大节约了CPU的资源。

2.idle中断的相关API:都是与接收数据相关的:

因为只有接收至少一个字节后,发现一个字节的数据帧的时间后没有接到数据,就会产生idle中断,通过idle中断我们来的处理相应的数据逻辑。

1.HAL_UARTEx_ReceiveToIdle

HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout);
功能:用于在接收数据时,当检测到 UART 接口的 IDLE 中断时停止接收,并返回已经接收到的数据长度。
这个函数用于处理不定长数据接收场景,在数据接收完成后自动触发回调,从而避免了需要预先知道数据长度的问题。

参数说明
huart:UART 句柄。
pData:指向接收数据缓冲区的指针。
Size:预期接收的数据大小。
RxLen:指向一个变量的指针,该变量在函数返回时包含实际接收的数据长度。
Timeout:指定超时时间。
返回值
HAL_OK:操作成功。
HAL_ERROR:操作失败。
HAL_BUSY:UART 正忙。
HAL_TIMEOUT:操作超时。

2.HAL_UARTEx_ReceiveToIdle_IT

HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout);
功能:结合了 IDLE 中断和中断驱动的接收机制,适用于处理不定长数据接收的场景。
参数说明
huart
:指向 UART 句柄的指针,用于指定使用的 UART 外设。
pData
:指向接收数据缓冲区的指针。数据将被接收到该缓冲区中。
Size
:接收缓冲区的大小。指定了缓冲区可以容纳的最大数据量。
返回值
HAL_OK:函数执行成功,数据接收已启动。
HAL_ERROR:发生了错误。
HAL_BUSY:UART 外设当前忙碌。
HAL_TIMEOUT:超时错误。
出现空闲时,回调中断处理函数:
实现 HAL_UARTEx_RxEventCallback 回调函数,以在 IDLE 中断时处理接收到的数据。

3.HAL_UARTEx_ReceiveToIdle_DMA

HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout);
功能:结合了 DMA 的高效数据传输和 IDLE 中断的检测机制,适合处理不定长的数据接收场景。
参数说明
huart:指向 UART 句柄的指针,用于指定使用的 UART 外设。
pData:指向接收数据缓冲区的指针。DMA 将数据从 UART 外设传输到此缓冲区中。
Size:接收缓冲区的大小。指定了缓冲区可以容纳的最大数据量。
返回值
HAL_OK:函数执行成功,DMA 接收已启动。
HAL_ERROR:发生了错误。
HAL_BUSY:UART 外设当前忙碌。
HAL_TIMEOUT:超时错误。
出现空闲时,回调中断处理函数:
实现 HAL_UARTEx_RxEventCallback 回调函数,以在 IDLE 中断时处理接收到的数据。

4.HAL_UARTEx_RxEventCallback回调函数:

__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);
作用是: STM32 HAL 库中用于处理 UART 接收事件的回调函数,特别是处理 IDLE 中断事件。
这一回调函数在 UART 外设接收到一段数据后并检测到数据传输结束时被调用
参数
UART_HandleTypeDef *huart:指向 UART 外设句柄的指针,包含了 UART 外设的配置信息和状态。
uint16_t Size:接收到的数据的长度,以字节为单位。

3.使用idle接收任意长度数据的实例,本想此实例为冲电朋友专属,感谢支持。本实例为冲电朋友专享内容。因为冲电与不冲电的朋友应该有不一样的待遇。

驱动:

测试:

#include "uart_app.h"
#include "uart_driver.h"
#include <string.h>
#include <stdbool.h>

//uart测试任务回调函数:
void uart_task_function(void* arg)
{
    const char* str = "Welcome uart_test,Please input CMD: \n";
    uart_send_by_dma((void*)str,strlen(str));
    char buf[128] = {0};
    while (true)
    {
        /* 测试uart串口收发数据 */
        memset(buf, 0,sizeof(buf));
        uart_recv_by_dmaToIdle(buf, sizeof(buf)-1);
        //发给串口,在PC串口终端进行显示:
        uart_send_by_dma(buf,strlen(buf));
    }
    
}

第五节、uart总结:

1.uart知识点结构:

2.uart终端的printf实现: 

 

工程编译使用MicroLib库:重新实现fputc函数即可。用于后续课程中的DeBug调试。
//重写putchar:
int fputc(int c, FILE* file)
{
        HAL_UART_Transmit(&huart1, (uint8_t*)&c, 1, portMAX_DELAY);
	    return c;
}

  • 31
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值