STM32基础开发入门:串口通信数据发送与接收详解

STM32基础入门开发: 串口数据发送与接收

引言

在嵌入式开发中,串口通信是一种常见的外设接口,广泛应用于数据传输和设备控制。本篇文章将介绍如何在STM32F103C8T6开发板上,通过串口1实现数据的发送和接收,并根据接收到的指令控制LED灯的开关。开发环境使用Keil 5,编程语言为C语言,库使用STM32标准库3.5版本。

硬件连接

  • STM32F103C8T6开发板
  • 串口1连接PC的串口通信工具(例如,使用USB转TTL模块)
  • 控制LED灯的引脚:PB0
  • LED灯通过限流电阻连接在PB0引脚上
  • 功能需求

  • 通过串口1接收数据,如果接收到"LED_ON"命令,则点亮LED灯;如果接收到"LED_OFF"命令,则关闭LED灯。
  • 使用串口进行数据的发送和接收。
  • 关键点

  • STM32的串口配置(波特率、数据位、停止位等)。
  • 使用定时器或轮询的方式处理串口接收数据。
  • 控制PB0引脚的输出,以控制LED灯的开关。
  • 开发步骤

    1. 硬件初始化

    首先,需要对PB0引脚进行初始化,将其设置为推挽输出模式,用于控制LED灯的开关。

    2. 串口初始化

    串口的初始化涉及到波特率、数据位、停止位、校验位等的配置。对于STM32F103C8T6,使用USART1进行串口通信。

    3. 串口发送和接收

    使用标准库提供的串口函数来发送和接收数据,通过中断或轮询方式读取接收到的数据并解析。

    4. 控制LED灯

    根据接收到的数据判断是否是"LED_ON"或"LED_OFF"指令,进而控制LED的点亮或熄灭。

    代码实现

    以下是基于STM32标准库3.5版本的完整代码,代码中包含详细注释说明。

    #include "stm32f10x.h"
    #include <string.h>
    
    #define LED_PIN    GPIO_Pin_0   // LED连接的引脚:PB0
    
    // 串口1的缓冲区
    #define RX_BUFFER_SIZE  64
    char RxBuffer[RX_BUFFER_SIZE];  // 接收数据的缓冲区
    volatile uint8_t RxIndex = 0;   // 接收数据的索引
    
    // 初始化LED引脚
    void LED_Init(void) {
        GPIO_InitTypeDef GPIO_InitStructure;
        
        // 使能GPIOB的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        
        // 配置PB0为推挽输出,LED控制引脚
        GPIO_InitStructure.GPIO_Pin = LED_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    }
    
    // 点亮LED
    void LED_On(void) {
        GPIO_SetBits(GPIOB, LED_PIN);  // 设置PB0为高电平,点亮LED
    }
    
    // 熄灭LED
    void LED_Off(void) {
        GPIO_ResetBits(GPIOB, LED_PIN);  // 设置PB0为低电平,熄灭LED
    }
    
    // 初始化串口1
    void USART1_Init(void) {
        USART_InitTypeDef USART_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        
        // 使能USART1和其对应的GPIO时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
        
        // 配置USART1的TX (PA9) 和 RX (PA10) 引脚
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           // TX
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     // 推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;          // RX
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        // 配置USART1
        USART_InitStructure.USART_BaudRate = 9600;          // 波特率9600
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;  // 数据位8位
        USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位1位
        USART_InitStructure.USART_Parity = USART_Parity_No;  // 无校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  // 发送接收模式
        USART_Init(USART1, &USART_InitStructure);
    
        // 使能USART1
        USART_Cmd(USART1, ENABLE);
        
        // 使能USART1接收中断
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    }
    
    // 串口发送字符
    void USART_SendChar(char c) {
        while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  // 等待发送缓冲区空
        USART_SendData(USART1, c);  // 发送数据
    }
    
    // 串口接收中断处理函数
    void USART1_IRQHandler(void) {
        if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
            char received = USART_ReceiveData(USART1);  // 接收数据
            if (RxIndex < RX_BUFFER_SIZE - 1) {
                RxBuffer[RxIndex++] = received;  // 存入缓冲区
                RxBuffer[RxIndex] = '\0';  // 保证字符串结尾
            }
        }
    }
    
    // 串口接收并处理命令
    void Process_Command(void) {
        if (strcmp(RxBuffer, "LED_ON") == 0) {
            LED_On();  // 点亮LED
        } else if (strcmp(RxBuffer, "LED_OFF") == 0) {
            LED_Off();  // 熄灭LED
        }
    }
    
    // 主程序
    int main(void) {
        // 初始化LED引脚
        LED_Init();
        
        // 初始化串口1
        USART1_Init();
        
        // 开启全局中断
        NVIC_EnableIRQ(USART1_IRQn);
    
        while (1) {
            // 在主循环中持续监控接收到的命令
            if (RxIndex > 0) {
                Process_Command();  // 处理接收到的命令
                RxIndex = 0;        // 重置接收索引,等待下一个命令
            }
        }
    }
    

    代码解析

    1. LED初始化LED_Init()函数配置PB0引脚为推挽输出,用于控制LED的点亮与熄灭。LED_On()LED_Off()函数分别控制LED的开与关。

    2. 串口初始化USART1_Init()函数配置了USART1的波特率、数据位、停止位等参数,并启用接收中断。PA9为串口1的TX(发送)引脚,PA10为RX(接收)引脚。

    3. 串口中断处理USART1_IRQHandler()是USART1的中断服务函数,当接收到数据时,数据被存入RxBuffer缓冲区。

    4. 命令处理Process_Command()函数根据接收到的字符串判断是否为"LED_ON"或"LED_OFF"命令,分别控制LED的状态。

    5. 主循环:在main()函数中,主循环持续监控串口接收缓冲区,当接收到数据时,调用Process_Command()处理命令并重置接收索引。

    测试

    使用串口调试工具(如PuTTY或Tera Term)与STM32开发板进行通信,发送以下命令测试LED灯控制功能:

  • 发送LED_ON:LED点亮
  • 发送LED_OFF:LED熄灭
  • 总结

    通过本文的学习,可以掌握如何在STM32F103C8T6开发板上实现基本的串口通信功能,完成数据的发送和接收,并通过串口接收控制命令来控制硬件(如LED灯)的状态。该示例代码简单而完整,为嵌入式开发中的串口通信奠定了基础。

    作者:开源云端架构师

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32基础开发入门:串口通信数据发送与接收详解

    发表回复