上一节我们学习了独立按键的原理,并基于C51语言实现短按和长按按键处理程序。本节我们继续学习更复杂的独立按键编程,实现单个按键执行不同功能。
注:本文中,独立按键指微动开关(按下闭合,松开自动弹起),而非拨码开关。
先看下图,这是一个自行车警示灯,用于夜骑提醒后方来车,预防骑行车被追尾,提高夜晚骑行安全。自行车警示灯具有多种警示模式,如长亮、闪烁和跑马灯,通常只有一个独立按键用于切换模式。本节我们尝试编程实现自行车警示灯功能,实现单键的高级应用。本例仅演示编程,硬件设计不在讨论范围。
1 某款自行车警示灯广告图
一、警示灯功能要求
1.四种闪烁模式:强光长亮,弱光长亮,闪烁,走马灯闪烁。
2.一个独立按键用于设置警示灯模式,短按顺序切换:强光长亮→弱光长亮→闪烁→走马灯闪烁。
二、编程思路
单键实现LED灯的亮灭控制很简单,但是要实现四种闪烁模式的顺序切换,感觉非常难,无从下手。怎么办呢?稍安勿躁,让我们先把警示灯的模式切换图画出来,如图2。其中,off为LED全灭,mode1为强光长亮,mode2为弱光长亮,mode3为闪烁,mode4为走马灯闪烁。
图2 警示灯模式切换状态图
由图2可知,警示灯存在五种状态,短按(short press)将在在五种状态顺序切换,在不同状态下执行对应闪烁模式的LED控制。为此,程序必须要存储当前状态,并能根据状态执行不同代码。于是,得到编程思路:
1. 短按改变状态值。
2. 根据状态值执行不同代码。
假设我们用一个变量mode存储警示灯状态,0表示off, 1表示mode 1,2表示mode 2,3表示mode 3,4表示 mode 4。根据以上分析,可以画出以下流程图:
图3 状态控制流程图
图4 LED控制流程图
从图3、图4流程图我们很容易地就可以写出代码。其中,图3对应按键检测处理程序,主要负责短按检测及处理(修改状态值);图4对应LED控制程序,主要根据警示灯当前状态值控制LED状态,实现LED模式。
三、编程实现
图3用一个函数void keyscan()实现,直接使用上节课的代码:
void keyScan()
{
unsigned char nCount;
if(key_s == 0) //判断按键是否按下
{ nCount = 0;
delayMS(10); //延时10ms,软件去抖动
if(key_s == 0 ) //再次判断按键是否按下
{
//按键一直按下的话,等待250*10ms=2.5s后退出按键检测
while((key_s ==0) && (nCount
{
delayMS(10); //延时10ms左右
nCount++;
}
if(nCount>250) //按键保持时间>2.5s, 长按
{
//长按处理
}
else //短按处理
{
if(mode == 4) //mode为4时,其下一个值为0
{
mode = 0; //mode为全局变量
}
else
{
mode++; //将状态值改为下一个状态。
图4也用一个函数实现void ledControl,如下:
void ledControl()
{
switch(mode)
case 0: led_off(); break; // LED全灭
case 1: led_solidOn(); break; // LED强光长亮
case 2: led_solidOnWeak(); break; // LED弱光长亮
case 3: led_flash(); break; // LED闪烁
case 4: led_horse(); break; // LED走马灯
default: led_off(); break;
}
完整代码见附录。
四、总结
本节我们通过“自制”自行车警示灯学习独立按键的“高级”编程,先是从分析需求入手,导出状态转换图,进而获得编程思路,再根据编程思路画出流程图,最后按图索骥(写代码),整个过程一气呵成,水到渠成,代码简洁,妙不可言。
本例其实已经运用状态机技术。状态机技术是EDA技术课程的必修内容之一,很少有单片机教材会介绍。
五、附录
参考源代码:
#include"reg52.h"
//LED接口及独立按键接口定义
#define led_port P1
//实际只控制P1.0~P1.4共五只LED
sbit key_s = P3^0;
unsigned char mode;
//函数声明,函数功能见对应的函数定义
void delayMS(unsigned char ms);
void keyScan();
void ledControl();
void led_off();
void led_flash();
void led_solidOn();
void led_solidOnWeak();
void led_horse();
void main()
{
while(1)
{
keyScan();
ledControl();
}
}
/********************
*函数名称:delayMS
*功能:ms级延时函数,
单次最大延时为255ms@12MHz
*参数:ms:unsigned char
*返回:无
*********************/
void delayMS(unsigned char ms)
{
unsigned char i,j;
for(i=0;i
for(j=0;j
}
/********************
*函数名称:keyScan
*功能:独立按键扫描函数,短按切换警示灯状态值mode
*参数:无
*返回:无
*********************/
void keyScan()
{
unsigned char nCount;
if(key_s == 0) //判断按键是否按下
{ nCount = 0;
delayMS(10); //延时10ms,软件去抖动
if(key_s == 0 ) //再次判断按键是否按下
{
//按键一直按下的话
//等待250*10ms=2.5s后退出按键检测
while((key_s ==0) && (nCount
{
delayMS(10); //延时10ms左右
nCount++;
}
if(nCount>250) //按键保持时间>2.5s, 长按
{
//长按处理
}
else
{
if(mode == 4) //mode为4,其下一个值为0
{
mode = 0; //mode为全局变量
}
else
{
mode++; //将状态值改为下一个状态。
/********************
*函数名称:ledControl
*功能:警示灯LED控制函数,根据工作模式mode控制LED
*参数:无
*返回:无
*********************/
void ledControl()
{
switch(mode)
{
case 0: led_off(); break; // LED全灭
case 1: led_solidOn(); break; // 强光长亮
case 2: led_solidOnWeak(); break; //弱光长亮
case 3: led_flash(); break; // LED闪烁
case 4: led_horse(); break; // LED走马灯
default: led_off(); break;
}
}
/********************
*函数名称:led_off
*功能:熄灭全部LED
*参数:无
*返回:无
*********************/
void led_off()
{
led_port = led_port|0x1F;
}
/********************
*函数名称:led_solidOn
*功能:LED强光长亮
*参数:无
*返回:无
*********************/
void led_solidOn()
{
led_port = led_port&0xE0;
}
/********************
*函数名称:led_solidOnWeak
*功能:LED弱光长亮,亮度30%(输出占空比为30%方波来实现)
*参数:无
*返回:无
*********************/
void led_solidOnWeak()
{
//亮5ms,灭5ms,速度很快,人眼看不出闪烁,但亮度减半
led_port = led_port&0xE0;
delayMS(3);
led_port = led_port|0x1F;
delayMS(7);
}
/********************
*函数名称:led_flash
*功能:LED闪烁(250ms亮,250ms灭,如此循环)
*参数:无
*返回:无
*********************/
void led_flash()
{
//亮250ms,灭250ms
led_port = led_port&0xE0;
delayMS(250);
led_port = led_port|0x1F;
delayMS(250);
}
/********************
*函数名称:led_horse
*功能:跑马灯模式,一共五只LED
*参数:无
*返回:无
*********************/
void led_horse()
{
//亮250ms,灭250ms
static unsigned char i = 0;
//利用左移实现跑马灯,任何时刻仅有一个LED亮
led_port = (led_port
i++;
delayMS(250);
if(i==5)
{
i=0;
led_port = 0xFF;
}
}
领取专属 10元无门槛券
私享最新 技术干货