历史上的今天
今天是:2024年10月25日(星期五)
2019年10月25日 | 基于AVR单片机的电子时钟
2019-10-25 来源:51hei
通过几天的AVR单片机学习,用AVR系列单片机中的ATMEGA16,LCD液晶屏LC1602,温度采集模块DS18B20,时钟模块DS1302,5V升压IC,和三个按键,以及一些电子元件完成了数字时钟系统的设计。在一块液晶显示屏上实现动态,时、分、秒、年、月、日、星期、温度数据的显示, 通过三个按键,S1调时键、S2时间加键、S3时间减键、实现时钟的年、月、日、星期、时、分、秒、的调整。本系统设计大部分功能由软件来实现,使电路简单明了。这次制作源代码,是从我已前的一个小制作基于51单片机的DS1302时钟上移植过来的所以制作没用多少时间。一开始用51单片机做这电子钟在调试时还是出了不少问题如,没考虑到51单片机P0口没有内至上拉电阻,结果在硬件上加了8个10K的电阻造成硬件焊接的复杂性。因为锂电池供电的只有3.6V左右而各种芯片要5V才正常工作,根据多年的数码产品维修经验用平板电板中的USB升压电路将3.6V升成了5V。因为没考虑这个自举升电路的频率很高1M到3M左右用了普通二极管做升压中的倍压管造成了电压升不到5V的问题最后改用了快恢复二极管才正常工作,本次制做中的按键调日期功能还没完善好,因每个月的天数都不一样最后决定为到32时把日期变为1。通过这次的制作让我全面的了解了单片机
相关产品的开发流程,及一些常用芯片驱动程序的编写。始我在单片机上的学习更上一层!
#include #include #include"delay.h" #define uchar unsigned char #define uint unsigned int #define S3_R PINA&BIT(0) #define S2_R PINA&BIT(3) #define S1_R PINA&BIT(6) #define RS_L PORTD&=~BIT(0) #define RS_H PORTD|=BIT(0) #define RS_OUT DDRD|=BIT(0) //宏定义单片机与其它芯片的连接方便IO口的操作 #define RW_L PORTD&=~BIT(1) #define RW_H PORTD|=BIT(1) #define RW_OUT DDRD|=BIT(1) #define EN_L PORTD&=~BIT(2) #define EN_H PORTD|=BIT(2) #define EN_OUT DDRD|=BIT(2) #define IO_L PORTB&=~BIT(5) #define IO_H PORTB|=BIT(5) #define IO_OUT DDRB|=BIT(5) #define IO_R PINB&BIT(5) #define IO_IN DDRB&=~BIT(5) #define SCK_L PORTB&=~BIT(6) #define SCK_H PORTB|=BIT(6) #define SCK_OUT DDRB|=BIT(6) #define RST_L PORTB&=~BIT(7) #define RST_H PORTB|=BIT(7) //宏定义单片机与其它芯片的连接方便IO口的操作 #define RST_OUT DDRB|=BIT(7) #define DQ_L PORTD&=~BIT(7) #define DQ_H PORTD|=BIT(7) #define DQ_OUT DDRD|=BIT(7) #define DQ_R PIND&BIT(7) #define DQ_IN DDRD&=~BIT(7) uchar tab4[]={0x82,0x85,0x88,0x8f,0xc0,0xc3,0xc6};//用来存放年月日星期时分秒的地址 uchar write_add[7]={0x8c,0x88,0x86,0x8a,0x84,0x82,0x80}; //写寄存器地址 uchar read_add[7]={0x8d,0x89,0x87,0x8b,0x85,0x83,0x81};//存放从1302中读数寄存器地址 uchar tab1[]="20 - - week "; //屏上要固定显示的字符 uchar tab2[]=" : : ";//屏上要固定显示的字符 uchar tab3[]; uchar tab[]={12,2,4,5,5,5,5};//年 月 日 周 时 分 秒的初值 char tung;//根据tung确定按键位置不能定成uchar型 void write_1602com(uchar com);//1602写地址函数 void init_1602(void);//1602初始化 void write_1302bvte(uchar);//1302写数据函数 uchar read_1302(uchar);//1302读数据函数 void write_1302(uchar,uchar);//1302指定地址定数据函数 void write_ds1302_1();//时间显示函数 void read_1302_1();//一次读出年月日 时分秒 void flx(uchar j); //时间转显示函数 void key(void); //按键函数 void set_rtc(void); //一次设置初始时间年月日函数 void init_18b20(void);//18b20初始化函数 void write_18b20(uchar value);//ds18b20写数据函数 uchar read_18b20(void);//读温度函数 uchar readtemperature(void);//一次性读出温度 void xianshi(void);//温度显示函数 void init_18b20(void) { DQ_OUT; DQ_L; delay_100us(5); DQ_H; //初始化18B20 delay_100us(5); } void write_18b20(uchar value) { uchar i; for(i=0;i<8;i++) { DQ_OUT; DQ_L; //写一位函数 delay_10us(); if(value&0x01)// { DQ_H; } } delay_100us(1); DQ_H; value=value>>1; } uchar read_18b20(void) { uchar i,value; for(i=0;i<8;i++) { value=value>>1; DQ_OUT; DQ_L; delay_10us();//读一位函数 DQ_H; DQ_IN; if(DQ_R) { value|=0x80; } delay_50us(); } return value; } uchar readtemperature(void)//一次性读出温度 { uint i,j;//一定要用int型j大于256 init_18b20; write_18b20(0xcc);//跳过ROM write_18b20(0x44);//启动温度测量 delay_100us(20); init_18b20(); write_18b20(0xcc); write_18b20(0xbe);//读取温度 i=read_18b20();//低位 j=read_18b20();//高位 i=i>>4; //因不用小数部分所以移4位 j=j*16+i; //将存放低8位的和高8位合到一块 return j ; } void xianshi(void) { uint temp,k,f; temp=readtemperature();//将温度保存到temp中 f=temp/10; //分离出十位跟个位 k=temp%10; write_1602com(0x80+0x40+10);//温度显示的位置 write_1602dat(f+0x30); write_1602dat(k+0x30); //将温度写到1602中 } void set_rtc(void) //一次设置初始时间年月日函数 { uchar i,j; for(i=0;i<7;i++) { j=tab[i]/10; //将设置的年月日时分解出十位放入J中 tab3[i]=tab[i]%10; //将设置的年月日时间分解出个位再放入time_data[]数组中 tab3[i]=tab3[i]+j*16;//将十进制的个位和十位转换为BCD码 } write_1302(0x8e,0x00);//去除写保护 for(i=0;i<7;i++) { write_1302(write_add[i],tab3[i]); //写要设置初始时间日期的操作寄存器的地址 } write_1302(0x8e,0x80);//加写保护 } void key(void) { uchar s1,s2,s3; if(~S1_R) //如果S1按下 { delay_1ms(3); //延时去抖 if(~S1_R) { while(~S1_R); // tung=0; //tung用来确定光标的位置 while(tung<=6) //循环7次 时分秒年月日星期 { if(~S2_R) { delay_1ms(3); if(~S2_R)//去抖动延时 { while(~S2_R); // 检测按键是否放开 tab[tung]++; //如果+键按下加1 } } if(~S3_R) { delay_1ms(3); // 检测按键是否放开 if(~S3_R) { while(~S3_R); //按键是否松手 tab[tung]--; //如果—键按下减1 } } switch(tung) { //通过tung的值确定光标的位置 case 0: if(tab[tung]<3) //如果tung=0;则表示正在调年让年在2004到2098这个范围内 tab[tung]=98; if(tab[tung]>98) tab[tung]=4; break; case 1: if(tab[tung]<1) tab[tung]=12; if(tab[tung]>12) //如果tung=1;则表示正在调月让月在1到12这个范围内 tab[tung]=1; break; case 2: if(tab[tung]==0) tab[tung]=31; if(tab[tung]==32) //如果tung=2;则表示正在调日让在1到31这个范围内 tab[tung]=1; break; case 3: if(tab[tung]<1) tab[tung]=7; if(tab[tung]>7) //如果tung =3则表示下在调星期让在1到7这个范围内 tab[tung]=1; break; case 4: if(tab[tung]<0) tab[tung]=23; if(tab[tung]>23) //如果tung=4则表示在调时让时在1到23这个范围内 tab[tung]=0; break; case 5: if(tab[tung]<0) tab[tung]=59; if(tab[tung]>59) //如果tung=5;则表示正在调分让分在1到59这个范围内 tab[tung]=0; break; default: if(tab[tung]<0) tab[tung]=59; if(tab[tung]>59) //如果tung=6;则表示正在调秒让秒在1到59这个范围内 tab[tung]=0; break; } write_1602com(tab4[tung]); //显示正在调的位置 flx(tab[tung]); //将数据分离成1602的显示码并送到1602显示屏 if(~S1_R) { while(~S1_R); //判断是否调好了时间如果好了则跳出key tung++; //每按一下S1调式模式键则加一次如果到了7次跳出KEY函数 } } } write_1602com(0x0c);//调完了时间关闭光标 set_rtc(); //把调好的时间数据送到DS1302芯片中 } } void flx(uchar j) { uchar k,a; write_1602com(0x0f); //开光标显示指令 k=j/10; //分离十位跟个位 a=j%10; if(tung!=3) //年月日时分秒分离 { write_1602dat(k+0x30); //将分离的十位跟个位换成LC1602能显示的码 write_1602com(0x0c);//关光标指令 write_1602dat(a+0x30); } else write_1602dat(a+0x30); //星期分离 } void read_1302_1(void)//一次读出年月日 时分秒函数 { uchar i,shi,ge,tun; for(i=0;i<7;i++) { tun=read_1302(read_add[i]); //一次将年月日从DS1302中读出送到数组中 ge=tun%16; shi=tun/16; //将BCD码分成十位和个位 tab[i]=shi*10+ge; //再换成十进制存到数组tab中 } } void write_ds1302_1() { read_1302_1();//一次读出年月日 时分秒函数 write_1602com(0x80+0x40+6);//秒的位置 write_1602dat(tab[6]/10+0x30); write_1602dat(tab[6]%10+0x30); write_1602com(0x80+0x40+3);// write_1602dat(tab[5]/10+0x30); //分的位置 write_1602dat(tab[5]%10+0x30); //将十进制的数据换成1602的显示码送到显示屏 write_1602com(0x80+0x40+0);// //时的地址 write_1602dat(tab[4]/10+0x30); //显示屏的第二排要加0x80+40 write_1602dat(tab[4]%10+0x30); write_1602com(0x80+2);// write_1602dat(tab[0]/10+0x30);//年的地址 write_1602dat(tab[0]%10+0x30); write_1602com(0x80+5);// 显示屏 的第一排地址要加0x80; write_1602dat(tab[1]/10+0x30); write_1602dat(tab[1]%10+0x30); //月的地址 write_1602com(0x80+8);// 日的地址 write_1602dat(tab[2]/10+0x30); write_1602dat(tab[2]%10+0x30); write_1602com(0x80+15); //星期的地址 write_1602dat(tab[3]%10+0x30); } void init_1302(void) { SCK_OUT; RST_OUT;//1302IO口初始化 } void write_1302(uchar dat ,uchar add) { RST_L; SCK_L; RST_H; write_1302bvte(dat);//指定地址写数据函数 write_1302bvte(add); RST_L; SCK_H; } void write_1302bvte(uchar add) { uchar i; RST_L; SCK_L; IO_OUT; delay_1ms(2); RST_H; for(i=0;i<8;i++) { if(add&0X01) { IO_H; //1302写函数 } else { IO_L; } SCK_H; SCK_L; add=add>>1; } } uchar read_1302(uchar dat) { uchar i,byte; write_1302bvte(dat); IO_IN; for(i=0;i<8;i++) { byte=byte>>1; if(IO_R) { //1302读数据函数 byte=byte|0x80; } SCK_H; SCK_L; } RST_L; return byte; } void write_1602com(uchar com) { RS_L; RW_L; //写指令函数 PORTC=com; EN_H; delay_1ms(4); EN_L; } void write_1602dat(uchar dat) { RS_H; RW_L; PORTC=dat; EN_H; //写数据函数 delay_1ms(4); EN_L; } void init_1602(void) { uchar tou; DDRC=0XFF; PORTC=0; RS_OUT; RW_OUT; EN_OUT; EN_L; write_1602com(0x38);// write_1602com(0x0C);// //1602初始化函数 write_1602com(0x06); write_1602com(0x01); write_1602com(0x80); write_1602com(0x80); //第一行显示的位置地址 for(tou=0;tou<16;tou++) { write_1602dat(tab1[tou]); //显示固定字符 } write_1602com(0x80+0x40); //第二行显示的位置地址 for(tou=0;tou<8;tou++) { write_1602dat(tab2[tou]); } write_1602com(0x80+0x40+12); write_1602dat(0xdf);//显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码 write_1602dat(0x43); //显示"C"符号,0x43是液晶屏字符库里大写C的地址码 */ } void main(void)
上一篇:自制AVR控制1W变频器
史海拾趣
|
随着汽车保有量的增加,汽车工业的发展越来越受到安全、环 保及节能要求的限制。安全、环保、节能体现了汽车科技创新的方向, 也是汽车工业竞争的焦点,汽车电子技术的发展将促进这三大难题的 解决。目前,全球各国对汽车研究的重点放在了如何提高 ...… 查看全部问答> |
|
一个地方下了一个WMV 解码的Dll. 另外一个地方下了一个TCPMP0.72, 它直接能用这个解码Dll播放WMV文件。(没有这个解码Dll,就不能播放WMV文件) TCPMP是按什么规则调解码Dll的(或解码插件)? … 查看全部问答> |
|
我把vxworks移植到了VMWARE的虚拟机上,编程时有两个问题想了解一下 1.我编译的VXWORKS内核是包含了target shell组件和一个host与target符号表同步的组件的,在TORNADO编好程序后download到虚拟机中,为什么在tornado的命令行下能运行程序中的函数 ...… 查看全部问答> |
|
帖子更新历史:11.2 7:05暂停更新,附件删除。最近感到精力不济,再说还有一些个别有待进一步提高的地方。还是等全部完成以后源码和一些文档一并公布。10.28 11:25 附件中添加新下载的官方demo压缩包和一个烧写HEX的软件(我还没有试验可不 ...… 查看全部问答> |
|
我想用手机蓝牙来控制灯牌的亮度,需要掌握什么知识?1,如何编写一个手机软件,来实现控制?2,在灯的硬件方面,用什么元件来接受蓝牙信号,蓝牙适配器? 求指教!!! … 查看全部问答> |
|
F2802X怎么在CCS看到的FLASH数据和HEX文件看到的数据不一样啊。 我用CODESKIN下载了hex文件,但是通过CCS看FLASH数据,却发现它们并不一致。确实有相同的数据,但是他们的地址不一样。这是怎么回事啊?… 查看全部问答> |




