[开源硬件]

【DIY】TM1650+DS3231+STC15LE计数数码管小时钟,复原电路重编程

[复制链接]
2452|1
手机看帖
扫描二维码
随时随地手机跟帖
straka|  楼主 | 2018-7-30 11:45 | 显示全部楼层 |阅读模式
本帖最后由 straka 于 2018-7-30 11:45 编辑

弄了个四位带冒号和小数点的数码管,想着快到1000天纪念日了,于是准备弄个计日的小东西,由于自己DIY的比较丑,就网上淘了一个,但是网上的不符合要求呢,没事,反正网上八成用的是51单片机,基本都可以在线编程了,所以买个回来复原下电路,然后自己在写程序呗。

找了个全白一体的模块,电路印刷也比较整齐的,显示效果如图:
090517wolrla2wa7terqyv.jpg
图1 数码管显示效果图
090516h1i1rolns0jjn04q.jpg
图2 模块电路板

由于电路是双面印刷,为保险起见,还是解焊了数码管,用万用表把电路测试一遍,确保恢复的是正确的电路。主控芯片是STC15LE,sop8封装,数码管驱动芯片是TM1650,sop16封装,时钟是DS3231模块,带有16个八位寄存器,也是sop16封装,数码管是八段4位的,第二位小数点被替换成了冒号。
090516w34kkb43yy2w33b2.jpg
图3 数码管背面
手动画出的电路复原图,还比较简单,毕竟就是个时钟和显示功能,并不复杂。然后开始写程序。
090516wg1uusurzbrz9jz2.jpg
图4 模块电路板背面
090518nu6pqhhdubw5obiu.jpg
图5 手画电路图
090517xaiv474jrf44ljid.jpg
图6 灵魂电路图草稿
先到官网上找到TM1650的芯片资料:
TM1650是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用IC
特性说明:
两种显示模式( 8段×4 位 和 7 段×4 位)
支持单个按键7x4bit(28个按键)和组合按键( 4个)
8级亮度可调
段驱动电流大于25mA,位驱动电流大于150mA
高速2线串行接口( CLK,DAT)
振荡方式:内置RC振荡
内置上电复位电路
内置数据锁存电路
支持3-5.5V电源电压
抗干扰能力强
重点是引脚定义:
090517lpiwy5ac912ifu29.jpg
图7 TM1650引脚定义
090517mguy2p3afi4pi2hh.jpg
图8 引脚定义
官网也有例程,其实用起来很简单,用TM1650可以很方便的驱动四位数码管,例:
先定义不同的字节对应的显示状态:
uchar CODE[] = {0xFC,0x84,0xBA,0xAE,0xC6,0x6E,0x7E,0xA4,0xFE,0xEE,0x00};//0-9,全灭状态
显示:
TM1650_Set(0x68, CODE[0]); //第一位显示0,第2、3、4位依次为0x6A、0x6C、0x6E
TM1650_Set(0x48,0x21); //设置亮度,亮度从低到高依次为
TM1650的显示内容、亮度状态设置和获取都是通过访问设置寄存器实现的,具体就是通过I2C总线发送地址、数据,所以看看文档里关于寄存器的定义就可以实现,而TM1650的扫描按键功能通过I2C总线发送0x49命令获取,根据I2C总线发回的值判断按下的键,同时要注意,当按揭释放后,第6bit会变为0,据此判断按键释放。
key = Scan_Key();
if(key==0x47)  //key set
{
    ……//do something here
    while(Scan_Key()==0x47);
}
DS3231也是I2C总线的,网上资料非常多,这里不复述,引用封装好的函数,可以很方便的完成时间获取、设置和寄存器的访问、设置。本程序中除了用DS3231获取设置时间,还利用DS3231产生的1HZ方波对51引发外部中断,完成调整时的冒号闪烁功能以及显示内容切换(主要在月-日显示与年-周显示之间切换)。外部中断函数如下:
void int2() interrupt 10   //DS3231输出1HZ方波,下降沿更新
{
    //display time now, flash colon
    if(dspmode == 0){
        sec=!sec; //sec标识冒号的显示与隐藏,实现闪烁
    }
    //when adjust date
    else if(dspmode == 1){
        secMode++;
        secMode%=8; //secMode标示显示子模式
    }
    //display date now
    else if(dspmode == 2){
    }
    AutoLight(); //根据当前小时信息进行时钟亮度调整
}
由于模块自带只有两个按键,所以设计功能逻辑的时候还毕竟麻烦,主函数里一堆switch—case,先根据dspmode变量判断显示模式,然后根据setmode判断调整模式,当setmode为0时为该显示模式下的正常显示状态,即不进行调整,当该模式下检测到set按键则跳转到对应的设置状态,当调整模式为0时检测到按键为add,则跳转到不同的显示模式,而除此以外的调整模式下按键add为调整状态。主要涉及时间、日期、年、星期、积日的显示和设定,因而逻辑毕竟繁杂,但是不难。伪代码如下:
switch(dspmode){
    case 0://时:分模式
         switch(setmode){
          case 0:
               //显示模式
             case 1:
              //调整小时
             case 2:
              //调整分
             case 3:
             //调整秒
         }
          break;
     case 1: //月:日----年-星期模式
          switch(setmode){
               case 0:
                      //显示模式
               case 1:
               //调整年份
               case 2:
                     //调整月份
               case 3:
                     //调整日期
               case 2:
                //调整星期
          }
          break;
     case 2://日期计数模式
          //显示当前日期累计值     
          break;
}
51单片机内置时钟中断,当调整模式时闪烁调整位,代码如下:
void timer0() interrupt 1
{
     uchar flag;
     TH0=(65536-50000)/256;
     TL0=(65536-50000)%256;
     flag++;
     if(flag==5)
     {
          flag=0;
          flash=!flash;
     }
}
通过flag标示闪烁与否,闪烁速度比DS3231输出中断快以示区别。
代码总览(代码参考:http://www.pudn.com/Download/item/id/2881058.html),因为STC15LE程序存储空间只有4kb,而程序一度达到4080字节,因而主函数用了整个大的switch-case语句,毕竟重用部分少没有另设函数,所以代码看起来没那么清晰。
最终效果见图1和下图:
090710f11xex7yhmduxtdx.jpg

090710ugcm2zyp4dsp2cyw.jpg

PS:

中间遇到显示乱码和显示值跳动问题,一直没解决,后来发现是中断函数中调用了某些函数导致函数重入破坏堆栈了,后来就把中断函数中的函数全部移到主函数中就OK了。

后面又改了下程序,弄成起始日期也可以设置的,就是在第三个模式下增加了日期调整功能,又加了200行代码,差点单片机空间不够烧不进去了。主要是只有两个按键造成程序的复杂和庞大,需要代码的留言或邮箱联系,因为增加的功能有点故弄玄虚,没有贴出来的必要。。。

附录:

详细信息可以见原文:【http://www.straka.cn/blog/nixie_tube_clock/】
原文访问不畅可以在此处下载:
代码见【http://download.csdn.net/download/atp1992/10208348】

参考资料【 http://download.csdn.net/download/atp1992/10208353 】

相关帖子

酷´_>`

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:一枚软件狗,欢迎访问我的博客: www.straka.cn

17

主题

46

帖子

2

粉丝