用C语言写LED灯嵌入式系统案例|STM32 LED控制与按键输入系统

张开发
2026/4/15 20:44:19 15 分钟阅读

分享文章

用C语言写LED灯嵌入式系统案例|STM32 LED控制与按键输入系统
我来为您提供一个基于STM32的LED灯嵌入式系统案例。这个案例使用标准库包含按键控制LED闪烁。案例STM32 LED控制与按键输入系统1. 项目结构LED_Project/ ├── Core/ │ ├── Src/ │ │ ├── main.c │ │ ├── gpio.c │ │ └── sys.c │ └── Inc/ │ ├── gpio.h │ └── sys.h ├── Drivers/ └── README.md2. 主要代码文件main.c/** * file main.c * brief STM32 LED控制主程序 * details 实现LED闪烁、按键控制、定时器控制功能 */ #include stm32f1xx.h #include gpio.h #include sys.h #include stdint.h /* 全局变量定义 */ volatile uint32_t systick_counter 0; volatile uint8_t led_mode 0; // 0:关闭, 1:常亮, 2:慢闪, 3:快闪, 4:呼吸灯 volatile uint8_t button_pressed 0; /* 函数声明 */ void SystemClock_Config(void); void SysTick_Handler(void); void Delay_ms(uint32_t ms); void LED_Breathing(void); /** * brief 主函数 * param 无 * retval int */ int main(void) { /* MCU初始化 */ HAL_Init(); SystemClock_Config(); /* 外设初始化 */ GPIO_Init(); /* 配置SysTick定时器为1ms中断 */ SysTick_Config(SystemCoreClock / 1000); /* LED初始状态 */ LED_OFF(LED1); LED_OFF(LED2); while (1) { /* 按键扫描 */ if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 0) { Delay_ms(20); // 按键消抖 if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 0) { button_pressed 1; while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 0); // 等待按键释放 } } /* 按键处理 */ if (button_pressed) { button_pressed 0; led_mode (led_mode 1) % 5; // 循环切换模式 } /* 根据模式控制LED */ switch (led_mode) { case 0: // LED关闭 LED_OFF(LED1); LED_OFF(LED2); break; case 1: // LED常亮 LED_ON(LED1); LED_ON(LED2); break; case 2: // LED慢闪 (500ms) if (systick_counter % 1000 500) { LED_ON(LED1); LED_OFF(LED2); } else { LED_OFF(LED1); LED_ON(LED2); } break; case 3: // LED快闪 (200ms) if (systick_counter % 400 200) { LED_ON(LED1); LED_OFF(LED2); } else { LED_OFF(LED1); LED_ON(LED2); } break; case 4: // 呼吸灯效果 LED_Breathing(); break; } } } /** * brief SysTick中断服务函数 * param 无 * retval 无 */ void SysTick_Handler(void) { systick_counter; } /** * brief 简单延时函数 * param ms: 延时的毫秒数 * retval 无 */ void Delay_ms(uint32_t ms) { uint32_t start_time systick_counter; while ((systick_counter - start_time) ms); } /** * brief LED呼吸灯效果 * param 无 * retval 无 */ void LED_Breathing(void) { static uint8_t pwm_value 0; static int8_t direction 1; static uint32_t last_time 0; /* 每10ms调整一次PWM值 */ if ((systick_counter - last_time) 10) { last_time systick_counter; /* 更新PWM值 */ pwm_value direction; /* 改变方向 */ if (pwm_value 100) direction -1; if (pwm_value 0) direction 1; /* 简单PWM实现 */ if ((systick_counter % 100) pwm_value) { LED_ON(LED1); } else { LED_OFF(LED1); } LED2_TOGGLE(); // LED2在呼吸灯模式下闪烁 } } /** * brief 系统时钟配置 * param 无 * retval 无 */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct {0}; // 配置HSE RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9; if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK) { Error_Handler(); } // 配置系统时钟 RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(RCC_ClkInitStruct, FLASH_LATENCY_2) ! HAL_OK) { Error_Handler(); } }gpio.h/** * file gpio.h * brief GPIO配置头文件 */ #ifndef __GPIO_H #define __GPIO_H #include stm32f1xx.h /* LED引脚定义 */ #define LED1_PIN GPIO_Pin_5 #define LED1_PORT GPIOA #define LED2_PIN GPIO_Pin_6 #define LED2_PORT GPIOA /* 按键引脚定义 */ #define BUTTON_PIN GPIO_Pin_0 #define BUTTON_PORT GPIOA /* LED控制宏 */ #define LED_ON(led) (led##_PORT-BRR led##_PIN) // 输出低电平LED亮 #define LED_OFF(led) (led##_PORT-BSRR led##_PIN) // 输出高电平LED灭 #define LED_TOGGLE(led) (led##_PORT-ODR ^ led##_PIN) // 翻转LED状态 /* 针对特定LED的宏 */ #define LED1_ON() LED_ON(LED1) #define LED1_OFF() LED_OFF(LED1) #define LED1_TOGGLE() LED_TOGGLE(LED1) #define LED2_ON() LED_ON(LED2) #define LED2_OFF() LED_OFF(LED2) #define LED2_TOGGLE() LED_TOGGLE(LED2) /* 函数声明 */ void GPIO_Init(void); void Error_Handler(void); #endif /* __GPIO_H */gpio.c/** * file gpio.c * brief GPIO初始化配置 */ #include gpio.h /** * brief GPIO初始化 * param 无 * retval 无 */ void GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; /* 使能GPIO时钟 */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /* 配置LED引脚 - 推挽输出 */ GPIO_InitStruct.Pin LED1_PIN | LED2_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED1_PORT, GPIO_InitStruct); /* 配置按键引脚 - 输入模式上拉 */ GPIO_InitStruct.Pin BUTTON_PIN; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(BUTTON_PORT, GPIO_InitStruct); /* 配置一个额外的GPIO用于调试 */ GPIO_InitStruct.Pin GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); } /** * brief 错误处理函数 * param 无 * retval 无 */ void Error_Handler(void) { /* LED1和LED2同时闪烁表示错误 */ while(1) { LED1_TOGGLE(); LED2_TOGGLE(); for(int i 0; i 1000000; i); // 简单延时 } }3. Makefile 示例# 编译器定义 CC arm-none-eabi-gcc OBJCOPY arm-none-eabi-objcopy OBJDUMP arm-none-eabi-objdump SIZE arm-none-eabi-size # 编译选项 CFLAGS -mcpucortex-m3 -mthumb -Wall -Og -g CFLAGS -DSTM32F103x6 CFLAGS -fdata-sections -ffunction-sections LDFLAGS -mcpucortex-m3 -mthumb -specsnano.specs LDFLAGS -Wl,--gc-sections -TSTM32F103C8Tx_FLASH.ld # 包含路径 INCLUDES -ICore/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc # 源文件 SRCS Core/Src/main.c \ Core/Src/gpio.c \ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c # 目标文件 OBJS $(SRCS:.c.o) # 目标名称 TARGET led_project # 默认目标 all: $(TARGET).elf $(TARGET).hex $(TARGET).bin # 生成elf文件 $(TARGET).elf: $(OBJS) $(CC) $(LDFLAGS) -o $ $^ $(SIZE) $ # 生成hex文件 $(TARGET).hex: $(TARGET).elf $(OBJCOPY) -O ihex $ $ # 生成bin文件 $(TARGET).bin: $(TARGET).elf $(OBJCOPY) -O binary $ $ # 编译规则 %.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $ -o $ # 清理 clean: rm -f $(OBJS) $(TARGET).elf $(TARGET).hex $(TARGET).bin # 烧录到设备 flash: $(TARGET).bin openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg \ -c program $(TARGET).bin verify reset exit 0x08000000 .PHONY: all clean flash4. 链接脚本 (STM32F103C8Tx_FLASH.ld)MEMORY { RAM (xrw) : ORIGIN 0x20000000, LENGTH 20K FLASH (rx) : ORIGIN 0x8000000, LENGTH 64K } SECTIONS { .isr_vector : { . ALIGN(4); KEEP(*(.isr_vector)) . ALIGN(4); } FLASH .text : { . ALIGN(4); *(.text) *(.text*) . ALIGN(4); } FLASH .rodata : { . ALIGN(4); *(.rodata) *(.rodata*) . ALIGN(4); } FLASH .data : { . ALIGN(4); _sdata .; *(.data) *(.data*) . ALIGN(4); _edata .; } RAM AT FLASH .bss : { . ALIGN(4); _sbss .; *(.bss) *(.bss*) . ALIGN(4); _ebss .; } RAM }5. 案例功能说明这个嵌入式LED系统实现了以下功能LED控制模式模式0关闭所有LED模式1LED常亮模式2双LED交替慢闪500ms模式3双LED交替快闪200ms模式4呼吸灯效果按键控制PA0作为按键输入支持按键消抖按键按下切换LED模式系统特性使用SysTick定时器实现精确延时支持PWM呼吸灯效果错误处理机制6. 硬件连接LED1 → PA5LED2 → PA6按键 → PA0按下为低电平使用8MHz外部晶振7. 编译和烧录# 编译项目 make # 清理编译文件 make clean # 烧录到STM32 make flash这个案例展示了嵌入式系统中LED控制的基本实现包括GPIO配置、中断处理、定时器使用和按键扫描等常用技术。您可以根据实际需求进行修改和扩展。

更多文章