历史上的今天
返回首页

历史上的今天

今天是: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)

推荐阅读

史海拾趣

DBS Microwave Inc公司的发展小趣事

作为一家有社会责任感的企业,DBS Microwave始终关注环境保护和可持续发展。公司积极采用环保材料和生产工艺,减少生产过程中的污染排放。同时,公司还积极参与社会公益活动,为当地社区的发展做出了积极贡献。这些举措不仅提升了公司的社会形象,也为公司的长期发展奠定了坚实的基础。

Hirose Electric公司的发展小趣事

DBS Microwave Inc公司起源于XXXX年,当时由几位志同道合的电子工程师创立。他们共同意识到,随着无线通信技术的飞速发展,微波器件的市场需求将会急剧增长。于是,他们凭借丰富的专业知识和对市场趋势的敏锐洞察,决定专注于研发和生产高质量的微波射频器件。起初,公司面临着资金紧张、市场竞争激烈等诸多挑战,但创始人团队凭借坚韧不拔的精神和对技术的执着追求,逐步在市场上崭露头角。

General Cable公司的发展小趣事
在红外遥控应用中,需要将YN5103的输出引脚连接到红外发射管驱动电路,以便将编码后的信号以红外光的形式发射出去。
AVAGO公司的发展小趣事

AVAGO公司(现更名为Broadcom)的创业故事始于上世纪八十年代。当时,几位工程师看到半导体行业的巨大潜力,决定创立一家公司来专注于高性能模拟半导体的研发。初始阶段,公司面临着资金短缺、市场竞争激烈等挑战,但凭借团队的技术实力和对市场的敏锐洞察,他们成功开发出了几款性能卓越的半导体产品,并逐渐在市场上获得了认可。

ADI(亚德诺半导体)公司的发展小趣事

尽管AVAGO公司在发展过程中取得了显著成就,但也面临着诸多挑战。随着全球半导体市场的竞争日益激烈,公司需要不断投入研发资金、加强人才培养、优化生产流程等方面来保持竞争优势。同时,公司还需要密切关注行业动态和市场需求变化,以便及时调整战略和产品线。在未来,AVAGO公司将继续致力于技术创新和市场拓展,为全球客户提供更优质的产品和服务。

以上五个故事仅是对AVAGO公司发展历程的简要描述,实际上公司在发展过程中还经历了许多其他重要事件和阶段。这些故事展示了AVAGO公司如何凭借技术实力、市场洞察力和战略眼光在电子行业中脱颖而出,并成为全球领先的半导体企业之一。

EMS GmbH公司的发展小趣事

作为欧洲最领先的生产商之一,EMS GmbH公司与各大国际整车厂建立了长期稳定的合作关系。这些合作不仅为公司带来了稳定的订单和收入来源,还使EMS GmbH能够深入了解市场需求和技术趋势,从而不断优化产品和服务。通过与国际整车厂的紧密合作,EMS GmbH公司在汽车转换器注塑件领域赢得了良好的口碑和声誉。

问答坊 | AI 解惑

安全系统开启汽车电子新市场(附图)

随着汽车保有量的增加,汽车工业的发展越来越受到安全、环 保及节能要求的限制。安全、环保、节能体现了汽车科技创新的方向, 也是汽车工业竞争的焦点,汽车电子技术的发展将促进这三大难题的 解决。目前,全球各国对汽车研究的重点放在了如何提高 ...…

查看全部问答>

FIFO Design for High-speed network interface

FIFO Design for High-speed network interface…

查看全部问答>

TCPMP是按什么规则调解码Dll的(解码插件)?

一个地方下了一个WMV 解码的Dll. 另外一个地方下了一个TCPMP0.72, 它直接能用这个解码Dll播放WMV文件。(没有这个解码Dll,就不能播放WMV文件) TCPMP是按什么规则调解码Dll的(或解码插件)?    …

查看全部问答>

vxworks初学者求助

我把vxworks移植到了VMWARE的虚拟机上,编程时有两个问题想了解一下 1.我编译的VXWORKS内核是包含了target shell组件和一个host与target符号表同步的组件的,在TORNADO编好程序后download到虚拟机中,为什么在tornado的命令行下能运行程序中的函数 ...…

查看全部问答>

单片机晶振与电压

大家好:          请问加在单片机引脚上的晶振与电压存在关系吗?单位同事讲过,一般情况下,3.3V电压下晶振最高频率10 MHz为好.          还有,单片机上电后,为了验证晶振是否工作,用 ...…

查看全部问答>

玩转LaunchPad第一季_自编改进上下位机软件

 帖子更新历史:11.2 7:05暂停更新,附件删除。最近感到精力不济,再说还有一些个别有待进一步提高的地方。还是等全部完成以后源码和一些文档一并公布。10.28 11:25 附件中添加新下载的官方demo压缩包和一个烧写HEX的软件(我还没有试验可不 ...…

查看全部问答>

如何用手机蓝牙控制外部设备

  我想用手机蓝牙来控制灯牌的亮度,需要掌握什么知识?1,如何编写一个手机软件,来实现控制?2,在灯的硬件方面,用什么元件来接受蓝牙信号,蓝牙适配器? 求指教!!! …

查看全部问答>

F2802X怎么在CCS看到的FLASH数据和HEX文件看到的数据不一样啊。

我用CODESKIN下载了hex文件,但是通过CCS看FLASH数据,却发现它们并不一致。确实有相同的数据,但是他们的地址不一样。这是怎么回事啊?…

查看全部问答>

来迟了,求BBB板一块。

来迟了,求BBB板一块。…

查看全部问答>

关于DMX512控制RGB的控制器解码讨论

关于DMX512控制RGB的控制器解码网上似不多,灌灌水也无妨,谈谈各自的见解………

查看全部问答>