本帖最后由 丄帝De咗臂 于 2015-6-12 21:34 编辑
【简介】定时器可以让我们更有时间观念,可以帮助我们更合力地管理时间。这里我使用四位数码管实现定时功能。该定时提醒器在工作时,从规定时间倒计时至0停止。主要练习四位数码管的使用,以及Arduino的计时功能。四位数码管只显示小时和分钟:(一)从左至右,第一个和第二个数码管显示小时,第三个和第四个数码管显示分钟(二)为提倡节约用电,小时和分钟不同时显示,而是闪烁显示,闪烁间隔为1秒,也借此显示出秒的功能(三)可通过上下两个干簧管调整时间,上面的为加一小时,下面的为减一分钟。最后完成图如下
【器材】Arduino Nano,共阳四位数码管,干簧管×2,面包板,面包线
【原理】电路原理图如下
【接线】接线示意图如下
【程序】代码程序如下
- /*24小时倒计时提醒器,能显示“小时”和“分钟”,“小时”和“分钟”每秒各轮流亮灭一次,显示出“秒”的功能,节省电能。
- 同时10小时、10分钟在0状态时,自动熄灭,以节省电能,同时有利于观察时间。程序带有时间范围限定功能,防止时钟计时器向上、下溢出:定时器内部时钟控制在24小时至48小时范围内,当显示0小时0分钟时,定时器提示灯(D13)点亮,同时接通继电器触发控制电路工作*/
- //设置8段笔画,采用超高亮度4位共阳极数码管
- int a = 15; //设置A1口连接数码管a段
- int b = 19; //设置A5口连接数码管b段
- int c = 7; //设置D7口连接数码管c段
- int d = 5; //设置D5口连接数码管d段
- int e = 4; //设置D4口连接数码管e段
- int f = 16; //设置A2口连接数码管f段
- int g = 8; //设置D8口连接数码管g段
- int dp = 6; //设置D6口连接数码管dp段
- int d1=14; //设置A0口连接第一个数码管共阳极,该数码管显示小时十位
- int d2=17; //设置A3口连接第二个数码管共阳极,该数码管显示小时个位
- int d3=18; //设置A4口连接第三个数码管共阳极,该数码管显示分钟十位
- int d4=9; //设置D9口连接第四个数码管共阳极,该数码管显示分钟个位
- //定义变量一天为69120000,一秒为800,和现实时间比对后所得数据。
- long oneDay =69120000;
- long n; //定义时间的自变量
- long aCount=0;//辅助计时器
- //改用此数值对时钟进行调整,最小单位分钟用48000~60000,可以变成毫秒、秒
- unsigned int oneMinute = 48000;
- int dela = 19; //此处数值对时钟的时进行微调,下同
- int delb = 19;
- int delc = 20;
- int deld = 20;
- /*采用变量:oneMinute = 48000;要比直接用48000运行速度慢;注释符号//越多,运行速度越慢。程序中的时钟调整必须在不改变程序其他代码和段落的情况下进行。目前最好的结果是int dela = 19;int delb = 19;int delc = 20;int deld = 20;*/
- //以下用数组赋值,程序很简洁,小数点不用
- byte segs[7] = { a, b, c, d, e, f, g };//除了小数点的7笔划段
- byte seven_seg_digits[10][7] =
- {
- { 1,1,1,1,1,1,0 },//设置数码管显示0的数组
- { 0,1,1,0,0,0,0 },//设置数码管显示1的数组
- { 1,1,0,1,1,0,1 },//设置数码管显示2的数组
- { 1,1,1,1,0,0,1 },//设置数码管显示3的数组
- { 0,1,1,0,0,1,1 },//设置数码管显示4的数组
- { 1,0,1,1,0,1,1 },//设置数码管显示5的数组
- { 1,0,1,1,1,1,1 },//设置数码管显示6的数组
- { 1,1,1,0,0,0,0 },//设置数码管显示7的数组
- { 1,1,1,1,1,1,1 },//设置数码管显示8的数组
- { 1,1,1,1,0,1,1 } //设置数码管显示9的数组
- };
- //********************************中断处理函数********************************//
- void addhour() //上面的干簧管触发,进行加1小时
- {
- digitalWrite(13,HIGH);//D13口置高电位
- digitalWrite(3, HIGH);//D3口置高电位
- aCount=0; //辅助计时器归0
- digitalWrite(10, LOW);//因为重新设置时间,则报警停止
- digitalWrite(12, LOW);//同上
- n=n+2880000; //1分钟为48000,乘以60即1小时为2880000
- //加1小时,即 +2880000
- if (n>2*oneDay) n=n-oneDay;
- }
- void cutmin() //下面的干簧管触发,进行减1分钟
- {
- digitalWrite(1, HIGH);//D1口置高电位
- digitalWrite(2, HIGH);//D2口置高电位
- aCount=0; //辅助计时器归0
- digitalWrite(10, LOW);//因为重新设置时间,则报警停止
- digitalWrite(12, LOW);//同上
- n=n-48000; //1分钟为48000,减少1分钟,即 -48000
-
- //当时间变量n减少到00:01时,再往下减1分钟,则n<0,这时定时器内部时钟就应重新从24小时开始,往下减。
- if (n<oneDay) n=n+oneDay;
- digitalWrite(10, LOW);//重新设置时间,则报警停止
- digitalWrite(12, LOW);//同上
- }
- //***********************************子函数**************************************//
- void dispDec(int x) //开启小数点
- {
- digitalWrite(dp, LOW); //小数点点亮
- }
- void clearLEDs()//清屏函数
- {
- digitalWrite(a, HIGH); //数码管所有管脚熄灭
- digitalWrite(b, HIGH);
- digitalWrite(c, HIGH);
- digitalWrite(d, HIGH);
- digitalWrite(e, HIGH);
- digitalWrite(f, HIGH);
- digitalWrite(g, HIGH);
- digitalWrite(dp, HIGH);
- }
- void lightSegments(int x)//点亮对应数字的数码管
- {
- for (int i = 0; i < 7; i++)
- {
- //点亮数字数组取反,点亮共阳极数码管
- digitalWrite(segs[i], !seven_seg_digits[x][i]);
- }
- }
- void pickDigit(int x) //定义pickDigit(x),其作用是开启哪一位数码管
- {
- digitalWrite(d1, LOW);//初始设置第一位位数码管熄灭
- digitalWrite(d2, LOW);//初始设置第二位位数码管熄灭
- digitalWrite(d3, LOW);//初始设置第三位位数码管熄灭
- digitalWrite(d4, LOW);//初始设置第四位位数码管熄灭
- switch(x)
- {
- case 1:
- //第一个数码管为小时十位,每秒闪烁一次,小于10小时熄灭
- digitalWrite(d1, n%800<400&&(n/48000/60)%24>9);
- break;
- case 2:
- //第二个数码管为小时个位,每秒闪烁一次
- digitalWrite(d2, n%800<400);
- break;
- case 3:
- //第三个数码管为分钟十位,每秒闪烁一次,小于10分钟熄灭;
- //1分钟时,还有10秒为0分时,从显示1变成现实01
- digitalWrite(d3, n%800>400&&(n/48000/10%6)>0||(n%oneDay<56000));
- break;
- default:
- //第四个数码管为分钟个位,每秒闪烁一次
- digitalWrite(d4, n%800>400);
- break;
- }
- }
- //*****************************初始化函数*****************************//
- void setup()
- {
- for (int i=4; i<20; i++)
- {
- pinMode(i, OUTPUT); //设置D4到D19引脚为输出模式
- digitalWrite(i, HIGH);//四位共阳数码管都熄灭
- }
- pinMode(2, INPUT); //内置上拉电阻,中断函数0
- pinMode(3, INPUT); //内置上拉电阻,中断函数1
- digitalWrite(2, HIGH); //内置上拉电阻
- digitalWrite(3, HIGH); //内置上拉电阻
- //设置引脚D13为输出模式(上面的for循环已设置)
- digitalWrite(13,LOW); //设置成加1小时的中断函数的地端
- pinMode(1, OUTPUT); //设置引脚D1为输出模式
- digitalWrite(1,LOW); //设置成减1分钟的中断函数的地端
- digitalWrite(10, LOW); //5V直流继电器线圈初始:不接通
- digitalWrite(12, LOW); //5V直流继电器线圈初始:不接通
- n=oneDay+25920000; //开机时间初始化设置为:8 小时59分
- //下面是两个干簧管按钮,触发相应的中断函数,调整时间
- attachInterrupt(1,addhour, LOW); //加1小时的中断函数;接D13
- attachInterrupt(0, cutmin, LOW); //减1分钟的中断函数,接 D1
- }
- //*******************************主函数*******************************//
- void loop()
- {
- aCount++;//计数累加
- if (aCount>300) //要等待0.375秒恢复中断开关的接地端功能
- {
- digitalWrite(13, LOW);//800=1秒,300=0.375秒
- digitalWrite(1, LOW); //800=1秒,300=0.375秒
- }
- /*以下是钟表的最关键代码——24小时进制的实现
- 为了实现24小时进制,通过尝试得到上面的代码,其原理是从原来的60分钟进制1小时得来的;在小时的基础上,除以10*/
- clearLEDs(); //数码管清屏
- pickDigit(1); //小时十位数码管,采用1天24小时
- //通过n除以48000再除以60再取除以24的余数再除以10来获取小时十位的数值并点亮数码管显示
- lightSegments((n/48000/60)%24/10);
- delayMicroseconds(dela);//微调时钟快慢
- clearLEDs(); //数码管清屏
- pickDigit(2); //小时个位数码管
- //通过n除以48000再除以60再取除以24的余数再取除以10的余数来获取小时个位的数值并点亮数码管显示
- lightSegments((n/48000/60)%24%10);
- dispDec(2); //点亮小数点
- delayMicroseconds(delb);//微调时钟快慢
- clearLEDs(); //数码管清屏
- pickDigit(3); //分钟十位数码管
- //通过n除以48000再除以10再取除以6的余数来获取分钟十位的数值并点亮数码管显示
- lightSegments((n/48000/10)%6);
- delayMicroseconds(delc);//微调时钟快慢
- clearLEDs(); //数码管清屏
- pickDigit(4); //分钟个位数码管
- //通过n除以48000再取除以10的余数来获取分钟个位的数值并点亮数码管显示
- lightSegments((n/48000)%10);
- delayMicroseconds(deld);//微调时钟快慢
- n--;//倒计时的时钟源,每次循环减一
- if (n%oneDay==oneMinute) //这是倒计时终点的提醒功能,从0:1——0:0就报警
- {
- digitalWrite(10, HIGH);//启动5V直流继电器
- digitalWrite(12, HIGH);//启动5V直流继电器
- }
- }
复制代码
【效果】最终效果展示两个图
(一)显示小时
(二)显示分钟
【拓展】利用继电器加上蜂鸣器,可实现定时报警功能,程序留给各位喽:-)
|