STM32独立按键控制LED流水灯详细解析
创作时间:
作者:
@小白创作中心
STM32独立按键控制LED流水灯详细解析
引用
CSDN
1.
https://blog.csdn.net/caoyang158332/article/details/146243006
在嵌入式开发中,按键控制LED进行不同的显示效果是一个常见的实验。本项目基于STM32单片机,实现四个独立按键控制LED进行不同的灯效变化。
1. 项目背景
在嵌入式开发中,按键控制LED进行不同的显示效果是一个常见的实验。本项目基于STM32单片机,实现四个独立按键控制LED进行不同的灯效变化。
2. 硬件设计
2.1 按键电路原理
从按键电路图来看,每个按键(KEY1-KEY4)都与GPIO端口(PC0-PC3)相连,同时通过220Ω的限流电阻接地。
- 按键按下时,GPIO读取为低电平(0)。
- 按键释放时,GPIO读取为高电平(1)。
2.2 LED控制电路
LED电路由8颗LED(LED1-LED8)组成,每个LED通过510Ω的限流电阻连接到VCC,并受PNP型三极管S8550控制。
- 三极管Q1的基极由LED_SW控制,当LED_SW置低时,三极管导通,LED获得驱动电流。
- 通过LED1至LED8对应的GPIO控制各个LED的亮灭状态。
3. 代码实现
3.1 按键扫描函数
uint8_t key_status(void)
{
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0)
{
key_flag = 1;
}
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0)
{
key_flag = 2;
}
if (HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == 0)
{
key_flag = 3;
}
if (HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == 0)
{
key_flag = 4;
}
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 1 &&
HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 1 &&
HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == 1 &&
HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == 1)
{
if (key_flag == 3 || key_flag == 4)
{
key_flag = 0;
}
}
return key_flag;
}
3.2 LED控制函数
单个LED控制
void led_on(uint8_t led) {
HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
switch (led) {
case 1: HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); break;
case 2: HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); break;
case 3: HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); break;
case 4: HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_RESET); break;
case 5: HAL_GPIO_WritePin(LED5_GPIO_Port, LED5_Pin, GPIO_PIN_RESET); break;
case 6: HAL_GPIO_WritePin(LED6_GPIO_Port, LED6_Pin, GPIO_PIN_RESET); break;
case 7: HAL_GPIO_WritePin(LED7_GPIO_Port, LED7_Pin, GPIO_PIN_RESET); break;
case 8: HAL_GPIO_WritePin(LED8_GPIO_Port, LED8_Pin, GPIO_PIN_RESET); break;
}
}
全部LED控制
void led_all_on(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
for (int i = 1; i <= 8; i++) {
led_on(i);
}
}
void led_all_off(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
for (int i = 1; i <= 8; i++) {
led_off(i);
}
}
3.3 流水灯功能
左移流水灯
void led_left(void){
uint8_t j;
HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
for(uint8_t i = 1; i <= 8; i++){
led_on(i);
HAL_Delay(DELAY_MS);
led_off(i-1);
for (j = 0; j < DELAY_MS / 10; j++) {
HAL_Delay(10);
key_status();
if (key_flag != 1) return;
}
}
}
右移流水灯
void led_right(void){
uint8_t j;
HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
for(uint8_t i = 8; i > 0; i--){
led_on(i);
HAL_Delay(DELAY_MS);
led_off(i+1);
for (j = 0; j < DELAY_MS / 10; j++) {
HAL_Delay(10);
key_status();
if (key_flag != 2) return;
}
}
}
3.4 红绿灯控制
void led_red(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
led_on(1); led_on(3); led_on(5); led_on(7);
}
void led_green(){
HAL_GPIO_WritePin(LED_SW_GPIO_Port,LED_SW_Pin,GPIO_PIN_RESET);
led_on(2); led_on(4); led_on(6); led_on(8);
}
4. 主循环
while(1){
key_status();
switch(key_flag){
case 0: led_all_off(); break;
case 1: led_left(); break;
case 2: led_right(); break;
case 3: led_red(); break;
case 4: led_green(); break;
}
}
目前led_left()和led_right()使用for循环逐个点亮LED,并在HAL_Delay过程中不断轮询按键状态。可以优化为:仅当key_flag仍为1或2时继续循环
避免多次调用HAL_GPIO_WritePin(LED_SW_GPIO_Port, LED_SW_Pin, GPIO_PIN_RESET);
void led_left(void) {
uint8_t i = 1;
while (key_flag == 1) {
led_on(i);
HAL_Delay(DELAY_MS);
led_off(i);
i = (i % 8) + 1; // 让LED依次点亮
}
}
使用数组优化LED控制
目前led_on()和led_off()代码冗余,可用数组优化:
GPIO_TypeDef* LED_PORTS[] = {LED1_GPIO_Port, LED2_GPIO_Port, LED3_GPIO_Port, LED4_GPIO_Port,
LED5_GPIO_Port, LED6_GPIO_Port, LED7_GPIO_Port, LED8_GPIO_Port};
uint16_t LED_PINS[] = {LED1_Pin, LED2_Pin, LED3_Pin, LED4_Pin,
LED5_Pin, LED6_Pin, LED7_Pin, LED8_Pin};
void led_on(uint8_t led) {
if (led >= 1 && led <= 8) {
HAL_GPIO_WritePin(LED_PORTS[led - 1], LED_PINS[led - 1], GPIO_PIN_RESET);
}
}
5. 结论
本项目实现了按键控制LED的不同显示模式,涵盖流水灯、红绿灯控制等。整个程序逻辑清晰,能够用于STM32的按键与LED控制实验。希望对大家有所帮助!
6. 优化
增加调试技巧
- 按键消抖
当前代码没有进行按键消抖,可能会导致误触发。可以使用简单的软件消抖,例如:
uint8_t read_key(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {
if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET) {
HAL_Delay(10); // 简单消抖
if (HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) == GPIO_PIN_RESET) {
return 1;
}
}
return 0;
}
然后在key_status()中使用read_key(KEY1_GPIO_Port, KEY1_Pin)代替HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)。
添加串口调试信息
在关键位置加入printf输出,有助于调试:
热门推荐
100分的色彩人物是这样的,这4个方法缺一不可
二十四节气与七十二候:解读中国传统物候历
白夜极光卡戎技能强度解析 卡戎角色评价
傅佩荣详解易经64卦革卦
遇网络安全如何报警
实地调查方法详解:从访问到实验的全方位指南
平安证券:社融开门红,货币政策或将密切关注基本面及外部环境边际变化
唇部填充剂与“翻唇“治疗,国外媒体大热
泰拉瑞亚PC版如何刷钱?高效方法揭秘
四点教你快速区分示波器间的差别
博弈论书籍推荐:从入门到进阶,带你解锁策略思维
《博弈书推荐:从入门到进阶,带你解锁策略思维》
关于「苗王」麻风腮,家长常问的都在这
第聂伯罗彼得罗夫斯克:乌克兰第四大城市的历史变迁
齐聚广州明城墙下,十八城联盟“墙墙”联手共话文旅融合发展
赛博是什么含义
北欧墙布木地板:书写质感与自然之美
北欧风格室内设计趋势:简约与实用并存
古代受过九锡之礼的是谁
甘草陈皮合用的功效是什么
上市公司收购的目的与程序详解
元宇宙技术的发展趋势是什么?
黄粱一梦与南柯一梦:两个典故的出处和意义解析
奇门遁甲排盘起局详解:从干支历到九星八门的完整步骤
炝虾(醉虾)的做法
都21世纪了,秦始皇地宫仍未打开,是技术不允许,还是有秘密?
无人驾驶车辆发生事故该由谁担责?律师解读
国产AI大战高考作文!20款大模型横评,看得我头皮发麻
如何恢复误删除的文件夹?一分钟教你解决问题!
分公司税务注销需要什么材料