找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10628|回复: 0
收起左侧

一次不算成功的16 LED摇摇棒制作经历分享

[复制链接]
ID:134687 发表于 2016-10-19 17:38 | 显示全部楼层 |阅读模式
       自从上次发了帖子: [C51]低成本制作32个LED的摇摇棒,用stc15w104可能么?是不是采用tm1628比74hc595要更好? 之后,一直琢磨着本着自己的狗粮自己吃的原则,自己提出的问题就自己DIY一把,
为了简化制作,就偷懒没有采用32 LED的方案,转而采用了简化版的16 LED的方案(采用天微的TM1617数码管驱动芯片 【 支持3位7段或者2位8段共阴数码管显示,同时还支持6个独立按键的扫描, 淘宝上几毛钱一片】),
实践证明,我当时写帖子时,坛友傻羊羊devcang 提的意见非常有先见之明,TM1617这类数码管驱动芯片的刷新率是不够高的,所以导致制作出来的摇摇棒无法一次同时显示多个字符,只能逐个字符地显示,
因此称这次的摇摇棒制作是不够成功的(TM1617的说明书里写的是显示的周期在4ms到20ms之间,本以为是够的,但实践证明显示的刷新不够高,对于数码管也许是足够了,但对于摇摇棒多列显示还是远远不够),
但从积极地一面来看,本次制作历尽艰辛,但锻炼了自己狗屎的焊接技术,同时也加强了自己对数码管驱动编程的学习(感谢张工的无私指导,没有他,我几乎一直怀疑自己的电路是否焊接有问题)

       这次的摇摇棒采用了16个蓝色高亮LED,因此开始打算采用一节5号电池的计划破产了(空载时有5.02V,但一带负载就不行了,降到了3.2V,无奈只好追加了一节5号电池,采用淘宝上1.4元的升压模块0.9V~5V升5V,
我拆掉了模块原本自带的USB母座,这样才好放置到洞洞板上焊接),TM1617芯片是SOP16的贴片封装,无法焊接到洞洞板上,因此用了一片PCB转接板加排针。切割洞洞板虽说用上了锋利的勾刀,但依然累得我半死。
板子之间的拼接用了M3的螺钉和螺栓,钻孔也是非常累人的活,尤其对一个初玩单片机的新手来说。

       原本打算采用水银开关作为运动方向检测的传感器,但考虑到水银开关容易氧化,而且有玻璃打破,水银泄露的风险,考虑家中小儿的安全,换成了滚珠震动开关(代码中也付出了代价,要增加开关消抖部分)。
       下面照例先上电路图吧:
108_1540354_8cbe8609b97d6dc.png




       呼应一下我之前的帖子,也算是一个交代:
       那就是,真正从低成本的角度来说,想用8脚的STC单片机配合数码管驱动芯片并不合适,似乎配合74HC595更恰当(淘宝上才两毛多一片, 16 LED就用两片),要想编程简单些,干脆使用二手的STC89C52RC(40个管脚)更省事,
淘宝上的价格也就比STC15W104贵几毛,还省得用外围扩展电路,一片搞定。

        接下来应该是代码:(虽说从摇摇棒的角度来说是不成功的,但代码对如何驱动TM1617这个3位7段或者2位8段的数码管的芯片编程还是有点帮助的,正所谓有心栽花,无心插柳)

  1. /*
  2. *版权信息:   sadate
  3. *文件名:      摇摇棒
  4. *当前版本:   1.0
  5. *单片机型号: STC15W104
  6. *开发环境:   Keil uVision4
  7. *晶震频率:   11.0592M
  8. *完成日期:   2016-09-08
  9. 功能:        驱动两路共阴8 LED组(8 * 2 = 16LED)做摇摇棒的点阵列显示,可由按键控制相关功能
  10. */
  11. #include
  12. #include




  13. #define NOP    _nop_();_nop_();_nop_();_nop_();_nop_();_nop_()
  14. #define uchar  unsigned char
  15. #define uint   unsigned int
  16. #define ulint  unsigned long int




  17. sbit  direct   = P3^2;                 //定义水银方向开关
  18. sbit  dio      = P3^3;                 //定义数据输入/输出通讯口
  19. sbit  clk      = P3^4;                 //定义时钟通讯口
  20. sbit  stb      = P3^5;                 //定义片选通讯口




  21. uchar ledlight       = 0x00;           //全局LED亮度定义,初始化为最低亮度
  22. bdata uchar showmode = 0x08;           //全局显示模式定义,默认开机以最低亮度显示
  23. uchar showflag       = 1;              //全局图像是否显示的标识,初始化为显示                  
  24. uchar word_index     = 0;
  25. uchar cyc_count      = 0;




  26. bdata uchar keybuf[5] = { 0 };         //键盘缓冲区
  27. sbit  Key1     = keybuf[2]^0;          //Key1 减弱LED亮度
  28. sbit  Key2     = keybuf[2]^3;          //Key2 增强LED亮度
  29. sbit  Key3     = keybuf[3]^0;          //Key3 选择前一幅文本
  30. sbit  Key4     = keybuf[3]^3;          //Key4 选择后一幅文本
  31. sbit  Key5     = keybuf[4]^0;          //Key5 图像显示乒乓开关
  32. sbit  Key6     = keybuf[4]^3;          //Key6




  33. uchar contentid = 0;                   //显示内容索引ID




  34. ulint   TimeCount =0;
  35. uint     DelayN    =0;        //延时临时计数
  36. uint    DelayTime =0;        //每次延时的周期个数




  37. uchar code TEXT1[]={                   // (16 X 16 , 新宋体 )
  38.         0x00,0x00,0x00,0x00,0x0F,0xF0,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0xFF,0xFF,
  39.         0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,/*"中",0*/

  40.         0x04,0x20,0x08,0x20,0x10,0x20,0x3F,0xA0,0xC0,0x20,0x04,0x20,0x04,0x20,0x08,0xFF,
  41.         0xFE,0x20,0x11,0x20,0x11,0x20,0x21,0x20,0x41,0x20,0x07,0x20,0x00,0x20,0x00,0x00,/*"华",1*/

  42.         0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x30,0x00,0xC0,0x03,0x00,0xFC,0x00,
  43.         0x03,0x00,0x00,0xC0,0x00,0x30,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0x01,0x00,0x00,/*"人",2*/

  44.         0x00,0x00,0x00,0x00,0x7F,0xFF,0x44,0x82,0x44,0x84,0x44,0x88,0x44,0x80,0x44,0x80,
  45.         0x47,0xC0,0x44,0xB0,0x44,0x88,0x44,0x84,0x7C,0x82,0x00,0x8F,0x00,0x00,0x00,0x00,/*"民",3*/

  46.         0x00,0x00,0x00,0x20,0x08,0x21,0x08,0x22,0x08,0x24,0xFF,0xE8,0x08,0x20,0x08,0x20,
  47.         0x08,0x20,0x08,0x20,0xFF,0xE8,0x08,0x24,0x08,0x22,0x08,0x21,0x00,0x20,0x00,0x00,/*"共",4*/

  48.         0x04,0x08,0x24,0x10,0x24,0x60,0x25,0x80,0x7F,0xFF,0xC4,0x80,0x44,0x60,0x04,0x00,
  49.         0x00,0x00,0x1F,0xFC,0x10,0x08,0x10,0x08,0x10,0x08,0x1F,0xFC,0x00,0x00,0x00,0x00,/*"和",5*/

  50.         0x00,0x00,0x7F,0xFF,0x40,0x02,0x48,0x12,0x49,0x12,0x49,0x12,0x49,0x12,0x4F,0xF2,
  51.         0x49,0x12,0x49,0x52,0x49,0x32,0x48,0x12,0x40,0x02,0x7F,0xFF,0x00,0x00,0x00,0x00,/*"国",6*/
  52. };




  53. uchar code TEXT2[]={                   // (16 X 16 , 新宋体 )
  54.         0x20,0x00,0x27,0xFF,0x24,0x00,0x24,0x10,0x26,0x90,0x25,0x90,0x24,0x90,0xFC,0xFE,
  55.         0x24,0x90,0x25,0x90,0x26,0x90,0x24,0x12,0x24,0x01,0x27,0xFE,0x20,0x00,0x00,0x00,/*"南",0*/

  56.         0x20,0x00,0x20,0x02,0x20,0x04,0x27,0xD8,0x24,0x40,0x24,0x42,0xA4,0x41,0x64,0x7E,
  57.         0x24,0x40,0x24,0x40,0x24,0x40,0x27,0xD0,0x20,0x08,0x20,0x06,0x20,0x00,0x00,0x00,/*"京",1*/
  58. };




  59. /*********************************
  60.     延时函数
  61. 功能: 1ms延时
  62. **********************************/
  63. void delay_ms(uchar cyc)
  64. {
  65.     uchar i, j, k;
  66.     for (k = 1; k <= cyc; k++)
  67.     {
  68.         _nop_();
  69.         _nop_();
  70.         _nop_();
  71.         i = 11;
  72.         j = 190;
  73.         do
  74.         {
  75.             while (--j);
  76.         } while (--i);
  77.     }
  78. }




  79. /*********************************   
  80. 功能: TM1617写数据
  81. **********************************/
  82. void send_8bit(uchar dat)              //发送8位数据,从低位开始
  83. {
  84.   uchar i;




  85.   for (i = 0; i < 8; i++)
  86.   {   
  87.         clk = 0;

  88.       if (dat & 0x01)
  89.       {
  90.           dio = 1;
  91.       }
  92.       else         
  93.       {
  94.           dio = 0;
  95.       }

  96.       _nop_();
  97.       _nop_();
  98.       _nop_();
  99.       clk = 1;     
  100.       dat >>= 1;     
  101.   }

  102.   clk = 0;
  103.   dio = 0;
  104. }




  105. /******************发送控制命令***********************/
  106. void send_command(uchar com)           //发送命令字节
  107. {
  108.     stb = 1;                           //stb置高
  109.     NOP;
  110.     stb = 0;                           //stb置低
  111.     send_8bit(com);                    //发送8bit数据
  112. }




  113. /*********************************
  114.     TM1617控制指令
  115. 功能: 驱动LED显示一列16个点)
  116. **********************************/
  117. void dispcol(uchar highcol, uchar lowcol)
  118. {   
  119.     send_command(0x00);                //显示模式设置,设置为8段2位的显示模式(8 x 2 = 16LED)
  120.     send_command(0x40);                //写数据到显示寄存器,采用地址自动加一
  121.     send_command(0xc0);                //显示寄存器的00H单元开始

  122.                                        //给显示寄存器送数据(一列16bit,拆分为4个字节发送)
  123.     send_8bit((lowcol  & 0xf0));       //地址0xC0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
  124.     send_8bit((lowcol  & 0x0f));       //地址0xC1
  125.     send_8bit((highcol & 0xf0));       //地址0xC2   
  126.     send_8bit((highcol & 0x0f));       //地址0xC3





  127.     send_command((0x80 | showmode));   //显示控制参数,开关显示用位4,亮度可以通过改变位3~0
  128.     stb = 1;
  129. }




  130. void showtext(uchar code *text, uchar len)//显示text中的所有字符
  131. {
  132.     uchar i;
  133.     uint  offset;




  134.     offset =  word_index * 32;

  135.     if (offset >= len)
  136.     {
  137.         word_index = 0;
  138.         offset = 0;
  139.     }

  140.     DelayN = DelayTime / (100 * 40);
  141.     for (i = offset; i < offset + 32; i += 2)
  142.     {
  143.         dispcol(text[ i], text[i + 1]);
  144.         delay_ms(DelayN);                  //列显示之间的延时,可控制字符显示宽度
  145.     }




  146.     if (cyc_count < 3)
  147.     {
  148.         cyc_count++;
  149.     }
  150.     else
  151.     {
  152.         cyc_count = 0;
  153.         word_index++;
  154.     }
  155. }




  156. void display(unsigned char index)      //根据ID选择要显示的文本内容
  157. {
  158.     switch (index)  
  159.     {        
  160.         case 0:   
  161.         {                     
  162.             showtext(TEXT1, sizeof(TEXT1));
  163.         }
  164.         break;

  165.         case 1:   
  166.         {
  167.             showtext(TEXT2, sizeof(TEXT2));
  168.         }
  169.         break;

  170.         //default:
  171.         //{
  172.         //    display_word(TEXT1);
  173.         //}

  174.     }
  175. }




  176. /*********************************  
  177. 功能:读取TM1617按键数据到键盘缓冲区
  178. **********************************/
  179. void readkey()
  180. {
  181.     uchar i, j;

  182.     send_command(0x42);                //送读按键命令(42H)
  183.     dio = 1;




  184.     for (i = 0; i < 5; i++)
  185.     {                                  //读TM1617的5BYTE按键数据到键盘缓冲区
  186.         for (j = 0; j < 8; j++)
  187.         {
  188.             clk = 0;
  189.             keybuf[ i] = keybuf[ i] >> 1;
  190.             clk = 1;
  191.             if (dio == 1)
  192.             {
  193.                 keybuf[ i] = keybuf[ i] | 0x80;
  194.             }
  195.             NOP;
  196.         }
  197.         NOP;
  198.         NOP;
  199.     }




  200.     clk = 0;
  201.     dio = 0;
  202.     stb = 1;
  203. }




  204. void exint0() interrupt 0              //INT0中断入口
  205. {               
  206.     EX0 = 0;
  207.     if (direct == 1)                   //INT0口的状态, INT0=0(下降沿); INT0=1(上升沿)
  208.     {
  209.         if (showflag == 1)
  210.         {
  211.             delay_ms(15);
  212.             if (direct == 1)
  213.             {
  214.                 delay_ms(20);
  215.                 DelayTime=TimeCount;   
  216.                 TimeCount=0;           //延时周期计数清零         
  217.                 display(contentid);    //根据contentid给显示寄存器送相应的显示数据
  218.             }
  219.         }
  220.     }
  221.     else
  222.     {                  
  223.         dispcol(0x00, 0x00);           //反向挥动时消影,立即关闭显示
  224.     }
  225.     EX0 = 1;
  226. }




  227. void timer0() interrupt 1        //定时器0中断子程序
  228. {
  229.     TimeCount++;
  230. }




  231. /*********************************
  232.     主函数
  233. **********************************/
  234. void main()
  235. {
  236.     dispcol(0x00, 0x00);               //初始化显示寄存器




  237.     direct = 1;
  238.     IT0    = 0;                        //设置INT0的中断类型 (1:仅下降沿 0:上升沿和下降沿)
  239.     EX0    = 1;                        //使能INT0中断
  240.     IP     = 0x02;    //设置中断优先级
  241.     AUXR  |= 0x80;  //定时器时钟1T模式
  242.     TMOD   = 0x02;    //定时器0方式2,8位重装载
  243.     TH0    = 0x80;    //设定定时器初值
  244.     TL0    = 0x80;           
  245.     EA     = 1;        //开放中断
  246.     ET0    = 1;    //开放定时器1中断
  247.     TF0    = 0;
  248.     TR0    = 1;    //启动定时器0,开始计时*/




  249.     while(1)                           //循环
  250.     {
  251.         readkey();                     //读键盘

  252.         if ((Key1 == 1) && (ledlight < 7))
  253.         {
  254.             ledlight++;                //按Key1表示升高LED亮度
  255.             showmode = (showmode & 0xf8) | ledlight;
  256.         }

  257.         if ((Key2 == 1) && (ledlight > 0))
  258.         {
  259.             ledlight--;                //按Key2表示降低LED亮度
  260.             showmode = (showmode & 0xf8) | ledlight;
  261.         }




  262.         if (Key3 == 1)                 //按Key3表示显示前一幅文本
  263.         {
  264.             if (contentid > 0)
  265.             {
  266.                contentid--;
  267.             }
  268.             else
  269.             {
  270.                contentid = 1;
  271.             }
  272.         }

  273.         if (Key4 == 1)                 //按Key4表示显示后一幅文本
  274.         {
  275.             if (contentid < 1)
  276.             {
  277.                contentid++;
  278.             }
  279.             else
  280.             {
  281.                 contentid = 0;
  282.             }
  283.         }




  284.         if (Key5 == 1)                 //Key5是控制文本是否显示的乒乓开关
  285.         {                    
  286.             if (showflag == 1)
  287.             {        
  288.                 showflag = 0;
  289.                 showmode = ledlight & 0x07;   //立即关闭显示
  290.                 dispcol(0x00, 0x00);
  291.             }
  292.             else
  293.             {
  294.                 showflag = 1;
  295.                 showmode = ledlight | 0x08;   //打开显示
  296.             }
  297.         }        
  298.     }
  299. }
复制代码




108_1540354_39a135b6acfabe3.jpg
108_1540354_b073779c4003aa1.jpg
108_1540354_b61a72fcd0b2ace.jpg
108_1540354_1c4d816b403defc.jpg
108_1540354_145e0cb03437184.jpg
108_1540354_8bb4204b6089095.jpg
108_1540354_e9a0f8b80cad4f7.jpg
108_1540354_b8f362f96946b8a.jpg
108_1540354_76c2429a9bcfa4b.jpg
108_1540354_d6d650301056814.jpg 108_1540354_e5f9d9ec0ccaa1d.jpg




108_1540354_4229ec07650645f.jpg



TM1617_ V1.2.pdf

639.9 KB, 下载次数: 6, 下载积分: 黑币 -5

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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