今年寒假在学校准备蓝桥杯,之前没有写过博客,想着乘着这次机会尝试一下,顺便加强一下蓝桥杯的练习。有什么我说的不对的地方,还请大家指正,谢谢了。
因为之前已经开始练习了蓝桥杯,所以就从ds1302开始,之前的流水灯,数码管,蜂鸣器已经继电器,就先不说。首先就是ds1302的驱动,这个不多说驱动网上都有,这里只是提供一个方便。(注意,向ds1302直接输入时分秒时不能直接写入,必须先把十进制的数据转化为BCD码,这时候写入才是有效的数据)
/*
程序说明: DS1302驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include <intrins.h>
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3; // DS1302复位
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
}
}
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
Write_Ds1302_Byte(dat);
RST=0;
}
unsigned char Read_Ds1302 ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0;
_nop_();
RST=0;
SCK=0;
_nop_();
SCK=1;
_nop_();
SDA=0;
_nop_();
SDA=1;
_nop_();
return (temp);
}
//--------------------------------------------------------------------------------------------
static int year,month,day,hour,min,sec;//定义的全局变量,为了方便写显示函数
int DEC_BCD(unsigned char dat)
{
unsigned char BCD;
BCD = dat / 10;
BCD <<= 4;
dat = dat % 10;
BCD = BCD | dat;
return BCD;
}
int BCD_DEC(unsigned char dat)
{
unsigned char DEC;
DEC = dat & 0x0f;
dat >>= 4;
DEC = dat * 10 + DEC;
return DEC;
}
void read_ds1302()
{
unsigned char t;
// EA = 0;
t = Read_Ds1302(0x81);sec = BCD_DEC(t);
t = Read_Ds1302(0x83);min = BCD_DEC(t);
t = Read_Ds1302(0x85);hour = BCD_DEC(t);
t = Read_Ds1302(0x87);day = BCD_DEC(t);
t = Read_Ds1302(0x89);month = BCD_DEC(t);
t = Read_Ds1302(0x8d);year = BCD_DEC(t);
// EA = 1;
}
void write_ds1302()
{
Write_Ds1302(0x8e,0x00);//注意这里在写入是必须有
Write_Ds1302(0x80,DEC_BCD(sec_t));
Write_Ds1302(0x82,DEC_BCD(min_t));
Write_Ds1302(0x84,DEC_BCD(hour_t));
Write_Ds1302(0x86,DEC_BCD(day_t));
Write_Ds1302(0x88,DEC_BCD(month_t));
Write_Ds1302(0x8c,DEC_BCD(year_t));
Write_Ds1302(0x8e,0x80);
}
我现在写的ds1302是电子表的时间,其中对于这种题目最重要的是显示部分,只有把显示的部分调好了,才能正确的调试出你想要的结果(当然不绝对),因为是显示时分秒,年月日所以我把显示分成了两部分(这是显示时分秒的,显示年月日的大部分一样,只是seven_duan[]中的变量不一样)unsigned char seven_duan[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
unsigned char seven_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
void display0()
{
char m;
switch(m)
{
case 0:dis_play(seven_wei[7],seven_duan[sec%10]);break;
case 1:dis_play(seven_wei[6],seven_duan[sec/10]);break;
case 2:dis_play(seven_wei[5],0xbf|flash);break;
case 3:dis_play(seven_wei[4],seven_duan[min%10]);break;
case 4:dis_play(seven_wei[3],seven_duan[min/10]);break;
case 5:dis_play(seven_wei[2],0xbf|flash);break;
case 6:dis_play(seven_wei[1],seven_duan[hour%10]);break;
case 7:dis_play(seven_wei[0],seven_duan[hour/10]);break;
}
m++;
if(m >= 8) m = 0;
}
而其中的dis_play函数是sfr P4 = 0xc0;
sbit wr = P4^2;
void dis_play(unsigned char x,unsigned char y)
{
wr = 0;
P2 = (P2&0x1f)|0xe0; //打开控制数码管的段选的573
P0 = 0xff;
P2 &= 0x1f; //把138的Y0置低
P2 = (P2&0x1f)|0xc0;//打开控制数码管的位选的573
P0 = x; //控制数码管显示的位置
P2 &= 0x1f;
P2 = (P2&0x1f)|0xe0;
P0 = y; //控制数码管显示的段数
P2 &= 0x1f;
wr = 1;
P0 = 0x00;
P2 = 0x00;
}
鉴于本人比较菜,所以大家理解一下,我放中断和主函数了(我上了,不怂)sfr AUXR = 0xa2;
void timer0_isr() interrupt 1
{
TH0 = (65536-2000)/256;
TL0 = (65536-2000)/256;
cp++;
if(cp >= 500)
{
cp = 0;
flash = ~ flash; //为了使电子表看起来更像,加了个闪烁的变量
cp1++;
read_ds1302();//一秒一读
}
if(cp1 >= 2)
{
cp1 = 0;
flag++;
if(flag == 2) flag = 0;
}
if(flag == 0 && mode == 0)//这样写是为了,我之后写一个可调的电子表
display0();
if(flag == 1 && mode == 0)
display1();
}
void timer0_init()
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD |= 0x01;
TH0 = (65536 - 2000)/256; //2ms
TL0 = (65536 - 2000)/256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
void main()
{
timer0_init();
while(1);
}
大家可以直接用STC公司的软件直接计算定时器的初值,好了,这就是我想说的ds1302的程序。大家可以留下自己想对我说的话,有需要的程序或者帮助话,我会回复的。