📄 ds1302.c
字号:
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
/*********************共阳极***0****1****2*****3****4****5****6****7****8****9*/
const unsigned char led[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //led段码
const char dig[] = { 0x01,0x02,0x04,0x08,0x10,0x20}; //led位选码
unsigned char bcd_dsp[6]={0,0,0}; //bcd码显示缓存
unsigned char dsp[6]={0,0,0,0,0,0}; //显示缓存
unsigned char dsp_state; //显示选择:0显示修改数据;1显示时分秒;2显示星期;3显示年月日
unsigned char time_dog,dog_none;//time_dog:
unsigned char modify_state=0,modify_bit=0,modify_enter=0,modify_key=0;
#define rst PD0
#define clk PD1
#define dat PD2
void out_byte(char addr,char data)//向DS1302写一个数
{
unsigned char i,temp;
DDRD|=(1<<rst);
DDRD|=(1<<clk);
DDRD|=(1<<dat);
PORTD&=~(1<<rst);
PORTD&=~(1<<clk);
PORTD|=(1<<rst);
for (i=0;i<8;i++) //发送读命令
{
temp=addr;
if((temp&(1<<i))!=0)
PORTD|=(1<<dat);
else
PORTD&=~(1<<dat);
PORTD|=(1<<clk);
PORTD&=~(1<<clk);
}
for (i=0;i<8;i++) //发送数据
{
temp=data;
if((temp&(1<<i))!=0)
PORTD|=(1<<dat);
else
PORTD&=~(1<<dat);
PORTD|=(1<<clk);
PORTD&=~(1<<clk);
}
PORTD&=~(1<<rst);
}
void write_ds1302(char addr,char data)//修改DS1302的一个字节
{
out_byte(0x8e,0x00);
out_byte(addr,data);
out_byte(0x8f,0x80);
}
char in_byte(char addr) //从ds1302读入一个字节
{
unsigned char i,temp,temp1;
DDRD|=(1<<rst);
DDRD|=(1<<clk);
DDRD|=(1<<dat);
PORTD&=~(1<<rst);
PORTD&=~(1<<clk);
PORTD|=(1<<rst);
for (i=0;i<8;i++) //发送读命令
{
temp=addr;
if((temp&(1<<i))!=0)
PORTD|=(1<<dat);
else
PORTD&=~(1<<dat);
PORTD|=(1<<clk);
PORTD&=~(1<<clk);
}
DDRD&=~(1<<dat);
temp=0; //准备接收数据
for (i=0;i<8;i++) //接收一个字节数据
{
temp1=PIND;
PORTD|=(1<<clk);
temp1=(temp1>>2)&0x01;
temp|=(temp1<<i);
PORTD&=~(1<<clk);
}
PORTD&=~(1<<rst);
return(temp);
}
void bcd_change(void) //三字节BCD码转换为六位led显示值
{
dsp[0]=led[bcd_dsp[0]>>4];
dsp[1]=led[bcd_dsp[0]&0x0f];
dsp[2]=led[bcd_dsp[1]>>4];
dsp[3]=led[bcd_dsp[1]&0x0f];
dsp[4]=led[bcd_dsp[2]>>4];
dsp[5]=led[bcd_dsp[2]&0x0f];
}
/*********************刷新数码管*********/
void reflash(void)
{
char i,j,mark;
DDRB=0xff;
DDRC=0xff;
mark=0;
for(i=0;i<=5;i++)
{
if(dsp[i]!=0xc0)
{
mark=i;
break;
}
}
if(i==5)
mark=6;
if(dsp_state==0) //修改数据时,在修改的位上显示一个点
{
for(i=0;i<=5;i++)
dsp[i]|=0x80;
dsp[modify_bit]&=0x7f;
}
if(dsp_state==1) //显示时间时,在时分秒之间显示一个闪烁的点
{
time_dog++;
if (time_dog<30)
{
dsp[1]&=0x7f;
dsp[3]&=0x7f;
}
if (dsp[5]!=dog_none)
{
dog_none=dsp[5];
time_dog=0;
}
}
if(dsp_state==3) //在显示年月日时,在年月日之间显示一个点
{
mark=0;
dsp[1]&=0x7f;
dsp[3]&=0x7f;
}
if(dsp_state==2)
mark=5;
for(j=0;j<2;j++)
{
while(mark<6)
{ PORTC=0;
PORTC=dig[mark];
PORTB=dsp[mark];
_delay_ms(2);
mark++;
}
}
}
void main(void)
{
/**********初始化int1中断及键盘*******************/
DDRB=0xff;
DDRD&=0x07;
MCUCR|=(1<<ISC11);//下降沿触发
MCUCR&=~(1<<ISC10);
GIFR&=~(1<<INTF1); //清中断标志
SREG|=(1<<SREG_I); //全局中断
GICR|=(1<<INT1); //int1开中断
/*************************************************/
write_ds1302(0x90,0b10100101); //写充电寄存器
if ((in_byte(0x81)&0x80)!=0) //如果没有启动时钟,则启动时钟
write_ds1302(0x80,0x00);
dsp_state=1; //初始化显示时分秒
DDRB=0xff;
DDRC=0xff;
while (1)
{
SREG&=~(1<<SREG_I);//显示时,关中断
switch(dsp_state)
{
case 0: //直接显示dsp的值
break;
case 1: //显示时分秒
bcd_dsp[0]=in_byte(0x85)&0x3f;
bcd_dsp[1]=in_byte(0x83)&0x7f;
bcd_dsp[2]=in_byte(0x81)&0x7f;
bcd_change();
break;
case 2: //显示星期
bcd_dsp[0]=0;
bcd_dsp[1]=0;
bcd_dsp[2]=(in_byte(0x8b)&0x07)-1;
bcd_change();
break;
case 3: //显示年月日
bcd_dsp[0]=in_byte(0x8d);
bcd_dsp[1]=in_byte(0x89)&0x1f;
bcd_dsp[2]=in_byte(0x87)&0x3f;
bcd_change();
break;
default:
break;
}
reflash();
SREG|=(1<<SREG_I); //显示完毕,开中断
}
}
/******************键盘中断*************************/
SIGNAL(SIG_INTERRUPT1)
{
char key,temp;
// _delay_ms(1); //此处为去抖动
temp=PIND;
if (temp&0xf0) //键有效
key=temp&0xf0;
temp=PIND;
while(temp&0xf0)//等待键释放
temp=PIND;
if (key==0x10&modify_state==0)//改变显示状态键:显示时分秒、年月日、星期
{
dsp_state++;
if (dsp_state>3)
dsp_state=1;
}
if (key==0x20&modify_state!=0)//数据加键
{
bcd_dsp[modify_bit]++;
if(bcd_dsp[modify_bit]>9)bcd_dsp[modify_bit]=0;
dsp[modify_bit]=led[bcd_dsp[modify_bit]];
}
if (key==0x40&modify_state!=0)//确认保存数据
{
if (modify_state==3)
{
write_ds1302(0x84,((bcd_dsp[0]<<4)|(bcd_dsp[1]&0xff)&0x3f));
write_ds1302(0x82,((bcd_dsp[2]<<4)|(bcd_dsp[3]&0xff)&0x7F));
write_ds1302(0x80,((bcd_dsp[4]<<4)|(bcd_dsp[5]&0xff)&0x7f));
dsp_state=1;
modify_state=0;
modify_key=0;
}
if (modify_state==2)
{
write_ds1302(0x8a,(bcd_dsp[5]&0x07)+1);
bcd_dsp[3]=in_byte(0x85)&0x3f;
bcd_dsp[4]=in_byte(0x83)&0x7f;
bcd_dsp[5]=in_byte(0x81)&0x7f;
dsp[0]=led[bcd_dsp[3]>>4];
dsp[1]=led[bcd_dsp[3]&0x0f];
dsp[2]=led[bcd_dsp[4]>>4];
dsp[3]=led[bcd_dsp[4]&0x0f];
dsp[4]=led[bcd_dsp[5]>>4];
dsp[5]=led[bcd_dsp[5]&0x0f];
bcd_dsp[0]=bcd_dsp[3]>>4;
bcd_dsp[1]=bcd_dsp[3]&0x0f;
bcd_dsp[2]=bcd_dsp[4]>>4;
bcd_dsp[3]=bcd_dsp[4]&0x0f;
bcd_dsp[4]=bcd_dsp[5]>>4;
bcd_dsp[5]=bcd_dsp[5]&0x0f;
modify_state=3;
modify_bit=0;
}
if (modify_state==1)
{
write_ds1302(0x8c,(bcd_dsp[0]<<4)|(bcd_dsp[1]&0xff));
write_ds1302(0x88,((bcd_dsp[2]<<4)|(bcd_dsp[3]&0xff)&0x1F));
write_ds1302(0x86,((bcd_dsp[4]<<4)|(bcd_dsp[5]&0xff)&0x3f));
dsp[0]=0xff;
dsp[1]=0xff;
dsp[2]=0xff;
dsp[3]=0xff;
dsp[4]=0xff;
dsp[5]=led[(in_byte(0x8b)&0x07)-1];
bcd_dsp[0]=0;
bcd_dsp[1]=0;
bcd_dsp[2]=0;
bcd_dsp[3]=0;
bcd_dsp[4]=0;
bcd_dsp[5]=(in_byte(0x8b)&0x07)-1;
modify_state=2;
modify_bit=5;
}
}
if (key==0x80)//数据修改键
{
if (modify_state==0&modify_key==0)
{
bcd_dsp[3]=in_byte(0x8d)&0x3f;
bcd_dsp[4]=in_byte(0x89)&0x1f;
bcd_dsp[5]=in_byte(0x87)&0x3f;
dsp[0]=led[bcd_dsp[3]>>4];
dsp[1]=led[bcd_dsp[3]&0x0f];
dsp[2]=led[bcd_dsp[4]>>4];
dsp[3]=led[bcd_dsp[4]&0x0f];
dsp[4]=led[bcd_dsp[5]>>4];
dsp[5]=led[bcd_dsp[5]&0x0f];
bcd_dsp[0]=bcd_dsp[3]>>4;
bcd_dsp[1]=bcd_dsp[3]&0x0f;
bcd_dsp[2]=bcd_dsp[4]>>4;
bcd_dsp[3]=bcd_dsp[4]&0x0f;
bcd_dsp[4]=bcd_dsp[5]>>4;
bcd_dsp[5]=bcd_dsp[5]&0x0f;
modify_state=1;
dsp_state=0;
modify_bit=0;
}
if (modify_state!=0&modify_key==1)
{
modify_bit++;
if (modify_bit>5&modify_state==1)modify_bit=0;
if (modify_bit>5&modify_state==2)modify_bit=5;
if (modify_bit>5&modify_state==3)modify_bit=0;
}
modify_key=1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -