完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
ds1302+lcd1602的电子时钟程序附带闹钟功能,本人亲调了两天仍无法找出bug,求大神指导.
以下是程序: #include #include #define MSB 0x80 //读忙位 #define HIGH 1 #define LOW 0 //***************************************** #define DATA_MODE 0x38 //LCD模式设置,0x28位四位数据线模式 #define OPEN_SCREEN 0x0C //打开LCD显示 #define DISPLAY_ADDRESS 0x80 //写地址指令 #define CLEARSCREEN LCD_en_com(0x01) //清屏 //***********//LCD1602的接线//***************************** #define LCDIO P0 //LCD1602的高四位接在P0口的高四位 ***it LCD1602_RS=P2^6; //RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。 ***it LCD1602_RW=P2^5; //RW为读写信号线,高电平时进行读操作,低电平时进行写操作。 ***it LCD1602_EN=P2^7; //E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 //*********************************************************// ***it alarm_speaker=P1^5; //蜂鸣器的接线 //***it DS18B20=P3^7; //自已定义的ds18b20口 ***it SCLK=P3^6; //ds1302的接线 ***it IO=P3^4; ***it RST=P3^5; ***it ACC7=ACC^7; //累加器 ***it ACC0=ACC^0; //unsigned char L_18B20,H_18B20; //分别存放低八位高八位的数据; //unsigned char fg=0,zhengshu,xiaoshu1,xiaoshu2; //fg为负数标志位,zhengshu是温度的整数部分,xiaoshu1是十分位,xiaoshu2是百分位 unsigned char times[7]={55,39,16,7,11,3,7}; //存放时间 unsigned char key=16; //存放健值 unsigned char alarm_clock[3]={0}; //用于存放闹钟的时间:时分和闹钟的标志位 //void Reset_18B20(void); //ds18b20复位程序 //void Wait_18B20(); //等待程序,等待ds18b20应答 //bit Readbit_18B20(void); //读取一个bit的数据 //unsigned char Readbyte_18B20(void); //读取一个字节的数据 //void Writebyte_18B20(unsigned char b); //写一个字节(控制字) //void Convert(void); //开始转换 //void Read_18B20(void); //读取ds18b20 void write_1302_byte(unsigned char d); //向1302写入一字节数据d unsigned char read_1302_byte(void); //从1302读出一字节数据并返回 void write_1302_reg(unsigned char add,unsigned char d); //向1302地址add处写入数据d unsigned char read_1302_reg(unsigned char add); //从1302地址add处读出数据并返回 void on_off_1302(unsigned char ch); //启动/停止计时,gate=0时启动计时,gate!=0时停止计时 void hour_mode_1302(unsigned char ch); //时间显示方式设置,ch=0时为24小时格式,ch!=0时为12小时格式 void write_1302_time(unsigned char *time); //设置时间 void read_1302_time(unsigned char time[]); //读出时间 //********************************************************************** void LCD_en_com(unsigned char command); //写命令指令 void LCD_en_dat(unsigned char temp); //写数据指令 void LCD_set_xy(unsigned char x, unsigned char y); //设置显示地址:X为横轴(0-15),Y为纵轴(0-1). void LCD_write_char(unsigned x,unsigned char y,unsigned char dat); //写一个字符 void LCD_write_string(unsigned char x,unsigned char y,unsigned char *s);//写一个字符串 void LCD_write_int(unsigned char x,unsigned char y,unsigned int intdat); //写无字符型整形数 void LCD_init(void); //lcd初始化 void LCD_Read_BF(void); //LCD读忙信号 //********************************************************************** /* LCD1602.c */ void LCD_Read_BF(void) { LCD1602_RW=1; //RW 1 LCD1602_RS=0; //RS 0 LCD1602_EN=1; //EN 1 读忙信号 LCDIO=LCDIO&0x0F|0xf0; while(LCDIO&MSB); LCD1602_EN=LOW; } void LCD_en_write(void) //EN端产生一个高电平脉冲,写LCD { LCD1602_EN=HIGH; _nop_(); LCD1602_EN=LOW; } //************************************* void LCD_en_com(unsigned char command) { LCD_Read_BF(); LCD1602_RS=LOW; //RS 0 写命令 LCD1602_RW=LOW; //RW 0 //LCDIO&=0x0F; LCDIO=command;//&0xf0 | LCDIO&0x0f; //先发送高四位数据 LCD_en_write(); //command=command<<4; //LCDIO&=0x0F; //LCDIO=command&0xf0 | LCDIO&0x0f; //发送低四位数据 //LCD_en_write(); } //********************************* void LCD_en_dat(unsigned char dat) { LCD_Read_BF(); LCD1602_RS=HIGH; //RS 1 写数据 LCD1602_RW=LOW; //RW 0 //LCDIO &=0x0F; LCDIO=dat;//&0xf0 | LCDIO&0x0f; //先发送高四位数据 LCD_en_write(); //dat=dat<<4; //LCDIO &=0x0F; //LCDIO=dat&0xf0 | LCDIO&0x0f; //发送低四位数据 //LCD_en_write(); } //**************设置显示地址:X为横轴(0-15),Y为纵轴(0-1)******************** void LCD_set_xy(unsigned char x,unsigned char y) { unsigned char address; x&=0x0f; if(!y) address=0x80+x; else address=(0x80+0x40)+x; LCD_en_com(address); } //***************写一个字符:X为横轴(0-15),Y为纵轴(0-1)********** void LCD_write_char(unsigned x,unsigned char y,unsigned char dat) { LCD_set_xy(x,y); LCD_en_dat(dat); } //****************写一个字符串*************************************** void LCD_write_string(unsigned char x,unsigned char y,const unsigned char *s) { LCD_set_xy(x,y); while(*s) //字符串以'0'结束 { LCD_en_dat(*s); s++; } } //****************写一个无字符整数*************************************** void LCD_write_int(unsigned char x,unsigned char y,unsigned int intdat) { unsigned char i=0,temp[5]; LCD_set_xy(x,y); if(intdat==0) { LCD_en_dat(0x30); //? return; } while(intdat/10 || intdat%10) { temp[i]=intdat%10; intdat/=10; i++; } while(i) { i--; LCD_en_dat(temp[i]+0x30); } } //*****//LCD的初始化函数(刚上电的时候一定要调用一次)//********************* void LCD_init(void) { LCD_en_com(DATA_MODE); //设计四位数据线模式 LCD_en_com(OPEN_SCREEN); //打开LCD显示 LCD_en_com(DISPLAY_ADDRESS);//设计首地址 CLEARSCREEN; //清屏 } /*void Reset_18B20(void)//ds18b20复位程序 { unsigned char i; DS18B20=0; i=110; while(i>0)i--; DS18B20=1; i=6; while(i>0)i--; } void Wait_18B20()//等待程序,等待ds18b20应答 { unsigned char i; while(DS18B20); while(~DS18B20); i=6; while(i>0)i--; } bit Readbit_18B20(void) //读取一个bit的数据 { unsigned char i; bit b; DS18B20=0; i++;i++; DS18B20=1; i++;i++;i++;i++;i++; b=DS18B20; i=13; while(i>0)i--; return b; } unsigned char Readbyte_18B20(void) //读取一个字节的数据 { unsigned char i,j,b; b=0; for(i=1;i<=8;i++) { j=Readbit_18B20(); b=(j<<7)|(b>>1); //又玩野 } return b; } void Writebyte_18B20(unsigned char b)//写一个字节(控制字) { unsigned char j,i; bit temp; for(j=1;j<=8;j++) { temp=b&0x01; b=b>>1; if(temp) // 写"1" { DS18B20=0; i++;i++;i++;i++;i++; DS18B20=1; i=13; while(i>0)i--; } else //写"0" { DS18B20=0; i=13; while(i>0)i--; DS18B20=1; i++;i++;i++;i++;i++; } } } void Convert(void) //开始转换 { Reset_18B20(); Wait_18B20(); //等待应答脉冲 Writebyte_18B20(0xcc); //跳过序列号脉冲 Writebyte_18B20(0x44); //转换命令 } void Read_18B20(void) //读取ds18b20 { Convert(); Reset_18B20(); Wait_18B20(); Writebyte_18B20(0xcc); //跳过ROM Writebyte_18B20(0xbe); //发送读取命令 L_18B20=Readbyte_18B20(); //读取低八位数据 H_18B20=Readbyte_18B20(); //读取高八位数据 if(H_18B20>0x7f) //最高位为1时温度是负 { L_18B20=~L_18B20; //补码转换,取反加一 H_18B20=~H_18B20+1; fg=1; //读取温度为负时fg=1 } zhengshu=L_18B20/16+H_18B20*16; //整数部分 xiaoshu1=(L_18B20&0x0f)*10/16; //小数第一位 xiaoshu2=(L_18B20&0x0f)*100/16%10;//小数第二位 } /*================================================================*/ /* 向1302当前地址处写入1字节数据 */ /*================================================================*/ void write_1302_byte(unsigned char d) { unsigned char i; ACC=d; //将8位数据写入ACC for(i=8;i>0;i--) //循环8次将ACC8位数据从低位到高位写入1302 { IO=ACC0; //将ACC的最低位转送到IO口 SCLK=1; //上升沿写入1位数据 SCLK=0; ACC=ACC>>1; //将ACC次低位变为最低位 } } /*=================================================================*/ /*=================================================================*/ /* 从1302的当前地址处读出1字节数据 */ /*=================================================================*/ unsigned char read_1302_byte(void) { unsigned char i; for(i=8;i>0;i--) { ACC=ACC>>1; ACC7=IO; SCLK=1; //时钟下降沿读1位数据 SCLK=0; } return (ACC); } /*=================================================================*/ /* 将数据Data写入1302寄存器add处 */ /*================================================================*/ void write_1302_reg(unsigned char add,unsigned char d) { RST= 0; SCLK=0; //只有sclk为低电平是RST才能被置为高电平 RST= 1; //只有RST为高电平是才允许数据传输 write_1302_byte(add); //将1302的指针移到add处 write_1302_byte(d); //往add处写入数据 SCLK=1; RST=0; //停止写数据 } /*=================================================================*/ /* 读寄存器add处的值 */ /*==================================================================*/ unsigned char read_1302_reg(unsigned char add) { unsigned char d; RST=0; SCLK=0; RST=1; write_1302_byte(add); d=read_1302_byte(); SCLK=1; RST=0; return (d); } /*=================================================================*/ /* 设置时间,time[0]-time[6]数据存放顺序为:秒,分,时,日,月,星期,年 */ /*===================================================================*/ void write_1302_time(unsigned char *time) { unsigned char add=0x80; //地址add初值(秒),偶数地址为只写 unsigned char i; unsigned char timeBCD[7]; //用以存放time数据的BCD码值 bdata unsigned char l,h; //单位变量,分别存放时间数据(8421BCD码)的低4位和高4位 for(i=0;i<7;i++) //将时间数据转为BCD码放入timeBCD中 { l=time[i]%10; h=time[i]/10; timeBCD[i]=h*16+l; } write_1302_reg(0x8e,0x00); //禁止写 //? for(i=0;i<7;i++) { write_1302_reg(add,timeBCD[i]); //将时间数据写入1302对应的寄存器 add+=2; //地址移动,确保地址为偶数 } write_1302_reg(0x8e,0x80); //允许写 } /*================================================================= =*/ /* 读取当前时间 */ /*======================= ===========================================*/ void read_1302_time(unsigned char time[]) { unsigned char i; unsigned char add=0x81; //设置地址add初值(秒),奇数为只读 bdata unsigned char l,h; //单位变量,分别存放时间数据(8421BCD码)的低4位和高4位,用以进行十进制转换 write_1302_reg(0x8e,0x00); //禁止写 for(i=0;i<7;i++) { time[i]=read_1302_reg(add); //将时间数据(8421BCD码)从1302对应的寄存器中读出 l=time[i]&0x0f; //l存放time的低4位,即个位 h=(time[i]>>4)&0x0f; //h存放time的高4位,即十位 time[i]=h*10+l; //时间数据以十进制形式放进time[i]中 add+=2; //地址移动,确保地址为奇数 } } /*======================================================================================*/ /*=====================================================================================*/ /* 启动/停止计时,gate=0时启动计时,gate!=0时停止计时 */ /*=====================================================================================*/ void on_off_1302(unsigned char ch) { unsigned char temp; if(ch) { temp=read_1302_reg(0x80); //将秒当前值读入temp暂存 temp=temp|0x80; //将秒数据最高位置1 ,允许写入?? write_1302_reg(0x80,temp); //将置1后的秒数据写入秒寄存器,以定止计时 } else { temp=read_1302_reg(0x80); //将秒当前值读入temp暂存 temp=temp&0x80; //将秒数据最高位置0 禁止写入?? write_1302_reg(0x80,temp); //将最高位置0后的秒数据写入秒寄存器,以启动计时 } } /*=====================================================================================*/ /*=========================================================================================*/ /* 时间显示方式设置,ch=0时为24小时格式,ch!=0时为12小时格式 */ /*=========================================================================================*/ void hour_mode_1302(unsigned char ch) { unsigned char temp; if(ch) { temp=read_1302_reg(0x85); //将小时当前值读入temp暂存 temp=temp|0x80; //将小时数据最高位置1 write_1302_reg(0x84,temp); //将置1后的小时数据写入小时寄存器,变为12小时格式 } else { temp=read_1302_reg(0x85); //将小时当前值读入temp暂存 temp=temp&0x80; //将小时数据最高位置0 write_1302_reg(0x84,temp); //将最高位置0后的小时数据写入小时寄存器,变为24小时格式 } } /*=========================================================================================*/ void delay(unsigned char i) //延时函数 { unsigned char j; while(i--) for(j=101;j>1;j--); } void key_scan() { unsigned char X,Y,Z,k=key; P1=0x0f; P1=0x0f; //先对P1置数行扫描 if(P1!=0x0f) //判断是否有键按下 { delay(5); //延时,软件去干扰 if(P1!=0x0f) //确认按键按下X = P1; { X=P1; //保存行扫描时有键按下时状态 P1=0xf0; //列扫描 delay(5); Y=P1; //保存列扫描时有键按下时状态 Z=X|Y; //取出键值 switch ( Z ) //判断键值(那一个键按下) {case 0xe7: k=13;break; //对键值赋值 case 0xd7: k=9;break; case 0xb7: k=5;break; case 0x77: k=1;break; case 0xeb: k=14;break; case 0xdb: k=10;break; case 0xbb: k=6;break; case 0x7b: k=2;break; case 0xed: k=15;break; case 0xdd: k=11;break; case 0xbd: k=7;break; case 0x7d: k=3;break; case 0xee: k=16;break; case 0xde: k=12;break; case 0xbe: k=8;break; case 0x7e: k=4;break; } key=k-1; } } P1=0xff; } void display_dat() //显示时间和温度的函数 { CLEARSCREEN; LCD_write_string(0,0,"DAT:"); LCD_write_int(4,0,2000+times[6]); //显示年份 LCD_en_dat('-'); LCD_write_int(9,0,times[4]/10); //显示月份 LCD_write_int(10,0,times[4]%10); LCD_en_dat('-'); LCD_write_int(12,0,times[3]/10); //显示日期 LCD_write_int(13,0,times[3]%10); LCD_write_int(15,0,times[5]); //显示星期 LCD_write_int(0,1,times[2]/10); //显示小时 LCD_write_int(1,1,times[2]%10); LCD_en_dat(':'); LCD_write_int(3,1,times[1]/10); //显示分钟 LCD_write_int(4,1,times[1]%10); LCD_en_dat(':'); LCD_write_int(6,1,times[0]/10); //显示秒 LCD_write_int(7,1,times[0]%10); //LCD_write_int(10,1,zhengshu); //显示温度的整数部分 //LCD_en_dat('.'); //LCD_en_dat(xiaoshu1+0x30); //显示温度的小数部分 //LCD_en_dat(0x27); //显示'号 //LCD_en_dat('C'); //显示C } void chang_time(unsigned char i) { unsigned char tem=0,temp_time=0,clock=0,temp_clock; CLEARSCREEN; if(i<=7) { if(i==0) LCD_write_string(0,0,"Change second:"); //修改秒 if(i==1) LCD_write_string(0,0,"Change minute:"); //修改分 if(i==2) LCD_write_string(0,0,"Change hour:"); //修改时 if(i==3) LCD_write_string(0,0,"Change day:"); //修改日 if(i==4) LCD_write_string(0,0,"Change month:"); //修改月 if(i==5) LCD_write_string(0,0,"Change week:"); //修改星期 if(i==6) LCD_write_string(0,0,"Change year:"); //修改年 if(i==7 && alarm_clock[2]==0) LCD_write_string(0,0,"Open AlarmClock");//修改闹钟 if(i==7 && alarm_clock[2]!=0) LCD_write_string(0,0,"AlarmClock:"); key=16; delay(250); while(1) { key_scan(); if(key<10) { tem=(tem*10)+key; if((i==0 || i==1 || clock==1) && tem>59) tem=59;//确保修改的数据不超出限制, if((i==2 || (clock==0 && i==7)) && tem>23) tem=23; //比如分不能超过60,月不能超过12等。 if(i==3 && tem>31) tem=31; //如超过限制,则定为最大 if(i==4 && tem>12) tem=12; if(i==5 && tem>7) {if(key<=7 && key!=0)tem=key; else tem=7; } delay(200); key=16; } if(key==14) { tem/=10; key=16; delay(200); } if(key==15 && i!=7)break; //确定闹钟之外的数据 if(key==15 && i==7) { if(clock==0) { temp_clock=tem; //确定闹钟的时 key=16; tem=0; clock=1; delay(200); } else //确定闹钟的分 { alarm_clock[0]=temp_clock; alarm_clock[1]=tem; alarm_clock[2]=1; return; } } if(key==12)return; if(key==13) { alarm_clock[2]=0; //取消闹钟功能 CLEARSCREEN; LCD_write_string(0,0,"Close AlarmClock"); delay(250); delay(250); delay(250); delay(250); delay(250); delay(250); return; } if(temp_time!=tem) { LCD_write_char(8,1,' '); //实时显示修改的数据 if(i==6) { LCD_write_int(9,1,20); LCD_en_dat(tem/10+0x30); LCD_en_dat(tem%10+0x30); } else if(clock==0) { LCD_write_int(7,1,tem); if(i==7) { LCD_en_dat(':'); //实时显示修改闹钟的数据 LCD_en_dat(0x30); LCD_en_dat(0x30); } } else { LCD_write_int(7,1,temp_clock/10); LCD_write_int(8,1,temp_clock%10); LCD_en_dat(':'); LCD_write_int(10,1,tem/10); LCD_write_int(11,1,tem%10); } temp_time=tem; } delay(100); read_1302_time(times); LCD_write_string(0,1,"Now: "); if(i<6)LCD_write_int(4,1,times[i]); //实时显示当前的数据 else if(i==6)LCD_write_int(4,1,times[i]+2000); else if(i==7) { LCD_write_int(0,1,alarm_clock[0]/10); //显示当前闹钟的时间 LCD_write_int(1,1,alarm_clock[0]%10); LCD_en_dat(':'); LCD_write_int(3,1,alarm_clock[1]/10); LCD_write_int(4,1,alarm_clock[1]%10); } } read_1302_time(times); times[i]=tem; write_1302_time(times); //把数据写进1302 } } void main() //主函数 { unsigned char temp=0; LCD_init(); write_1302_time(times); //把数据写进1302 while(1) { read_1302_time(times); //读ds1302的时间 key_scan(); //扫描键盘 if(key<8) //如果键盘值小于8则进入修改界面 { chang_time(key); key=16; } if(times[1]==alarm_clock[1] && times[2]==alarm_clock[0] && alarm_clock[2]==1)//如时间到,闹钟响 { if(key==16)alarm_speaker=0; } delay(30); alarm_speaker=1; delay(170); display_dat();//显示时间和温度 //Read_18B20(); } } |
|
相关推荐
5个回答
|
|
|
|
|
|
程序太长,只随便扫了一眼
void on_off_1302(unsigned char ch)中的 temp=read_1302_reg(0x80); //将秒当前值读入temp暂存 还有几个其他地方的read_1302_reg(0x80); 地址最后一位是读写,写的话是0x80,读就是读0x81了。 调试的话建议写一段调试一下吧,不行的话就先下别人的程序,运行没问题比对一下看看哪里出问题。 我也遇到一个问题,比对后是一个简短的delay函数有问题。然后想不通那样写有什么问题,那样才让人困扰; 评分
|
||
|
||
|
|
|
|
olive2003 发表于 2014-6-23 22:37 看来我还是缺少经验,谢谢解答 |
|
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-TF卡烧录流程之烧写过程
495 浏览 0 评论
740 浏览 0 评论
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程之烧写原理
859 浏览 0 评论
请问SPH0641LU4H这款麦克风如何在不使用I2S的情况下,单纯通过GPIO来进行驱动且正常读取数据呢
680 浏览 1 评论
466 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
12093 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-1 12:24 , Processed in 0.469219 second(s), Total 51, Slave 44 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号