这是今天二刷的一道题目,其中用的了ds1302和onewire协议。
底层代码就不放了,前面讲模块的文章也有,用的是官方的底层驱动。
下面直接上主函数,在程序中讲解
#include
#include "ds1302.h"
#include "onewire.h"
#define uchar unsigned char
#define uint unsigned int
uchar code adress[]={
0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//数码管显示地址
uchar code display[]={
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40,0x39};
//共阴数码管显示编码表,在stc中的范例程序->实验箱->数码管显示中有
uchar Trg,cont,key_count=0,key_flag=0;//键盘有关
uchar shi,fen,miao,set_num,m,send_num;//时间有关
uchar nz_shi_ture=0,nz_fen_ture=0,nz_miao_ture=0;//闹钟参数
uchar nz_shi=0,nz_fen=0,nz_miao=0;//闹钟显示
uchar i=0,buff[8];//显示有关
uchar flag=0;//启动停止标志位
uchar tempe;//温度
uint display_count=0;//控制闪烁
uchar display_flag=1;
uchar sz_mode=0,nz_mode=0;//模式控制
uchar led_flag=0,LED_f=1,LED;
uint led_count=0;//led控制
void init()//初始化关蜂鸣器,继电器,led
{
P2=0xa0;P0=0x00;P2=0x00;
P2=0x80;P0=0xff;P2=0x00;
}
void set_time(uchar shi,uchar fen,uchar miao)//设置初始时间
{
Write_Ds1302_Byte(0x8e,0);//关写保护
Write_Ds1302_Byte(0x84,(shi/10)*16+shi%10);//记住时分秒的写地址 0x84,0x82,0x80;
Write_Ds1302_Byte(0x82,(fen/10)*16+fen%10);
Write_Ds1302_Byte(0x80,(miao/10)*16+miao%10);
Write_Ds1302_Byte(0x8e,0x80);//开写保护
}
void read_time()//读取时间,读取前关中断
{
EA=0;
shi=Read_Ds1302_Byte(0x85);//记住时分秒的读取地址
fen=Read_Ds1302_Byte(0x83);
miao=Read_Ds1302_Byte(0x81);
EA=1;
}
void stop()//停止功能,这个非常重要
{
Write_Ds1302_Byte(0x8e,0);
if(miao<0x80)//停止
{
Write_Ds1302_Byte(0x80,miao|0x80);//高位置1
flag=1;
}
else//启动
{
Write_Ds1302_Byte(0x80,miao&0x7f);//高位值0
flag=0;
}
Write_Ds1302_Byte(0x8e,0x80);
}
uchar read_tempe()//读温度
{
uint temp;
uchar tempe;
uchar high,low;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay_OneWire(200);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low=Read_DS18B20();
high=Read_DS18B20();
temp=high&0x0f;
temp<<=8;
temp=temp|low;
tempe=(uchar)(temp*0.0625);//精度是0.0625摄氏度
return tempe;
}
void read_key()//独立键盘读取
{
uchar readData=P3^0xff;
Trg=readData&(readData^cont);
cont=readData;
}
void key_function()//按键功能
{
if(Trg&0x01||Trg&0x02||Trg&0x04||Trg&0x08)//任意键关闹钟
{
led_flag=0;
LED_f=1;
led_count=0;
}
if(Trg&0x01)//s7,时钟设置
{
if(nz_mode==0)
sz_mode++;
if(sz_mode==1)
stop();
if(sz_mode==4)
{
stop();
sz_mode=0;
}
}
if(Trg&0x02)//s6,闹钟设置
{
if(sz_mode==0)
nz_mode++;
if(nz_mode==4)
{
nz_mode=0;
nz_shi_ture=nz_shi;//这个是更新闹钟的比较参数,和显示参数,就是,你在改变闹钟后要完全返回后,参数才生效
nz_fen_ture=nz_fen;
nz_miao_ture=nz_miao;
LED_f=1;
}
}
if(Trg&0x04)//s5,加
{
if(sz_mode!=0&&nz_mode==0&&flag==1)//时钟暂停时,调节时钟
{
//选择当前要调节是时分秒
if(sz_mode==1)//时
m=0x84;
else if(sz_mode==2)
m=0x82;
else if(sz_mode==3)//秒
m=0x80;
EA=0;set_num=Read_Ds1302_Byte(m+1);EA=1;//读取当前的时间
send_num=(set_num/16&0x07)*10+set_num%16+1;//BCD转十进制之后加一,注意这个&0x07,是秒特有的,为了不分类,时分也可以
//注意边界属性
if(m==0x84)
send_num=send_num%24;
else
send_num=send_num%60;
Write_Ds1302_Byte(0x8e,0x00);//关写保护
if(m==0x80)//秒的时候BCD码要|0x80,高位置1,不然会出错
Write_Ds1302_Byte(m,(send_num/10*16+send_num%10)|0x80);
else
Write_Ds1302_Byte(m,send_num/10*16+send_num%10);
Write_Ds1302_Byte(0x8e,0x80);//开写保护
}
if(nz_mode!=0&&sz_mode==0)//增加闹钟
{
if(nz_mode==1)
nz_shi=(nz_shi+1)%24;
if(nz_mode==2)
nz_fen=(nz_fen+1)%60;
if(nz_mode==3)
nz_miao=(nz_miao+1)%60;
}
}
if(Trg&0x08)//s4减,类似于加,注意边界属性,不能减出来负数
{
if(sz_mode!=0&&nz_mode==0&&flag==1)
{
if(sz_mode==1)//ʱ
m=0x84;
else if(sz_mode==2)
m=0x82;
else if(sz_mode==3)//Ãë
m=0x80;
EA=0;set_num=Read_Ds1302_Byte(m+1);EA=1;
send_num=(set_num/16&0x07)*10+set_num%16;
if(send_num==0)
{
if(m==0x84)send_num=23;
else send_num=59;
}
else
send_num=send_num-1;
Write_Ds1302_Byte(0x8e,0x00);
if(m==0x80)//
Write_Ds1302_Byte(m,(send_num/10*16+send_num%10)|0x80);
else
Write_Ds1302_Byte(m,send_num/10*16+send_num%10);
Write_Ds1302_Byte(0x8e,0x80);
}
if(nz_mode!=0&&sz_mode==0)
{
if(nz_mode==1)
{
if(nz_shi==0)nz_shi=23;
else nz_shi--;
}
if(nz_mode==2)
{
if(nz_fen==0)nz_fen=59;
else nz_fen--;
}
if(nz_mode==3)
{
if(nz_miao==0)nz_miao=59;
else nz_miao--;
}
}
}
}
void set_buff()//设置显示数组
{
if(cont&0x08&&sz_mode==0&&nz_mode==0)//长按 s4 在时钟显示界面,显示温度
{
tempe=read_tempe();
buff[0]=10;
buff[1]=10;
buff[2]=10;
buff[3]=10;
buff[4]=10;
buff[5]=tempe/10;
buff[6]=tempe%10;
buff[7]=12;//c
}
else if(nz_mode==0)//时钟界面
{
if(sz_mode==1)//时闪烁
{
if(display_flag==1)
{
buff[0]=shi/16;buff[1]=shi%16;
}
else
{
buff[0]=10;buff[1]=10;
}
}
else
{
buff[0]=shi/16;buff[1]=shi%16;
}
if(sz_mode==2)//分闪烁
{
if(display_flag==1)
{
buff[3]=fen/16;buff[4]=fen%16;
}
else
{
buff[3]=10;buff[4]=10;
}
}
else
{
buff[3]=fen/16;buff[4]=fen%16;
}
if(sz_mode==3)//秒闪烁
{
if(display_flag==1)
{
buff[6]=miao/16&0x07;buff[7]=miao%16;
}
else
{
buff[6]=10;buff[7]=10;
}
}
else
{
buff[6]=miao/16&0x07;buff[7]=miao%16;
}
buff[2]=11;buff[5]=11;
}
else if(nz_mode!=0)
{
if(nz_mode==1)//闹钟时闪烁
{
if(display_flag==1)
{
buff[0]=nz_shi/10;buff[1]=nz_shi%10;
}
else
{
buff[0]=10;buff[1]=10;
}
}
else
{
buff[0]=nz_shi/10;buff[1]=nz_shi%10;
}
if(nz_mode==2)//分闪烁
{
if(display_flag==1)
{
buff[3]=nz_fen/10;buff[4]=nz_fen%10;
}
else
{
buff[3]=10;buff[4]=10;
}
}
else
{
buff[3]=nz_fen/10;buff[4]=nz_fen%10;
}
if(nz_mode==3)//秒闪烁
{
if(display_flag==1)
{
buff[6]=nz_miao/10;buff[7]=nz_miao%10;
}
else
{
buff[6]=10;buff[7]=10;
}
}
else
{
buff[6]=nz_miao/10;buff[7]=nz_miao%10;
}
buff[2]=11;buff[5]=11;
}
}
void set_led()//设置led
{
if(shi==nz_shi_ture&&fen==nz_fen_ture&&miao==nz_miao_ture)
{
led_flag=1;
}
if(led_flag==1)
{
if(LED_f==1)
LED=0x01;
else
LED=0x00;
}
else
LED=0x00;
}
void Timer0Init(void) //[email protected]
{
EA=1;
ET0=1;
AUXR |= 0x80; //?????1T??
TMOD &= 0xF0; //???????
TL0 = 0xCD; //??????
TH0 = 0xD4; //??????
TF0 = 0; //??TF0??
TR0 = 1; //???0????
}
void time0() interrupt 1
{
if(++key_count==10)//扫描键盘
key_flag=1;
if(++display_count==1000)//控制1s闪烁
{
display_flag=~display_flag;
display_count=0;
}
if(led_flag==1)//led闪烁
{
led_count++;
if(led_count%200==0&&led_count<=5000)//5s内,0.2s闪烁
LED_f=~LED_f;
if(led_count>5000)//超过5s 关闹钟
{
led_flag=0;
LED_f=0;
led_count=0;
}
}
//数码管显示
P2=0xc0;P0=adress[i];P2=0x00;
P2=0xe0;P0=~display[buff[i]];P2=0x00;
i++;if(i==8)i=0;
}
void main()
{
init();//初始化
read_tempe();//读一下温度
Timer0Init();//定时器0初始化
set_time(23,59,55);//设置初始时间
while(1)
{
if(key_flag==1)//按键按下
{
key_flag=0;
key_count=0;
read_key();//读键盘
key_function();//键盘功能
}
read_time();//读温度
set_led();//设置led
set_buff();//设置显示数组
P2=0x80;P0=~LED;P2=0x00;
}
}
这篇博客是清明节写的,当时只写了一半,现在过了一个星期补了回来,发现有大问题。当时,因为第二天要模拟考,没写完,但是第二天正好考到了时钟,是一道国赛题,其中就有时钟显示,和调节时间,当时因为矩阵键盘的原因,一直无法让选中的时分秒,间隔一秒闪烁,耽误了很长时间,大概有两个小时时钟模块还没写好,决定放弃,因为下面还有好几个模块,幸好下面的模块比较简单,不到两个小时全写完了。
因为下面有个调节参数要用到键盘的模块时,发现了是矩阵键盘的问题,我一开始写的会一直读矩阵键盘,后来我灵光一现,换成Trg 判断,和独立键盘差不多,因为两个的读取原理一样的。键盘的问题解决了。但是时钟的暂停不下了。暂停可以按下时间就会走的非常快。改了好久,不行,于是放弃,一度以为是stop()函数记错了。可是就那么几行,不可能错的。。。而且时钟的加减都没问题。最终还是没有发现。最后就改成了,时钟边走边调节时间。
考后发参考代码才知道!
要改底层驱动!!!!要改底层驱动!!!!要改底层驱动!!!!
不改也可以,但是读取和改时间就没那么简单了,要注意读取的时间。
下面来对照改一下驱动
void Write_Ds1302(unsigned char temp)//写字节
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
SCK=0;//改,这是增加的语句
}
}
unsigned char Read_Ds1302_Byte ( unsigned char address )读字节
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
//SCK=0;//删去
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
SCK=0;//改,新增
}
RST=0; _nop_();
//SCK=0; _nop_();//删去
//SCK=1; _nop_();//删去
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
这两个子函数要改一下。所以说要记得东西又增加了。
此为还有一个个坑就是。onewire的驱动竟然也要改!!!onewire的驱动竟然也要改!!!onewire的驱动竟然也要改!!!
之前几场模拟没用的采集温度,昨天做了一个有采集温度的国赛题,第一个模块就是采集温度,也幸好我用了从实验室拷贝的驱动,我之前模块题的时候把驱动改了都不记得了,之前做的好几个省赛题,直接拿之前的驱动,所以一直不知道。幸好做了遇到的这个问题。如果不改,温度读不出。第一怀疑的read_temp()是不是写错了。对照了一下,没有!!也是突然想到了换底层驱动,结果就是竟然可以了。对照了一下发现驱动果然不一样,就一点点不一样——延时函数!!!
void Delay_OneWire(unsigned int t) //STC89C52RC
{
t=t*10;//增加,这个要乘10
while(t--);
}
很迷吧。快考试了,因为之前十年没考过超声波和串口,现在预测说可能考。要抓紧复习啊。