【第1期】串口1和串口2驱动调试完成

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
好的,编写STM32的串口程序是入门和项目开发中最常见的任务之一。下面我将为您提供一个从零开始、非常详细的教程,包含两种最主流的方法:使用HAL库使用LL库,并以轮询中断两种方式为例。

我们以最常见的场景 UART1 为例,实现发送和接收功能。


准备工作

  1. 硬件: 一块STM32开发板(如STM32F103C8T6最小系统板),USB转TTL串口模块(如CH340、CP2102)。
  2. 软件: STM32CubeIDE(它集成了STM32CubeMX和代码编辑、编译功能,是ST官方推荐的工具)。
  3. 连接:
    • 将开发板的 UART1_TX (通常是PA9) 连接到USB转TTL模块的 RX
    • 将开发板的 UART1_RX (通常是PA10) 连接到USB转TTL模块的 TX
    • 共地! 将开发板的 GND 与USB转TTL模块的 GND 连接。

方法一:使用STM32CubeIDE和HAL库(最推荐,最快)

HAL库抽象程度高,代码可移植性好,适合快速开发。

步骤1:创建工程并配置时钟
  1. 打开STM32CubeIDE,新建一个工程,选择你的MCU型号(例如STM32F103C8Tx)。
  2. 在图形化配置界面(Pinout & Configuration)中:
    • 在左侧System Core -> SYS中,将Debug选为Serial Wire(如果要用ST-Link调试)。
    • RCC中,将High Speed Clock (HSE) 选为Crystal/Ceramic Resonator(使用外部高速晶振)。
步骤2:配置UART引脚和参数
  1. 在左侧Connectivity -> USART1中:
    • Mode设置为 Asynchronous(异步模式)。
    • 此时,右边的芯片图上PA9和PA10会自动被设置为USART1_TX和USART1_RX。
  2. 在下方Parameter Settings中配置串口参数:
    • Baud Rate: 115200 (常用波特率)
    • Word Length: 8 Bits (数据位)
    • Parity: None (校验位)
    • Stop Bits: 1 (停止位)
    • Over Sampling: 16 Samples (默认)
    • 其他保持默认。
步骤3:生成代码
  1. 点击右上角的"GENERATE CODE"按钮。
  2. STM32CubeIDE会自动生成一个完整的MDK/IDE/IAR等工具链的项目代码。
步骤4:编写用户代码

生成的代码中,你的用户代码应该写在/* USER CODE BEGIN ... *//* USER CODE END ... */ 之间,以防止下次重新生成代码时被覆盖。

示例1:轮询方式发送 + 中断方式接收(最常用)

我们实现一个回声(Echo) 功能:单片机收到一个字节,就原样发回给电脑。

  1. 首先开启接收中断

    • main.c/* USER CODE BEGIN 2 */部分,启动UART的接收中断。
    /* USER CODE BEGIN 2 */
    // 启动UART1的接收中断
    // 参数1: UART句柄, 参数2: 存放接收数据的缓冲区, 参数3: 接收的数据量(1字节)
    HAL_UART_Receive_IT(&huart1, &rx_data, 1);
    /* USER CODE END 2 */
    
  2. 定义全局变量

    • /* USER CODE BEGIN PV */部分,定义接收缓冲区。
    /* USER CODE BEGIN PV */
    uint8_t rx_data; // 用于存放接收到的1个字节
    /* USER CODE END PV */
    
  3. 重写接收中断回调函数

    • main.c文件的末尾,/* USER CODE BEGIN 4 */部分,重写HAL库的UART接收完成中断回调函数。当收到一个字节后,这个函数会被自动调用。
    /* USER CODE BEGIN 4 */
    // UART接收完成中断回调函数
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
      // 判断是否是UART1触发的中断
      if (huart->Instance == USART1)
      {
        // 1. 将收到的字节原样发送回去(轮询方式发送)
        HAL_UART_Transmit(&huart1, &rx_data, 1, 1000); // 超时时间1000ms
    
        // 2. !!!重要:重新启动接收中断,以等待下一个字节 !!!
        HAL_UART_Receive_IT(&huart1, &rx_data, 1);
      }
    }
    /* USER CODE END 4 */
    

代码解释:

  • HAL_UART_Receive_IT(...): 启动一次中断接收,设置好接收缓冲区和长度后,UART硬件会在收到数据时自动产生中断,并将数据存入缓冲区,然后调用回调函数。
  • HAL_UART_RxCpltCallback: 这是一个弱定义函数,我们重写它来加入自己的逻辑。在这里,我们简单地回传收到的数据。
  • 必须重新启动接收中断:因为HAL库的中断接收是一次性的,每次完成后都需要重新启动才能进行下一次接收。

示例2:轮询方式发送和接收(简单,但会阻塞)

/* USER CODE BEGIN 2 */
uint8_t tx_buffer[] = "Hello World!\r\n"; // 要发送的数据
uint8_t rx_buffer[10]; // 接收缓冲区

// 轮询发送字符串
HAL_UART_Transmit(&huart1, tx_buffer, sizeof(tx_buffer) - 1, 1000);

// 轮询接收10个字节(程序会停在这里,直到收到10个字节或超时)
HAL_UART_Receive(&huart1, rx_buffer, 10, 1000);

// 将接收到的10个字节再发送回去
HAL_UART_Transmit(&huart1, rx_buffer, 10, 1000);
/* USER CODE END 2 */

方法二:使用LL库(更接近底层,效率更高)

LL库提供了对寄存器的直接操作,代码量小,运行效率高,但需要开发者对寄存器有更多了解。

步骤1&2:工程配置

与HAL库步骤相同,但在Project Manager -> Advanced Settings中,将USART1的API全部改为LL

步骤3:编写LL库代码

同样实现Echo功能。

  1. 开启中断并编写中断服务函数

    • main.c/* USER CODE BEGIN 2 */部分,使能UART接收中断。
    /* USER CODE BEGIN 2 */
    // LL库:使能UART1的接收寄存器非空中断
    LL_USART_EnableIT_RXNE(USART1);
    /* USER CODE END 2 */
    
  2. 编写中断服务函数

    • stm32f1xx_it.c文件中,找到USART1_IRQHandler函数。
    // 在 stm32f1xx_it.c 文件中
    void USART1_IRQHandler(void)
    {
      /* USER CODE BEGIN USART1_IRQn 0 */
      // 检查是否是"接收寄存器非空"中断标志
      if(LL_USART_IsActiveFlag_RXNE(USART1))
      {
        // 读取接收到的数据(这个操作会自动清除RXNE标志)
        uint8_t rx_data = LL_USART_ReceiveData8(USART1);
    
        // 等待发送寄存器为空,确保可以发送新数据
        while(!LL_USART_IsActiveFlag_TXE(USART1));
    
        // 将收到的数据发送回去
        LL_USART_TransmitData8(USART1, rx_data);
      }
      /* USER CODE END USART1_IRQn 0 */
      // ... 其他代码
    }
    

LL库代码解释:

  • LL_USART_EnableIT_RXNE: 使能"接收寄存器非空"中断。当UART收到数据后,状态寄存器的RXNE位会置1,并产生中断。
  • LL_USART_IsActiveFlag_RXNE: 在中断服务函数中检查是否是接收中断。
  • LL_USART_ReceiveData8: 读取接收到的数据,读取后硬件会自动清除RXNE标志。
  • LL_USART_IsActiveFlag_TXELL_USART_TransmitData8: 检查发送寄存器是否为空,然后写入要发送的数据。

测试与调试

  1. 编译并下载程序到STM32开发板。
  2. 连接串口模块到电脑。
  3. 在电脑上打开串口调试助手(如Putty、SecureCRT、或者STM32CubeIDE自带的串口监视器)。
  4. 选择正确的COM口,设置波特率为115200,8N1。
  5. 在串口调试助手的发送框中输入任意字符,点击发送,你应该能看到对方立即回复同样的字符。这就是Echo功能。

总结与关键点

特性HAL库LL库
易用性,函数抽象好,逻辑清晰,需要了解寄存器
效率/代码大小较低,代码较大,代码精简
可移植性,在不同STM32系列间移植容易一般,与系列相关性高
推荐场景快速原型开发、初学者、复杂应用对性能和资源有严格要求的项目

关键注意事项:

  • 中断 vs 轮询:中断方式不阻塞主程序,是实际项目中的首选。轮询方式简单,但会浪费CPU时间。
  • 重入中断:使用HAL库中断接收时,务必在回调函数中重新启动接收
  • 缓冲区管理:上面的例子是单字节收发。如果处理不定长数据,需要设计环形缓冲区,并结合空闲中断(IDLE) 来判定一帧数据接收完成。HAL库提供了HAL_UARTEx_ReceiveToIdle_IT函数来处理这种情况。
  • 引脚复用:确保你的UART引脚没有和其他功能(如USB)冲突。

通过以上步骤,你应该可以成功编写并运行你的第一个STM32串口程序。从简单的Echo开始,逐步尝试更复杂的功能,如解析指令、传输数据包等。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值