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改名大学已经确认名单:改名会对学校的发展带来哪些深远影响?
俄罗斯二战历史:重要战役及其影响
如何在未购房的情况下规划婚姻生活?这种规划方式有哪些潜在挑战?
干货攻略!数学本科可以选择哪些研究生专业?
从文字到视频,由AI生成的内容是怎么被识别出来的?
房价下行,物业费收缴率进一步承压
付氏家族的五大来源
财务总监的工作压力大吗?
天价彩礼为何屡屡触动社会神经?
“汉字叔叔”的故事:一位美国学者跨世纪的汉字情缘
真的想问:彩条牙膏挤出的颜色为什么不会混在一起?
藕粉是凉性的还是热性的
如何做前端模组设计
睡眠时心率40正常吗
兰寿金鱼能和什么鱼混养,混养需要注意什么
美国AEB新规:特斯拉夜间表现受挑战?
虚拟机如何映射游戏软件
心理学:为什么讨厌一个人的时候,会讨厌与这个人有关的一切?
漫画大师-路飞和黑胡子
空调最低温度的影响和应用(探讨空调最低温度对健康和节能的影响及优化策略)
爱牙护牙从小做起之预防儿童龋齿小知识
王者荣耀法术吸血率计算攻略:装备、铭文与英雄技能详解
工会专项业务费的申请条件是什么?
冬季神器保温杯,你选对了吗?
放下执念,拥抱平和:构建"不执着之爱"的认知与实践路径
木地板和复合地板有什么区别?哪个更适合家庭装修?
AI能从视频中学习吗?NTU S-Lab团队首个视频知识获取能力评测基准
智能电视如何安装云盘软件
骨髓瘤看哪几个指标