STM32实现LED闪烁和串口打印案例

一、实验目的

在嵌入式开发中,GPIO(通用输入输出)和UART(串口通信)是最基础的两个外设。本次实验通过点亮一个LED灯,同时用串口打印LED的开关状态,完成从硬件控制到信息反馈的完整流程。

主要目标:

  • 掌握STM32的GPIO输出控制

  • 掌握USART串口的基本配置与使用

  • 理解printf重定向到串口的实现原理

  • 体会"嵌入式系统的Hello World"

二、硬件准备

序号 元件/模块 数量 说明
1 STM32最小系统板 1 我使用的是GD32F103VET6
2 LED发光二极管 1 若使用板载LED则不需要(我的是板载LED)
3 限流电阻 1 220Ω~1kΩ均可,板载LED不需要
4 USB转TTL模块 1 CH340/CP2102等(我的板载)
5 ST-Link下载器 1 烧录程序用(我的是DAP-Link)
6 杜邦线 若干

💡 提示 :很多开发板(如常见的Blue Pill板)板载LED连接在 PC13 引脚,低电平点亮。你可以根据自己的板子实际情况修改引脚,后面代码处会标注修改位置。

三、软件环境

  • 开发环境: Keil MDK

  • HAL库版本:GigaDevice.GD32F10x_DFP.2.0.3 固件包

  • 串口调试工具:SSCOM、MobaXterm、Putty 任意一款均可

四、硬件连接

4.1 LED连接

  • 使用板载LED:无需额外接线,板载LED通常接PC13,注意该引脚低电平点亮。

  • 使用外接LED:LED正极串联限流电阻后接GPIO引脚,负极接GND。

本文示例:LED接PC13引脚,低电平点亮(你可以改为自己的引脚)。

4.2 串口连接

使用USART0,引脚对应如下:

GD32引脚 USB转TTL模块 说明
PA9 RXD GD32的TX→模块的RX
PA10 TXD GD32的RX→模块的TX
GND GND 务必共地

五、工程配置

  1. 新建工程 ,选择芯片型号 GD32F103VET6

  2. 配置调试接口SYSDebug 选择 CMSIS-DAP Debugger(SWD下载,根据自己情况选择)。

  3. 配置时钟RCCHSE 选择 Crystal/Ceramic Resonator(使用外部晶振),Clock Configuration中设置主频为72MHz。

  4. 配置GPIO :将你的LED引脚(本示例为PC13)设置为 GPIO_Output,初始电平根据点亮逻辑设置。低电平点亮则初始给高电平让LED灭。

  5. 配置串口USART0Mode 选择 Asynchronous,波特率 115200,数据位8,停止位1,无校验。其他保持默认。

  6. 生成代码:Project Manager中设置工程名和路径,Toolchain选择你的IDE,勾选"Generate peripheral initialization as a pair of '.c/.h' files",点击GENERATE CODE。

六、代码实现

6.1 串口重定向(printf支持)

在 main.c,添加以下代码,让 uart_send_string()和UART0WriteData()直接通过串口输出:

bash 复制代码
//串口0数据接收buff大小
#define UART0_RX_BUFF_SIZE          (512)

//串口0接收到的数据长度
#define UART0_RX_DATA_LEN           ((gUart0RxData.tail + UART0_RX_BUFF_SIZE - gUart0RxData.head) % UART0_RX_BUFF_SIZE)

//删除串口0已读取的数据,len为删除数据长度
#define UART0_RX_DATA_DELETE(len)   (gUart0RxData.head = (gUart0RxData.head + (len)) % UART0_RX_BUFF_SIZE)

//判断串口0接收buff是否已满
#define UART0_RX_BUFF_IS_FULL()     (((gUart0RxData.tail + 1) % UART0_RX_BUFF_SIZE == gUart0RxData.head) ? TRUE : FALSE)


void UART0Init(void)
{
    // 打开GPIOA和串口0时钟
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_USART0);    

    //串口0引脚配置
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, 0U, GPIO_PIN_10);

    //初始化配置
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    
    /* enable USART0 receive interrupt */
    usart_interrupt_enable(USART0, USART_INT_RBNE);
    nvic_irq_enable(USART0_IRQn, 1U, 3U);

    /* enable USART0 */
    usart_enable(USART0);
}


//方式1
//1para
void uart_send_string(char *str) {
    while (*str) {
        usart_data_transmit(USART0, *str);
        while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
        str++;
    }
}

方式2
//2 para
int UART0WriteData(char *pBuff, int len)
{    
	int i;
    if (pBuff == NULL || len == 0)
    {
        return 0;
    }

    for (i = 0; i < len; i++)
    {
        usart_data_transmit(USART0, pBuff[i]);
        while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    }

    return len;
}

6.2 主循环逻辑

main.cmain() 函数中,while(1)循环部分编写如下:

bash 复制代码
int main(void)
{
	systick_config(); // 初始化计时器
	
		    /* 初始化中断向量        */
    //NVIC_Init();
	    nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
    //nvic_vector_table_set(NVIC_VECTTAB_FLASH, FLASH_APP_ADDR);
    __enable_irq();
	
	rcu_periph_clock_enable(RCU_GPIOC); //打开GPIOA时钟
	gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13); //将PA0配置为浮空输入,最高支持50MHZ
	

	UART0Init();
    uart_send_string("System started\r\n");     // 
	

	
    while(1)
	{
		gpio_bit_reset(GPIOC, GPIO_PIN_13); //将PC13置低电平,点亮LED
		UART0WriteData("LED ON\r\n",6);
		delay_1ms(3000);
		gpio_bit_set(GPIOC, GPIO_PIN_13); //½<<PC13ÖÃ¸ßµçÆ½£¬Ï¨ÃðLED
		UART0WriteData("LED OFF\r\n",7);
		delay_1ms(1000);
	}
	
    return 0;
}

七、编译烧录与串口验证

  1. 编译工程,确认0错误0警告。

  2. 通过DAP-Link将程序烧录到开发板。

  3. 将USB转TTL模块插入电脑,打开串口调试助手。

  4. 设置参数:波特率115200、8数据位、1停止位、无校验

  5. 给开发板上电或按复位键。

此时应看到LED灯亮3秒,灭1秒,串口输出类似以下内容:

八、实验总结

本次实验成功实现了两个核心功能:

  1. GPIO输出控制:通过对引脚写高/低电平来控制LED的亮灭,这是嵌入式系统中最基础的"数字输出"操作。

  2. 串口通信 :通过USART将MCU内部信息发送到PC端显示,实现了人机交互的最简单形式。printf重定向是嵌入式调试中非常实用的技巧。

这个实验打通了"写代码 → 控制硬件 → 获取反馈"的完整链路,是后续学习定时器、中断、I2C/SPI等外设的坚实基础。

相关推荐
济6172 小时前
FreeRTOS 系统监控任务设计(上篇) ---MonitorTask的 基础框架
单片机·嵌入式·freertos
LCG元2 小时前
STM32实战:基于STM32F103的智能语音识别系统(LD3320)
stm32·嵌入式硬件·语音识别
Jason_zhao_MR2 小时前
RK3576 MIPI Camera ISP调试:客观标定与环境准备(上)
人工智能·嵌入式硬件·机器人·嵌入式·接口隔离原则
深圳市晶科鑫实业有限公司2 小时前
RTC模块vs. 32.768KHz晶振:深度对比与选型指南
stm32·单片机·嵌入式硬件·实时音视频·rtc
weixin_452077642 小时前
VS code 使用STM32CubelDE for Visual Studio Code环境,如何配置CMakeLists.txt新增其他.C文件路径
c语言·vscode·stm32
jghhh012 小时前
STM32F103 驱动 BMP180 气压传感器源码
stm32·单片机·嵌入式硬件
踏着七彩祥云的小丑2 小时前
嵌入式测试学习第 5 天:电阻分类、色环电阻读数、贴片电阻
单片机·嵌入式硬件
济6173 小时前
MonitorTask 系统监控任务(下篇)---完善堆内存 、任务栈监控
单片机·嵌入式·freertos
代码又报错la3 小时前
5、电源保护板
单片机·嵌入式硬件