第4章 串口通信实验

第四章 串口通信实验

1. 硬件设计

本实验需要使用的硬件资源有:

  1. 指示灯DS0

  2. 串口1

串口 1 之前还没有介绍过,本实验用到的串口 1 与 USB 串口并没有在 PCB 上连接在一起,需要通过跳线帽来连接一下。这里我们把 P6 的 RXD 和 TXD 用跳线帽与 PA9 和 PA10 连接起来。

屏幕截图 2024 09 09 111837

2. 软件设计

2.1 编程大纲

  1. 串口GPIO配置

  2. 串口参数配置

  3. 主函数测试串口收发

2.2 代码分析

2.2.1 串口GPIO初始化

// 此函数会被HAL_UART_Init()调用,用于初始化串口外设的GPIO
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    if(huart->Instance==USART1) // 如果是串口1,则初始化GPIO和NVIC
    {
        __HAL_RCC_USART1_CLK_ENABLE(); // 使能串口1时钟
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
        // 初始化串口1的TX、RX引脚
        GPIO_InitStructure.Pin = GPIO_PIN_9 | GPIO_PIN_10;
        GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStructure.Pull = GPIO_PULLUP;
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStructure.Alternate = GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
        // NVIC配置
        HAL_NVIC_EnableIRQ(USART1_IRQn);
        HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    }
}

2.2.2 串口配置

UART_HandleTypeDef UART1_Handler;

void UART_Init(uint32_t baudrate)
{
    UART1_Handler.Instance = USART1;
    UART1_Handler.Init.BaudRate = baudrate;
    UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B;// 8位数据位
    UART1_Handler.Init.StopBits = UART_STOPBITS_1;     // 1位停止位
    UART1_Handler.Init.Parity = UART_PARITY_NONE;      // 无校验位
    UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;// 无硬件流控
    UART1_Handler.Init.Mode = UART_MODE_TX_RX;         // 收发模式
    HAL_UART_Init(&UART1_Handler);
}

2.2.3 主函数

extern UART_HandleTypeDef UART1_Handler; // 串口句柄

int main(void)
{
    HAL_Init();
    UART_Init(115200);  // 初始化串口1,波特率115200

    uint8_t buf[100];   // 接收缓冲区
    uint16_t len = 0;   // 接收到的长度

    while(1)
    {
        memset(buf, 0, sizeof(buf));  // 清空接收缓冲区
        HAL_UART_Receive(&UART1_Handler, buf, 100, 100); // 接收数据

        // 找到接收到的数据末尾并手动添加结束符
        len = strlen((char*)buf); 
        if (len > 0 && buf[len - 1] != '\0') 
        {
            buf[len] = '\0'; // 确保字符串以NULL结尾
        }

        HAL_UART_Transmit(&UART1_Handler, buf, len, 100); // 发送接收到的字符串
    }
}

在此我们需要分析三个重要的HAL库函数:

2.2.3.1 memset函数

memset 是 C 语言标准库中的一个函数,用于设置一块内存区域的值。它通常用于初始化数组或内存块,将特定的字节值填充到内存中。

void *memset(void *s, int c, size_t n);

参数说明:

  • s: 指向要设置值的内存区域的指针,通常是一个数组或者一块动态分配的内存。
  • c: 要设置的值,memset 会将这个值填充到内存区域中的每个字节。虽然参数类型是 int,但 memset 会将其转换为 unsigned char 类型,然后填充到内存中。
  • n: 要设置的字节数,即将 c 的值写入 s 所指向内存块的前 n 个字节。
2.2.3.2 HAL_UART_Receive函数

HAL_UART_Receive 是 STM32 HAL 库中用于接收串口数据的函数,它通过 UART 外设接收数据并将其存储在提供的缓冲区中。

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

参数说明:

  • huart: 指向 UART_HandleTypeDef 结构体的指针。这个结构体包含了 UART 外设的配置信息,指明了要操作的 UART 外设(如 USART1, USART2 等),以及该外设的配置参数(波特率、数据位、停止位等)。

  • pData: 指向接收数据缓冲区的指针。在函数执行时,接收到的数据将被存储在这个缓冲区中。缓冲区需要足够大来存储预期的接收数据。

  • Size: 接收的数据字节数,即期望从 UART 接收多少个字节的数据。如果是一个字符,可以设置为 1;如果需要接收多个字节,可以设置为更大的值。

  • Timeout: 接收超时时间(以毫秒为单位)。这是函数等待数据接收的最大时间。如果在此时间内未能接收到所需的字节,函数将返回超时错误。

2.2.3.3 HAL_UART_Transmit函数

HAL_UART_Transmit 是 STM32 HAL 库中用于发送数据通过 UART 外设的函数。它将数据从内存缓冲区传输到 UART 外设并通过串口发送出去。

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

参数说明:

  • huart: 指向 UART_HandleTypeDef 结构体的指针,该结构体包含了 UART 外设的配置和状态信息(例如波特率、数据位、停止位等),指明了要操作的 UART 外设(如 USART1USART2 等)。

  • pData: 指向包含要发送数据的缓冲区的指针。该缓冲区中的数据将被逐字节发送到 UART 外设。

  • Size: 要发送的数据字节数。即你希望从缓冲区发送的字节数。

  • Timeout: 发送数据的超时时间(以毫秒为单位)。如果在此时间内数据没有成功发送完毕,函数将返回超时错误。

3. 小结

本章经过改写后,应该是变简单了许多,第一版因为考虑到可以用到os,编写了其他函数,但是我们如果单单学习串口的话就显得复杂了。


2024.9.28 第一次修订,后期不再维护

2024.12.21 整体大改,因为只是学习串口,移除了第一版的自编通讯协议

posted @ 2024-09-28 10:14  hazy1k  阅读(38)  评论(0编辑  收藏  举报