基于32×32点阵LED模块的书写显示屏

    LED点阵显示屏被用到很多领域,随着电子技术的发展,LED点阵书写显示屏的广泛应用是一种趋势。传统的LED点阵显示是由微处理器实现的,但是以FPGA做控制器将成为发展趋势。FPGA的结构灵活,其逻辑单元、可编程内部连线和I/O单元都可以由用户编程,可以实现复杂逻辑功能,满足各种设计需求。其速度快,功耗低,通用性强,特别适用于大型系统的设计。使用FPGA还可以实现动态配置、在线系统重构(可以在系统运行的不同时刻,按需要改变电路的功能,使系统具备多种空间相关或时间相关的任务)及硬件软化、软件硬化等功能。本作品用FPGA做为控制器,来实现LED点阵书写显示屏的功能。

1.2 本课题主要研究内容

设计任务:设计并制作一个基于32×32点阵LED模块的书写显示屏,其系统结构如图1所示。在控制器的管理下,LED点阵模块显示屏工作在人眼不易觉察的扫描微亮和人眼可见的显示点亮模式下;当光笔触及LED点阵模块表面时,先由光笔检测触及位置处LED点的扫描微亮以获取其行列坐标,再依据功能需求决定该坐标处的LED是否点亮至人眼可见的显示状态(如图1中光笔接触处的深色LED点已被点亮),从而在屏上实现“点亮、划亮、反显、整屏擦除、笔画擦除、连写多字、对象拖移”等书写显示功能。

图1-1 LED点阵书写显示屏系统结构示意图

(1)在“点亮“功能下,当光笔接触屏上某点LED时,能即时点亮该点LED,并在控制器上同步显示该点LED的行列坐标值(左上角定为行列坐标原点)。

(2)在“划亮”功能下,当光笔在屏上快速划过时,能同步点亮划过的各点LED,其速度要求2s内能划过并点亮40点LED。

(3)在“反显”功能下,能对屏上显示的信息实现反相显示(即:字体笔画处不亮,无笔画处高亮)。

(4)在“整屏擦除”功能下,能实现对屏上所显示信息的整屏擦除。

从理论上说,不论显示图形还是文字,只要控制与组成这些图形或文字的各个点所在位置相对应的LED器件发光,就可以得到我们想要的显示结果,这种同时控制各个发光点亮灭的方法称为静态驱动显示方式。32*64的点阵共有2048个发光二极管,显然单片机没有这么多端口,如果我们采用锁存器来扩展端口,按8位的锁存器来计算,32*64的点阵需要256个锁存器。这个数字很庞大,而且成本很昂贵,我们仅仅是32*64的8个汉字点阵,在实际应用中的显示屏往往要大得多,这样在锁存器上花的成本将是一个很庞大的数字。因此在实际应用中的显示屏几乎都不采用这种设计,而采用另一种称为动态扫描的显示方法。

动态扫描的意思简单地说就是逐行轮流点亮,这样扫描驱动电路就可以实现多行(比如8行)的同名列共用一套列驱动器。具体就32*64的点阵来说,把所有同一列的发光管的阴极连在一起,再去驱动这一列LED (共阳接法),每一列先送出对应第1行发光管对应的数据并锁存,再选通第1行使其点亮一定的时间,然后熄灭;再送出第2行的数据并锁存,再选通第2行使其点亮相同的时间,然后熄灭……第8行之后,又重新点亮第1行,反复轮回。当这样轮回的速度足够快(每秒24次以上),由于人眼的视觉暂留现象,就能看到显示屏上稳定的图形了。

采用扫描方式进行显示时,每行有一个行驱动器,各行的同名列共用一个列驱动器。显示数据通常存储在单片机的程序存储器中,按8位一个字节的形式顺序排放。显示时要把一行中各列的数据都传送到相应的列驱动器上去,这就存在一个显示数据传输的问题。从控制电路到列驱动器的数据传输可以采用并行方式或串行方式。采用并行方式时,32*64的LED点阵有8列8*8的点阵,需要8*8=64个列数据输入口,而一个89C51只有32个I/O接口,还要同时驱动行数据,根本不够用;并且从控制电路到列驱动器的线路数量大,相应的硬件数目多,由此可以得出,当列数很多时,并行传输的方案是不可取的。

采用串行传输的方法,控制电路可以只用2根线:数据线、时钟线。将行数据一位一位传往行驱动器,在硬件方面无疑是十分经济的。但是,串行传输过程较长,数据按顺序一位一位地输出给行驱动器,只有当一行的各列数据都已传输到位之后,这一行的各列才能并行地进行显示。这样,对于一行的显示过程就可以分解成列数据准备(传输)和列数据显示两个部分。对于串行传输方式来说,列数据准备时间可能相当长,在行扫描周期确定的情况下,留给显示的时间就太少了,以致影响到LED的亮度。

解决串行传输中列数据准备和列数据显示的时间矛盾问题,可以采用重叠处理的方法。即在显示本行数据的同时,传送下一行的数据。为了达到重叠处理的目的,列数据的显示驱动电路就需要具有锁存功能。经过上述分析,可以归纳出列驱动器电路应具备的主要功能:对数据准备来说,它应能实现串入并出的移位功能;对数据显示来说,应具有并行锁存的功能。这样,本行已准备好的数据打人并行锁存器进行显示时,串并移位寄存器就可以准备下一行的列数据,而不会影响本行的显示。同时为了LED显示的亮度,采用8行扫描,每个汉字上面有2个16列驱动器驱动,列驱动器的位置应该是在第1行跟第9行,即每个16*16的汉字点阵是有4个8*8的点阵组成的阵列,扫描的时候同时扫描显示第1行跟第9行,第二次扫描的时候显示第2行跟第10行,以此类推,最后显示第8行跟第16行,如图所示:

 

 

图 4-1 16*16LED显示屏

4.2 系统总体方案的确定

·主控器选择方案论证

    方案一:以ARM为系统控制器

采用32位RISC微处理器ARM实现点阵屏的控制和编码功能,基本上能完成题目的要求,但是 ARM 不适合多线程操作,如果应用在系统中会使电路和软件设计变得复杂。

    方案二:用 FPGA 作为系统控制器

FPGA可以直接用硬件扫描、编码、解码、纠错,速度快、稳定性高、扩展性能好、体积小,可以提供丰富的逻辑单元和I/O 资源。用SOPC工具可以快速生成片上软核处理器,将所有的控制单元集成在一片FPGA芯片内,降低了额外的功耗开支。采用并行的输入/输出方式,可以达到很快的速度。这样合理的分配了FPGA 资源,具有很强的实时性和准确性。可以实现各种灵活控制。

本系统我们采用方案二。

·点阵驱动方案论证

    方案一:串行方式显示

这种显示方式由译码器单元74HC138、数据移位寄存器74HC595和列驱动器组成,点阵显示屏可以用少量I/O口接收控制器传输下来的大量数据,此方案为点阵显示屏系统中比较常用的,所用器件也比较常用,容易买到。但是它存在一个致命的缺点,就是刷新速度不够快,高速度的地址编码信息无法发送。

方案二:并行方式显示

可以通过锁存器芯片来增强FPGA的I/O口的驱动能力,将32位宽的数据同时输入到LED点阵列中,达到并行控制LED点阵的目的。方案中运用4片锁存器74HC573来组成双缓冲寄存器,驱动LED点阵行线,用5片3-8译码器74HC138组合成5-32译码器对LED点阵的32列进行选取。这样就避免了各行数据显示不同步的问题。由于并行数据传输速度非常快,所以高速度的地址编码信息可以同步发出。

本设计选择第二个方案。

    系统总体结构如下所示:

 

 

图 4-2 系统工作原理框图

 

系统总体工作流程如下所示:

    由于本系统有四中工作模式, “点亮“功能,“划亮”功能,“反显”功能,“整屏擦除”功能,在这里,我们第一这四个工作模式为四个状态S1,S2,S3,S4,系统的初始状态S0,那么这个系统可以设计为状态机的工作模式。其工作模式如下所示:

 

 

本章,我们将详细介绍系统的设计与实现。

5.1“点亮功能

5.1.1设计要求

当光笔接触屏上某点LED时,能即时点亮该点LED,并在控制器上同步显示该点LED的行列坐标值(左上角定为行列坐标原点)。

5.1.2设计思路

    通过按键的控制,我们将系统切换到点亮功能模块,由于本系统采用的LED显示屏是32*32的,估当光笔点击某个LED的时候,显示屏将产生一个中断给FPGA,然后由FPGA控制发出中断的LED点亮,然后通过中断值,分析出当前LED所在的位置,在发光数码管中显示出相应的坐标点。同时对于LED点阵,我们对其产生中断扫描,用于准确的识别被点击的LED灯。

5.1.3设计流程

     整个S1状态的设计代码如下所示:

·坐标计算模块:

               case(x[31:0])

               32'b00000000_00000000_00000000_00000001:xc<=0;

               32'b00000000_00000000_00000000_00000010:xc<=1;

               32'b00000000_00000000_00000000_00000100:xc<=2;

               32'b00000000_00000000_00000000_00001000:xc<=3;

               32'b00000000_00000000_00000000_00010000:xc<=4;

               32'b00000000_00000000_00000000_00100000:xc<=5;

               32'b00000000_00000000_00000000_01000000:xc<=6;

               32'b00000000_00000000_00000000_10000000:xc<=7;             

               32'b00000000_00000000_00000001_00000000:xc<=8;

               32'b00000000_00000000_00000010_00000000:xc<=9;

               32'b00000000_00000000_00000100_00000000:xc<=10;

               32'b00000000_00000000_00001000_00000000:xc<=11;

               32'b00000000_00000000_00010000_00000000:xc<=12;

               32'b00000000_00000000_00100000_00000000:xc<=13;

               32'b00000000_00000000_01000000_00000000:xc<=14;

               32'b00000000_00000000_10000000_00000000:xc<=15; 

               32'b00000000_00000001_00000000_00000000:xc<=16;

               32'b00000000_00000010_00000000_00000000:xc<=17;

               32'b00000000_00000100_00000000_00000000:xc<=18;

               32'b00000000_00001000_00000000_00000000:xc<=19;

               32'b00000000_00010000_00000000_00000000:xc<=20;

               32'b00000000_00100000_00000000_00000000:xc<=21;

               32'b00000000_01000000_00000000_00000000:xc<=22;

               32'b00000000_10000000_00000000_00000000:xc<=23;                                              

               32'b00000001_00000000_00000000_00000000:xc<=24;

               32'b00000010_00000000_00000000_00000000:xc<=25;

               32'b00000100_00000000_00000000_00000000:xc<=26;

               32'b00001000_00000000_00000000_00000000:xc<=27;

               32'b00010000_00000000_00000000_00000000:xc<=28;

               32'b00100000_00000000_00000000_00000000:xc<=29;

               32'b01000000_00000000_00000000_00000000:xc<=30;

               32'b10000000_00000000_00000000_00000000:xc<=31;                

               endcase

·亮灯模块

begin

          if(enable==1'b1)

          begin

               if(interrupt==1'b1)

               begin

               light<=1'b1;

               x_out<=x;

               end

          else begin

               light<= light;

               x_out<= x_out;           

               end           

          end

     else begin

          light<=1'b0;

          x_out<=33'd0;   

          end

     end     

·数码管坐标显示模块

begin

          if(enable==1'b1)

          begin

          LED_x<=xc;

          LED_y<=yc;

          end

     else begin

          LED_x<=8'd0;

          LED_y<=8'd0;

          end

     end     

 

5.1.4设计仿真

图5-1 S1状态仿真图

如图所示:当输入的坐标信号为1_00001000_00000000_00000000_00000000, 0_00000000_00000000_00000000_01000000,即输入的中断坐标为X:27,Y:6,所以最后数码管要显示的数据为(27,06)即中断点的坐标。

5.2“划亮”功能

5.2.1设计要求

在“划亮”功能下,当光笔在屏上快速划过时,能同步点亮划过的各点LED,其速度要求2s内能划过并点亮40点LED。

5.2.2设计思路

    我们要求同时点亮40个点,即在2S中内,我们要保持所有点的坐标信息,然后对这些坐标所对应的数据在LED点阵上显示出来,由于这个模块对应的点比较多,所以我们不在对这些点显示坐标。当光笔在LED上滑动的时候,会不断的产生中断信号,当中断产生的时候,我们通过FPGA内部的计数器来记录中断所持续的时间,然后当中断结束的时候,计数器停止计数,同时LED点灯使能信号被锁存,从而在显示屏上显示出一条线段。

    那么在设计本质上,这个功能主要是实现当光笔划结束以后,系统能够记录光笔划过的LED点,然后FPGA循环的发出使能信号和其对应的坐标信号使线段持续显示。

5.2.3 设计流程

begin

                      if(enable==1'b1)

                      begin

                              if(interrupt==1'b1)//产生中断

                              begin

                     men_x[1]<=x;

                     for(i=2;i<=50;i=i+1)

                     men_x[i]<=men_x[i-1];

                              end

                      else begin

                  for(i=1;i<=50;i=i+1)

                  men_x[i]<=men_x[i];                          

                  end

                      end

        else    begin

                      cnt         <=8'b00000000;

                      final_number<=8'b00000000;    

             end              

     end

5.2.4设计仿真

图5-2 线段显示

从仿真图中,可以看到,当输入中断结束以后,FPGA可以循环输出被光笔划过的LED灯,从而达到持续显示多个LED灯的效果。

5.3“反显”功能

5.1.1设计要求

在“反显”功能下,能对屏上显示的信息实现反相显示(即:字体笔画处不亮,无笔画处高亮)。

5.1.2设计思路

    反显的功能和前面我们介绍的相似,就是将光笔点击的LED灯熄灭,而初始的LED灯全为亮,故我们要做的就是改变系统的初始状态,然后输出的LED使能信号取反即可。这个模块的功能比较简单,我们在这里就不多做介绍了。

 

 

 

5.4“整屏擦除”功能

5.1.1设计要求

当光笔接触屏上某点LED时,能即时点亮该点LED,并在控制器上同步显示该点LED的行列坐标值(左上角定为行列坐标原点)。

5.1.2设计思路

    这个模块就是使LED的显示返回到初始的状态,如初始为全亮,则LED会自动消除暗的灯,如LED初始为全暗,则LED会熄灭所有亮的灯。这个模块设计比较简单,这里就不做详细介绍了。

5.5 系统总体设计

5.5.1系统初始状态的设计与实现

    这个模块主要功能就是使LED显示屏全灭或则全亮。即通过循环发送LED灯的地址,达到全亮或则全灭的效果。其实现代码如下所示:

//坐标扫描

always @(posedge flag)

begin

     if(!rst)

     begin

     xc<=0;

     yc<=0;

     end

else begin

          if(xc==31)

          begin

          xc<=0;

               if(yc==31)

               yc<=0;

          else

               yc<=yc+1'b1;

          end

     else begin

          xc<=xc+1'b1;

          end

     end

end

 

 

 

//X,Y坐标交替输出

always @(posedge clk)

begin

     if(!rst)

     x_out<=33'd0;

else begin

          if(flag==1'b1)

          x_out<=x_tmp;

     else

          x_out<=y_tmp;

     end    

end

其仿真结果:

图5-3 坐标输出

    下面我们将对每个模块在顶层文件进行调用。

always @(posedge clk)

begin

     if(~rst)

     begin

     x_out<=33'd0;

     light<=1'd0;

     LED_x<=8'd0;

     LED_y<=8'd0;

     end

else begin

                    if(k3==0)//正显示

                    begin

                         if(k1==1'b1)//点亮

                         begin

                                  x_out<=x_out_tmp1;

                                  light<=light_tmp1;

                                  LED_x<=LED_x_tmp1;

                                  LED_y<=LED_y_tmp1;                    

                         end

                    else if(k2==1'b1)划亮    

                         begin

                                  x_out<=x_out_tmp2;

                                  light<=light_tmp2;

                         end

                    else if(k4==1'b1)//清屏     

                         begin

                                  x_out<=x_out_tmp0;

                                  light<=~light_tmp0;                 

                         end

                    end

                    if(k3==1)//反显示

                    begin

                         if(k1==1'b1)//点亮

                         begin

                                  x_out<=x_out_tmp1;

                                  light<=~light_tmp1;

                                  LED_x<=LED_x_tmp1;

                                  LED_y<=LED_y_tmp1;                    

                         end

                    else if(k2==1'b1)划亮    

                         begin

                                  x_out<=x_out_tmp2;

                                  light<=~light_tmp2;

                         end

                    else if(k4==1'b1)//清屏     

                         begin

                                  x_out<=x_out_tmp0;

                                  light<=light_tmp0;                   

                         end                   

                    end    

     end

end      

5.5.3 仿真

点亮:

图5-5 点亮

划亮:

图5-6 点亮

清屏:

图5-7 清屏

 

 

 

 

 

 

 

 

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpga和matlab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值