首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

C51编程入门(九)独立按键编程(中)——“自制”自行车警示灯

上一节我们学习了独立按键的原理,并基于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;

}

}

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181226G1EUU700?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券