我去年使用DS1307郁闷了几天. 基于I2C总线,时钟没有工作.结果是软件配置问题.
下面为一参考程序.百分百可以跑.
//******************************************************************* //***此程序为调试通过的源程序 //***文件名:SY1126.C***// //***是51系例单片机的最小系统 //***有AT89S8252/AT89S51/52的在线下载功能 //***IIC总线芯片为24C02,记存密码 //******************************************************************* #include"at89x52.h" #include<intrins.h> #define uchar unsigned char #define uint unsigned int #define nop _nop_() /* 定义空操作指令 */ #define VAR P1 sbit clk=P2^0; /*DTLED-6显示芯片/时钟芯片DS1302时钟输入端*/ sbit dout=P2^1; /*DTLED-6显示芯片数据读入端*/ sbit en =P2^2; /*DTLED-6显示芯片使能端*/ sbit RST=P2^3; /*DS1302芯片复位起始端*/ sbit DINOUT=P2^4; /*DS1302时钟芯片数据输入输出端*/ sbit enable=P2^5; /*LCD模块用*/ sbit rw=P2^6; /*LCD模块用*/ sbit rs=P2^7; /*LCD模块用*/
sbit SCL=P3^4; /*24C01 CSL接脚=89C51 T0 P3.4*/ sbit SDA=P3^5; /*24C01 SDA接脚=89C51 T1 P3.5*/
bit FLAG0=0; /*位标号FLAG0=1键盘扫描回应*/ bit FLAG1=1; /*位标号20H.1比较密码回应旗号*/ bit FLAG2=1; /*位标号FLAG2=0时,进入键盘操作*/ bit FLAG3=1; /*位标号FLAG3=0时,键盘操作*/ bit FLAG4=0; /*位标号FLAG4=0时,键盘操作*/ bit FLAG5=0; /*位标号FLAG5=1时,存储*键按下*/ bit FLAG6=0; /*位标号FLAG6=1时,有串行信号输入*/ bit TSendAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no); /* 向有子地址器件写入6字节数据函数 */ bit TRcvAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no); /* 向有子地址器件读取6字节数据函数 */ bit acknow; /* 应答标志位 acknow=1 表示正常响应 acknow=0 表示未响应 */ static const char tab[16]={0x01,0x02,0x03,0x0c, /*键盘码00,01,02,03,*/ 0x04,0x05,0x06,0x0d, /*键盘码04,05,06,07,*/ 0x07,0x08,0x09,0x0e, /*键盘码08,09,0a,0b,*/ 0x0a,0x00,0x0b,0x0f};/*键盘码0c,0d,0e,0f*/ //static const char tab1[6]={0x01,0x01,0x01,0x01,0x01,0x01};/*内定密码"888888"*/ uchar char1[]="Syber Nanjing.Co"; uchar char2[]="Password:"; uchar dispbuf[9]; /*显示值存放阵列*/ uchar clocktmp[3]; /*显示值存放阵列*/ uchar bufdata[9]; uchar bufuart[6]; /*串口接收值存放阵列*/ uchar a1=0,clockbak,b1=100,stand=0,m=0,busy,count=10; char ww=0,ptr=0,ptr1=0; /*PTR键盘扫描指标,ptr1显示器扫描指标*/ void delay (unsigned int value) /*延时副程式*/ { while (value!=0) value--; /*10US延时*/ } void Enable(uchar c); void Write1(char *c1); void Write2(char c2); void Write3(void); /* 显示密码字符串 */ void Initial(); /*LCD模块初始化*/ void tsled(void); /*串行发送到DTLED-6副程式*/ void BCD(void); /*BCD码转换副程式*/ void scan(void); /*键盘扫描副程式*/ void clear(void); /*清除按键存放/显示器阵列dispbuf[]副副程式*/ void open(void); /*开门比较密码副程式*/ void read24c02(); /*读24c02的存储值*/ void write24c02(); /*写24c02的存储值*/ void IICSAVE(void); /*设定密码并存入buft[]阵列副程式*/ void disp(void); /*显示存放在dispbuf[]阵列的密码副程式*/ void tserial(void); /*串口serial发送副程式*/ void rserial(void); /*串口serial接收副程式*/ void temp(void); void Rd1302st(void); /*读时钟芯片DS1302*/ void Rd1302(void); /*读时钟芯片DS1302*/ void Wr1302(void); /*写时钟芯片DS1302*/ void Start(); /* 起动总线函数 */ void Stop(); /* 结束总线函数 */ void SendByte(uchar c); /* 8951发数据或地址给8583 字节数据发送函数 */ uchar RcvByte(); /* 8951从24C01读数据字节数据接收函数 */ void Ack(bit a); /* 主机8951应答子函数 */ void xch(void); /*宣告按键存放/显示器阵列dispbuf[]右键滚入副程式*/ void wxb1(void); /*0~9计数,秒*/ void wxb2(void); /*0~9计数,分*/ void wxb3(void); /*0~9计数,时*/ void save_clocks(void); /*按显示时间更改时钟*/ void speekclose(void); void LCD_disple(void); /*液晶显示*/ /***********************************************************************/ main() /*主程式*/ { TMOD=0x11; /*TIMER0工作在案MODE1,16位定时器*/ /*TIMER1工作在MODE2,自动重新装载模式*/ /*方式寄存器TMOD___________________________*/ /*| 定时器1 | 定时器1 |*/ /*| GATE|C/T| M1 | M0 | GATE|C/T| M1 | M0 |*/ /*|___________________|___________________|*/ TH1=256-(28800/9600); /*设定传输波特率9600,晶体振荡器=11.059Mhz*/ /*|波特率9600时|SMOD=0|C/T=0|模式=2|自动载入TH1=FD|*/ /*|波特率4800时|SMOD=0|C/T=0|模式=2|自动载入TH1=FA|*/ /*|波特率2400时|SMOD=0|C/T=0|模式=2|自动载入TH1=F4|*/ /*|波特率1200时|SMOD=0|C/T=0|模式=2|自动载入TH1=E8|*/ TR1=1; /*启动TEMER0*/ // T2MOD=0x02; /*定时器2工作在输出模式*/ T2CON=0x38; /*定时器2工作控制寄存器T2CON_________________*/ /*| TF2|EXF2|RCLK|TCLK|EXEN2|TR2|C/T2|CP/RL2|*/ /*|___________________|_____________________|*/ TL2=0xfd; /*设定传输波特率9600,晶体振荡器=11.059Mhz*/ TH2=0xff; /*设定传输波特率9600,晶体振荡器=11.059Mhz*/ RCAP2L=0xdc; /*设定传输波特率9600,晶体振荡器=11.059Mhz*/ RCAP2H=0xff; /*设定传输波特率9600,晶体振荡器=11.059Mhz*/ TH2=256-(28800/9600); /*设定传输波特率9600,晶体振荡器=11.059Mhz*/ /*|波特率9600时|SMOD=0|C/T=0|模式=2|自动载入TH1=FD|*/ /*|波特率4800时|SMOD=0|C/T=0|模式=2|自动载入TH1=FA|*/ /*|波特率2400时|SMOD=0|C/T=0|模式=2|自动载入TH1=F4|*/ /*|波特率1200时|SMOD=0|C/T=0|模式=2|自动载入TH1=E8|*/ TR2=1; /*启动TEMER2*/ SCON=0x50; /*设定UART工作在MODE3模式,可传送和接收数据 REN=1*/ /*串列控制寄存器SCON_______________________*/ /*| 7 6 5 4 | 3 2 1 0 |*/ /*| SM0| SM1| SM2| REN| TB8| RB8| TI | RI |*/ /*|___________________|___________________|*/ IE=0x98; /*8是允许中断,a是TIMER0,TIMER1中断致能位*/ /*| 7 6 5 4 | 3 2 1 0 |*/ /*| EA | | ET2| ES | ET1| EX1| ET0| EX0|*/ /*|___________________|___________________|*/ IP=0x18; /*中断优先级寄存器IP_______________________*/ /*| | | PT2| PS | PT1| PX1| PT0| PX0|*/ /*|___________________|___________________|*/ read24c02(); /*呼叫读取密码存放在DATE1[]副程式*/ dispbuf[0]=0x03; /*小数点位*/ dispbuf[7]=0x01; /*ID号码*/ dispbuf[8]=0x01; /*蜂鸣器设定开/二次分频*/ Rd1302st(); /*读时钟芯片DS1302*/ LCD_disple(); /*液晶显示*/ P0=0xff; while(1) { scan(); /*呼叫键盘扫描副程式有按FLAG0会为1*/ if(FLAG0==1) { temp(); /*判断有按键输入否?*/ } else {FLAG4=FLAG5=0; if(FLAG2==1) { Rd1302(); /*读时钟芯片DS1302*/ if(dispbuf[1]!=clockbak) /*秒加一*/ { clockbak=dispbuf[1]; tsled(); /*串行发送到DTLED-6副程式*/ tserial(); /*宣告串口serial发送副程式*/ } } } } } //*********************************************************************/ //串行发送DTLED-6显示 //dispbuf0-dispbuf1-dispbuf2-dispbuf3-dispbuf4-dispbuf5-dispbuf6-dispbuf7-dispbuf8 // 小数点 - 数码管1- 数码管2- 数码管3- 数码管4- 数码管5- 数码管6-ID识别码-BZ识别码 //00000xxx-0000xxxx-0000xxxx-0000xxxx-0000xxxx-0000xxxx-0000xxxx-0000xxxx-0000xxxx //小数点=1~6,其它为不显示 //数码管1-6=0~15, //ID识别码=0~15 //BZ识别码=BZ.3为蜂鸣输出控制位,0=关闭,1=打开 // BZ0~2为蜂鸣频率输出设定为,000=不分频, 最高频率输出=4800Hz; // 001=一次分频,频率输出=4800/ 2 =2400Hz; // 010=二次分频,频率输出=4800/ 4 =1200Hz; // 011=三次分频,频率输出=4800/ 8 =600Hz; // 100=四次分频,频率输出=4800/ 16=300Hz; // 101=五次分频,频率输出=4800/ 32=150Hz; // 110=六次分频,频率输出=4800/ 64=75Hz; // 111=七次分频,频率输出=4800/128=38Hz; //====================================================================== void tsled(void) /*串行发送DTLED-6显示副程式*/ { char ts0,i,j; clk=0; en=0; delay(10); for(j=0;j<9;j++) { ts0=dispbuf[j]; for(i=0;i<4;i++) /*发小数点码8,4,2,1*/ { clk=1; ts0=ts0<<1; if(AC==1) dout=1; else dout=0; clk=0; nop; delay(3); } } en=1; } /*返回主程式*/ /***********************************************************************/ // 设定 字符型LCD模块, 使用DB0--DB7,显示两行, // 使用5*7字型 显示器要显示 光标要显示但不闪烁 */ //====================================================================== void LCD_disple() /*液晶显示*/ { delay(1000); Initial(); Enable(0x80); /* 从第1行第1列开始显示 */ Write1(char1); /* 显示第1行字符串 */ Enable(0xc0); /* 从第2行第1列开始显示 */ Write1(char2); /* 显示第2行字符串 */ Enable(0xc9); /* 从第2行第1列开始显示 */ Write3(); /* 显示第2行字符串 */ } //====================================================================== void Initial() /*LCD模块初始化*/ { Enable(0x01); /*清除显示*/ delay(300); /*清除需大于1.64ms*/ Enable(0x38); /*LCD功能设定,8位元数据传送,2行显示*/ Enable(0x0f); /*屏幕设定,游标ON,游标闪烁*/ Enable(0x06); /*加一状态,游标向右移*/ } //====================================================================== void Write1(char *c1) {while(*c1!=0) {Write2(*c1); c1++; } } //====================================================================== void Write3(void) {uchar i=6; while(i>0) { P0=bufdata|0x30; rs=1;rw=0; enable=1; delay(2); enable=0; i--; } } //====================================================================== void Write2(char c2) {P0=c2; rs=1;rw=0;enable=1; delay(2); enable=0; } //====================================================================== void Enable(uchar c) { P0=c; rs=0; rw=0; enable=1; delay(2); enable=0; }
/***********************************************************************/ void temp(void) { FLAG2=0; if(tab[ptr]==0x0e) {disp(); /*如果是按“C”则呼叫显示密码DISP*/ while(m==P1); /*按钮放开否?*/ dispbuf[0]=0x03; /*小数点位*/ } else /*否则往下执行*/ { switch(tab[ptr]) /*是则测试ptr键盘扫描计数器指标至TAB[]取到的键盘码*/ { case 0x0a: write24c02(); /*是否按“*”是则呼叫设定密码SET*/ clear(); /*是否按“#”是则呼叫清除显示器CLEAR*/ while(m==P1); /*按钮放开否?*/ break; /*跳出此循环*/ case 0x0b: clear(); /*是否按“#”是则呼叫清除显示器CLEAR*/ while(m==P1); /*按钮放开否?*/ break; /*跳出此循环*/ case 0x0c: /*是否按“A”,未规划键待用户自己定义*/ FLAG2=1; P3_2=1; dispbuf[0]=0x03; /*小数点位*/ break; /*跳出此循环*/ case 0x0d: /*是否按“B”,未规划键待用户自己定义*/ break; /*跳出此循环*/ case 0x0e: /*是否按“C”,已侦测过*/ read24c02(); /*呼叫读取密码存放在DATE1[]副程式*/ break; /*跳出此循环*/ case 0x0f: while(m==P1); /*按钮放开否?*/ open(); /*是否按“D”,是则呼比较密码开门副程式*/ dispbuf[0]=0x03; /*小数点位*/ goto openend; break; /*跳出此循环*/ default: xch(); /*以上均不是则为数字键呼叫XCH作右键滚入*/ break; /*跳出此循环*/ } /*跳出SWITCH*/ delay(100); /*按钮抗机械反弹跳*/ while(m==P1); /*按钮放开否?*/ tsled(); /*串行发送到DTLED-6副程式*/ openend: nop; } } /*返回上一层程式*/ /****************************************************/ void temp_setclock(void) /*判断有按键输入否?*/ { switch(dispbuf[0]) /*是则测试ptr键盘扫描计数器指标至TAB[]取到的键盘码*/ { case 0x01: wxb1(); /*0~9计数*/ break; /*跳出此循环*/ case 0x03: wxb1(); /*0~9计数*/ break; /*跳出此循环*/ case 0x05: wxb2(); /*0~2,0~4计数*/ break; /*跳出此循环*/ default: /*以上均不是*/ break; /*跳出此循环*/ } delay(100); /*按钮抗机械反弹跳*/ while(m==P1); /*按钮放开否?*/ tsled(); /*串行发送到DTLED-6副程式*/ } /*返回上一层程式*/ /****************************************************/ void wxb1(void) { switch(tab[ptr]) /*是则测试ptr键盘扫描计数器指标至TAB[]取到的键盘码*/ { case 0x02: dispbuf[dispbuf[0]]++; /*是按“上”,是则呼叫设定密码SET*/ if(dispbuf[dispbuf[0]]>9) {dispbuf[dispbuf[0]+1]++; dispbuf[dispbuf[0]]=0; } if(dispbuf[dispbuf[0]+1]==6) {dispbuf[dispbuf[0]+1]=dispbuf[dispbuf[0]]=0; } break; /*跳出此循环*/ case 0x08: if(dispbuf[dispbuf[0]]==0) /*是按“下”,是则呼叫清除显示器CLEAR*/ {if(dispbuf[dispbuf[0]+1]==0) dispbuf[dispbuf[0]+1]=6; dispbuf[dispbuf[0]]=10; dispbuf[dispbuf[0]+1]--; } dispbuf[dispbuf[0]]--; break; /*跳出此循环*/ case 0x04: /*是按“左”,未规划键待用户自己定义*/ dispbuf[0]=dispbuf[0]+2; /*小数点左移一位*/ if(dispbuf[0]>6) dispbuf[0]=1; break; /*跳出此循环*/ case 0x06: /*是按“右”,未规划键待用户自己定义*/ if(dispbuf[0]<3) dispbuf[0]=7; dispbuf[0]=dispbuf[0]-2; /*小数点右移一位*/ break; /*跳出此循环*/ case 0x0a: /*是按“*”,已侦测过*/ FLAG5=1; break; /*跳出此循环*/ case 0x0c: /*是否按“A”,未规划键待用户自己定义*/ FLAG4=FLAG5=P3_2=1; dispbuf[0]=0x03; /*小数点位*/ break; /*跳出此循环*/ default: /*以上均不是*/ break; /*跳出此循环*/ } } /*返回上一层程式*/ /****************************************************/ void wxb2(void) {switch(tab[ptr]) /*是则测试ptr键盘扫描计数器指标至TAB[]取到的键盘码*/ {case 0x02: dispbuf[dispbuf[0]]++; /*是按“上”,是则呼叫设定密码SET*/ if(dispbuf[dispbuf[0]+1]==2) {if(dispbuf[dispbuf[0]]>4) {dispbuf[dispbuf[0]+1]=dispbuf[dispbuf[0]]=0;} } else {if(dispbuf[dispbuf[0]]>9) {dispbuf[dispbuf[0]+1]++; dispbuf[dispbuf[0]]=0;} if(dispbuf[dispbuf[0]+1]>2) {dispbuf[dispbuf[0]+1]=dispbuf[dispbuf[0]]=0;} } break; /*跳出此循环*/ case 0x08: if(dispbuf[dispbuf[0]]==0) /*是按“下”,是则呼叫清除显示器CLEAR*/ {if(dispbuf[dispbuf[0]+1]==0) {dispbuf[dispbuf[0]+1]=2; dispbuf[dispbuf[0]]=5; } else {dispbuf[dispbuf[0]]=10; dispbuf[dispbuf[0]+1]--; } } dispbuf[dispbuf[0]]--; break; /*跳出此循环*/ case 0x04: /*是按“左”,未规划键待用户自己定义*/ dispbuf[0]=dispbuf[0]+2; /*小数点左移一位*/ if(dispbuf[0]>6) dispbuf[0]=1; break; /*跳出此循环*/ case 0x06: /*是按“右”,未规划键待用户自己定义*/ if(dispbuf[0]<3) dispbuf[0]=7; dispbuf[0]=dispbuf[0]-2; /*小数点右移一位*/ break; /*跳出此循环*/ case 0x0a: /*是按“*”,已侦测过*/ FLAG5=1; break; /*跳出此循环*/ case 0x0c: /*是否按“A”,未规划键待用户自己定义*/ FLAG4=FLAG5=P3_2=1; dispbuf[0]=0x03; /*小数点位*/ break; /*跳出此循环*/ default: /*以上均不是*/ break; /*跳出此循环*/ } } /*返回上一层程式*/ /****************************************************/ void save_clocks(void) /*按显示时间更改时钟*/ {clocktmp[0]=dispbuf[1]|(dispbuf[2]<<4); clocktmp[1]=dispbuf[3]|(dispbuf[4]<<4); clocktmp[2]=dispbuf[5]|(dispbuf[6]<<4); Wr1302(); FLAG2=1; nop; } /****************************************************/ void xch(void) /*显示向右移动副程式*/ {char c; /*宣告变数*/ for(c=6;c>0;c--) {dispbuf[c]=dispbuf[c-1];/*将显示器dispbuf[]移位交换,dispbuf[3]->dispbuf[4]->dispbuf[5]...*/ } dispbuf[0]=0; /*有安键时,小数点不亮*/ dispbuf[1]=tab[ptr]; /*新的按键值存入dispbuf[1],最低位*/ } /*返回上一层程式*/ /****************************************************/ void open(void) /*开门比较密码副程式*/ {char c; /*宣告变数*/ FLAG1=1; /*设开门标号为1*/ for(c=1;c<6;c++) /*比较六个密码*/ {if(dispbuf[c]!=bufdata[c]) /*显示值(按键值disbuf[])与密码TAB[]比较是否相等*/ FLAG1=0; if(FLAG1==0) /*FLAG1=0 表示不相等*/ break; /*跳出此循环*/ } if(FLAG1==1) /*如FLAG1=1 表示密码相等,令电锁P2.0置0动作*/ { /*密码正确*/ dispbuf[8]=0x09; /*蜂鸣器设定开/二次分频*/ dispbuf[0]=0x01; /*小数点到最高位位*/ P3_2=0; /*P3.2置0,使绿色下载指示灯亮(喇叭响)*/ // TMOD=0x11; TR1=1; /**/ TF1=0; IE=0x9f; /*8是允许中断,a是TIMER0,TIMER1中断致能位*/ tsled(); /*串行发送到DTLED-6副程式*/ while(FLAG5==0) /*等待设置死循环*/ { scan(); /*呼叫键盘扫描副程式有按FLAG0会为1*/ if(FLAG0==1) { temp_setclock(); /*判断有按键输入否?*/ } if(FLAG6==1) {tsled(); /*串行发送到DTLED-6副程式*/ FLAG6=0; } } if(FLAG4==0) save_clocks(); /*按显示时间更改时钟*/ } else P3_2=1; /*密码错,P3.2置1,关闭绿色下载指示灯灭(喇叭不响)*/ } /*返回上一层程式*/ /******************************************************/ void clear(void) /*清除显示器dispbuf[]为00副程式*/ {char c; /*宣告变数*/ for(c=1;c<7;c++) /*将00存入显示阵列dispbuf[]*/ {dispbuf[c]=0x00; } } /*返回上一层程式*/ /******************************************************/ void Wr1302(void) /*写时钟芯片DS1302*/ {char i,j,ts0,conb,conbyt; conb=0x80; ts0=conb; // for(j=0;j<3;j++) /*写秒,分,时三次循环*/ {clk=RST=0; /*DS1302系统初始化*/ nop;nop; RST=1; for(i=0;i<8;i++) /*写控制字到DS1302*/ {clk=0; /*清时钟*/ if(conb&0x01) DINOUT=1; else DINOUT=0; clk=1; /*时钟上升沿,发送数据有效*/ conb=conb>>1; nop; } clk=0; /*清时钟*/ conb=ts0+2+j*2; conbyt=clocktmp[j]&0x7f; for(i=0;i<8;i++) /*写设定值到DS1302*/ {clk=0; /*清时钟*/ if(conbyt&0x01) DINOUT=1; else DINOUT=0; &n |