概述
完成目标
任务书+闹钟(串口通信要用的T1被占了,没做(故意的还是不小心的))
编写的思路
尝试性的把数码管的扫描输出放进了定时器,这样就不用到处写显示函数了。
不同模式有不同的循环函数。
通过tmp_time[]表示定时时间。
应该改进的
编写思路太倾向于大循环里套小循环。
其实可以单一循环,然后根据多个flag来执行需要执行的操作。
矩阵键盘的扫描里有个空的while会卡CPU,解决方法是上次开会讲的根据上升下降沿,太久过去忘了应用(被打)
最好还是不要让定时器来干比较复杂的事情,耗时太久会进入一个闭环。
关键代码
(Nixie.c中修改索引10显示为‘-’)
DS1302_mine.h
#ifndef __DS1302_MINE_H__
#define __DS1302_MINE_H__
extern char time[];
void DS1302_Init(void);
void DS1302_wr(char cmd,char Data);
char DS1302_re(char cmd);
void DS1302_wr_time(void);
void DS1302_re_time(void);
#endif
DS1302_mine.c
#include <REGX52.H>
#define p_s 0x80
#define p_m 0x82
#define p_h 0x84
sbit SCLK1=P3^6;
sbit IO1=P3^4;
sbit CE1=P3^5;
char time[3]={12,0,0};
char to_BCD(char num)
{
return num%10+num/10*16;
}
char to_num(char bcd)
{
return bcd%16+bcd/16*10;
}
void DS1302_wr(char cmd,char Data)//写入函数
{
unsigned char i;
CE1=1;
for(i=0;i<8;i++)
{
SCLK1=0;
IO1=cmd&(0x01<<i);
SCLK1=1;
}
for(i=0;i<8;i++)
{
SCLK1=0;
IO1=Data&(0x01<<i);
SCLK1=1;
}
CE1=0;
}
char DS1302_re(char cmd)//读取函数
{
char i,Data=0x00;
CE1=1;
cmd |= 0x01;
for(i=0;i<8;i++)
{
IO1=cmd&(0x01<<i);
SCLK1=0;
SCLK1=1;
}
for(i=0;i<8;i++)
{
SCLK1=1;
SCLK1=0;
if(IO1){Data|=(0x01<<i);}
}
CE1=0;
IO1=0;
return Data;
}
void DS1302_wr_time(void){ //time[]全部写入
DS1302_wr(p_h,to_BCD(time[0]));
DS1302_wr(p_m,to_BCD(time[1]));
DS1302_wr(p_s,to_BCD(time[2]));
}
void DS1302_re_time(void){ //读取芯片数据到time[]
time[0]=to_num(DS1302_re(p_h));
time[1]=to_num(DS1302_re(p_m));
time[2]=to_num(DS1302_re(p_s));
}
void DS1302_Init(void) //初始化
{
SCLK1=0;
CE1=0;
DS1302_wr(0x8E,0x00);//使得可以写入
}
main.c
#include <REGX52.H>
#include <INTRINS.h>
#include "nixie.h"
#include "MatrixKey.h"
#include "DS1302_mine.h"
#include "Delay.h"
char shining=1;//闪烁标记位
char flag_s_ctrl=0,flag_setting=0,flag_boom=0;
//时分秒哪个闪烁;是否在设定闹钟(切换到显示tmp_time[]);是否到钟
char key=0;//表示按下的按键
char tmp_time[3]={0,0,0};//设定的闹钟时间
unsigned char code Animation[]={
0x78,0x84,0x82,0x41,0x41,0x82,0x84,0x78,
0x00,0x38,0x44,0x22,0x22,0x44,0x38,0x00,
};//忘记删了,尝试用点阵屏,但是没有
void show_time(char h,char m,char s)//集成的显示函数
{
//根据shining和flag_s_ctrl确定是否点亮那个部分
if (shining==0) {Nixie(3,10);Nixie(6,10);}
if (shining==1||flag_s_ctrl!=1){Nixie(1,h/10%10);Nixie(2,h%10);}
if (shining==1||flag_s_ctrl!=2){Nixie(4,m/10%10);Nixie(5,m%10);}
if (shining==1||flag_s_ctrl!=3){Nixie(7,s/10%10);Nixie(8,s%10);}
}
void Timer0_Init(void) //1毫秒@11.0592MHz 半秒计时
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
IP=0x02; //保证计时的高优先级
}
void Timer1_Init(void) //20毫秒@11.0592MHz,用来刷新显示函数
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x00; //设置定时初始值
TH1 = 0xB8; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1=1;
}
/*以下为各个函数的模式*/
void show_mode()//显示模式
{
while(key!=4&&key!=12)
{
key=MatrixKey();
DS1302_re_time();
if(time[0]==tmp_time[0] && time[1]==tmp_time[1] && time[2]==tmp_time[2])//判断时间到没到
{
flag_boom=1;
while(key!=8){
key=MatrixKey();
}
flag_boom=0;
}
}
}
void adjust_mode()//调整模式
{
while(key!=8&&key!=12)
{
key=MatrixKey();
if(key==1){flag_s_ctrl=1;time[0]=(time[0]+1)%24;}
if(key==5){flag_s_ctrl=1;time[0]=(time[0]-1+24)%24;}
if(key==2){flag_s_ctrl=2;time[1]=(time[1]+1)%60;}
if(key==6){flag_s_ctrl=2;time[1]=(time[1]-1+60)%60;}
if(key==3){flag_s_ctrl=3;time[2]=(time[2]+1)%60;}
if(key==7){flag_s_ctrl=3;time[2]=(time[2]-1+60)%60;}
}
flag_s_ctrl=0;//所有数字停止闪烁
DS1302_wr_time();//讲设定的值写入芯片中
}
void setting_mode()//设定闹钟模式
{
flag_setting=1;//切换显示为tmp_time[]
while(key!=8&&key!=4)
{
key=MatrixKey();
if(key==1){flag_s_ctrl=1;tmp_time[0]=(tmp_time[0]+1)%24;}
if(key==5){flag_s_ctrl=1;tmp_time[0]=(tmp_time[0]-1+24)%24;}
if(key==2){flag_s_ctrl=2;tmp_time[1]=(tmp_time[1]+1)%60;}
if(key==6){flag_s_ctrl=2;tmp_time[1]=(tmp_time[1]-1+60)%60;}
if(key==3){flag_s_ctrl=3;tmp_time[2]=(tmp_time[2]+1)%60;}
if(key==7){flag_s_ctrl=3;tmp_time[2]=(tmp_time[2]-1+60)%60;}
}
flag_s_ctrl=0;
flag_setting=0;//退出tmp_time[]的显示
}
void main() //主函数
{
Timer0_Init();
Timer1_Init();
DS1302_Init();
while(1)
{
DS1302_wr_time();//初始化为12-00-00,等待模式的选择
key=MatrixKey();
if(key==8||key==4||key==12){
while(1)
{
if(key==12) //进入对应具体的模式,函数结束全局的key肯定会有一个新的值,
{setting_mode();}//就不用再读取新的key了,不然会使得key=0然后程序停留在左侧这个循环中
if(key==8)
{show_mode();}
if(key==4)
{adjust_mode();}
}
}
}
}
void shining_ctrl() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
T0Count++;
if(T0Count>=500)
{
T0Count=0;
shining=1-shining;
}
}
void kee_show() interrupt 3
{
char i;
TL1 = 0x00; //设置定时初始值
TH1 = 0xB8; //设置定时初始值
if(flag_boom==0){
if(flag_setting) //显示的切换
{
show_time(tmp_time[0],tmp_time[1],tmp_time[2]);
}else{
show_time(time[0],time[1],time[2]);
}
}else{ //我去,闹钟怎么响了
for(i=1;i<80;i++){
if (shining==0){Nixie(i/10,10);}
}//很莫名其妙,不懂事写着玩的是
}
}