找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7274|回复: 13
打印 上一主题 下一主题
收起左侧

Proteus仿真《用51单片机制作的6位数码管GPS授时时钟》

  [复制链接]
跳转到指定楼层
楼主
ID:149389 发表于 2019-5-18 14:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
原贴: http://www.51hei.com/bbs/dpj-100009-1.html
仿真环境:Proteus 8.5 SP0

仿真说明:在Proteus仿真中使用AT89C52单片机,在原始程序的基础上,调整了部分引脚定义,只测试了GPS授时功能。仿真不包含红外部分。


1、为了对照说明GPS授时效果,DS1302,取消该选项的勾选。


2、仿真开始,时间从0:00:00 开始


3、闭合开关,获取GPS授时信息,GPS授时的标记点亮,串口可观察GPS信息,DS1302成功写入获取的时间。


4、断开开关,时钟从DS1302获取时间值



5、仿真文件,含Proteus 8.5格式的工程文件,以及Hex文件,程序请参照原贴。



全部资料51hei下载地址(仿真+hex文件 不带源码):
6位数码管GPS时钟.rar (20.61 KB, 下载次数: 190)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏11 分享淘帖 顶2 踩
回复

使用道具 举报

沙发
ID:601774 发表于 2019-8-23 08:17 | 只看该作者
谢谢,学习了
回复

使用道具 举报

板凳
ID:601774 发表于 2019-8-23 08:18 | 只看该作者
谢谢,学习了,刚好准备弄一个,就是不知道gps串口读取的时间精度是到哪一位的,只是到秒级,还是能读取毫秒,微秒
回复

使用道具 举报

地板
ID:99130 发表于 2020-2-17 22:45 来自手机 | 只看该作者
正好需要
回复

使用道具 举报

5#
ID:637324 发表于 2020-3-21 13:21 | 只看该作者
原贴不存在了,想看楼主大哥的程序
回复

使用道具 举报

6#
ID:149389 发表于 2020-4-9 08:58 | 只看该作者
gspt 发表于 2020-3-21 13:21
原贴不存在了,想看楼主大哥的程序

C源程序, main.rar (3.36 KB, 下载次数: 47)

  1. #include <reg52.H>
  2. //--------数码管段选定义--------
  3. #define LEDPORT P0
  4. #define uchar unsigned char
  5. #define uint unsigned int
  6. //--------数码管位选定义--------
  7. sbit D1=P2^0;
  8. sbit D2=P2^1;
  9. sbit D3=P2^2;
  10. sbit D4=P2^3;
  11. sbit D5=P2^4;
  12. sbit D6=P2^5;
  13. //--------DS1302接口定义--------
  14. sbit CLK =P3^7;                                         
  15. sbit IO  =P3^6;
  16. sbit RST =P3^1;
  17. //--------状态标记--------
  18. sbit LED1=P2^6;
  19. sbit LED2=P2^7;
  20. sbit ACC0=ACC^0;
  21. sbit ACC7=ACC^7;
  22. unsigned char hour,min,sec;                //小时、分钟、秒
  23. bit rev_start,rev_stop;                        //GPS接收开始、结束标志位
  24. unsigned char code tab[ ]={
  25.   0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xFF};//共阳极0-9,灭
  26. unsigned char  buf[10];         //GPS数据接收缓冲
  27. unsigned char  irtime;//红外用全局变量,用于计算2个下降沿之间的时间
  28. bit decode_ok,irok;
  29. static unsigned char ircode[4];
  30. unsigned char irdata[33];
  31. uchar set,temp,dot;
  32. bit flag,test;                                          
  33. uint cnt;
  34. /******************************************************************************************
  35. *函数名称:Timer_Init
  36. *功能描述:定时器初始化
  37. ******************************************************************************************/
  38. void Timer_Init()
  39. {
  40.   TMOD=0x22;
  41.   TH0=0x00; //重载值
  42.   TL0=0x00; //初始化值
  43.   ET0=1;    //开中断
  44.   TR0=1;
  45.   IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
  46.   EX0 = 1;   //使能外部中断

  47.   TL2 = 0xCD;                //设置定时初值
  48.   TH2 = 0xF8;                //设置定时初值
  49.   RCAP2L = 0xCD;        //设置定时重载值
  50.   RCAP2H = 0xF8;        //设置定时重载值
  51.   ET2=1;
  52.   TR2=1;

  53.   TH1 = 0xFD;                //9600波特率的初值
  54.   TL1 = TH1;                //9600波特率的初值
  55.   TR1 = 1;  
  56.   SCON = 0x50;        //使用串行工作方式1,10位异步收发8位数据,波特率可变(由T1的溢出率控制)
  57.   //        ES = 1;
  58.   EA=1;
  59. }
  60. //--------数据串行输入--------
  61. void inputbyte(unsigned char ucDa)
  62. {
  63.   unsigned char i;
  64.   ACC = ucDa;
  65.   for(i=8; i>0; i--)
  66.   {
  67.     IO = ACC0;                   //相当于汇编中的 RRC
  68.     CLK = 1;
  69.     CLK = 0;
  70.     ACC = ACC >> 1;
  71.   }
  72. }
  73. //--------数据并行输出--------
  74. unsigned char outputbyte(void)
  75. {
  76.   unsigned char i;
  77.   for(i=8; i>0; i--)
  78.   {
  79.     ACC = ACC >>1;                      //相当于汇编中的 RRC
  80.     ACC7 = IO;
  81.     CLK = 1;
  82.     CLK = 0;
  83.   }
  84.   return(ACC);
  85. }
  86. //--------数据写入--------
  87. void write(unsigned char ucAddr, unsigned char ucDa)
  88. {
  89.   RST = 0;
  90.   CLK = 0;
  91.   RST = 1;
  92.   inputbyte(ucAddr);                    //地址,命令
  93.   inputbyte(ucDa);                      //写1Byte数据
  94.   CLK = 1;
  95.   RST =0;
  96. }
  97. //--------数据读出--------
  98. unsigned char read(unsigned char ucAddr)
  99. {
  100.   unsigned char ucDa;
  101.   RST = 0;
  102.   CLK = 0;
  103.   RST = 1;
  104.   inputbyte(ucAddr);                    //地址,命令
  105.   ucDa = outputbyte();                 //读1Byte数据
  106.   CLK = 1;
  107.   RST =0;
  108.   return(ucDa);
  109. }
  110. //--------DS1302初始化--------
  111. void DS1302_init()
  112. {
  113.   if(read(0xc1)!=0x82)  //如果1302掉电,写入下面的初始值
  114.   {
  115.     write(0x8e,0x00);//关闭写保护
  116.     write(0x80,0x22); //设置秒
  117.     write(0x82,0x22);//设置分钟
  118.     write(0x84,0x22); // 小时
  119.     write(0x90,0xa5);//涓流充电
  120.     write(0xc0,0x82);//掉电标志位
  121.   }
  122. }
  123. //------------------------------------------------------------
  124. //--------------遥控器操作部分--------------------------------
  125. void decode(void)//红外码值处理函数
  126. {
  127.   unsigned char i, j, k;
  128.   unsigned char cord,value;
  129.   k=1;
  130.   for(i=0;i<4;i++)      //处理4个字节
  131.   {
  132.     for ( j=1; j<=8;  j++) //处理1个字节8位
  133.     {
  134.       cord=irdata[k];
  135.       if(cord>7)//大于某值为1,这个和晶振有绝对关系,这里使用12M计算,此值可以有一定误差
  136.       {
  137.         value=value|0x80;
  138.       }
  139.       else
  140.       {
  141.         value=value;
  142.       }
  143.       if(j<8)
  144.       {
  145.         value=value>>1;
  146.       }
  147.       k++;
  148.     }
  149.     ircode[i]=value;
  150.     value=0;     
  151.   }
  152.   if(ircode[2]==~ircode[3])
  153.     decode_ok=1;//解码完毕后标志位置1
  154. }
  155. void ir_work()
  156. {
  157.   if(ircode[2]==0x1e)
  158.     test=!test;                //熄灭屏幕标记
  159.   if(ircode[2]==0x05)
  160.   {
  161.     set++;
  162.     if(set==4)
  163.       set=0;
  164.   }
  165.   if(set==1)
  166.   {
  167.     if(ircode[2]==0x02|ircode[2]==0x06)                                                //hour
  168.     {
  169.       temp=(read(0x85)/16)*10+read(0x85)%16;
  170.       temp++;
  171.       if(temp==24)temp=0;
  172.       write(0x84,(temp/10)*16+temp%10);
  173.     }
  174.     if(ircode[2]==0x08|ircode[2]==0x04)
  175.     {
  176.       temp=(read(0x85)/16)*10+read(0x85)%16;
  177.       temp--;
  178.       if(temp==-1)temp=23;
  179.       write(0x84,(temp/10)*16+temp%10);
  180.     }         
  181.   }
  182.   if(set==2)                                                                         //min
  183.   {
  184.     if(ircode[2]==0x02|ircode[2]==0x06)       
  185.     {
  186.       temp=(read(0x83)/16)*10+read(0x83)%16;
  187.       temp++;
  188.       if(temp==60)temp=0;
  189.       write(0x82,(temp/10)*16+temp%10);
  190.     }
  191.     if(ircode[2]==0x08|ircode[2]==0x04)
  192.     {
  193.       temp=(read(0x83)/16)*10+read(0x83)%16;
  194.       temp--;
  195.       if(temp==-1)temp=59;
  196.       write(0x82,(temp/10)*16+temp%10);
  197.     }         
  198.   }
  199.   if(set==3)                                                                         //sec
  200.   {
  201.     if(ircode[2]==0x02|ircode[2]==0x06)       
  202.     {
  203.       temp=(read(0x81)/16)*10+read(0x81)%16;
  204.       temp++;
  205.       if(temp==60)temp=0;
  206.       write(0x80,(temp/10)*16+temp%10);
  207.     }
  208.     if(ircode[2]==0x08|ircode[2]==0x04)
  209.     {
  210.       temp=(read(0x81)/16)*10+read(0x81)%16;
  211.       temp--;
  212.       if(temp==-1)temp=59;
  213.       write(0x80,(temp/10)*16+temp%10);
  214.     }         
  215.   }
  216.   decode_ok=0;       
  217. }
  218. //--------数码管显示--------
  219. void Display(unsigned char a,b,c)   //数码管显示
  220. {
  221.   static unsigned char i;
  222.   LEDPORT=0xff;
  223.   switch (i)
  224.   {
  225.   case 0:
  226.     if(a/16)                                //不为零则显示
  227.       LEDPORT=tab[a/16]˙
  228.     else
  229.       LEDPORT=tab[10]˙        //最高位"0",消隐字符
  230.     D1=0;
  231.     D2=D3=D4=D5=D6=1;       
  232.     break;
  233.   case 1:
  234.     LEDPORT=tab [a%16];   
  235.     D2=0;
  236.     D1=D3=D4=D5=D6=1;   
  237.     break;
  238.   case 2:
  239.     LEDPORT=tab [b/16];            
  240.     D3=0;
  241.     D1=D2=D4=D5=D6=1;       
  242.     break;
  243.   case 3:
  244.     LEDPORT=tab [b%16];       
  245.     D4=0;
  246.     D1=D2=D3=D5=D6=1;       
  247.     break;
  248.   case 4:
  249.     LEDPORT=tab [c/16];            
  250.     D5=0;
  251.     D1=D2=D3=D4=D6=1;       
  252.     break;
  253.   case 5:
  254.     LEDPORT=tab [c%16];   
  255.     D6=0;
  256.     D1=D3=D4=D5=D2=1;       
  257.     break;
  258.   }
  259.   i++;
  260.   if(i==6)i=0;
  261. }
  262. /******************************************************************************************
  263. *函数名称:main
  264. *功能描述:主函数
  265. ******************************************************************************************/
  266. void main()
  267. {
  268.   Timer_Init();
  269.   DS1302_init();
  270.   dot=0xFF;
  271.   flag=1;
  272.   while(1)
  273.   {                 
  274.     hour= read(0x85);
  275.     min = read(0x83);
  276.     sec  = read(0x81);
  277.     /*        if((hour==0x08)&&(min==0x00) )                         //可以设置为每天的某个时间打开GPS对一下时间再关掉,这里设置的是8:00
  278.              ES=1;
  279.              else
  280.              ES=0;*/
  281.     if(flag==1&&cnt>500)                                  //上电稍做延时再打开串口,防止数码管显示出错
  282.     {
  283.       flag=0;
  284.       cnt=0;
  285.       ES=1;
  286.     }
  287.     if((rev_stop==1)&&(buf[1]=='M')&&(buf[2]=='C')&&(buf[3]==','))//如果接收到GPRMC        就把GPS接收到的时间写入DS1302
  288.     {
  289.       LED1=1;
  290.       ES=0;
  291.       hour= (buf [4]-0x30)* 16+ buf[5] -0x30;
  292.       min=  (buf [6]-0x30)* 16+ buf[7]-0x30;
  293.       sec=  (buf[8]-0x30)* 16+ buf[9]-0x30;
  294.       hour=  hour / 16 * 10 + hour % 16;
  295.       hour= (hour+8) % 24;        //UTC Time换算成北京时间
  296.       hour=hour/10*16+hour%10;
  297.       write(0x84,hour);
  298.       write(0x82,min);
  299.       write(0x80,sec);       
  300.       ES=1;
  301.       rev_stop=0;
  302.     }                       
  303.     if( sec==  (buf[8]-0x30)* 16+ buf[9]-0x30)                                        //用左上角的小点显示有无GPS信号
  304.       dot=0x7f;
  305.     else
  306.       dot=0xff;
  307.     if(irok)                         //如果接收到正确的红外信号后进行红外处理
  308.     {   
  309.       decode();
  310.       irok=0;
  311.     }
  312.     if(decode_ok)                //如果解码正确就进入调时程序
  313.     {
  314.       ir_work();
  315.     }
  316.     if(test)                        //需要时可以遥控关闭屏幕
  317.     {
  318.       ET2=0;
  319.       P0=0xff;
  320.       LED1=LED2=1;
  321.     }
  322.     else
  323.     {
  324.       ET2=1;
  325.     }          
  326.   }                    
  327. }
  328. void int0 (void) interrupt 0 //外部中断0服务函数           用于红外解码
  329. {
  330.   static unsigned char  i;             //接收红外信号处理
  331.   static bit startflag;                //是否开始处理标志位
  332.   if(startflag)                        
  333.   {
  334.     if(irtime<63&&irtime>=33)//引导码 TC9012的头码,9ms+4.5ms
  335.       i=0;                  
  336.     irdata[i]=irtime;//存储每个电平的持续时间,用于以后判断是0还是1
  337.     irtime=0;
  338.     i++;
  339.     if(i==33)
  340.     {
  341.       irok=1;
  342.       i=0;
  343.     }
  344.   }
  345.   else
  346.   {
  347.     irtime=0;
  348.     startflag=1;
  349.   }
  350. }
  351. /******************************************************************************************
  352. *函数名称:timer0
  353. *功能描述:红外解码计算脉冲宽度
  354. ******************************************************************************************/
  355. void timer0 (void) interrupt 1 //定时器0中断服务函数 ,红外解码
  356. {
  357.   irtime++; //计算2个下降沿之间的时间
  358. }
  359. void Uart_Receive(void) interrupt 4         //串口中断,用于GPS数据接收
  360. {
  361.   unsigned char ch,num;
  362.   ES = 0;
  363.   if (RI)                                        //如果接收完成则进入
  364.   {
  365.     ch = SBUF;
  366.     if (ch == 'R')  //如果收到字符'



  367. ,便开始接收
  368.     {
  369.       rev_start = 1;
  370.       rev_stop  = 0;                  //接收停止标志
  371.     }
  372.     if (rev_start == 1)       //标志位为1,开始接收
  373.     {
  374.       buf[num++] = ch;  //字符存到数组中
  375.       if (ch == '.')       //如果接收到换行
  376.       {
  377.         buf[num] = '\n';
  378.         rev_start = 0;
  379.         rev_stop  = 1;          //接收停止标志
  380.         num = 0;
  381.       }
  382.     }
  383.   }
  384.   RI = 0;         //RI清0,重新接收
  385.   ES = 1;         //串口1中断允许                       
  386. }
  387. /******************************************************************************************
  388. *函数名称:Timer2
  389. *功能描述:定时刷新显示
  390. ******************************************************************************************/
  391. void Timer2() interrupt 5                                //2mS                          //用于刷新数码管的显示
  392. {
  393.   TF2=0;          //定时器2必须由软件对溢出标志位清零,硬件不能清零,这里与定时器0和定时器1不同!!!
  394.   switch(set)
  395.   {
  396.   case 0:
  397.     Display(hour,min,sec);
  398.     LED1=0;
  399.     LED2=0;
  400.     break;
  401.   case 1:
  402.     Display(hour,0xaa,0xaa);
  403.     LED1=0;
  404.     LED2=1;
  405.     break;
  406.   case 2:
  407.     Display(0xaa, min,0xaa);
  408.     break;
  409.   case 3:
  410.     Display(0xaa, 0xaa,sec);
  411.     LED1=1;
  412.     LED2=0;
  413.     break;
  414.   }
  415.   cnt++;
  416. }
复制代码




回复

使用道具 举报

7#
ID:637324 发表于 2020-4-27 09:24 | 只看该作者

谢谢!
回复

使用道具 举报

8#
ID:762924 发表于 2020-6-1 15:40 | 只看该作者

老哥,那个电路图有吗,楼主的文件打不开(闪退)
回复

使用道具 举报

9#
ID:771461 发表于 2020-6-6 21:25 | 只看该作者
很有帮助,很需要这个资料的内容进行学习。
回复

使用道具 举报

10#
ID:653173 发表于 2020-8-13 10:01 | 只看该作者
楼主能否分享一个Proteus8.5能用的key?
回复

使用道具 举报

11#
ID:889564 发表于 2021-3-8 15:17 | 只看该作者
没有VGPS这个元件啊
回复

使用道具 举报

12#
ID:611269 发表于 2021-8-7 21:33 | 只看该作者
非门是干啥的呀,没搞懂
回复

使用道具 举报

13#
ID:51443 发表于 2021-9-8 17:22 | 只看该作者
有个疑问,一旦接收到GPS信号,就把时间写入DS1302中,这样不停的写入,DS1302中储存器的写入次数寿命到底能撑多久?
回复

使用道具 举报

14#
ID:317629 发表于 2023-10-3 10:50 | 只看该作者
非常好的东西,非常有帮助
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表