转自我的单片机博客:http://sincos.in/
先看看效果:
这段时间一直在折腾单片机的显示设备,今天折腾到了点阵LED。板子上配的是8X8的点阵LED,不过学会了8X8的之后更大的点阵LED也可以套用这个模式进行编程啦。
Y1到Y8就不多说了,D24和D25控制一个8 位串入、并出移位寄存器,也就是74HC164,这个东西的作用一开始我不明白,后来自己做了几个小实验之后就明白是怎么回事了。资料中如是说:数据通过两个输入端(DSA 或 DSB)之一串行输入;任一输入端可以用作高电平使能端,控制另一输入端的数据输入。两个输入端或者连接在一起,或者把不用的输入端接高电平,一定不要悬空。时钟 (CP) 每次由低变高时,数据右移一位,输入到 Q0, Q0 是两个数据输入端(DSA 和 DSB)的逻辑与,它将上升时钟沿之前保持一个建立时间的长度。
按照图中的接法,DSA和DSB的逻辑与,也就是D25本身。而它的输出Q0~Q7就是一个队列,输出这样一个8位二进制数 [Q7Q6Q5Q4Q3Q2Q1Q0],Q0这端是新值进入的地方,每进入一个新元素,队列整体左移,原来的Q6的值移到Q7的位置,依此类推,新插入的值就是新的Q0。那输入的是什么值呢,就是DSA和DSB的逻辑与,在这里也就是D25。 那知道了插入的顺序和结果,那怎样控制呢?就是让CP从0变到1,也就是D24从0变到1。
模拟一下:Q0到Q7初始值都是0,那么原来的输出就是0000,0000
D25 | D24 | 输出 |
1 | 0->1 | 0000,0001 |
0 | 0->1 | 0000,0010 |
1 | 0->1 | 0000,0101 |
1 | 0->1 | 0000,1011 |
这输出的8位,每一位对应图3中的某一列,假如Y1到Y8输入的都是低电平,而74HC164输出的是0000,1011,那么这时点阵LED中会有3列是全亮的,这么干是不行的,不想办法的话又会遇到8个数码管一起亮的那种情况。用动态扫描!这里扫描的方法是:
(一)P0输入0xff
(二) 74HC164 输出清零
(三) 将1移到指定的列
(四)输入这列对应的P0并延迟一小段时间,让LED亮度高点,继续第一步
要计算出8X8的所有P0还真不是件容易的事,有种软件叫字模软件,能让你花的图形输出成16进制数。有了这个就大大减少了计算这些数值的时间。
额,突然发现也没什么好讲的了,完整源代码如下:
#include <reg52.h> #include <intrins.h> typedef unsigned char uint8; typedef unsigned int uint16; sbit D24 = P2^4; sbit D25 = P2^5; sbit U1 = P2^6; sbit U2 = P2^7; uint8 counter = 0; uint8 offset = 0; code uint8 table[]={ 0xFF,0xC3,0xBD,0xBD,0xAD,0x9D,0x83,0x7F, //Q 0xFF,0xFF, 0xFF,0x81,0x81,0xE7,0xE7,0xE7,0xE7,0xFF, //T 0xFF,0xFF, 0xC1,0xC1,0xF9,0xF9,0xC1,0xC1,0xF9,0xF9, //F 0xFF,0xFF, 0x81,0xC3,0xE7,0xE7,0xE7,0xE7,0xC3,0x81, 0xFF,0xFF, //插入2行空行 0x99,0x0,0x0,0x0,0x81,0xC3,0xE7,0xFF, 0xFF,0xFF, 0xFF,0x99,0xDB,0xDB,0xDB,0xDB,0xE7,0xFF, 0xFF,0xFF, }; //分别是 I和爱心,还有U三个图形 void init_timer0() { TH0 = 0xB1; TL0 = 0xE0; TR0 = 1; TMOD |= 0x01; //计时模式选01模式 } void init_interrupt() { EA = 1; //中断总开关 ET0 = 1; //定时器1中断 } delay(uint8 t) { while (t--) {;} } void init_74hc164() { uint8 i =0; D25 = 0; for(;i<8;i++) { D24 = 0; D24 = 1; } } void refresh_led(uint8 offset) { int i = 0; int j = 0; init_74hc164(); //把74HC164里的高电平全清掉。 for(;i<8;i++) { P0 = 0xff; //消隐 U1 = 1; U1 = 0; init_74hc164(); D25 = 1; for(j = 0; j<=i; j++) //把高电平定位到想要的位置 { D24 = 0; D24 = 1; D25 = 0; } P0 = table[offset++]; U1 = 1; U1 = 0; delay(50); if(offset == 60) { offset = 0; } } } void main(void) { P0 = 0xff; U2 = 1; U2 = 0; P0 = 0xff; D25 = 1; P0 =0xff; U1 = 1; U1 = 0; P0 = 0xff; init_timer0(); init_interrupt(); init_74hc164(); while(1) { refresh_led(offset); } } void timer0_interrupt() interrupt 1 { //每次计时是20ms,达到20ms后计时器0的溢出位位1,进行软件清零和计时器初始化. counter++; TF0=0; TH0 = 0xB1; //12MHZ的晶振算出来是从45536开始计时,十六进制就是 0xB1E0 TL0 = 0xE0; //高位取0xB1,低位取0xE0 P0 = 0xff; U1 = 1; U1 = 0; if(counter == 10) { counter = 0; offset++; if(offset == 60) { offset = 0; } } }
用户1519616 2011-9-22 08:35
用户388269 2011-9-8 23:51
xucun915_925777961 2011-9-8 13:14
用户1609127 2011-9-8 12:54