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输出,有助于调试:
热门推荐
中兵红箭基本面向好还是向差?
植物神经紊乱患者适宜的运动选择
股票期权证券账户注销如何处理?
认识呼吸系统的“肿瘤君”——肺结核
六级听力突破:高效策略与听力技巧全解析
2025年外资银行行业分析:机遇与挑战并存
人才税收优惠政策解读,吸引和留住人才更有力
普通人如何自学中医?
木星:太阳系的塑造者和行星杀手
几十块和几千块的枕头,到底有什么区别?挑对枕头要看这些→
安全性高的普伐他汀,为什么用的人不多,是有什么限制吗?
鱼缸巧放置 风水旺家运
国际贸易术语基本知识点
消化不良有哪些症状表现?四大症状需警惕
JCTH指南|李兰娟/张文宏/任红/赵英仁:中国乙肝母婴传播防治指南更新要点
恩捷股份先涨10倍再跌9成,A股最妖的“茅”
公务员可以停薪留职吗?法律依据与实施条件深度解析
假如人民币兑美元1:1会怎么样?那么,中国GDP会超过美国吗?
大腿外侧疼痛挂什么科
投影仪光源的演变
柴油发动机的工作原理(第一部分)
银行员工行为管理办法
出租房卫生如何要求和约定
长文本向量模型分块策略大比拼:不分块、朴素分块与迟分的优劣分析
起名八字和三才五格哪个重要
学科评估为B等级并不意味着很差
避开这3个误区,拥抱真正的有效恋爱
了见水中月,青莲出尘埃。
感冒血常规化验单怎么看
“吃饭八分饱”错了?过了60岁,吃饭要尽量做到这3点