|
自从上次发了帖子: [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的螺钉和螺栓,钻孔也是非常累人的活,尤其对一个初玩单片机的新手来说。
原本打算采用水银开关作为运动方向检测的传感器,但考虑到水银开关容易氧化,而且有玻璃打破,水银泄露的风险,考虑家中小儿的安全,换成了滚珠震动开关(代码中也付出了代价,要增加开关消抖部分)。
下面照例先上电路图吧:
呼应一下我之前的帖子,也算是一个交代:
那就是,真正从低成本的角度来说,想用8脚的STC单片机配合数码管驱动芯片并不合适,似乎配合74HC595更恰当(淘宝上才两毛多一片, 16 LED就用两片),要想编程简单些,干脆使用二手的STC89C52RC(40个管脚)更省事,
淘宝上的价格也就比STC15W104贵几毛,还省得用外围扩展电路,一片搞定。
接下来应该是代码:(虽说从摇摇棒的角度来说是不成功的,但代码对如何驱动TM1617这个3位7段或者2位8段的数码管的芯片编程还是有点帮助的,正所谓有心栽花,无心插柳)
- /*
- *版权信息: sadate
- *文件名: 摇摇棒
- *当前版本: 1.0
- *单片机型号: STC15W104
- *开发环境: Keil uVision4
- *晶震频率: 11.0592M
- *完成日期: 2016-09-08
- 功能: 驱动两路共阴8 LED组(8 * 2 = 16LED)做摇摇棒的点阵列显示,可由按键控制相关功能
- */
- #include
- #include
- #define NOP _nop_();_nop_();_nop_();_nop_();_nop_();_nop_()
- #define uchar unsigned char
- #define uint unsigned int
- #define ulint unsigned long int
- sbit direct = P3^2; //定义水银方向开关
- sbit dio = P3^3; //定义数据输入/输出通讯口
- sbit clk = P3^4; //定义时钟通讯口
- sbit stb = P3^5; //定义片选通讯口
- uchar ledlight = 0x00; //全局LED亮度定义,初始化为最低亮度
- bdata uchar showmode = 0x08; //全局显示模式定义,默认开机以最低亮度显示
- uchar showflag = 1; //全局图像是否显示的标识,初始化为显示
- uchar word_index = 0;
- uchar cyc_count = 0;
- bdata uchar keybuf[5] = { 0 }; //键盘缓冲区
- sbit Key1 = keybuf[2]^0; //Key1 减弱LED亮度
- sbit Key2 = keybuf[2]^3; //Key2 增强LED亮度
- sbit Key3 = keybuf[3]^0; //Key3 选择前一幅文本
- sbit Key4 = keybuf[3]^3; //Key4 选择后一幅文本
- sbit Key5 = keybuf[4]^0; //Key5 图像显示乒乓开关
- sbit Key6 = keybuf[4]^3; //Key6
- uchar contentid = 0; //显示内容索引ID
- ulint TimeCount =0;
- uint DelayN =0; //延时临时计数
- uint DelayTime =0; //每次延时的周期个数
- uchar code TEXT1[]={ // (16 X 16 , 新宋体 )
- 0x00,0x00,0x00,0x00,0x0F,0xF0,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0xFF,0xFF,
- 0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,/*"中",0*/
- 0x04,0x20,0x08,0x20,0x10,0x20,0x3F,0xA0,0xC0,0x20,0x04,0x20,0x04,0x20,0x08,0xFF,
- 0xFE,0x20,0x11,0x20,0x11,0x20,0x21,0x20,0x41,0x20,0x07,0x20,0x00,0x20,0x00,0x00,/*"华",1*/
- 0x00,0x01,0x00,0x02,0x00,0x04,0x00,0x08,0x00,0x30,0x00,0xC0,0x03,0x00,0xFC,0x00,
- 0x03,0x00,0x00,0xC0,0x00,0x30,0x00,0x08,0x00,0x04,0x00,0x02,0x00,0x01,0x00,0x00,/*"人",2*/
- 0x00,0x00,0x00,0x00,0x7F,0xFF,0x44,0x82,0x44,0x84,0x44,0x88,0x44,0x80,0x44,0x80,
- 0x47,0xC0,0x44,0xB0,0x44,0x88,0x44,0x84,0x7C,0x82,0x00,0x8F,0x00,0x00,0x00,0x00,/*"民",3*/
- 0x00,0x00,0x00,0x20,0x08,0x21,0x08,0x22,0x08,0x24,0xFF,0xE8,0x08,0x20,0x08,0x20,
- 0x08,0x20,0x08,0x20,0xFF,0xE8,0x08,0x24,0x08,0x22,0x08,0x21,0x00,0x20,0x00,0x00,/*"共",4*/
- 0x04,0x08,0x24,0x10,0x24,0x60,0x25,0x80,0x7F,0xFF,0xC4,0x80,0x44,0x60,0x04,0x00,
- 0x00,0x00,0x1F,0xFC,0x10,0x08,0x10,0x08,0x10,0x08,0x1F,0xFC,0x00,0x00,0x00,0x00,/*"和",5*/
- 0x00,0x00,0x7F,0xFF,0x40,0x02,0x48,0x12,0x49,0x12,0x49,0x12,0x49,0x12,0x4F,0xF2,
- 0x49,0x12,0x49,0x52,0x49,0x32,0x48,0x12,0x40,0x02,0x7F,0xFF,0x00,0x00,0x00,0x00,/*"国",6*/
- };
- uchar code TEXT2[]={ // (16 X 16 , 新宋体 )
- 0x20,0x00,0x27,0xFF,0x24,0x00,0x24,0x10,0x26,0x90,0x25,0x90,0x24,0x90,0xFC,0xFE,
- 0x24,0x90,0x25,0x90,0x26,0x90,0x24,0x12,0x24,0x01,0x27,0xFE,0x20,0x00,0x00,0x00,/*"南",0*/
- 0x20,0x00,0x20,0x02,0x20,0x04,0x27,0xD8,0x24,0x40,0x24,0x42,0xA4,0x41,0x64,0x7E,
- 0x24,0x40,0x24,0x40,0x24,0x40,0x27,0xD0,0x20,0x08,0x20,0x06,0x20,0x00,0x00,0x00,/*"京",1*/
- };
- /*********************************
- 延时函数
- 功能: 1ms延时
- **********************************/
- void delay_ms(uchar cyc)
- {
- uchar i, j, k;
- for (k = 1; k <= cyc; k++)
- {
- _nop_();
- _nop_();
- _nop_();
- i = 11;
- j = 190;
- do
- {
- while (--j);
- } while (--i);
- }
- }
- /*********************************
- 功能: TM1617写数据
- **********************************/
- void send_8bit(uchar dat) //发送8位数据,从低位开始
- {
- uchar i;
- for (i = 0; i < 8; i++)
- {
- clk = 0;
- if (dat & 0x01)
- {
- dio = 1;
- }
- else
- {
- dio = 0;
- }
- _nop_();
- _nop_();
- _nop_();
- clk = 1;
- dat >>= 1;
- }
- clk = 0;
- dio = 0;
- }
- /******************发送控制命令***********************/
- void send_command(uchar com) //发送命令字节
- {
- stb = 1; //stb置高
- NOP;
- stb = 0; //stb置低
- send_8bit(com); //发送8bit数据
- }
- /*********************************
- TM1617控制指令
- 功能: 驱动LED显示一列16个点)
- **********************************/
- void dispcol(uchar highcol, uchar lowcol)
- {
- send_command(0x00); //显示模式设置,设置为8段2位的显示模式(8 x 2 = 16LED)
- send_command(0x40); //写数据到显示寄存器,采用地址自动加一
- send_command(0xc0); //显示寄存器的00H单元开始
- //给显示寄存器送数据(一列16bit,拆分为4个字节发送)
- send_8bit((lowcol & 0xf0)); //地址0xC0
- send_8bit((lowcol & 0x0f)); //地址0xC1
- send_8bit((highcol & 0xf0)); //地址0xC2
- send_8bit((highcol & 0x0f)); //地址0xC3
- send_command((0x80 | showmode)); //显示控制参数,开关显示用位4,亮度可以通过改变位3~0
- stb = 1;
- }
- void showtext(uchar code *text, uchar len)//显示text中的所有字符
- {
- uchar i;
- uint offset;
- offset = word_index * 32;
- if (offset >= len)
- {
- word_index = 0;
- offset = 0;
- }
- DelayN = DelayTime / (100 * 40);
- for (i = offset; i < offset + 32; i += 2)
- {
- dispcol(text[ i], text[i + 1]);
- delay_ms(DelayN); //列显示之间的延时,可控制字符显示宽度
- }
- if (cyc_count < 3)
- {
- cyc_count++;
- }
- else
- {
- cyc_count = 0;
- word_index++;
- }
- }
- void display(unsigned char index) //根据ID选择要显示的文本内容
- {
- switch (index)
- {
- case 0:
- {
- showtext(TEXT1, sizeof(TEXT1));
- }
- break;
- case 1:
- {
- showtext(TEXT2, sizeof(TEXT2));
- }
- break;
- //default:
- //{
- // display_word(TEXT1);
- //}
- }
- }
- /*********************************
- 功能:读取TM1617按键数据到键盘缓冲区
- **********************************/
- void readkey()
- {
- uchar i, j;
- send_command(0x42); //送读按键命令(42H)
- dio = 1;
- for (i = 0; i < 5; i++)
- { //读TM1617的5BYTE按键数据到键盘缓冲区
- for (j = 0; j < 8; j++)
- {
- clk = 0;
- keybuf[ i] = keybuf[ i] >> 1;
- clk = 1;
- if (dio == 1)
- {
- keybuf[ i] = keybuf[ i] | 0x80;
- }
- NOP;
- }
- NOP;
- NOP;
- }
- clk = 0;
- dio = 0;
- stb = 1;
- }
- void exint0() interrupt 0 //INT0中断入口
- {
- EX0 = 0;
- if (direct == 1) //INT0口的状态, INT0=0(下降沿); INT0=1(上升沿)
- {
- if (showflag == 1)
- {
- delay_ms(15);
- if (direct == 1)
- {
- delay_ms(20);
- DelayTime=TimeCount;
- TimeCount=0; //延时周期计数清零
- display(contentid); //根据contentid给显示寄存器送相应的显示数据
- }
- }
- }
- else
- {
- dispcol(0x00, 0x00); //反向挥动时消影,立即关闭显示
- }
- EX0 = 1;
- }
- void timer0() interrupt 1 //定时器0中断子程序
- {
- TimeCount++;
- }
- /*********************************
- 主函数
- **********************************/
- void main()
- {
- dispcol(0x00, 0x00); //初始化显示寄存器
- direct = 1;
- IT0 = 0; //设置INT0的中断类型 (1:仅下降沿 0:上升沿和下降沿)
- EX0 = 1; //使能INT0中断
- IP = 0x02; //设置中断优先级
- AUXR |= 0x80; //定时器时钟1T模式
- TMOD = 0x02; //定时器0方式2,8位重装载
- TH0 = 0x80; //设定定时器初值
- TL0 = 0x80;
- EA = 1; //开放中断
- ET0 = 1; //开放定时器1中断
- TF0 = 0;
- TR0 = 1; //启动定时器0,开始计时*/
- while(1) //循环
- {
- readkey(); //读键盘
- if ((Key1 == 1) && (ledlight < 7))
- {
- ledlight++; //按Key1表示升高LED亮度
- showmode = (showmode & 0xf8) | ledlight;
- }
- if ((Key2 == 1) && (ledlight > 0))
- {
- ledlight--; //按Key2表示降低LED亮度
- showmode = (showmode & 0xf8) | ledlight;
- }
- if (Key3 == 1) //按Key3表示显示前一幅文本
- {
- if (contentid > 0)
- {
- contentid--;
- }
- else
- {
- contentid = 1;
- }
- }
- if (Key4 == 1) //按Key4表示显示后一幅文本
- {
- if (contentid < 1)
- {
- contentid++;
- }
- else
- {
- contentid = 0;
- }
- }
- if (Key5 == 1) //Key5是控制文本是否显示的乒乓开关
- {
- if (showflag == 1)
- {
- showflag = 0;
- showmode = ledlight & 0x07; //立即关闭显示
- dispcol(0x00, 0x00);
- }
- else
- {
- showflag = 1;
- showmode = ledlight | 0x08; //打开显示
- }
- }
- }
- }
复制代码
|
|