不知不觉我又被自己的惰性拖住了小一个月,今天在宿舍窗边吸烟时候,看着楼下人来人往的道路不由自主的感到一丝惭愧,手里的小视频也被我刷出来一条鸡汤,在这儿我要写下来记录给将来又在颓废的我:
OK,食归大肠,水入膀胱,咱们言归正传。今儿做的是时钟升级版实验——秒表。
同样利用上次的时钟原理图,改写成为可记录多人的秒表。( ヾ(TДT;))))…!脑子里不知不觉想到在部队生活时的夺命追魂表。。。)
要求:
为了提升自己的能力,从本次开始程序构想统统以流程图来呈现。(画的不好还请高人多多指教,上图),别问我为啥不用 ProcessOn 、Mindmanage 来画,因为我没钱
K1按键对应P3.2 , K2按键对应P3.3 ,(表达不好截图来搞,整体如下图所示)
先把框架码起来,根据流程图可以看出主要需要以下几个动作:
void init(void)/*初始化程序*/
void SaveTime(u8 nsave) /*储存当前时间 */
void Output(u8 x)/*显示第x个成员的时间成绩*/
void main()//主函数(必不可少)
void K1() interrupt 0 //INT0外部中断 K1 开始/结束/清零 计时
void K2() interrupt 2 //INT1外部中断 K2 记录时间/切换显示内容
void TimePulse() interrupt 1 //T0定时器 产生时间脉冲
void LedShow() interrupt 3 //T1定时器 动态显示 按键中断 4ms进入一次
框架打好,慢慢填写内容:
void TimePulse() interrupt 1 //T0定时器 产生时间脉冲
{
static u8 i=0,ii=0;
i++; //每0.2ms进入一次中断 500次为0.1s
if(i>=50)
{
i=0;
ii++;
if(ii==10)
{
(*ss)++; //ss加1 *ss为显示的最后一位
ii=0;
i=0;
}
}
}
void LedShow() interrupt 3 //T1定时器 动态显示 按键中断 4ms进入一次
{
static u8 w=0;
P2 = 0;
TH1 = TScan/256; //
TL1 = TScan%256;
/* 将时间赋值给 数组led_show[] */
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; //计时到9分59秒自动停止计时
*ss=9;
*sl=9;
*sh=5;
*m=9;
}else{}
/* 显示led_show[] */
P1 = led_scan[w];
P2 = led_cc[ led_show[w] ]; //
w++;
if(w==8)
{
w=0;
}else{}
/* 防抖70*4ms = 280ms */
if(as>0)
{
as++;
if(as==71)
{
as=0;
IE0=0; //清空外部中断0中断源
EX0=1; //打开外部中断0
IE1=0; //清空外部中断1中断源
EX1=1; //打开外部中断1
}else{}
}else{}
}
void K1() interrupt 0 //INT0外部中断 K1 开始/结束/清零 计时
{
as=1; //标记进入防抖
EX0 = 0;
k1f++; //k1f:K1状态标识 0初始化准备开始 1计时状态 2停止计时状态
if(k1f==1) //计时开始
{
TR0 = 1;
}
if(k1f==2) //全部结束计时
{
TR0 = 0;
SaveTime((*num)); //记录当前显示的时间
Output((*num)); //输出当前显示的时间
}
if(k1f>=3) //清零 重新加载
{
k1f=0;
init();
}
}
void K2() interrupt 2 //INT1外部中断 K2 记录时间/切换显示内容
{
as=1; //标记进入防抖
EX1 = 0;
if(TR0 == 1) //计时状态K2动作
{
SaveTime((*num));
(*num)++;
}
if((*num)>=10) //9人记录全部完成,停止并显示
{
TR0 = 0;
k1f = 2;
(*num)=(*num)-1;
Output((*num));
return ; // 这个return退出很重要
}
if(TR0==0&&k1f!=0) //停止计时状态下查询各成员的用时成绩
{
(*num)=(*num)+1; //向下切换成员序号 最多9个成员
if((*num)>=10)
{
(*num)=1;
}
Output((*num)); // 显示第(*num)个成绩
}
}
4. 存储当前时间,显示以储存的时间
原本憨憨的我是用了一个9*8的二维数组,来强行储存存显示内容,就像这样
u8 player[9][8]; //定义9人成员成绩 二维数组 用于存储9个人的成绩
结果编译器狠狠的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); //储存 分钟 和 100ms 对应的数值
player[n][2] = (*sh)*10+(*sl); //储存 秒 对应的两个数值
}
}
void Output(u8 x)/*显示第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; //读取 100ms值
*sh = player[n][2]/10; //读取 秒高位
*sl = player[n][2]%10; //读取 秒低位
}else //如果当前没有存入成绩,显示第1名成绩
{
*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
#define u8 unsigned char
#define u16 unsigned int
#define TScan (65536-4000)//(65536-4000) 动态扫描4ms移位一次
//共阴数码管 0 1 2 3 4 5 6 7 8 9 - _ “空”
u8 led_cc[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x40,0x08,0x00};
//数码管从左往右,第1 2 3 4 5 6 7 8个
u8 led_scan[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//数码管初始显示内容:1_0-00-0
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]; //(*ss)* 100毫秒
u8 *num=&led_show[0]; //成员序号
u8 player[9][3]; //定义9人成员成绩 二维数组 用于存储9个人的成绩
u8 as=0; //防抖标识
u8 itemp,jtemp; //用作循环语句的中间变量
u8 k1f; //K1键标识
void init(void)/*初始化程序*/
{
EA = 1; //打开中断总开关
IE0 = 0;//清除外部中断0 中断源
EX0 = 1;//打开外部中断0
IT0 = 1;//下降沿触发
IE1 = 0;//清除外部中断1 中断源
EX1 = 1;//打开外部中断1
IT1 = 1;//下降沿触发
TMOD = 0x12;//定时器1 方式1工作 ;定时器0 方式2工作
ET0 = 1;//打开定时器0中断
TR0 = 0;//关闭定时器0
TH0 = (256-200); //200*1us=0.2ms 机械周期:12/f = 1us
TL0 = (256-200);
ET1 = 1;//打开定时器1中断
TR1 = 1;//启动定时器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; //K1状态 标志符
}
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)/*显示第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 //如果当前没有存入成绩,显示第1名成绩
{
*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 //INT0外部中断 K1 开始/结束/清零 计时
{
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 //INT1外部中断 K2 记录时间/切换显示内容
{
as=1; //标记进入防抖
EX1 = 0;
if(TR0 == 1)
{
SaveTime((*num));
(*num)++;
}
if((*num)>=10) //
{
TR0 = 0;
k1f = 2;
(*num)=(*num)-1;
Output((*num));
return ; // 这个return退出很重要
}
if(TR0==0&&k1f!=0)
{
(*num)=(*num)+1; //向下切换成员序号 最多9个成员
if((*num)>=10)
{
(*num)=1;
}
Output((*num)); // 显示第(*num)个成绩
}
}
void TimePulse() interrupt 1 //T0定时器 产生时间脉冲
{
static u8 i=0,ii=0;
i++; //每0.2ms进入一次中断 500次为0.1s
if(i>=50)
{
i=0;
ii++;
if(ii==10)
{
(*ss)++; //ss加1 *ss为显示的最后一位
ii=0;
i=0;
}
}
}
void LedShow() interrupt 3 //T1定时器 动态显示 按键中断 4ms进入一次
{
static u8 w=0;
P2 = 0;
TH1 = TScan/256; //
TL1 = TScan%256;
/* 将时间赋值给 数组led_show[] */
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; //计时到9分59秒自动停止计时
*ss=9;
*sl=9;
*sh=5;
*m=9;
}else{}
/* 显示led_show[] */
P1 = led_scan[w];
P2 = led_cc[ led_show[w] ]; //
w++;
if(w==8)
{
w=0;
}else{}
/* 防抖70*4ms = 280ms */
if(as>0)
{
as++;
if(as==71)
{
as=0;
IE0=0; //清空外部中断0中断源
EX0=1; //打开外部中断0
IE1=0; //清空外部中断1中断源
EX1=1; //打开外部中断1
}else{}
}else{}
}
o(︶︿︶)o 唉!今晚还要码MATLAB的作业,
去窗边吹吹风抽根烟,为了生活为了她,继续努力吧骚年。