2.7 I/O口控制LED点阵应用实例
LED点阵可以用于显示字母、数字、汉字及符号。在本实例中,以ATmega128作为主控制器来驱动LED点阵显示电路,并使用8片8×8LED串联显示。
2.7.1 LED点阵基础知识
把多个LED封装在一起就构成了一个LED点阵显示模块,其中最典型的是8×8LED矩阵,共64个LED。其结构为每一行中的LED的正极负极连在一块组成矩阵。LED点阵显示模块分共阳极和共阴极两种,在一个共阳极LED点阵模块里,把每一行中LED的阳极连在一起,每一列中LED的阴极连在一起。共阴极模块则正好相反,共阳极和共阴极模块的原理图如图2-19所示。
图2-19 LED模块内部
一个典型的8×8单色点阵模块有16个引脚,8行8列。也可以使用双色模块(如红色和绿色)甚至全色RGB(红色、绿色、蓝色)模块——该模块常用于大型电视墙上。双色或全色模块在每个像素点上有两个或三个LED,它们非常小并且距离非常近。
通过改变每个像素点上红、绿、蓝的组合模式及亮度可以得到任何颜色。
所有行或列的引线连在一起的原因是最小化所需要引脚的数量。如果不采用这种方法,一个单色8×8点阵模块就要用到65个引脚,每一个LED需要一个引脚加上一个共阴极或共阳极的引脚,而使用把行和列连起来的方法只需要16个引脚。
然而,问题是如果想点亮一个特定位置上的特定的LED,例如,有一个共阳极模块,希望点亮X和Y位置为5和3(第5列第3行)的LED,那么需要给第3行的阳极通电,第5列的阴极接地。
第5列第3行的LED将被点亮(如图2-20所示)。
图2-20 第5列第3行的LED被点亮
如果还想同时点亮第3列第6行的LED,因此要给第6行施加电流,第3列引脚连到地。第3列第6行的LED将被点亮,但是因为第3行、第5列也施加了电流,所以第3列第6行和第5列第6行的LED也将被点亮(如图2-21所示)。
图2-21 第3列第6行LED和第5列第3行同时被点亮
也就是给第3行和第6行LED供电,第3列和第5列接地。所以在不关掉希望点亮的LED的前提下,不能关闭不希望点亮的LED。很明显,没有办法只点亮所需要的LED而不点亮不希望点亮的LED,因为它们的行列线连在一起。
2.7.2 CD4511芯片简介
CD4514是4位锁存/4-16线译码器。CD4514由构成一个4位频闪锁存器和一个4-16线解码器构成。CD4514抑制控制允许数据或频闪输入时,所有输出要为0状态。
(1)CD4514引脚 CD4514引脚图如图2-22所示。引脚功能如表2-14所示。
图2-22 CD4514引脚图
表2-14 CD4514引脚功能说明
(2)CD4514的真值表 如表2-15所示。
表2-15 CD4514的真值表
注:1=高电平;0=低电平;×=随意。
(3)CD4514特性
①CD4514选择高电平输出。
②选通输入锁存。
③抑制控制。
④在20V时,100%测试静态电流。
⑤在18V、全温度范围时最大输入电流为1μA,在18V,+25℃时,电流为100nA。
2.7.3 硬件设计
如图2-23所示是本实例的硬件框图。从图中可以看出,采用ATmega128来驱动LED显示,CD4514作为编译码芯片使用,在显示器部分,采用8片8×8LED串联显示,并可进行扩展用来一次性显示更多内容。具体硬件电路图如图2-24所示。
图2-23 硬件框图
图2-24 硬件连接图
2.7.4 程序设计
软件程序流程如图2-25所示。
图2-25 程序流程图
具体的程序代码如下:
# define LED_DATA-LOW PORTA # define LED_DDR-LOW DDRA # define LED_DATA-HIGH PORTB # define LED_DDR-HIGH DDRB # define LED_SCAN-DATA PORTC # define LED_SCAN-DDR DDRC # define uchar unsigned char # define uint unsigned int //缓存大 小,对应 LED解的大小 # define buffer_long 64 //定义字模数 据数组的大小,即所存字的个数 # define gb16_table_long 62 /*利用定时器 1定时扫描 LED屏 */ /*定时参数对显示效果影响很大 */ # define T1_TIME_H 0xe7 # define T1_TIME_L 0x50 enum direction(right,left)dit_f; uchar display_buffer[buffer_long]; /************************LED屏初始化 *******************************/ viod led_initial(viod) { uchar i; //显示缓冲区初始化 for (i= 0;i< buffer_long;i+ + ) diplay_buffer[i]= 0x00; //端口初始化 LED_DDR_LOW= 0xff; LED_DDR_HIGH= 0xff; LED_SCAN_DDR= 0xff; //移动方向 dir_f= left; //t0 initial CL10://关中断 TCCR1B= 0xe0;//停止 TCNT1H= T1_TIME_H;//开始 TCNT1L= T1_TIME_L; OCR1AH= 0x01; OCR1AL= 0xF4; OCR1BH= 0x01; OCR1BL= 0xF4; ICR1H= 0x01; ICR1L= 0xF4; TCCR1A= 0x00; TCCR1B= 0x02;//开始定时 MCUCR= 0x00; GICR= 0x00; TIMSK= 0x04;//定时器中断源 SEI0;//开中断 } /*********************字符串输出子程序*******************************/ void print_char(char*p) { uchar tab_n,j,i= 0 int k; uchar d0,d1; while(p[i]> 0) { if(p[i]> = 128)//如果是汉字 /* 查找移位输出 */ for(j= 0;j< = gb16_table_long;j+ + ) { if (dit_f= = left)//如果字向左移动就顺序读字模 for(k= 0;k< 32;k+ + ) { d0_gb_16[j].mask[k]; k+ + ; d1= gb_16[j].mask[k]; move_to_buffer(d0,d1); delay(1); } else//如果字向右移动就逆序读字模 for(k= 3;k> = 0;k- - ) { d1= gb_16[j].mask[k]; K--; d0= gb_16[j].mask[k]; move_to_buffer(d0,d1); delay(1); } break;//找到了就退出循环 } /* 字库没有的字,则输出空白0x00 */ if(j> b16_table_long)// for(k= 0;k< 16;k+ + ) { d0= 0x00; d1= 0x00; move_to_buffer(d0,d1); delay(1); } i+ 2; } else //如果是字符 { j= p[i]_32; if(dir_f= = left) for(k= 0;k< 16;k+ + ) { d0= ASC_MSK[(j*16)+ k]; k+ + ; d1= ASC_MSK[(j+ 16)+ k]; move_to_buffer(d0,d1); delay(1); } else for(k= 15;k> 0;k- - ) k- - ; d0= ASC_MSK[(j+ 16)+ k]; move_to_bufer(d0,d1); delay(1); } i+ + ; } } } /***************************数据移入缓存***************************/ /*d0移入数据高8位,d1称入数据低8位*/ void move_to_buffer(uchar d0,uchar d1) { uchar i; if(dir_f= = right)//判断移动方向 { for(i= 0;i< (buffer_long_2);i+ + ) { display_buffer[buffer_long-1-i]= display_buffer[buffer_long-1-i-2]; } display_buffer[0]= d0; display_buffer[1]= d1; } else { for(i= 0;i<(buffer_long-2);i+ + ) { display_buffer[i]= display_buffer[i+ 2] } display_buffer[buffer_long- 2]= d0; display_buffer[buffer_long- 1]= d1; } } /*************************显示数据扫描********************************/ # pragme interrupt_handler scan_led:9 Void scan_led(viod) { Uchar buf_c,scan_c= 0; TCNT1H= T1_TIME_H;//重新装载计数器高位 TCNT1L= T1_TIME_L;//计数器低位 for(buf_c= 0;buf_c< buffer_long( { LED_DATA_HIGH= display_buffer[buf_c]; buf_c+ + ; LED_DATA_LOW= display_buffer[buf_c]; buf_c+ + ; LED_SCAN_DATA= scan_c; delay(8); scan_c+ + ; } } /**********************延时子程序*********************************/ viod delay(uchar d_time) { uchar i,j; for (i= 0;i< = d_time;i+ + ) { j= 25; while(j- - ) } }