设计与开发

单片机整点报时 51单片机学习20-简易电子钟

小编 2024-11-24 设计与开发 23 0

51单片机学习20-简易电子钟

前面几篇我们说到了 LED灯,数码管,按键和蜂鸣器等内容,根据以上内容可以设计一个简易电子钟。

硬件组成:单片机最小系统+数码管显示电路+4个按键+蜂鸣器电路+LED灯指示电路

功能:

1、数码管显示目前时间;

2、实现四个按键操作控制;

3、复位后内定数码管显示时间为00:00:00;

4、具有闹钟和整点报时功能

仿真图:

程序:

程序内容比较多,详细的参考源代码

源程序:

#include<reg52.h>

#define uint unsigned int

#define uchar unsigned char

/****共阳数码管0--9+全灭段码****/

uchar code led[]={

0xc0,0xf9,0xa4,0xb0,

0x99,0x92,0x82,0xf8,

0x80,0x90,0xff};

uchar a[6];//数码管显示

uchar b[6]={0xFB,0XF7,0XEF,0XDF,0XBF,0X7F};//数码管位码

/****子函数声明****/

void delay_ms(uint z);//带参数ms级延时子函数

void init();//初始化函数

void timechuli();//时间处理

void key();//按键函数

void display();//显示函数

/****变量定义****/

uint num; // 记录毫秒为秒的变量

uchar hour=23;

uchar minite=59;

uchar second=56;

uchar hour1=0;

uchar minite1=1;

uchar second1=0;

uchar k;

uchar flag;//更新时间的4种模式加上正常模式

uchar S_flag;//闪烁标志位

/****位定义****/

sbit beep=P3^6; //蜂鸣器

sbit led0=P1^0; //整点报时显示

sbit led1=P1^7; //闹钟报时显示

sbit key1=P3^2;//模式切换键1正常模式 2时钟时调整 3时钟分调整 4闹钟时调整 5闹时钟分调整

sbit key2=P3^3;//加1

sbit key3=P3^4;//减1

sbit key4=P3^5; //复位键

void main()

{

init();

while(1)

{

key();

display();

}

}

void display()

{

switch(flag)

{

case 0: //时钟显示模式

{

a[5]=led[hour/10];

a[4]=led[hour%10];

a[3]=led[minite/10];

a[2]=led[minite%10];

a[1]=led[second/10];

a[0]=led[second%10];

}

break;

case 1: // 时钟 时调整模式

{

if(S_flag==1) //标志位为1

{

a[5]=led[hour/10]; //调整时钟的时

a[4]=led[hour%10];

}

else

{

a[5]=led[11]; //关闭显示

a[4]=led[11];

}

a[3]=led[minite/10];

a[2]=led[minite%10];

a[1]=led[second/10];

a[0]=led[second%10];

}

break;

case 2: //时钟 分调整模式

{

a[5]=led[hour/10];

a[4]=led[hour%10];

if(S_flag==1)

{

a[3]=led[minite/10];

a[2]=led[minite%10];

}

else

{

a[3]=led[11];

a[2]=led[11];

}

a[1]=led[second/10];

a[0]=led[second%10];

}

break;

case 3: // 闹钟 时调整模式

{

if(S_flag==1)

{

a[5]=led[hour1/10];

a[4]=led[hour1%10];

}

else

{

a[5]=led[11];

a[4]=led[11];

}

a[3]=led[minite1/10];

a[2]=led[minite1%10];

a[1]=led[11];

a[0]=led[11];

}

break;

case 4:

{

a[5]=led[hour1/10];

a[4]=led[hour1%10];

if(S_flag==1)// 闹钟 分调整模式

{

a[3]=led[minite1/10];

a[2]=led[minite1%10];

}

else

{

a[3]=led[11];

a[2]=led[11];

}

a[1]=led[11];

a[0]=led[11]; //

}

break;

}

}

void init()

{

beep=0;//关闭蜂鸣器

flag=0;//正常时钟显示模式

S_flag=0;//闪烁标志位

TMOD=0X01;//定时器T0 方式1

TH0=(65536-50000)/256;//重装初值

TL0=(65536-50000)%256;

EA=1;//开总中断

ET0=1;//开启定时器T0

TR0=1;

}

void time0() interrupt 1

{

TH0=(65536-50000)/256;//重装初值

TL0=(65536-50000)%256;

num++;

if(num==20)//1S到

{

num=0;

timechuli();//时间处理函数

}

if(hour1==hour&&minite1==minite&&second<5)//闹钟时间到

{

beep=!beep;

led1=!led1;

}

else//闹钟提醒时间到后 关闭蜂鸣器和指示灯

{

beep=0;

led1=1;

}

if((minite==0)&&(second==0)) //整点到

{

led0=!led0;

}

else //关闭LED指示

led0=1;

if(num%20==0) //1S取反一次

S_flag=!S_flag; //闪烁标志位取反

for(k=0;k<6;k++)

{

P2=b[k]; //送位码

P0=a[k]; //送段码

delay_ms(2);

P2=0xff;//消影

}

}

void key()

{

if(key1==0) //模式切换键按下

{

delay_ms(10);

if(key1==0)

{

flag++;

if(flag==5)

{

flag=0;

}

}

while(!key1) ; //等待按键释放

}

if(flag!=0)

{

switch(flag)

{

case 1: //时钟时调整

{

if(key2==0) //时钟时加1

{

delay_ms(10);

if(key2==0)

{

if(hour<23) hour++;

else hour=0;

}

while(!key2);

}

if(key3==0) //时钟时减1

{

delay_ms(10);

if(key3==0)

{

if(hour> 0) hour--;

else hour=23;

}

while(!key3) ;

}

}

break;

case 2: //时钟分调整

{

if(key2==0) //时钟分加1

{

delay_ms(10);

if(key2==0)

{

if(minite<59) minite++;

else minite=0;

}

while(!key2);

}

if(key3==0) //时钟分减1

{

delay_ms(10);

if(key3==0)

{

if(minite> 0)minite--;

else minite=59;

}

while(!key3);

}

}

break;

case 3: //闹钟时调整

{

if(key2==0) //闹钟时加1

{

delay_ms(10);

if(key2==0)

{

if(hour1<23) hour1++;

else hour1=0;

}

while(!key2);

}

if(key3==0) //闹钟时减1

{

delay_ms(10);

if(key3==0)

{

if(hour1> 0) hour1--;

else hour1=23;

}

while(!key3);

}

}

break;

case 4: //闹钟分调整

{

if(key2==0) //闹钟分加1

{

delay_ms(10);

if(key2==0)

{

if(minite1<59) minite1++;

else minite1=0;

}

while(!key2) ;

}

if(key3==0) //闹钟分减1

{

delay_ms(10);

if(key3==0)

{

if(minite1> 0)minite1--;

else minite1=59;

}

while(!key3);

}

}

break;

}

}

if(key4==0) //复位键

{

delay_ms(10);

if(key4==0)

{

flag=0;

hour=0;

minite=0;

second=0;

}

while(!key4);

}

}

void delay_ms(uint z)

{

uint x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);

}

void timechuli()

{

second++;

if(second==60)

{

second=0;

minite++;

}

if( minite==60)

{

minite=0;

hour++;

}

if(hour==24)

hour=0;

}

仿真结果:

单片机实例分享,能“变频”显示的电子钟台灯

(此处已添加圈子卡片,请到今日头条客户端查看)

电子钟的功能

我们先来看看这个时钟都有什么能耐。

◆ 24像素×7像素LED点阵显示[单色]

◆日期、时间、星期[年、月、日、星期显示]

◆温度[0 ~60℃]

◆闹铃[20组,可独立设置开关]

◆ LED台灯[99级亮度调整,自动亮度记忆]

◆走时补偿,自动较准[按天较正,范围±25s]

◆整点报时[可设定开或关]

◆整机声音开关设定

◆整屏信息切换显示

◆ 4按键操控,也可无线操控

◆后备可充电电池,断电依然走时

◆ 6 ~9V电源供电

它也就这么多能耐了,怎么样,是不是感觉比台灯功能要全面多了?目的只有一个,继续向人性化迈进。你可能会问,这个是不是很复杂啊,我能完成吗?不用担心,再复杂的东西也都是由一个个简单的东西组成的,只要各个击破就可以完成一个复杂的制作。但是你会不会看着这些功能很面熟?不错,这个时钟功能上跟杜洋老师制作的3208大体相似,但还是有些不同的。为了提起大家的兴趣,我特意在这里单独来讲这个时钟的独特之处,不然怎么吸引你继续往下阅读呢,当然也不会浪费你的时间。

个性的才是品牌的

前面已经提到,这款时钟是使用方形点阵屏,因为圆形点阵屏构成的笔划看起来连贯性不够好,点跟点之间是相切的,而方形点阵屏就不一样了,连贯性很好,很美观。只有美观我可不满意,讨个老婆只漂亮可不行,最好是又漂亮又贤惠,于是我就给它整合了LED台灯功能,让它更有魅力。可人心不足蛇吞象,你讨到了漂亮贤惠的老婆后可能还是会花心,身在福中不知福,这可真是一个头疼的问题。还好,有我在,想花心?嘿嘿,我再升级,教它用更聪明的办法处理事情,扫描显示屏的时候不会一列接一列地扫描,不管是否有数据显示,也不管显示多少数据。它只会在需要显示的地方显示,不需要就直接跳过不去扫描了。而且这种方法对由于营养不良(驱动功率不足)引起的面部雀斑(各点亮度不均匀)有很好的疗效,这个具体会在后面详细讲解。最后我还给它加上杀手锏,在它的背后左右分别装上一个蓝色的LED灯,工作时渐明渐暗好像会呼吸一样。这下你该死心踏地了吧?

硬件装备5大件

口水溅干,终于把全部功能特点讲述完毕,喝口水。接下来到了我们了解硬件装备的时候!我们按其功能先后来看,首先就是点阵屏,选用6×7的点阵模块,共4块拼成24×7分辨率的点阵屏。你也可以用其他方法组成24×7的屏,只要达到目的就可以。选择点阵屏要注意尽量挑选亮度高、电流小的,亮度低了效果不好,谁又能忍受整天对着一个灰蒙蒙的脸呢?选好屏之后,接下来就要考虑屏的驱动方式,为了节省口袋中的零花钱,我们采用动态扫描的方式,这样不仅可以在硬件装备上节省我们不少的投资,电路结构上也会变得更简单。可能你对“动态扫描”不太了解,有一头的问号,没关系,带着问号耐心往下看吧,后面我会为你详细道来。

由于单片机的I/O口资源是比较宝贵的,虽然动态扫描可以节省不少I/O口,但还远远不够,所以我们还要加上串入并出的芯片来进行扩展I/O口,常用的芯片型号有74HC164和74HC595,我选择74HC164进行列驱动。但测试后发现它的电流不够,显示亮度偏低,为了节省三极管,简化电路结构,最后选用74ACT164,它的电流足够大,而且经过我的特殊扫描处理后,亮度问题迎刃而解。这样,经过74ACT164一扩展,我们就可以只用2个I/O口对24列数据进行列扫描。

接着是日期、时间、星期功能,我们有两种方法可以解决:一是用单片机进行这部分数据的运算处理;二是用专用芯片进行协助处理,相当于单片机把这部分工作外包,在需要的时候直接拿结果,而不用自己操心去处理。前者虽然可以让电路简单,但是却会额外增加单片机的程序,最大的缺点是走时不准确,也不容易做到断电依然走时;用专用芯片就不一样了,作为一个独立的部件,走时准确,不受其他部分干扰。综合这些优缺点,我们选用DS1302专用芯片来处理,走时准确、断电依然走时的功能是很重要的。

同样,温度测量的实现办法也有好多种,比如可以用热敏电阻、二极管或三极管、专用芯片等,都可以用来检测温度。热敏电阻、二极管或三极管虽然可以检测温度,但需要配合电路,进行模数转换,再经单片机运算处理才可得到温度值。而专用芯片DS18B20就省去了很多麻烦,传感器、模数转换、运算处理等都集于一体,而且精度、准确度都很高,单片机在需要的时候直接去读结果就行。

至于闹铃功能就好办了,我们可以选择一款记忆力好的单片机,自带EEPROM,把闹铃设定数据都存在里面,掉电也不用怕丢失数据。或者如果选择的单片机不带EEPROM,DS1302内部还集成了31个RAM,也可以用来存储闹铃数据,只要DS1302不掉电就不会丢失数据。我们再来看看台灯功能,独立的台灯在台灯制作中已经介绍得很详细,现在只是将它跟时钟结合在一起就可以了,但是为了大功率LED的寿命,我们这次给它的驱动电路进行一下升级,搭个简单的恒流电路来更好地控制LED的工作电流,使其电流更稳定。

最后,核心出场,你是否已经猜到是什么?当然是统管整个电路的经理人——单片机是也,关于单片机的选择,各有所好,所谓萝卜白菜,各有所爱。只要符合要求,你自己喜欢都可以。这里我选用的是性价比很高的Atmel公司的ATmega8L,内置了很多常用的硬件资源,比如上面提到的EEPROM,真是价格便宜量又足!而且它还可以很方便地在电路上用下载线下载编译好的程序,而不用将芯片拔下来放到编程器上下载程序,下载完后再插到电路上那么麻烦,这对调试程序是非常方便的。

OK,几个大件我们都已确定,现在可以将电路设计出来,完整的电路原理图如图28.1所示。

硬件电路原理

图28.1是整个电路的设计图,左上角的model就是把4块6×7的方形点阵块的7条行线并接在一起组成的显示模块,共24列,由3片74ACT164进行列驱动。HA1是无源蜂鸣器,用于整机的声音提示。VT2、VT3、R11、R12组成LED台灯的恒流电路。这个恒流电路其实很简单,它们是一环套一环的,我们一步一步来推导。

图28.1 电路原理图

首先,LED是直接由VT2来控制的,而VT2的基极又受制于VT3,如果VT3导通则VT2截止,VT2的集电极和发射极之间没有电流通过,这样LED就不能点亮,反之则可以点亮。我们再向后推一步,VT3是受R12控制的,VT3的基极电压即为R12两端电压,该电压大于0.7V时,VT3就导通,反之则截止。R12两端的电压和通过R12的电流成正比,而通过R12的电流即通过VT2发射极的电流。聪明的你是否发现,绕来绕去最后又回到了VT2?不错,整个电路组成了一个反馈回路,互相牵制着。是不是拐来拐去看得有点眼花了?呵呵,不要急,慢慢看,分析电路这可是电子爱好者的基本功,相信你一定可以分析清楚。我们发现,当VT2发射极电流变大,R12两端电压就增加,到超过0.7V,VT3就导通,VT2截止,VT2的发射极电流想大也大不了;反之,如果VT2发射极电流变小,R12两端电压也减小,小于0.7V,VT3就截止,VT2就导通,VT2的发射极电流想变小也不行,所以VT2的发射极电流会稳定在某个值。你是不是已经想到了,对,由于VT3的导通、截止的基极电压界限是0.7V,所以R12两端电压会稳定在0.7V。根据LED的功率先计算它的正常工作电流大小,这也就是要控制的VT2发射极电流,VT2的发射极电流控制到多少又要看R12的取值,根据公式I=0.7V/R12就可以得到R12的值了。提醒一下,计算好R12的值还不要忘记计算R12的功率哦。关于LED的相关计算,大家可以去查阅,这里不再重复。左下角的IC6与周围元件组成+5V稳压电路,给整机供电。由于LED台灯有了恒流电路的控制,不用担心工作电压不稳定,所以LED台灯的电源没有经过稳压,直接用接入电压驱动,这样也可以让接入电压的范围增大。右上角为DS1302、DS18B20与单片机直接相连,接口电路很简单。P3为下载线接口,P6为预留的无线模块接口。轻触按键S1~S4为了兼容无线模块的电平,还是以下拉的方式接入。差点忘了,VD1、VD2就是杀手锏,蓝色的“呼吸”灯,夜间看起来很炫,由一个I/O口控制,其实它们的“呼吸”效果也是用PWM来实现的。扯了这么多终于算是把硬件大致讲完了,不知你是否已经明白,面对这么一大片文字我肯定会头晕的,不清楚没关系,多看几遍就好了,一回生,二回熟。

硬件电路制作

我们看看元器件清单,如表28.1所示。

这个时钟电路看起来比台灯电路复杂多了,不知你是否已经学会用电脑设计PCB板,如果已经学会,你大可以利用这次制作的机会练练手,温习一下。否则,还像LED台灯那样,用万用板来焊接仿制,可能得耐心花上几天功夫。如果有兴趣愿意这样做,那倒是好事,就怕你花了几天苦功夫焊好的板子,到时候会出现各种意外的错误,头都大了。更有甚者,把板子往角落里一扔,不玩了,那我就汗颜啦。所以,如果决定用万用板来仿制,就要做好心理准备,而且要耐心、细心。动手之前按照表28.1所示清单准备好材料。好了,接下来就是你动手的时候!祝你一次成功。

表28.1 采购清单

点阵LED屏扫描原理

漫长的几天等待,你的硬件是否已经准备好了?OK,很有效率。如图28.2所示,看看我焊的,我就没这么有耐心,画了块PCB板做出来的。硬件准备好了我们是不是要进入软件部分?你真聪明。不过在写软件之前我们得弄清楚扫描显示的原理及处理方法,不然写软件就会无从下手。重点来了,到底什么是扫描显示呢?说到底就是利用了人的视觉暂留效应实现的,即在光线消失的一定时间内,人的眼睛会感觉光线还存在着,这个时间一般为1/24s或者更久。或者你可以这么想,人的眼睛反应很迟钝,它会把1/24s时间内看到的景象当作一幅景象来处理。举个简单的例子,晚上你拿着手电筒照着墙上,会看到是一个光斑,但是如果你快速左右挥动的话,你就会看到照在墙上的光变成一条条的线,其实这就是一种方式的扫描。虽然在任意一刻,手电筒照在墙上的光都是一个光斑,但呈现在眼前的却是线。文字写多了我都烦,所谓百“文”不如一见,我想,用以下的图来对显示屏的原理进行解说,应该会更容易理解,我们来边看图边认识吧。

图28.2 制作好的硬件

图28.3 点阵模块结构

首先,我们来了解一下点阵屏的内部结构,本文所用到的6×7的点阵模块结构如图28.3所示,就是由一个个的发光二极管组合而成,将这些发光二极管按行列的方式焊接在一起,大家注意仔细看它的焊接方式,焊接完后,最后再封装成一个模块。了解了内部的结构后,如果你很感兴趣又不怕麻烦,我们也可以用LED自己动手制作显示模块,这样灵活性更大。现在我们要让这个显示模块显示如图28.3所示的“H”字符,由于模块内部已经将发光二极管按行列方式焊接在一起,我们要一下子显示“H”字符是不行的。那用什么方法才能让它显示呢?也许聪明的你会立马想到,那我们能不能分步骤来显示出来呢?答案是肯定的。如果你还能根据前面我所讲的一堆文字想到分步骤显示的方法,那你为什么不跳过这段直接去读下段呢?不要紧张,其实分步骤显示原理很简单,即刚才讲的扫描显示,利用人眼的视觉暂留效应,在比较短的时间内每次显示一部分内容,最后由于眼睛的迟钝反应,感觉这些内容就是一次显示出来的。还有疑问?带着疑问继续看图吧。

如图28.4所示,箭头代表电流的流向,灰色的方块代表亮起的点。总共6帧图,即显示“H”字符的整个过程图解。“H”字符共5列数据,加上字符后的空格共6列数据,我们就把它分成6个步骤来显示,从左至右一列一列地显示,每次只亮起一列数据,每幅图表示每一次显示的状态。请注意,它每次只显示一列数据。前面已经讲过,我们人眼的视觉暂留效应时间一般是1/24s或者更久,如果是只显示这个“H”字符,那只要保证6列数据都显示完一次的总时间在1/24s内,我们就会感觉这6次显示的画面是一次显示出来的画面。但这个时钟的屏是24列显示的,同样的道理,只要保证在1/24s内显示完这24列数据就可以让我们感觉是一次显示出了整个画面,我们把显示完一次这24列数据叫做“刷新一次”。换个说法,就是一秒钟内能将整屏数据刷新24遍以上。就像电视的显示一样,1s钟刷新24遍以上,我们才不会感觉画面有闪烁。是不是有点头昏脑胀呢?不用急,闭上眼睛仔细体会一下整个扫描过程,但千万不要睡着,我们还要接着往下思考呢。

图28.4 点阵LED扫描过程

程序流程

我已经绞尽脑汁用各种通俗的方法来描述这个时钟的显示和工作原理,能不能理解得看你的造化,希望到此时你已经理解。整理整理思路,我们进入下个步骤。还是那句话,保持良好的习惯,在准备动手写程序之前不要忘记流程图,根据对显示原理的了解,我们先用流程图的方式把这一过程表达出来,写程序时就会轻松得多。流程图如图28.5所示。

图28.5只是一个抽象的流程图,具体到每块功能处理又会有很多流程。框架搭好后,再向里面添砖就比较容易,具体每块功能的流程就交给你自己去解决。在写程序之前你最好能将所有流程都整理出来,待思路清晰后再动手。否则,你可能会陷入程序的迷宫中辨不清方向,迷迷糊糊,人世间还有什么事情比这更痛苦呢?

在程序中,按键的处理是最为复杂的,你得很花一些功夫在里面,主要在按键操作之后菜单的进出和显示的配合部分,处理不好很可能会出现画面定格,整机无反应的现象,像是死机了,其实是已经进入了某个死循环。

闹铃的判断方法是在每次分钟值更新后将各组闹铃设定的分钟值与之比较,如有相同,则继续与相同的这路闹铃的小时值比较,如又有相同,则进行响闹一分钟,反之则不响闹。整点报时的实现方法比较容易一些,只需要判断小时的数据是否更新,如有更新则进行整点报时即可。

好了,现在行动起来,按照流程图与之前的分析理解,开始动手写程序吧!我写的源程序可以在本书配套光盘上找到。

图28.5 流程图

调试秘籍

制作这个时钟你是否会感觉我进行得一切顺利?如果是的话,那肯定是你的错觉。每个制作过程中都多少会出现各种问题,这些并不可怕,重要的是遇到这些问题,我们动力十足,有一颗持之以恒的心去解决它,不知你是否拥有这种耐性呢?在这个时钟制作中,我遇到过一些问题,其中记忆比较深刻的有几个,在这里跟大家分享一下,希望能对你有所帮助。

和你一样,当制作好硬件时,我便兴冲冲地拿着它连接好电脑,开始写屏幕测试程序,可问题接踵而至,马上打击了我的兴致。最不想出现的问题居然出现——屏幕显示有问题。只能显示前8列数据,后面的都不能显示。这是硬件问题还是软件问题呢?谁才是真正的幕后黑手?为了揭密事情的真相,我修改屏幕测试程序为单一竖条流动循环显示,发现8列以后的数据虽然不能显示,但竖条的流动时间还是花了那么多,并不是8列流动完就再从第一列开始,这说明软件应该没有问题。排除了软件,那会不会是硬件问题呢?“8”在数字电路中是一个很特殊的数字,资料总会有“8”或者它的倍数。

74ACT164是一个串入并出的芯片,输出并行的8位数据,那会不会是第一块芯片的数据没有传送到下一块芯片呢?带着这个疑问我将74ACT164都加焊了一遍,再测试还是不行,我又用示波器测试了第2块74ACT164的串行输入脚,终于有重大发现,输入脚当接收到“0”数据时低电平不到位,只是稍微凹了一下,导致“0”数据不能正常传送。接着顺藤摸瓜,幕后黑手终于浮出水面,原来是因为74ACT164在回路中的内阻有点大,导致该列LED的电流流通时这个内阻分到了一半以上的电压,强行地将低电平拉高而引起不正常。能想到的硬件解决办法是增加限流电阻值以减少74ACT164的分压值,可这样做显示亮度会大大减低,显示效果不理想。

硬件方面没辙了,那能不能从软件方面着手解决这个问题呢?当然可以,不然我还如何继续写完这篇文章,如何向大家交待?不知你是否已经想到解决的方法,不妨先听我说。其实做法很简单,既然是因为LED的电流引起电平不正常,那就从根本治理,在每次74ACT164的数据移位前先关闭LED的显示,移位之后重新开启,从关闭到重新开启LED显示这段时间极短,对显示的影响是微不足道的。

话虽如此,可由于LED显示屏材料和74ACT164的驱动电流问题,显示屏的亮度还是让我不能接受,而且由于驱动电流不足,导致显示亮度随每列亮起的点数不同而不同。这个问题困扰了我好一段时间,电路已经确定,想更换材料来解决问题不太现实,思路还是锁定在软件上。万能的软件,遇到问题总可以靠它来解决,这种可以节省出午餐费用的方法也总能得到我的青睐,这一次又是软件解决了问题。这是某天中午我对着它发呆时突然想到的方法,传统的扫描方法是,逐列地扫描显示,每扫描一列给予固定的显示时间,不管该列是否有点亮起,亮起的点数有多少。

这样的显示刷新频率是固定的,而且很浪费资源,当某列没有点亮起的时候,为什么还要浪费这个固定的显示时间呢,在这一刻整个屏幕是处于无显示状态的。那我为何不直接跳过?节省这些时间就提高了显示的刷新频率,也间接地提高了显示亮度,真可谓是两全齐美。虽然是两全齐美,可这怎么就能够满足贪心的我,还要继续琢磨。这一琢磨又发现,每列用固定的显示时间并不科学。每列亮起的点数不同亮度也不同,因为每列共7个点,这样就有7种不同的显示亮度,亮起的点数越多亮度越低,那我为何不在亮起点数少的时候减少显示时间,亮起点数多的时候增加其显示时间呢,对应7种显示亮度给出7种显示时间。

这样一折腾,又来了个两全齐美。亮度继续提升而且均匀,刷新频率又有所增加,完全响应口号“不闪的才是健康”。不知是否有朋友想到这样的方法,但我真的很佩服自己能想到这个方法,我称这个方法为“时间扫描法”。把刷新一次的时间看作一个整体,分成24×7份,传统的扫描方法需要24×7份时间,而经过我优化后的方法需要的时间理论上接近亮起的点数,屏幕上有多少个点亮起就需要多少份时间,当只有一个点显示时就只需要一份时间,刷新频率远比传统的显示方法高,是一个动态的刷新频率,套用流行的新名词叫做“变频”显示。一不留神,扯远了,体验了一回王婆卖瓜的感受。

可别高兴得太早,显示的问题是解决了,可摆在床头使用一段时间后发现走时总是会有误差,隔三岔五的要调整一次时间,这可不是什么愉快的事儿。细心的你可能已经发现,图28.5所示的程序图里有个时间校正功能,到现在压根儿还没讲是咋实现的呢。到这里终于暴露出来,我还是老老实实地招了吧。时钟难免会出现走时不准的现象,对硬件上的处理调校比较麻烦,从软件上下功夫进行走时的调校是一个不错的方法,灵活性大且容易调整。实现原理比较简单,在菜单中先设定为不校正,以较准确的钟表或电视时间为标准,让时钟走时一天,观察其秒钟值的误差是多少。

如果有误差则在系统菜单中设定相对应的校正值。在程序编写时设置一个固定的时间每天进行校正一次,比如晚上一点钟。到了晚上一点钟,它就会按照设定的校正值进行加或减的校正,校正的时候会看到秒值突然变化。写程序时你可千万别一定等到晚上一点钟去验证这个一天才有一次的景观,可以调整时间接近一点钟,也可以在程序中将校正时间改变。随时都可以进行验证。所谓“师父领进门,修行在个人”,方法教给了你,具体的运用还得靠自己。

发挥创意锦上添花

不知上述经历对你是否有帮助,你的时钟已经工作了吗?程序是否已经调试完毕?如果还在调试中,不要着急,继续加油!如果已经成功制作,那么恭喜你!苦心人,终不负,你可以端着咖啡坐在椅子上静静地欣赏着它。

但是你觉得它很完美了吗?如果到这里就已经很满足,表示你还没有让脑子动起来,充分发挥你的想象力,让它更具有个性色彩吧!我的电子钟虽然早已摆上床头,孜孜不倦地工作数日,像大多数花心的人一样,时间久了,总会有点不满意。对于这个时钟,我已经有了许多新的改进想法,但现在还没有去实现。做完这个时钟后,发现原来很多朋友都喜欢大的点阵屏,实在是对我的爱好汗颜,但是大的方形点阵屏很少见,如果找不到,自己用方形LED制作一个这样的屏也未尝不可,玩在其中,乐在其中。倘若你是一个贪睡的人,你还可以给这个时钟加上贪睡功能。倘若你是一个重视视觉感受的人,你可以试着增加显示的方式,比如上下翻屏、流动显示等。倘若你是一个喜欢人性化的人,你不妨在闹铃功能里加上台灯控制功能,给予3种控制状态:开灯、关灯、保持,用两组闹铃就可设置一个开关灯循环,你更可以在每组闹铃里增加亮度值设置。

想想,每天晚上6点天快黑下来的时候,它自动渐渐亮起,到晚上10点你快休息的时候它又自动将亮度渐渐减低作夜灯照明,清晨7点,你睁开惺忪的眼睛看到第一缕阳光的时候,它又会自动渐渐灭掉。想到这些是多么惬意,它就像一个任劳任怨的仆人永远为你服务,而你却不用担心薪水支付问题。原来闹铃不只是可以做闹铃功能,那你有没有想过显示屏也可以当做台灯来照明呢?用超高亮的白光LED自制点阵屏,当需要点亮台灯的时候就全屏点亮,这样不失为一种精简电路而节约出早餐费用的好方法。

这些想法都只是围绕生活的,其他方面有没有呢?贪心的我总是异想天开地想让它拥有尽可能多的功能而变成超强的电子制作,电子爱好者们做一些实验的时候经常会用到显示屏来进行调试,这么好的一个点阵屏不用简直是浪费,可以给它增加一个通用显示屏功能,当切换到该功能时,屏幕作为一个通用的显示屏来使用,主控芯片内置数字、字母及符号字库,通过串口通信。也可进一步用些方法进行拼屏显示,每个屏手动设置一个编号作为自己的地址,而且可以直接用上位机发送数据进行显示,这样它摇身一变又成为一个串口调试显示屏了。如果继续拿它做文章,你还可以将它变成能够自己下载显示内容的广告牌。恐怕我再写下去有人要扔月光宝盒了,当年《大话西游》的唐僧又在脑海浮现,所以赶紧停下唾沫横飞的入镜状态。

当然,这些想法可能因为一些原因而不能同时实现,萝卜白菜,各有所爱,如果你对这些想法感兴趣,不妨一试,希望你能做得比我更好,到时不要忘记和我分享喜悦哦!

(此处已添加圈子卡片,请到今日头条客户端查看)

相关问答

肿么使用 单片机 控制蜂鸣器发声-ZOL问答

两种蜂鸣器用单片机的控制方法是一样的,对于无源的,要求单片机送出一组断续的音频信号,使蜂鸣器按要求发声,对于有源蜂鸣器,要求单片机送出一组断续的电脉冲信号...

怎么样学好51 单片机 ?

单片机的学习绝不仅仅是对一项知识的掌握。想要学好单片机,需要从硬件结构、内部资源、外设应用等几个方面多方位入手。而要想成为一名嵌入式工程师,就要对单片...

猜你喜欢