这里的代码是主文件的代码,其他的头文件之前已经提供,下面的代码仅提供思路,不提供原理,如有错误请及时留言提醒。
#include <stc15f2k60s2.h>
#include <intrins.h>
#include "ds1302.h"
#include "iic.h"
typedef unsigned char uchar;
typedef unsigned int uint;
code uchar TAB[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xbf};//显示1-9 灭 -
uchar tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8;
uchar key, sec, min, hour, AD, dat;//常用的参数,秒,分,时,数据存放,AD读取
uint fre_time, frequ, H_tem, L_tem, H, L;//定义频率采集所需的变量
bit fre_state;
uint dat_t;
bit time_state, AD_state;//读取时间标志位,读取电压标志位
uchar function;
uchar T_set, V_set;//记录时间显示状态,电压显示状态
bit F_T;//记录频率周期显示状态
uchar hour_tem, min_tem, sec_tem;//时间调节临时存放
uchar V_h = 20, V_l = 10;//电压上限=2.0V 电压下限=1.0V
bit inqu_state, thing_num;//记录查询显示状态,存放事件类型
uchar hour_in = 13, min_in = 50, sec_in = 12;//存放发生时间
bit times;//触发标志位
void delay(uint z)//延时函数
{
uint x, y;
for(x=z; x>0; x--)
for(y=845; y>0; y--);
}
void timer_int()//定时器初始,一般是手写放在这里面
{
EA = 1;
TR0 = 1;//定时器0,16位,定时1ms,定时中断
ET0 = 1;
TMOD |= 0X01;
TH0 = (65535-1000)/256;
TL0 = (65535-1000)%256;
TMOD |= 0X20;// 定时器1,8位自动装载,用来定时采样频率,5us
TH1 = 255-5;
TL1 = 255-5;
}
void display()//显示函数,配合定时器0中断使用,达到循环扫描
{
static uchar i;//定义静态变量i
switch(i)
{
case 0: P2=0XC0; P0=0X01; P2=0XE0; P0=TAB[tab1]; i=1; break;
case 1: P2=0XC0; P0=0X02; P2=0XE0; P0=TAB[tab2]; i=2; break;
case 2: P2=0XC0; P0=0X04; P2=0XE0; P0=TAB[tab3]; i=3; break;
case 3: P2=0XC0; P0=0X08; P2=0XE0; P0=TAB[tab4]; i=4; break;
case 4: P2=0XC0; P0=0X10; P2=0XE0; P0=TAB[tab5]; i=5; break;
case 5: P2=0XC0; P0=0X20; P2=0XE0; P0=TAB[tab6]; i=6; break;
case 6: P2=0XC0; P0=0X40; P2=0XE0; P0=TAB[tab7]; i=7; break;
case 7: P2=0XC0; P0=0X80; P2=0XE0; P0=TAB[tab8]; i=0; break;
}
}
void key_scan()//半矩阵键盘扫描,常用需要理解记住
{
key = 0;
P44=1; P42=1; P3=0X00;
if((P44==0)|(P42==0))//判断竖行
{
delay(2);//消抖
P44=1; P42=1; P3=0X00;
if((P44==0)|(P42==0))
{
if(P44==0) key = 4;
if(P42==0) key = 8;
}
P44=0; P42=0; P3=0X3F;
if(P3!=0X3F)//判断横行
{
P44=0; P42=0; P3=0X3F;
delay(2);//消抖
if(P3!=0X3F)
{
if(P33==0) key += 0;
if(P32==0) key += 1;
if(P31==0) key += 2;
if(P30==0) key += 3;
}
}
while(P3!=0X3F);//判断抬手
}
}
void time_read()//时间读取函数,需要赋值几个变量,所以放在主函数写
{
EA = 0;//使用时间读取,需要关闭中断
Write_Ds1302_Byte(0x8e,0x00);
sec = Read_Ds1302_Byte(0x81);
min = Read_Ds1302_Byte(0x83);
hour = Read_Ds1302_Byte(0x85);
Write_Ds1302_Byte(0x8e,0x80);
EA = 1;//写完后,打开中断
}
void time_display()//时间显示函数,里面附加调整参数,里面附加切换按键
{
if(key==4)//功能按键,切换显示功能
{
if(T_set==0) { T_set = 1; hour_tem = hour, min_tem = min, sec_tem = sec; }//临时赋值时间,好处,调整时间的时候,时间显示不会正常走时
else if(T_set==1) T_set = 2;//1-3循环,依照题目的要求,只有按下S7的时候,保存数据
else if(T_set==2) T_set = 3;
else if(T_set==3) T_set = 1;
}
else if(key==10)//减按键
{
if(T_set==1) { if(hour_tem==0) hour_tem=1; hour_tem--; }//注意设置范围
else if(T_set==2) { if(min_tem==0) min_tem=1; min_tem--; }
else if(T_set==3) { if(sec_tem==0) sec_tem=1; sec_tem--; }
}
else if(key==11)//加按键
{
if(T_set==1) { hour_tem++; if(hour_tem==24) hour_tem=23;}//注意设置范围
else if(T_set==2) { min_tem++; if(min_tem==60) min_tem=59;}
else if(T_set==3) { sec_tem++; if(sec_tem==60) sec_tem=59;}
}
if(T_set==0)//正常时间显示
{
tab1=hour/10; tab2=hour%10; tab3=11; tab4=min/10; tab5=min%10; tab6=11; tab7=sec/10; tab8=sec%10;
}
else if(T_set==1)//时间调整
{ //所调整的值闪烁
if(sec%2==0) { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
else { tab1=10; tab2=10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
}
else if(T_set==2)//分钟调整
{
if(sec%2==0) { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
else { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=10; tab5=10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
}
else if(T_set==3)//秒调整
{
if(sec%2==0) { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=sec_tem/10; tab8=sec_tem%10; }
else { tab1=hour_tem/10; tab2=hour_tem%10; tab3=11; tab4=min_tem/10; tab5=min_tem%10; tab6=11; tab7=10; tab8=10; }
}
}
void voltage_display()//电压显示函数,里面附加调整参数,里面附加切换按键
{
if(key==4)//功能按键,切换显示功能
{
if(V_set==0) V_set = 1;
else if(V_set==1) V_set = 2;
else if(V_set==2) V_set = 1;
}
else if(key==10)//减按键
{
if(V_set==1) { if(V_h==0) V_h = 5; if(V_h>V_l) V_h-=5; }//注意设置范围,加减500mV
else if(V_set==2) { if(V_l==0) V_l = 5; V_l-=5; }
}
else if(key==11)//加按键
{
if(V_set==1) { V_h+=5; if(V_h==55) V_h = 50; }
else if(V_set==2) { if(V_h>V_l) V_l+=5; if(V_l==55) V_l = 50; }
}
if(V_set==0)//正常电压显示
{
tab1=11; tab2=1; tab3=11; tab4=10; tab5=AD/10; tab6=AD%10; tab7=0; tab8=0;
}
else if(V_set==1)//调整上限电压
{ //所调整的值闪烁
if(sec%2==0) { tab1=V_h/10; tab2=V_h%10; tab3=0; tab4=0; tab5=V_l/10; tab6=V_l%10; tab7=0; tab8=0; }
else { tab1=10; tab2=10; tab3=10; tab4=10; tab5=V_l/10; tab6=V_l%10; tab7=0; tab8=0; }
}
else if(V_set==2)//调整下限电压
{
if(sec%2==0) { tab1=V_h/10; tab2=V_h%10; tab3=0; tab4=0; tab5=V_l/10; tab6=V_l%10; tab7=0; tab8=0; }
else { tab1=V_h/10; tab2=V_h%10; tab3=0; tab4=0; tab5=10; tab6=10; tab7=10; tab8=10; }
}
}
void frequ_display()//频率显示函数,里面附加切换按键
{
if(key==4) F_T = ~F_T;//功能按键,切换显示功能
if(F_T==0)//显示频率
{
tab1=11; tab2=2; tab3=11; tab4=frequ/10000; tab5=frequ%10000/1000; tab6=frequ%1000/100; tab7=frequ%100/10; tab8=frequ%10;
}
else //显示周期
{
tab1=11; tab2=2; tab3=11; tab4=fre_time/10000; tab5=fre_time%10000/1000; tab6=fre_time%1000/100; tab7=fre_time%100/10; tab8=fre_time%10;
}
}
void inquiry()//查询显示函数,里面附加切换按键
{
if(key==4) inqu_state = ~inqu_state;
if(inqu_state==0)//显示事件类型
{
tab1=10; tab2=10; tab3=10; tab4=10; tab5=10; tab6=10; tab7=0; tab8=thing_num;
}
else//显示发生时间
{
tab1=hour_in/10; tab2=hour_in%10; tab3=11; tab4=min_in/10; tab5=min_in%10; tab6=11; tab7=sec_in/10; tab8=sec_in%10;
}
}
void dat_read()//从EEPROM获取题目所需的变量
{
if(EEPROM_read(0x01)!=3)//初始化参数,第一遍烧录程序只执行一次,比较好的模板,可记住
{
delay(3);
EEPROM_write(0x01,3); delay(3);
EEPROM_write(0x11,20); delay(3);
EEPROM_write(0x12,10);
}
delay(3);
V_h = EEPROM_read(0x11); delay(3);//连续读取或写入,必须加小延迟
V_l = EEPROM_read(0x12); delay(3);
thing_num = EEPROM_read(0x20); delay(3);
hour_in = EEPROM_read(0x21); delay(3);
min_in = EEPROM_read(0x22); delay(3);
sec_in = EEPROM_read(0x23); delay(3);
}
void dat_gain()//定时数据获取函数
{
if(AD_state==1) //一般可在获取数据后判断状态,保证数据正确
{
AD_state = 0; AD = AD_read(0x03)/5.1; //读取电压*10
if((V_h<AD)&(times==0)) //判断超过上限
{
times = 1;
thing_num = 1;
hour_in = hour; min_in = min; sec_in = sec;
EEPROM_write(0x20,thing_num); delay(5); //向EEPROM写入事件类型,发生时间
EEPROM_write(0x21,hour_in); delay(5);
EEPROM_write(0x22,min_in); delay(5);
EEPROM_write(0x23,sec_in);
}
else if((AD<V_l)&(times==0))//判断低于下限
{
times = 1;
thing_num = 0;
hour_in = hour; min_in = min; sec_in = sec;
EEPROM_write(0x20,thing_num); delay(5); //向EEPROM写入事件类型,发生时间
EEPROM_write(0x21,hour_in); delay(5);
EEPROM_write(0x22,min_in); delay(5);
EEPROM_write(0x23,sec_in);
}
else if((AD>=V_l)&(AD<=V_h)) times = 0;//判断电压是否回到正常值,times只有置零,才能开始下次判断
}
else if(time_state==1) { time_state = 0; time_read();}
}
void key_function()//按键功能
{
if((key==7)&(V_set==0))//时钟按键,进入相关显示函数
{
function = 0;
if(T_set!=0)//判断是否处于设置界面
{
T_set = 0;
EA = 0;
Write_Ds1302_Byte(0x8e,0x00);//重新写入所设置的时间
Write_Ds1302_Byte(0x80,sec_tem);
Write_Ds1302_Byte(0x82,min_tem);
Write_Ds1302_Byte(0x84,hour_tem);
Write_Ds1302_Byte(0x8e,0x80);
EA = 1;
}
}
else if((key==6)&(T_set==0))//电压测量按键,进入相关显示函数
{
function = 1;
if(V_set!=0)//判断是否处于设置界面
{
V_set = 0;
EEPROM_write(0x11,V_h);//向EEPROM写入所设置的时间
delay(3);
EEPROM_write(0x12,V_l);
}
}
else if((key==5)&(V_set==0)&(T_set==0))//频率测量按键,进入相关显示函数
{
function = 2;
if(F_T!=0) F_T = 0;//返回初始界面
}
else if(key==9)//查询按键,进入相关显示函数
{
function = 3;
if(inqu_state!=0) inqu_state = 0; //返回初始界面
}
//function 0为时间显示界面 1为电压测量界面 2为电压阈值设置界面 3为查询界面
if(function==0) time_display();
else if(function==1) voltage_display();
else if(function==2) frequ_display();
else if(function==3) inquiry();
}
void main()
{
P2=0XA0; P0=0X00; P2=0X80; P0=0XFF;//初始化,熄灭灯,关闭蜂鸣器和继电器
Write_Ds1302_Byte(0x8e,0x00);//写入时间 23-59-55
Write_Ds1302_Byte(0x80,55);
Write_Ds1302_Byte(0x82,59);
Write_Ds1302_Byte(0x84,23);
Write_Ds1302_Byte(0x8e,0x80);
dat_read();//初始化读取
timer_int();//定时器初始化
while(1)
{
key_scan();//按键扫描
dat_gain();//定时获取时间
key_function();//按键功能
}
}
void display_timer0()interrupt 1
{
TH0 = (65535-1000)/256;//定时器1装载
TL0 = (65535-1000)%256;
display();//数码管扫描显示
dat_t++;//定时数据获取的时刻,定义时,记得超过256,需要定义为 unsigned int
if(dat_t==50) AD_state = 1;
else if(dat_t==150) time_state = 1;
else if(dat_t==250) //打开定时器1中断,开始计数
{ TR1 = 1; ET1 = 1; }
else if(dat_t==280)
{
TR1 = 0; ET1 = 0;//关闭定时器1中断,计数完毕
fre_time = (H_tem + L_tem)*5;//计算周期
frequ = 1000000/fre_time;//计算频率
}
else if(dat_t==400) dat_t = 0;//时间最后记得清零
}
void frequ_time1()interrupt 3//定时器1中断,因为存在2个中断,所以有一个中断必须限制中断时长,在定时器0中断中设置30ms的使用时间
{
if(P34==1)//判断高电平
{
H++;//记录高电平周期数
if(fre_state==1)//保存一次低电平的周期数
{
fre_state = 0;
L_tem = L;//赋值
L = 0;//清零,为下次读取做准备
}
}
else if(P34==0)//判断低电平
{
L++;//记录低电平周期数
if(fre_state==0)//保存一次高电平的周期数
{
fre_state = 1;
H_tem = H;//赋值
H = 0;//清零,为下次读取做准备
}
}
}