前言
不知不觉我又被自己的惰性拖住了小一个月,今天在宿舍窗边吸烟时候,看着楼下人来人往的道路不由自主的感到一丝惭愧,手里的小视频也被我刷出来一条鸡汤,在这儿我要写下来记录给将来又在颓废的我:
OK,食归大肠,水入膀胱,咱们言归正传。今儿做的是时钟升级版实验——秒表。
任务介绍
同样利用上次的时钟原理图,改写成为可记录多人的秒表。( ヾ(TДT;))))…!脑子里不知不觉想到在部队生活时的夺命追魂表。。。)
要求:
- 显示格式为X-XX-X,例如1-56-7表示1分56.7秒(或1点56分7钞),即以1/10秒的速度运行
- 使用两个按键 K1、K2 实现 开始/结束、记录/查询 的功能
实验目的
- 1、掌握数码管动态扫描显示的原理及过程。
- 2、掌握单片机定时/计数中断程序的设计方法。
- 3、掌握单片机定时计数器去按键抖动的原理及编程方法。
程序构想
为了提升自己的能力,从本次开始程序构想统统以流程图来呈现。(画的不好还请高人多多指教,上图),别问我为啥不用 ProcessOn 、Mindmanage 来画,因为我没钱🤐
K1按键对应P3.2 , K2按键对应P3.3 ,(表达不好截图来搞,整体如下图所示)
码代码开始
先把框架码起来,根据流程图可以看出主要需要以下几个动作:
void init(void)
void SaveTime(u8 nsave)
void Output(u8 x)
void main()
void K1() interrupt 0
void K2() interrupt 2
void TimePulse() interrupt 1
void LedShow() interrupt 3
框架打好,慢慢填写内容:
- 产生一个1/10秒的信号驱动:
这里我用T0定时器的方式二产生,因为是自动TL0是被TH0自动重置的,所以可以提高一定的精准度。这里用的单片机晶振频率为12MHz,通过公式 机械周期 = 12 / 12M = 1us ,为了达到100ms的周期需要两个循环(因为定时器方式二最大计数值为256),具体如下:
void TimePulse() interrupt 1
{
static u8 i=0,ii=0;
i++;
if(i>=50)
{
i=0;
ii++;
if(ii==10)
{
(*ss)++;
ii=0;
i=0;
}
}
}
- 动态显示
这个没什么好说的大家都会就不啰嗦了,利用定时器T1动态扫描显示,同时解决按键防抖动
void LedShow() interrupt 3
{
static u8 w=0;
P2 = 0;
TH1 = TScan/256;
TL1 = TScan%256;
if(*ss>=10)
{
*ss=0;
(*sl)++;
}else{}
if(*sl>=10)
{
*sl=0;
(*sh)++;
}else{}
if(*sh>=6)
{
*sh=0;
(*m)++;
}else{}
if(*m>=10)
{
TR0=0;
*ss=9;
*sl=9;
*sh=5;
*m=9;
}else{}
P1 = led_scan[w];
P2 = led_cc[ led_show[w] ];
w++;
if(w==8)
{
w=0;
}else{}
if(as>0)
{
as++;
if(as==71)
{
as=0;
IE0=0;
EX0=1;
IE1=0;
EX1=1;
}else{}
}else{}
}
- K1 、K2分别对应外部中断0 、 外部中断1
根据流程图描写构建对应的功能,K1负责 开始/结束 K2负责 记录/切换。这里我主要通过对TR0状态的判断决定按下按键后进行的动作,我们结合来看:
void K1() interrupt 0
{
as=1;
EX0 = 0;
k1f++;
if(k1f==1)
{
TR0 = 1;
}
if(k1f==2)
{
TR0 = 0;
SaveTime((*num));
Output((*num));
}
if(k1f>=3)
{
k1f=0;
init();
}
}
void K2() interrupt 2
{
as=1;
EX1 = 0;
if(TR0 == 1)
{
SaveTime((*num));
(*num)++;
}
if((*num)>=10)
{
TR0 = 0;
k1f = 2;
(*num)=(*num)-1;
Output((*num));
return ;
}
if(TR0==0&&k1f!=0)
{
(*num)=(*num)+1;
if((*num)>=10)
{
(*num)=1;
}
Output((*num));
}
}
4. 存储当前时间,显示以储存的时间
原本憨憨的我是用了一个9*8的二维数组,来强行储存存显示内容,就像这样
u8 player[9][8];
结果编译器狠狠的Duang了一声,成这样了“*** ERROR L107: ADDRESS SPACE OVERFLOW”,有道老师告诉我这是地址空间溢出了。后来,我想过用xdata来修饰一下,但是我发现这个片外RAM访问需要间接寻址,通过翻书看资料智商欠费的我在桌子前徘徊了三趟,终究还是没有掌握这个知识点(给我点儿时间等我搞懂了就回来专门写一篇)。可是问题它不管你会还是不会,它始终就在那不离不弃。于是只能另辟蹊径,别说还真让我想到了PlanB。挠掉三根头发后滚轮让我看见定时器T1的赋初值的方法,于是“储存”和“显示”这两个函数就成了这样:
void SaveTime(u8 nsave)
{
static u8 n;
n = nsave-1;
if(n<9)
{
player[n][0] = nsave;
player[n][1] = (*m)*10+(*ss);
player[n][2] = (*sh)*10+(*sl);
}
}
void Output(u8 x)
{
static u8 n;
n = x-1;
if(n<9&&player[n][0]!=0)
{
*num = player[n][0];
*m = player[n][1]/10;
*ss = player[n][1]%10;
*sh = player[n][2]/10;
*sl = player[n][2]%10;
}else
{
*num = player[0][0];
*m = player[0][1]/10;
*ss = player[0][1]%10;
*sh = player[0][2]/10;
*sl = player[0][2]%10;
}
}
5. 最后根据上述的思路流程对单片机进行初始化就可以了
下面是程序的全部面貌,为了让各位看官能方便使用,源码也会上传,portues工程文件和上次时钟的一样,等会儿网络通畅了我全部给上传,有需要的同学请进入我的 “主页” >> “资源” ,进行下载。
C程序: test5_StopWatch.c
protues工程: timer.pdsprj
最后,再次感谢您的浏览。
#include <reg51.h>
#define u8 unsigned char
#define u16 unsigned int
#define TScan (65536-4000)
u8 led_cc[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x40,0x08,0x00};
u8 led_scan[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
u8 led_show[]={1,11,0,10,0,0,10,0};
u8 *m=&led_show[2];
u8 *sh=&led_show[4];
u8 *sl=&led_show[5];
u8 *ss=&led_show[7];
u8 *num=&led_show[0];
u8 player[9][3];
u8 as=0;
u8 itemp,jtemp;
u8 k1f;
void init(void)
{
EA = 1;
IE0 = 0;
EX0 = 1;
IT0 = 1;
IE1 = 0;
EX1 = 1;
IT1 = 1;
TMOD = 0x12;
ET0 = 1;
TR0 = 0;
TH0 = (256-200);
TL0 = (256-200);
ET1 = 1;
TR1 = 1;
TH1 = TScan/256;
TL1 = TScan%256;
led_show[0]=1;
led_show[2]=0;
led_show[4]=0;
led_show[5]=0;
led_show[7]=0;
for(itemp=0;itemp<9;itemp++)
{
for(jtemp=0;jtemp<2;jtemp++)
{
player[itemp][jtemp]=0;
}
}
player[0][0]=1;
k1f = 0;
}
void SaveTime(u8 nsave)
{
static u8 n;
n = nsave-1;
if(n<9)
{
player[n][0] = nsave;
player[n][1] = (*m)*10+(*ss);
player[n][2] = (*sh)*10+(*sl);
}
}
void Output(u8 x)
{
static u8 n;
n = x-1;
if(n<9&&player[n][0]!=0)
{
*num = player[n][0];
*m = player[n][1]/10;
*ss = player[n][1]%10;
*sh = player[n][2]/10;
*sl = player[n][2]%10;
}else
{
*num = player[0][0];
*m = player[0][1]/10;
*ss = player[0][1]%10;
*sh = player[0][2]/10;
*sl = player[0][2]%10;
}
}
void main()
{
init();
while(1);
}
void K1() interrupt 0
{
as=1;
EX0 = 0;
k1f++;
if(k1f==1)
{
TR0 = 1;
}
if(k1f==2)
{
TR0 = 0;
SaveTime((*num));
Output((*num));
}
if(k1f>=3)
{
k1f=0;
init();
}
}
void K2() interrupt 2
{
as=1;
EX1 = 0;
if(TR0 == 1)
{
SaveTime((*num));
(*num)++;
}
if((*num)>=10)
{
TR0 = 0;
k1f = 2;
(*num)=(*num)-1;
Output((*num));
return ;
}
if(TR0==0&&k1f!=0)
{
(*num)=(*num)+1;
if((*num)>=10)
{
(*num)=1;
}
Output((*num));
}
}
void TimePulse() interrupt 1
{
static u8 i=0,ii=0;
i++;
if(i>=50)
{
i=0;
ii++;
if(ii==10)
{
(*ss)++;
ii=0;
i=0;
}
}
}
void LedShow() interrupt 3
{
static u8 w=0;
P2 = 0;
TH1 = TScan/256;
TL1 = TScan%256;
if(*ss>=10)
{
*ss=0;
(*sl)++;
}else{}
if(*sl>=10)
{
*sl=0;
(*sh)++;
}else{}
if(*sh>=6)
{
*sh=0;
(*m)++;
}else{}
if(*m>=10)
{
TR0=0;
*ss=9;
*sl=9;
*sh=5;
*m=9;
}else{}
P1 = led_scan[w];
P2 = led_cc[ led_show[w] ];
w++;
if(w==8)
{
w=0;
}else{}
if(as>0)
{
as++;
if(as==71)
{
as=0;
IE0=0;
EX0=1;
IE1=0;
EX1=1;
}else{}
}else{}
}
END
o(︶︿︶)o 唉!今晚还要码MATLAB的作业,
去窗边吹吹风抽根烟,为了生活为了她,继续努力吧骚年。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)