基于AVR单片机的万年历程序设计

avr单片机万年历程序
//***************************filename:rtc.c************************//
//***************************iccavrv6.30编译**********************//
#include//寄存器定义文件
#include//使用到宏
#defineucharunsignedchar//数据类型定义
#defineuintunsignedchar//数据类型定义
#definesd23030x64//sd2303器件iic识别码
uchartable[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x38,0x76};
//显示数据表0123456789lh
uchardata[4]={0,0,0,0};//ds1722
ucharenter_flag;//确定
ucharf_flag;//数据应答标志
voiddelayms(uinti)//延时函数1
{ucharj;
for(;i!=0;i--)
{for(j=2000;j!=0;j--){;}}
}
voiddisplay(uchar*p)//显示函数
{uchari,sel=0x00;
for(i=0;i《16;i++)
{portc=sel;
porta=table[p[i]];
delayms(10);
sel=sel《《1;
}
}
voidnopnop(uchari)//延时函数2
{for(;i!=0;i--)nop();}
voidsetscl(uchari)//iic时钟线scl设置
{if(i==1)portb=portb|0x01;
elseportb=portb&0xfe;}
voidsetsda(uchari)//iic数据线sda设置
{if(i==1)portb=portb|0x02;
elseportb=portb&0xfd;}
//scl=pb^0;sd2303时钟线
//sda=pb^1;sd2303数据线
//intrb=pb^3;sd2303中断线a
//intra=pb^2;sd2303中断线b
voidstart()//iic总线开始信号
{setsda(1);
setscl(1);
nopnop(50);
setsda(0);
nopnop(50);
setscl(0);
}
voidstop()//iic总线停止信号
{setsda(0);
setscl(1);
nopnop(50);
setsda(1);
nopnop(50);
setscl(0);
}
voidack()//单片机应答信号
{setsda(0);
setscl(1);
nopnop(50);
setscl(0);
setsda(1);
}
voidnack()//单片机非应答信号
{setsda(1);
setscl(1);
nopnop(50);
setscl(0);
setsda(0);
}
voidcheck_ack()//器件应答信号检查
{setsda(1);
setscl(1);
f_flag=0;
ddrb=ddrb&0xfd;
if((pinb&0x02)==0)
{setscl(0);
nopnop(50);}
else
{f_flag=1;
setscl(0);
nopnop(50);}
ddrb=ddrb|0x02;
}
voidwrite_bit0()//向iic总线写0
{setsda(0);
setscl(1);
nopnop(50);
setscl(0);
}
voidwrite_bit1()//向iic总线写1
{setsda(1);
setscl(1);
nopnop(50);
setscl(0);
setsda(0);
}
voidwrite_byte(uchardata)//向iic总线写一字节数据
{uchari;
for(i=0;i《8;i++)
{if((data&0x80)》0)
write_bit1();
else
write_bit0();
data《《=1;
}
}
ucharread_byte()//从iic总线读一字节数据
{ucharnn=0xff;
ucharj;
for(j=0;j《8;j++)
{setsda(1);
setscl(1);
ddrb=ddrb&0xfb;
if((pinb&0x02)==0)
{nn《《=1;
nn=(nn&0xfe);
setscl(0);}
else
{nn《《=1;
nn=(nn|0x01);
setscl(0);}
}
ddrb=ddrb|0x02;
return(nn);
}
//****************************写n个字节子程序**********************//
//函数参数说明:
//slave:iic器件地址,如上文定义的sd2303
//address:起始地址
//array:读数据存放的数组
//number:读取的字节数
voidwrite_nbyte(ucharslave,ucharaddress,uchar*array,ucharnumber)
{uchark;
writ:do//开始-》写iic器件地址-》检查应答位
{start();
write_byte(slave);
check_ack();
}while(f_flag==1);
do
{write_byte(address《《4);//送起始地址-》检查应答位
check_ack();
}while(f_flag==1);
for(k=0;k{write_byte(*array);
array++;
check_ack();}//检查应答位
stop();
}
//****************************写一个字节子程序**********************//
//函数参数说明:
//slave:iic器件地址,如上文定义的sd2303
//address:iic器件寄存器地址
//data:数据
voidwrite_1byte(ucharslave,ucharaddress,uchardata)
{writ:do//开始-》写iic器件地址-》检查应答位
{start();
write_byte(slave);
check_ack();
}while(f_flag==1);
do
{write_byte(address《《4);//送起始地址-》检查应答位
check_ack();
}while(f_flag==1);
write_byte(data);
check_ack();//检查应答位
stop();//停止信号
}
//***************************读n个字节子程序***********************//
//函数参数说明:
//slave:iic器件地址,如上文定义的sd2303
//address:起始地址
//array:读数据存放的数组
//number:读取的字节数
voidread_nbyte(ucharslave,ucharaddress,uchar*array,ucharnumber)
{uchardata0,x;
//第一步:开始信号-》写iic器件地址-》检查应答位
do{start();write_byte(slave);check_ack();}while(f_flag==1);
//第二步:写起始地址-》检查应答位
do{write_byte(address《《4);check_ack();}while(f_flag==1);
//第三步:开始信号-》写iic器件地址+1(表示读)-》检查应答位
do{start();write_byte(slave+1);check_ack();}while(f_flag==1);
//第四步:读n字节,每读完一字节发一个ack应答,最后一字节发nack
for(x=0;x{data0=read_byte();*array=data0;array++;
if(x《(number-1)){ack();}}
nack();
//第五步:发停止信号,结束读操作
stop();
}
//***************************按键处理程序**************************//
//说明:为简化程序设计,此程序不保证输入的时间数据的合理性。
voidkey_process(void)
{uchartemp1[17]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//输入数据格式依次为年、月、日、星期、小时和分钟
uchartemp2[7]={0,0,0,0,0,0,0,};
uchartemp3[3]={0,0,0xff};
//输入数据格式依次为小时和分钟
ucharkey;
uchar*flag;
uchari;
flag=temp1;
if(pind!=0xff)
{delayms(20);//延时去抖
if(pind!=0xff)
key=pinb;
if(key==0xfe)//“时间设置”键按下
{temp1[0]|=0x80;//年高位设置提示
while(!enter_flag)//直到按下确定键方停止
{for(i=0;i《50;i++)
display(temp1);//显示和延时
key=~pind;
switch(key)
{case0x04://“+”键处理
(*flag)++;
if(((*flag)&0x7f)==10)*flag=0|0x80;
break;
case0x08://“-”键处理
if(((*flag)&0x7f)==0)*flag=10|0x80;
(*flag)--;
break;
case0x10://“下一位”键处理
flag++;
(*(flag-1))&=0x7f;//上一位去掉小数点显示
(*flag)|=0x80;//当前位加上小数点显示
if(flag==temp1+13)
{flag=temp1;
(*flag)|=0x80;
(*(flag+13))&=0x7f;}
break;
case0x20://“上一位”键处理
if(flag==temp1)
{(*flag)&=0x7f;
flag=temp1+13;
(*flag)|=0x80;}
elseflag--;
(*flag)|=0x80;//当前位加上小数点显示
(*(flag+1))&=0x7f;//下一位去掉点小数点显示
break;
case0x40:enter_flag=1;break;//“确定”键处理
//case0x80:enter_flag=1;break;//测试用
default:break;}
}
enter_flag=0;//按键状态恢复
temp2[0]=0x00;//秒,默认从00开始计时
temp2[1]=(temp1[11]《《4)|temp1[12];//分
temp2[2]=(temp1[9]《《4)|temp1[10];//时
temp2[3]=temp1[8];//周
temp2[4]=(temp1[6]《《4)|temp1[7];//日
temp2[5]=(temp1[4]《《4)|temp1[5];//月
temp2[6]=(temp1[2]《《4)|temp1[3];//年
write_nbyte(sd2303,0x00,temp2,7);//初始化设定时间
}
if(key==0xfd)//“闹铃设置”键按下
{temp1[9]|=0x80;
flag=temp1+9;//定时小时高位设置提示
while(!enter_flag)//直到按下确定键方停止
{for(i=0;i《50;i++)
display(temp1);
key=~pinb;
switch(key)
{case0x04://“+”按键处理
(*flag)++;
if(((*flag)&0x7f)==10)*flag=0|0x80;
break;
case0x08://“-”按键处理
if(((*flag)&0x7f)==0)*flag=10|0x80;
(*flag)--;
break;
case0x10://“下一位”按键处理
flag++;
(*(flag-1))&=0x7f;//上一位去掉小数点显示
(*flag)|=0x80;//当前位加上小数点显示
if(flag==temp1+13)
{(*flag)&=0x7f;
flag=temp1+9;
(*flag)|=0x80;}
break;
case0x20://“上一位”按键处理
if(flag==temp1+9)
{(*flag)&=0x7f;
flag=temp1+13;
(*flag)|=0x80;}
elseflag--;
(*flag)|=0x80;//当前位加上小数点显示
(*(flag+1))&=0x7f;//下一位去掉小数点显示
break;
case0x40:enter_flag=1;break;//“确定”键处理
//case0x80:enter_flag=1;break;//测试用
default:break;}
}
enter_flag=0;
temp3[0]=((temp1[11]《《4)|temp1[12])&0x7f;//分数据处理,去掉小数点
temp3[1]=((temp1[9]《《4)|temp1[10])&0x7f;//时数据处理,去掉小数点
if((temp3[0]《0x60)&&(temp3[1]《0x24))//判断是否为合法时间
{write_1byte(sd2303,0x0e,0b10110000);//开启闹铃使能
write_1byte(sd2303,0x0f,0b00101000);//开始中断使能
write_nbyte(sd2303,0x08,temp3,3);}//初始化闹铃设置
else
write_1byte(sd2303,0x0e,0b00110000);//取消闹铃功能
}
}
}
//***************************ds1722函数开始************************//
voidconvert(ucharp1,uchar*p2)
{uchartemp;
if(p1&0x80)
{p2[13]=10;//零下温度用10表示
p1=0xff-p1;}//温度绝对值
else
p2[13]=11;//零上温度用11表示
p2[14]=p1/10;//温度十位
p2[15]=p1-p2[14]*10;//温度个位
}
//***************************通过spi接口写数据函数*****************//
//函数参数说明:
//address:ds1722寄存器地址
//data:写入的数据
voiddswrite_byte(ucharaddress,uchardata)
{ucharclear;
portb=portb|0x10;//使能spi器件
spdr=address;
while(!(spsr&0x80)){;}
clear=spsr;
clear=spdr;
spdr=data;
while(!(spsr&0x80)){;}
clear=spsr;
clear=spdr;
portb=portb&0xef;
}
//***************************通过spi接口读数据函数*****************//
//函数参数说明:
//address:ds1722寄存器地址
//返回值:读取的温度数据
uchardsread_byte(ucharaddress)
{ucharclear;
uchardata;
portb=portb|0x10;
spdr=address;
while(!(spsr&0x80)){;}
clear=spsr;
clear=spdr;
spdr=address;//发空数据
while(!(spsr&0x80)){;}
clear=spsr;
data=spdr;
portb=portb&0xef;
return(data);
}
voidmain(void)
{uchari;
uchartime[16]={2,0,0,4,1,2,2,7,1,1,7,3,0,0,0,0};
ucharset_time[7]={0x50,0x30,0x20,0x03,0x05,0x01,0x05};
//初始化时间2005-01-05wed20-30-50
ucharsd,ds;
ucharsd2303_controller1=0x00;//禁止中断
ucharsd2303_controller2=0x20;//时间格式:24小时制
ddra=0xff;//a口输出
ddrc=0xff;//c口输出
ddrd=0x80;//d口最高位输出,其他带上拉输入
portd=0x7f;
ddrb=0xf3;//b口带第2、3位带上拉输入,其他输出
portb=0xf3;
write_1byte(sd2303,0x0e,sd2303_controller1);//写控制字
write_1byte(sd2303,0x0f,sd2303_controller2);//写控制字
write_nbyte(sd2303,0x00,set_time,7);//初始化时间
spcr=0b01011100;
dswrite_byte(0x80,0xf0);//ds17228位分辨率自由转换模式
while(1)
{key_process();//按键处理
read_nbyte(sd2303,0x00,set_time,7);//读取时间
time[2]=set_time[6]》》4;//年高位;
time[3]=set_time[6]&0x0f;//年低位;
time[4]=set_time[5]》》4;//月高位;
time[5]=set_time[5]&0x0f;//月低位;
time[6]=set_time[4]》》4;//日高位;
time[7]=set_time[4]&0x0f;//日低位;
time[8]=set_time[3];//星期;
time[9]=set_time[2]》》4;//时高位;
time[10]=set_time[2]&0x0f;//时低位;
time[11]=set_time[1]》》4;//分高位;
time[12]=set_time[1]&0x0f;//分低位;
time[13]=set_time[0]》》4;//秒高位;
time[14]=set_time[0]&0x0f;//秒低位;
read_nbyte(sd2303,0x0f,&sd,1);//读取中断标志位
if(sd&0x02)portd=portd|0x80;//响铃1分钟
elseportd=portd&0x7f;//关闭闹铃
ds=dsread_byte(0x02);//读取温度值
convert(ds,time);
display(time);//时间显示
}
}
来源;21ic

虹科案例 | 订单自动分拣效率居然这么高?
一个非常简单的基于IC LS7220的电子密码锁
2023上海全球投资促进大会 | 宝武集团和亮风台现场签约元宇宙重点应用场景
高低温磁场型霍尔效应测试仪技术参考
推进5G网络信息技术和实体经济深度融合的三大措施
基于AVR单片机的万年历程序设计
兆芯与中孚正式达成产品兼容互认证明
电压波形驱动喇叭发音的原理
SpaceX的2020年第一次发射,携带60星链卫星
云服务、OEM 借助 NVIDIA AI让AI训练更上层楼
中微电携自研GPU产品亮相ELEXCON深圳国际电子展
关于STM32串口通信使用printf发送数据的配置方法
通用抢先福特部署商业化自动驾驶打车服务,2019年商用
深入探讨在FPGA设计中要避免的10大错误
pcba工厂里的呆滞拆机料都流向了哪里呢?
病害肉检测仪器的相关功能介绍
宝马的电动化攻势打响!
工控中伺服驱动系统的接线方法
商汤AIDC赋能三大领域,加速全产业数字化转型
马斯克称在考虑使特斯拉以每股420美元的价格退市