niosii软核的点阵控制设计课程设计论文.docx
SOPC课程设计报告NIOSII软核的点阵控制设计 2015.7.4引言当今,数字系统的设计可以直接面向用户的需求,根据系统功能的要求,从上到下逐层完成相应的描述、综合、优化、仿真与验证,直到生成器件。而FPGA(Field Programmable Gate Array,现场可编程门镇列)以设计灵活及速度快的特点,在数字专用集成电路的设计中得到了广泛应用。一、实验内容本实验要求完成的任务是利用 Nios 软核处理器为核心控制器,在软核 CPU 中添加点阵控制接口并搭建对应电路,利用软件控制点阵的运行,在点阵的循环显示每个组员的名字、学号等信息。二、点阵显示原理1 点阵模块说明 此设计采用4块8*8的点阵块组成16*16的点阵显示模块1.1 8*8点阵块工作原理如图1所示。8*8点阵块工作方式:Q端加正电压,COM端接地时发光二管点亮。例如,当COM8接地且Q1Q8分别接高电平时,第一行亮。同理,当COM7接地,Q1Q8分别接高电平时,第二行亮。依此类推。当Q5端加高电平时,分别让COM1COM8接地,第一列亮。其它列依此类推。1.216*16点阵模块用4块8*8的点阵块组成16*16的点阵模块显示汉字,连接关系如图2所示。Q0Q15成为点阵块的行线,COM0COM15形成点阵块的列线。1.3 行列驱动由循环计数器输出经放大后的驱动点阵,形成动态扫描,分别控制一列中的每个灯,当列线发出信号后,行线同时发出数据,这样就将一个汉字由左到右分成16列。在完成各列的同时,行线发出行数据,一个循环就可以将一个汉字完整的重现在16*16的点阵模块上。 本实验主要完成汉字字符在LED上的显示,16*16扫描LED点阵的工作原理与8位扫描数码管类似,只是显示的方式与结果不一样而已。下面就本实验系统的16*16点阵的工件原理做一些简单的说明。16*16点阵由此256个LED通过排列组合而形成16行*16列的一个矩阵式的LED阵列,俗称16*16点阵。单个的LED的电路如下图11-1所示:图11-1 单个LED电路图由上图可知,对于单个LED的电路图当Rn输入一个高电平,同时Cn输入一个低电平时,电路形成一个回路,LED发光。也就是LED点阵对应的这个点被点亮。16*16点阵也就是由16行和16列的LED组成,其中每一行的所有16个LED的Rn端并联在一起,每一列的所有16个LED的Cn端并联在一起。通过给Rn输入一个高电平,也就相当于给这一列所有LED输入了一个高电平,这时只要某个LED的Cn端输入一个低电平时,对应的LED就会被点亮。具体的电路如下图11-2所示:图11-2 16*16点阵电路原理图在点阵上显示一定有字符是根据其字符在点阵上的显示的点的亮灭来表示的如下图11-3所示: 图11-3 字符在点阵上的显示在上图中,显示的是一个“汉”字,只要将被“汉”字所覆盖的区域的点点亮,则在点阵中就会显示一个“汉”字。根据前面我们所介绍的点阵显示的原理。当我们选中第一列后,根据要显示汉字的第一列中所需要被点亮的点对应的Rn置为高电平,则在第一列中需要被点亮的点就会被点亮。依此类推,显示第二列、第三列第N列中需要被点亮的点。然后根据人眼的视觉原理,将每一列显示的点的间隔时间设为一定的值,那么我们就会感觉显示一个完整的不闪烁的汉字。同时也可以按照这个原理来显示其它的汉字。下在上图中,在系统时钟的作用下,首先选取其中的一列,将数据输入让这列的LED显示其数据(当为高电平时LED发光,否则不发光)。然后选取下一列来显示下一列的数据。当完成一个16*16点阵的数据输入时,即列选择计数到最后一列后,再从第一列开始输入相同的数据。这样只要第一次显示第一列的数据和第二次显示第一列的数据的时间足够短,那么人的眼睛就会看到第一列的数据总是显示的,而没有停顿现象。同样的道理其它列也是这样,直到显示下一个汉字。在实际的运用当中,一个汉字是由多个八位的数据来构成的,那么要显示多个汉字的时候,这些数据可以根据一定的规则存放到存储器中,当要显示这个汉字的时候只要将存储器中对应的数据取出显示即可。本实验的示例程序依次显示的是“欢迎使用嵌入式SOC开发系统 ”。数据量不大,所以没有放入存储器中,而在程序中直接输入对应的一个16位的数据。示例程序的字库数据的格式如下图11-5所示:图11-5 字库格式 图11-7 16*16点阵显示的电路框图在此实验中,16*16点阵由4个8*8点阵组成,考虑到LED电流功耗与FPGA电流功耗的关系,在实验的电路中加入驱动电路。具体电路如下图11-6所示。与FPGA的管脚连接如表11-1所示。图11-6 16*16点阵电路图信号名称对应FPGA管脚名说明DOT-C0W19点阵的第1列输入端口DOT-C1U17点阵的第2列输入端口DOT-C2R8点阵的第3列输入端口DOT-C3T8点阵的第4列输入端口DOT-C4U7点阵的第5列输入端口DOT-C5W8点阵的第6列输入端口DOT-C6W10点阵的第7列输入端口DOT-C7Y11点阵的第8列输入端口DOT-C8AB18点阵的第9列输入端口DOT-C9AA18点阵的第10列输入端口DOT-C10AB20点阵的第11列输入端口DOT-C11AA20点阵的第12列输入端口DOT-C12AB21点阵的第13列输入端口DOT-C13W17点阵的第14列输入端口DOT-C14Y15点阵的第15列输入端口DOT-C15Y13点阵的第16列输入端口DOT-R0AD8点阵的第1行输入端口DOT-R1AC9点阵的第2行输入端口DOT-R2AD10点阵的第3行输入端口DOT-R3AC10点阵的第4行输入端口DOT-R4AD11点阵的第5行输入端口DOT-R5AC11点阵的第6行输入端口DOT-R6AD12点阵的第7行输入端口DOT-R7AC12点阵的第8行输入端口DOT-R8AD4点阵的第9行输入端口DOT-R9AC5点阵的第10行输入端口DOT-R10AD5点阵的第11行输入端口DOT-R11AC6点阵的第12行输入端口DOT-R12AD6点阵的第13行输入端口DOT-R13AC7点阵的第14行输入端口DOT-R14AD7点阵的第15行输入端口DOT-R15AC8点阵的第16行表11-1 16X16点阵与FPGA的管脚连接表三、设计步骤 1. 下面我们建立一个点阵显示的工程1)选择 开始 > 程序 > Altera > QuartusII5.1,运行QUARTUSII软件。或者双击桌面上的QUARTUSII的图标运行QUARTUSII软件,出现如图1-3所示。 图1-3 QUARTUSII软件运行界面2)选择软件中的菜单File > New Project Wizard,新建一个工程。如图1-4所示。图1-4 新建工程对话框3)点击图1-4中的NEXT进入工作目录,工程名的设定对话框如图1-5所示。第一个输入框为工程目录输入框,用户可以输入如e:/eda等工作路径来设定工程的目录,设定好后,所有的生成文件将放入这个工作目录。第二个输入框为工程名称输入框,第三个输入框为顶层实体名称输入框。用户可以设定如EXP1,一般情况下工程名称与实体名称相同。使用者也可以根据自已的实际情况来设定工程名和顶层文件名。注:本处的顶层文件名必须和程序的实体名一致,否则编译会出错。图1-5 指定工程名称及工作目录4)点击NEXT,进入下一个设定对话框,按默认选项直接点击NEXT进行器件选择对话框。如图1-6所示。这里我们以选用CycloneII系列芯片EP2C35F672C8为例进行介绍。用户可以根据使用的不同芯片来进行设定。图1-6 器件选择界面首先在对话框的左上方的Family下拉菜单中选取CycloneII,在中间右边的Speed grade下拉菜单中选取8,在左下方的Available devices框中选取EP2C35F672C8,点击NEXT完成器件的选取,进入EDA TOOL设定界面如图1-7所示。图1-7 EDA TOOL对话框5)按默认选项,点击Next出现新建工程以前所有的设定信息,如图1-8所示,点击Finish完成新建工程的建立。图1-8 新建工程信息2.硬件模块添加通过SOPC Builder添加工程所需组件。在QuartusII中,点击工具栏中右侧的图标,或者通过单击菜单“Tools->SOPC Builder”都可以启动它。1)添加NiosII CPU Core 双击左侧选择组件栏中的NiosII Processor,弹出配置对话框2)添加RAM添加内部RAM:选择memoryon-chip memory,改名RAM;3)添加JTAG UART双击左侧选择组件栏中interface Protocols->Serial->JTAG UART。选用所有的默认设置,点击“Finish”完成添加,如下图所示。4)添加pio在左组件栏中添加GPIO。 因为要定制4个按键输入I/O口,所以设定数据宽度“Width”为4,设定方向为“Itput ports only”,点击“Finish”,如下图所示。依次添加下图pio5)添加完元件后,就要为每个外设分配基地址以及中断号(IRQ)。SOPC Builder给我们提供了配置这两个的命令,通过这两个命令就可分别快速简单分配外设基地址和中断。下图是添加完所有组件后的SOPC Builder配置情况。然后生成硬件系统。6)设计顶层文件在quartus II中的图形编辑界面中进行管脚连接锁定工作将生成模块以图标形式添加到BDF文件中:于Quartus 界面NewBlock Diagram/Schematic File,于弹出画图界面双击空白弹出添加界面完成模块的输入输出接口连接7)引脚锁定和编译新建引脚锁定命令文件,FileNewTcl Script File,弹出新窗口,将引脚锁定文件输入进去,通过查阅引脚文件从而对相应输入输出对应到硬件引脚上。然后编译工程: ProcessStart compilation。8)配置FPGA这里要打开实验板电源、连接USB下载线将生成的SOF文件下载到目标板上。步骤:ToolsProgrammer目标文件夹下载,选择USB-Blaster模式,通过JTAG口对FPGA进行配置;然后点Start,进度达到100%便可将其关闭9)NIOS II软件设计a) 打开NIOS II IDE, 新建工程:FileNewProject,选择C/C+Application,Browse选择工程里面的ptf后缀文件,选择hello world smallFinish。b) 添加.c主程序文件:选中工程右击NewNIOS II C/C+Application,输入程序。完成程序的添加后右击工程Builder Projectd对工程编译。c) 选择RUNRUN·····,系统自动检测JTAG连接电缆于弹出窗口Main中选中工程,在Target Connection选择电缆USB-BlasterRUN,观察实验结果。四、程序文件-下面是引用库 library ieee; -库函数use ieee.std_logic_1164.all;-定义了std_logic数据类型及相应运算use ieee.std_logic_arith.all;-定义了signed和unsigned数据类型、相应运算和相关类型转-换函数use ieee.std_logic_unsigned.all;-定义了一些函数,可以使std_logic_vector类 -型被当作符号数或无符号数一样进行运算-entity exp11 is -exp11为实体名 port( clk : in std_logic; -时钟输入 keyc : out std_logic_vector(15 downto 0); -点阵列控制 keyr : out std_logic_vector(15 downto 0) -点阵行显示 ); end exp11;-结束实体-architecture behave of exp11 is -behave为结构体名 signal cdount : std_logic_vector(3 downto 0);-信号量 表示列扫描频率 signal dount : std_logic_vector(8 downto 0);-计数, signal S : std_logic_vector(3 downto 0);-单个汉字的扫描周期 begin process(clk) -显示时序控制 进程1 begin -以begin为标志开始结构体的描述 if clk'event and clk='1' then -上升沿 dount<=dount+1;-计数累加 if dount=255 then if S=15 then S<="0000" else s<=S+1; end if; s<=s+1; else s<=S; end if; if cdount<15 then -控制列扫描频率 cdount<=cdount+1; else cdount<="0000" end if; end if; end process; -结束进程1 process(cdount,s)-进程2 汉字扫描 begin case cdount is -列扫描频率 when "0000"=>keyc<="0000000000000001" when "0001"=>keyc<="0000000000000010" when "0010"=>keyc<="0000000000000100" when "0011"=>keyc<="0000000000001000" when "0100"=>keyc<="0000000000010000" when "0101"=>keyc<="0000000000100000" when "0110"=>keyc<="0000000001000000" when "0111"=>keyc<="0000000010000000" when "1000"=>keyc<="0000000100000000" when "1001"=>keyc<="0000001000000000" when "1010"=>keyc<="0000010000000000" when "1011"=>keyc<="0000100000000000" when "1100"=>keyc<="0001000000000000" when "1101"=>keyc<="0010000000000000" when "1110"=>keyc<="0100000000000000" when "1111"=>keyc<="1000000000000000" when others=>keyc<="0000000000000000" end case; if s="0000" then case cdount is when "0000"=>keyr<="1101111111100011" when "0001"=>keyr<="1100111111000011" when "0010"=>keyr<="1010001110011011" when "0011"=>keyr<="1011000000111011" when "0100"=>keyr<="1011110000011011" when "0101"=>keyr<="1001000010000011" when "0110"=>keyr<="1101011111000011" when "0111"=>keyr<="1100111111100001" when "1000"=>keyr<="1110001111100001" when "1001"=>keyr<="1111000000010001" when "1010"=>keyr<="1111100000010111" when "1011"=>keyr<="1110000111110111" when "1100"=>keyr<="1100011111010111" when "1101"=>keyr<="1000111111000111" when "1110"=>keyr<="1001111111100011" when "1111"=>keyr<="1001111111110011" when others=>keyr<="1111111111111111" end case; elsif s="0001" then case cdount is when "0000"=>keyr<="1011111110111111" - when "0001"=>keyr<="1001111110111101" when "0010"=>keyr<="1100000000100001" when "0011"=>keyr<="1100000000100011" when "0100"=>keyr<="1100111111110111" when "0101"=>keyr<="1011100000000111" when "0110"=>keyr<="1011100000000111" when "0111"=>keyr<="1011110011110011" when "1000"=>keyr<="1011111011111011" when "1001"=>keyr<="1010000000000011" when "1010"=>keyr<="1010000000000111" when "1011"=>keyr<="1011110111110111" when "1100"=>keyr<="1011100111110111" when "1101"=>keyr<="1011100000000111" when "1110"=>keyr<="1011110000000111" when "1111"=>keyr<="1011111111111111" when others=>keyr<="1111111111111111" end case; elsif s="0010" then case cdount is when "0000"=>keyr<="1111111101111111" - when "0001"=>keyr<="1111111100111111" when "0010"=>keyr<="1000000000011111" when "0011"=>keyr<="1000000000000111" when "0100"=>keyr<="1011111111000001" when "0101"=>keyr<="1011110000010001" when "0110"=>keyr<="1001110000010011" when "0111"=>keyr<="1100011011010111" when "1000"=>keyr<="1110011011010111" when "1001"=>keyr<="1110000000000001" when "1010"=>keyr<="1110100000000001" when "1011"=>keyr<="1100111011010111" when "1100"=>keyr<="1100111011010111" when "1101"=>keyr<="1001110000010111" when "1110"=>keyr<="1001110000010111" when "1111"=>keyr<="1101111111110111" when others=>keyr<="1111111111111111" end case;elsif s="0011" then case cdount is when "0000"=>keyr<="1111111111111111" - when "0001"=>keyr<="1001111111111111" when "0010"=>keyr<="1100011111111111" when "0011"=>keyr<="1110000000000001" when "0100"=>keyr<="1111100000000001" when "0101"=>keyr<="1111111011011101" when "0110"=>keyr<="1111111011011101" when "0111"=>keyr<="1111111011011101" when "1000"=>keyr<="1000000000000001" when "1001"=>keyr<="1000000000000001" when "1010"=>keyr<="1111111011011101" when "1011"=>keyr<="1101111011011101" when "1100"=>keyr<="1001111011011101" when "1101"=>keyr<="1000000000000001" when "1110"=>keyr<="1100000000000001" when "1111"=>keyr<="1111111111111111" when others=>keyr<="1111111111111111" end case;elsif s="0100" then case cdount is when "0000"=>keyr<="1111111111111111" - when "0001"=>keyr<="1111111110111111" when "0010"=>keyr<="1100000000010011" when "0011"=>keyr<="1100000000010011" when "0100"=>keyr<="1110110110110111" when "0101"=>keyr<="1100000000010111" when "0110"=>keyr<="1000000000010111" when "0111"=>keyr<="1001111010110001" when "1000"=>keyr<="1100111001110001" when "1001"=>keyr<="1110011100010111" when "1010"=>keyr<="1110000010010111" when "1011"=>keyr<="1111000010110111" when "1100"=>keyr<="1100011010110011" when "1101"=>keyr<="1000111000110011" when "1110"=>keyr<="1001111100111111" when "1111"=>keyr<="1101111111111111" when others=>keyr<="1111111111111111" end case;elsif s="0101" then case cdount is when "0000"=>keyr<="1011111111111111" - when "0001"=>keyr<="1001111111111111" when "0010"=>keyr<="1101111111111111" when "0011"=>keyr<="1110111111111111" when "0100"=>keyr<="1110001111111101" when "0101"=>keyr<="1111000011111001" when "0110"=>keyr<="1111110000010001" when "0111"=>keyr<="1111111100000011" when "1000"=>keyr<="1111111100001111" when "1001"=>keyr<="1111111000111111" when "1010"=>keyr<="1111100011111111" when "1011"=>keyr<="1111000111111111" when "1100"=>keyr<="1100011111111111" when "1101"=>keyr<="1000111111111111" when "1110"=>keyr<="1001111111111111" when "1111"=>keyr<="1101111111111111" when others=>keyr<="1111111111111111" end case;elsif s="0110" then case cdount is when "0000"=>keyr<="1111111111100111" - when "0001"=>keyr<="1101111111100111" when "0010"=>keyr<="1001111011001111" when "0011"=>keyr<="1000111011001111" when "0100"=>keyr<="1100000011001111" when "0101"=>keyr<="1110000011001111" when "0110"=>keyr<="1110011011001111" when "0111"=>keyr<="1111011011001111" when "1000"=>keyr<="1111011000000001" when "1001"=>keyr<="1111100000000001" when "1010"=>keyr<="1110000111001111" when "1011"=>keyr<="1100011111001001" when "1100"=>keyr<="1001111111001001" when "1101"=>keyr<="1011111111001111" when "1110"=>keyr<="1000111111001111" when "1111"=>keyr<="1000111111100111" when others=>keyr<="1111111111111111" end case;elsif s="0111" then case cdount is when "0000"=>keyr<="1111101110011111" - when "0001"=>keyr<="1111001000001111" when "0010"=>keyr<="1111000011001111" when "0011"=>keyr<="1111100111011111" when "0100"=>keyr<="1111111111111111" when "0101"=>keyr<="1111110000111111" when "0110"=>keyr<="1111100000011111" when "0111"=>keyr<="1111001111001111" when "1000"=>keyr<="1111001111001111" when "1001"=>keyr<="1111100000011111" when "1010"=>keyr<="1111110000111111" when "1011"=>keyr<="1111111111111111" when "1100"=>keyr<="1111100000011111" when "1101"=>keyr<="1111001111001111" when "1110"=>keyr<="1111001111001111" when "1111"=>keyr<="1111101111011111" when others=>keyr<="1111111111111111" end case;elsif s="1000" then case cdount is when "0000"=>keyr<="11111