找回密码
 立即注册

QQ登录

只需一步,快速开始

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

万年历集大成版之调试程序

  [复制链接]
跳转到指定楼层
楼主
因上次转让出的万年历集大成版控制板主要是针对我的数码管设计的,测试中的程序没法直接给LCD12864和LCD240128使用,这两天应个别坛友要求,特调制了两个小程序供买板的坛友直接拿过去使用。仅调试了个把小时,没实际进行老化试验,bug难免。还是老话,我主攻的数码管显示,没精力折腾其他程序。而且工作合同即将到期,很多杂事要处理!
发现bug自己修改,并欢迎技术回帖!

第一个:GPS+LCD12864+DS3231
图片:
大字体主界面(我故意调到911,以测试自动校时用的):




郑重提示:下载程序时必须将GPS断开!
万年历运行中使用GPS时,电脑串口断不断开无所谓。

K4切换至GPS显示界面:


在此界面随时使用K1(MOD)键强制手动校时。

GPS信息完整显示界面:


经纬度第一个小数点前为度,第一个小数点后为分。
如:东经118度59.00分。如需显示秒,自己转换:0.00*60=0.0秒。
定位信息出现后5分钟自动与DS3231校时。


一广州坛友打电话要求设个定时几小时校准一次DS3231。
我说首先DS3231已经很准了,日误差远低于1s;第二如果把GPS一直挂在万年历上,还不如直接把GPS当RTC得了,何须浪费个DS3231!
因此特专做了个GPS+LCD12864的程序供选择。

二、GPS+LCD12864
大字体主界面(早上手机拍的,将就看):


GPS没有温度了,需要的自己加18B20。

K4切换至GPS信息界面:



在运行模式下K3键是屏幕背景灯开关,GPS支持热插拔。
只要波特率是9600,NMEA-0183协议就可以直接使用。
如果波特率是4800(GPS常用就这两个波特率),就可以在程序里面将宏定义BAUD 9600改为 BAUD 4800
#define BAUD 9600  
不建议使用4800,虽然波长大抗干扰好,毕竟速度慢,个人意见。


淘宝2手gps风险大,几块钱一个,一般都是随机选择不包好,本人曾买过8个坏了两个,那两个明显受了外伤的,没办法,卖家连这最基本的常识都不知道?
最后教大家一招如何简单测试GPS好坏的方法。


外壳上有 9.6kps,恭喜你,我的程序你可以直接使用了。淘宝最常见的二手GPS八成以上都是韩国货,质量也还过得去。

拆开,接线端子上一般是四根线,最外端的红黑一般是5V供电+-。
如果不是红黑色,那么在端子旁边有个小纽扣电池,电池上有标正负。万用表测短路档,一端接电池-,另一端去测试接线端子,找到-。其次可以顺着电池+极找到3.3v的稳压块,可以在稳压块上找到5V供电+。
5V接上通电后板载指示灯会亮:



拿一发光二极管,二极管-接电源-。正极接任意一根未知端子。
如果发光二极管有规律的一秒亮一次就确定了这根是TX,即接万年历的RX。因为GPS是每秒发送一次数据,不管有没有接受到卫星信号。如果两根线分别接上发光二极管都常亮或不亮,那就只有默哀了。

常规情况下靠近电源+极的就是TX。
另一根线应该是RX用来刷机用的,我们空置不管。
因为常规的TTL排序是 VCC  TX  RX GND。



还有个别种类gps带绿色寻星指示灯,寻星中为绿色闪烁,定位成功为绿色常亮。如果刚送电就常亮绿灯显然是坏了。

原本想淘它几百个来测试挑选出无故障的再来一乐论坛转让的,但实在没精力了……
最后向此次买万年历控制板的几个坛友说声抱歉。
本人平常上班,晚上下班回来都6:30过了,故平常没法发快递。所以我转让的东西都是挑周末或节假日发布。
这次刚好撞上了中秋节快递爆仓,虽然是两家小快递,平常也还能实现江浙沪次日达的,这次居然发货后3天都还没出本地中转,实在意外。
所以补发两个GPS程序以精神安慰!
各收一个币,象征一下:
GPS+LCD12864+DS3231大字体翻页版:
GPS 3231 12864.rar (99.22 KB, 下载次数: 89)

GPS+LCD12864大字体翻页版:
GPS 12864.rar (69.63 KB, 下载次数: 60)

应部分坛友要求,把二手GPS淘宝链接发了

提醒:
1、gps模块实际会裹满泥巴的,没照片上好看
2、店主对gps一问三不知,她的主业是卖耳机等配件的
3、建议多淘几个。自己承担风险!
4、选这家是因为其价格算是比较低的了
5、本人跟卖家无任何经济利益关系,里面最长的评论是我的

  1. /*---------------------------------------------------------------------------
  2.                 GPS+DS3231+LCD12864 万年历大字体翻页版程序
  3.                 单 片 机:STC89C58RD+
  4.                 晶    振:12MHz
  5.                 时钟芯片:DS3231
  6.                 液 晶 屏:LCM-12864-ST7920                 LCM12864使用并口连接方式,PSB、RST接高电平
  7.                 GPS模块 :JSA-S100         ATMEL方案
  8.                 通信格式:NMEA0183
  9.                 通信协议:9600,8,N,1               
  10.                 时    间:2014年9月10日
  11. ------------------------------------------------------------------------------*/
  12. /*
  13.                 运行界面分 DS3231大字体 与 GPS时间定位 ;通过K4键切换,详见下面 按键定义
  14.                 GPS界面获取有效定位信息连续超过5min即自动给DS3231校时。

  15.                 如果一些汉字不能正常显示如"三"等,说明keil需打汉字补丁
  16.                 GPS支持热插拔,如果供电电源质量差,插入GPS后LCD屏幕对比度会明显变差!

  17.                 经纬度显示为DD.MM.MM(度分格式)
  18.                 如东经:118.58.99  表示为118度58.99分
  19.                 如果要显示秒,则为0.99*60=59.4秒,需要的自己动手改进!!

  20.                 程序仅经初步测试,用以临时测试GPS、DS3231、LCD12864和【集大成万年历】控制板焊接组装是否正常,并未经老化实验!
  21.                
  22.                 核心程序都是博采众长,自己付出的仅是删减组合微调而已,向原作者致敬!*/       
  23.                                           
  24. /*-------------------------------头文件---------------------------------------*/
  25. #include <reg52.h>
  26. #include <intrins.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include "LCD12864.h"
  30. #include "DS3231.h"

  31. #include "nongli.h"
  32. #include "displaytime.h"
  33. #include "dashuzi.h"
  34. const char chHex[16] = "0123456789ABCDEF";
  35. /********************************************************************************************************************
  36.                 以下为GPS部分定义 (如果纯为显示GPS信息只需要定义变量RsBuf[80]就够了,两个结构体可以不要,边解析边显示  )
  37. ********************************************************************************************************************/
  38. //串口中断需要的变量
  39. uchar seg_count;             /**  逗号计数器 **/
  40. uchar byte_count;            /**  位数计数器 **/

  41. uchar mode;                  /**  0:结束模式,1:命令模式,2:数据模式         **/
  42. uchar buf_full;              /**  1:整句接收完成,相应数据有效。0:缓存数据无效  **/

  43. typedef xdata struct
  44. {
  45.     uchar TIME[10];       
  46.     uchar VA[2];               
  47.     uchar WD[11];       
  48.     uchar WDNS[2];       
  49.     uchar JD[12];       
  50.     uchar JDWE[2];       
  51.     uchar DATE[9];                 
  52. } GPS_GPRMC;

  53. GPS_GPRMC  gps;

  54. typedef xdata struct                  /** 作时区转换时需要用到年、月、日进一 **/
  55. {
  56.     uchar Hour;
  57.     uchar Min;
  58.     uchar Sec;
  59.     uchar Day;
  60.     uchar Mon;
  61.     uchar Year;
  62. } TIMER;
  63. TIMER Timer;

  64. char idata RsBuf[80];     /**  全局变量 **/
  65. void InitBps();                           /**  串口初始化 **/

  66. void UTCToLocal(TIMER *GPS_DataTmp);

  67. /****          以上为GPS部分定义  ***************************************************/

  68. /*--------------------定义按键-----------------------------------------------*/
  69. sbit K1  = P3 ^ 4; //K1-进入设置;GPS模式下为强制校时
  70. sbit K2  = P1 ^ 7; //K2-调时模式下为 加
  71. sbit K3  = P1 ^ 6; //K3-调时模式下为 减;运行模式下为背景灯控制
  72. sbit K4  = P1 ^ 5; //K4-调时模式下为 确认、返回         ;运行模式下为DS3231与GPS运行界面切换

  73. sbit BLK = P2 ^ 0; //液晶背光控制输出,低电平有效,PNP三极管控制。

  74. sbit Bell_Out  = P1 ^ 2;

  75. /*---------------------函数声明------------------------------*/
  76. void DelayM(uint);
  77. void Delay(int);
  78. void ds_w(void);
  79. void        GetDS3231(void);
  80. void Conver_week(uchar year, uchar month, uchar day);
  81. /*-----------------------------定义全局变量------------------------------*/
  82. bit q = 0, w = 0; //调时标志位
  83. uchar yy, mo, dd, xq, hh, mm, ss, month_moon, day_moon, week, tiangan, dizhi, moontemp1, moontemp2; //定义时间映射全局变量(专用寄存器)
  84. signed char address, item, max, mini;

  85. /*-----------------------------延时函数 1MS/次-------------------------------*/
  86. void DelayM(uint a)
  87. {
  88.     uchar i;
  89.     while( --a != 0)
  90.     {
  91.         for(i = 0; i < 125; i++);
  92.     }
  93. }
  94. /*-----------------------------日期、时间设置函数-----------------------------*/

  95. void tiaozheng(void)
  96. {
  97.     yy = read_random(DS3231_YEAR);               
  98.     mo = read_random(DS3231_MONTH);       
  99.     dd = read_random(DS3231_DAY);       
  100.     week = read_random(DS3231_WEEK);

  101.     lcm_w_test(0, 0x80);

  102.     lcm_w_word("20");           //显示内容字符20
  103.     lcm_w_test(1, yy / 10 + 0x30);         //函数参数1,代表本行写数据,YY/10+0X30得出年十位数字的显示码地址,送显示
  104.     lcm_w_test(1, yy % 10 + 0x30);        
  105.     lcm_w_word("年");

  106.     lcm_w_test(1, mo / 10 + 0x30);
  107.     lcm_w_test(1, mo % 10 + 0x30);                
  108.     lcm_w_word("月");                           //调用字符显示函数,显示文字 月

  109.     lcm_w_test(1, dd / 10 + 0x30);
  110.     lcm_w_test(1, dd % 10 + 0x30);        
  111.     lcm_w_word("日");                         //显示字符 日

  112.     if(read_random(DS3231_HOUR) != hh)          //如果程序中的小时与1302芯片中的不同,
  113.     {
  114.         hh = read_random(DS3231_HOUR);                 //刷新程序中的小时数据
  115.     }
  116.     lcm_w_test(0, 0x91);                       //第一个参数0,表示本行写入LCM的是指令,指定显示位置88H(第三行左端)
  117.     lcm_w_test(1, (hh / 10) + 0x30); //显示十位
  118.     lcm_w_test(1, hh % 10 + 0x30);         //显示个位
  119.     lcm_w_word("时");

  120.     if(read_random(DS3231_MINUTE) != mm)                 //如果1302芯片中的分钟数据与程序中的分钟变量不相等
  121.     {
  122.         mm = read_random(DS3231_MINUTE) ;                //刷新程序中的分钟数据
  123.     }
  124.     lcm_w_test(1, (mm / 10) + 0x30);         //向液晶写数据,显示分钟的十位数
  125.     lcm_w_test(1, mm % 10 + 0x30);                 //向液晶写数据,显示分钟的个位数
  126.     lcm_w_word("分");

  127.     if(read_random(DS3231_SECOND) != ss)                         //如果1302芯片中的分钟数据与程序中的秒钟变量不相等
  128.     {
  129.         ss = read_random(DS3231_SECOND);                        //刷新程序中的秒钟数据
  130.     }
  131.     lcm_w_test(1, (ss / 10) + 0x30);         //向液晶写数据,显示分钟的十位数
  132.     lcm_w_test(1, ss % 10 + 0x30);                 //向液晶写数据,显示分钟的个位数
  133.     lcm_w_word("秒");
  134. }

  135. /**********************************************************************************************************/
  136. //调整时间子函数,设置键、数据范围、上调加一,下调减一功能。
  137. void Set_time(unsigned char sel)  //根据选择调整的相应项目加1并写入DS1302,函数参数是按动设置键的次数
  138. {

  139.     write_com(0x30);
  140.     write_com(0x06);

  141.     lcm_w_test(0, 0x98); //第一参数0表示本行写入指令,指定下面行的 调整 显示起始位置为9AH
  142.     lcm_w_word("★调整");//调用字符显示函数,显示 调整字样

  143.     if(sel == 5)
  144.     {
  145.         lcm_w_word("秒钟");
  146.         address = DS3231_SECOND;
  147.         max = 59;
  148.         mini = 0;
  149.         tiaozheng();  //调用日期、时间调整函数
  150.         ds_w();                  //被调数据加一或减一函数
  151.         tiaozheng();

  152.     }        //秒7,按动7次显示 调整秒钟
  153.     //并指定秒钟数据写入1302芯片的地址是0x82,秒钟数据的最大值是59,最小值是0

  154.     if(sel == 4)
  155.     {
  156.         lcm_w_word("分钟");
  157.         address = DS3231_MINUTE;
  158.         max = 59;
  159.         mini = 0;
  160.         tiaozheng();
  161.         ds_w();
  162.         tiaozheng();

  163.     }        //分钟6,按动6次显示 调整分钟
  164.     //并指定分钟数据写入1302芯片的地址是0x82,分钟数据的最大值是59,最小值是0

  165.     if(sel == 3)
  166.     {
  167.         lcm_w_word("小时");
  168.         address = DS3231_HOUR;
  169.         max = 23;
  170.         mini = 0;

  171.         tiaozheng();
  172.         ds_w();
  173.         tiaozheng();

  174.     }        //小时5,按动5次显示 调整小时
  175.     //规定小时数据写入1302芯片的位置是0x84,小时数据最大值23,最小值是0       

  176.     if(sel == 2)
  177.     {
  178.         lcm_w_word("日期");
  179.         address = DS3231_DAY;

  180.         mo = read_random(DS3231_MONTH);//读月数据
  181.         yy = read_random(DS3231_YEAR);//读年数据

  182.         if(mo == 2 && yy % 4 != 0)
  183.         {
  184.             max = 28;    //平年2月28天
  185.             mini = 1;
  186.         }
  187.         if(mo == 2 && yy % 4 == 0)
  188.         {
  189.             max = 29;    //闰年2月29天
  190.             mini = 1;
  191.         }
  192.         if(mo == 1 || mo == 3 || mo == 5 || mo == 7 || mo == 8 || mo == 10 || mo == 12)
  193.         {
  194.             max = 31;    //31天的月份
  195.             mini = 1;
  196.         }
  197.         if(mo == 4 || mo == 6 || mo == 9 || mo == 11)
  198.         {
  199.             max = 30;    //30天的月份
  200.             mini = 1;
  201.         }
  202.         tiaozheng();
  203.         ds_w();
  204.         tiaozheng(); //调用日期、时间调整函数

  205.     }        //日3,按动3次显示 调整日期
  206.     //规定日期数据写入1302的位置地址是0x86,日期最大值31,最小值是1

  207.     if(sel == 1)
  208.     {
  209.         lcm_w_word("月份");
  210.         address = DS3231_MONTH;
  211.         max = 12;
  212.         mini = 1;
  213.         tiaozheng();
  214.         ds_w();
  215.         tiaozheng();

  216.     }        //月2,按动2次显示 调整月份
  217.     //规定月份写入1302的位置地址是0x88,月份最大值12,最小值1

  218.     if(sel == 0)
  219.     {
  220.         lcm_w_word("年份");
  221.         address = DS3231_YEAR;
  222.         max = 99;
  223.         mini = 0;
  224.         tiaozheng();
  225.         ds_w();                //被调数据加一或减一函数
  226.         tiaozheng();        //调用日期、时间调整函数

  227.     }        //年1,按动1次显示 调整年份,
  228.     //规定年份写入1302的地址是0x8c,年份的最大值99,最小值0

  229. }

  230. /*****************************************************************************/
  231. //被调数据加一或减一,并检查数据范围,写入1302指定地址保存
  232. void ds_w(void)
  233. {
  234.     item = read_random(address);
  235.     if(K2 == 0) //如果按动上调键
  236.     {
  237.         item++;//数加 1
  238.     }
  239.     if(K3 == 0) //如果按动下调键
  240.     {
  241.         item--;//数减 1
  242.     }
  243.     if(item > max) item = mini;         //查看数值是否在有效范围之内
  244.     if(item < mini) item = max;         //如果数值小于最小值,则自动等于最大值

  245.     ModifyTime(address, item);
  246. }

  247. //=================================BEEP驱动===========================================//
  248. //需要定义Delay,输出Bell_Out引脚
  249. /********************************************************************************************/
  250. void beep (        unsigned char a, unsigned char b,
  251.             unsigned char c, unsigned char d)
  252. {
  253.     for(; a > 0; a--) //第一个声音的长度
  254.     {
  255.         Bell_Out = ~Bell_Out;//取反扬声器驱动口,以产生音频
  256.         Delay(b);//音调设置延时
  257.     }
  258.     for(; c > 0; c--) //同上
  259.     {
  260.         Bell_Out = ~Bell_Out;
  261.         Delay(d);//
  262.     }
  263.     Bell_Out = 1;
  264. }


  265. void Beep_y(void)
  266. {
  267. ……………………

  268. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码



评分

参与人数 1黑币 +5 收起 理由
陈润源home + 5 很给力!

查看全部评分

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

使用道具 举报

沙发
ID:233911 发表于 2017-9-18 17:50 | 只看该作者
问:仿制成功,温度显示有问题,不能大于26度,是哪的问题啊
答:
  1. 好多人反应都有这个问题,一超过25.5就回到了20多,暂时没条件测试了,等我的新的大数字万年历板子回来了再测试。
  2. 怀疑是DS3231.h中的 uint    read_temp()   是否有问题(26度的临界bug)。
  3. uint    read_temp()       /* -------- read temperature -------- */
  4. {
  5.                 int     itemp;
  6.                 float   ftemp;
  7.                 //温度数据是以2 进制格式存储的并不需要数制转换
  8.                 write_byte(0x0e,0x20);//0x0e寄存器的CONV位置1开启温度转换

  9.         itemp = ( (int) read_random(0x11) << 5 );          //放大32倍
  10.         itemp += ( read_random(0x12)>> 3);
  11.         Stop_I2C();
  12.         if(itemp & 0x1000)
  13.                         itemp += 0xe000;        /* if sign bit set, make 16 bit 2's comp */

  14.         ftemp = 0.3125 * (float) itemp+0.5;    /* 放大10倍 */
  15.                 return  (uint) ftemp;
  16. }
  17. 该read_temp() 函数放在C++编译环境中测试是可以大于26度的。

  18. 和温度相关的另一个函数是displaytime.h中的:
  19. /*温度值显示-----------------------------------------------------------------*/
  20. void displaytemp()
  21. {
  22.         uint tvalue=read_temp();

  23.         set1616pic(5,4,0,1);                                         //显示"温度计图标"
  24.         write_com(0x30); write_com(0x06);        
  25.         write_com(0x9d);           //在液晶上显示温度起始位置:"28.8°C"
  26.         if(tvalue>=100)
  27.         write_data(tvalue%1000/100+0x30);    //显示十位
  28.         else
  29.                  write_data(0x20);    //不显示十位
  30.         write_data(tvalue%100/10+0x30);    //显示个位         
  31.         write_data(0x2e);          //显示小数点         
  32.         write_data(tvalue%10+0x30);    //显示小数位
  33.         set1616pic(8,4,0,0);           //在第8列第4行不反白的°C图标
  34. }
复制代码

此函数似乎没多大问题。

但是我用同样的DS3231.h做的其他几个时钟温度是可以大于26度的:






29度!

希望其他懂单片机的坛友看到了此回复有精力就帮忙测试下DS3231的温度函数问题。

如果温度不够,可以用手触摸ds3231芯片让其升温至26度上!

原因已找到,  ds3231芯片的问题  ,换了个就没事了,用的是一年前买的不带#号的片子。
回复

使用道具 举报

板凳
ID:82765 发表于 2017-9-18 19:55 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

地板
ID:225681 发表于 2017-10-28 09:51 | 只看该作者
没看到电路图是什么个意思?可否提供下
回复

使用道具 举报

5#
ID:90212 发表于 2018-2-17 21:59 | 只看该作者
2014年的测试图片,2017年发帖……
回复

使用道具 举报

6#
ID:116551 发表于 2018-6-28 22:11 | 只看该作者
楼主,想问一下,P2.0用PNP三极管控制的液晶屏的背光有什么作用吗,可不可以直接接电源的负,谢谢
回复

使用道具 举报

7#
ID:116551 发表于 2018-7-14 20:24 | 只看该作者
您好,我做了一个您设计的时钟,第一个,您的程序里不是有一个12小时自动对时一次吗,我测试了好几天这个功能都实现不了,我又改了一下,1小时自动对时一次,也不行,是程序的问题吗,想问一下您做的第一个时钟有没有这个问题,我用的GPS是GPS模块 NEO-7N UBLOX。麻烦您能解答一下,谢谢
回复

使用道具 举报

8#
ID:116551 发表于 2018-12-31 22:11 | 只看该作者
您好,我做了一个您设计的时钟,第一个,您的程序里不是有一个12小时自动对时一次吗,我测试了好几天这个功能都实现不了,我又改了一下,1小时自动对时一次,也不行,是程序的问题吗,想问一下您做的第一个时钟有没有这个问题,我用的GPS是GPS模块 NEO-7N UBLOX。麻烦您能解答一下,谢谢
回复

使用道具 举报

9#
ID:190223 发表于 2019-3-22 23:42 来自手机 | 只看该作者
为什么gps校准不了时间啊
回复

使用道具 举报

10#
ID:567636 发表于 2019-7-16 19:34 | 只看该作者
看上去好像不错了!
回复

使用道具 举报

11#
ID:138130 发表于 2019-9-18 18:42 | 只看该作者
各位朋友,大家好!谁有以上不带#号的ds3231芯片购链接,帮忙发一下,将不胜感谢!(因本人DIY的时候碰到以上的温度问题得不到解决。)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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