访问手机版页面
你的位置:老古开发网 > AVR单片机 > AVR单片机的应用 > 正文  
基于AVR单片机的万年历程序设计
内容导读:

AVR单片机万年历程序

基于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

标签:万年历,AVR单片机,
来源:工程师周亮 作者:21ic 时间:2019/10/12 16:46:00
相关阅读
推荐阅读
阅读排行
最近更新
商品推荐