文档库 最新最全的文档下载
当前位置:文档库 › Verilog自学笔记

Verilog自学笔记

Verilog自学笔记2——点亮流水灯

module Ledwater (CLK,LED);

input CLK;

output [7:0] LED;

reg [7:0] LED;

reg [24:0] counter;

always @ (posedge CLK)

begin

counter <= counter + 1;

if (counter == 25'b1001100010010110100000000)

begin

LED <= LED<<1;

counter <= 0;

end

if (LED == 0)

begin

LED <= 8'b00000001;

end

end

endmodule

程序中,counter 在每个时钟的上升沿加1 次,然后进行判断是否记数满

25'b1011011100011011000000000(十进制的20000000,我的开发板上晶振为20M),如果记数达到这个值,表明满足我们输出时间的要求,这个时候就执行12 行开始的begin 段的代码,对8 个LED 的状态进行取反操作,然后对计数器清零重新开始计数;当counter 再次满足技术要求时,再次触发LED状态的翻转。

对于这个程序,我补充一些关于assign 和always的用法:

assign 用于描述组合逻辑,always@(敏感事件列表) 用于描述时序逻辑,其敏感事件指上升沿(posedge),下降沿(negedge),或电平。敏感事件列表中可以包含多个敏感事件,但不可以同时包括电平敏感事件和边沿敏感事件,也不可以同时包括同一个信号的上升沿和下降沿,这两个事件可以合并为一个电平敏感事件。合法的写法:

always@ *

always@ (posedge clk1,negedge clk2)

always@ (a or b)

`timescale 100ns/100ns //定义仿真基本周期为100ns

always #1 clk=~clk //#1代表一个仿真周期即100ns

所有的assign 和always 块都是并行发生的!

如果你无法理解并行和顺序,我再重复一下,并行是所有语句不分先后一起执行,顺序是语句按模块中的书写顺序执行。

并行执行的语句模块:

fork

……

join

//语句并行执行

顺序执行的语句模块

begin

……

end

//语句顺序执行

并行块和顺序块都可以写在initial 或always@ 之后,也就是说写在块中的语句是时序逻辑的,对assign之后不能加块,实现组合逻辑只能用逐句的使用assign。组合逻辑如果不考虑门的延时的话当然可以理解为瞬时执行的,因此没有并行和顺序之分,并行和顺序是针对时序逻辑来说的。值得注意的是所有的时序块都是并行执行的。initial块只在信号进入模块后执行1次而always块是由敏感事件作为中断来触发执行的

FPGA/CPLD实验教程三(流水灯)

1. 实验要求及目的:

这次的实验我们要做的是流水灯,顾名思义就是要LED象水一样的点亮(好像有点不怎么顾名思义啊),这样说吧,就是先单独点亮第一个,然后点亮第二个(这个时候有两个灯亮了),然后……

这一个实验主要教会大家一个比较方便的锁定引脚的办法,另外就是使用移位运算符。

使用软件:Quartus II 5.0。

2. 硬件原理图:

这个是我自己制作的开发板上的LED的原理图,一共有8个,IO和别的共用的,使用八个LED 的时候板上的JP1和JP5全部戴上短接帽,JP2则空出。如果要点亮这些LED,只需要把与其相连接的FPGA管脚输出低电平“0”就可以实现这个功能了。(我焊板子的时候把LED1弄坏了,不能用。)

LED管脚对应的情况如下:

D1------PIN_97

D2------PIN_94

D3------PIN_91

D4------PIN_84

D5------PIN_82

D6------PIN_78

D7------PIN_76

D8------PIN_74

另外,本实验需要用到时钟计数,时钟对应的引脚为PIN_16。

本文均采用输出“0”点亮的模式,以下就不再另外再说明了。

——这几句话我直接抄袭上第一个实验的了,因为是一样的。

3. 程序设计

(1)设计分析:我们要求这次8个灯流水一样的点亮(如果实在我讲解的不清楚,可以先看看最后的实验录像)。

具体分析一下,我们需要每个1秒钟的时间点亮一个灯,从D1开始,然后点亮D2(这个时候点亮了D1和D2),依此类推,直到点亮八个灯,然后熄灭;然后又从头开始……

FPGA输出的数据就应该首先是11111110,隔1秒钟变成11111100……一直变化到00000000,这就可以实现流水灯了。

基本上看明白了吧,那就来看看源程序吧。

(2)源程序exp2.v

程序代码:

// Light 8 LED (water light)

// Designed By Smokingfish @ https://www.wendangku.net/doc/aa11136960.html, zhiyuh@https://www.wendangku.net/doc/aa11136960.html,

module exp3(LED,CLK,reset);

output[7:0] LED;

input CLK,reset;

reg [7:0] LED;

reg [24:0] counter;

//initial

//LED=8'b11111111;

always@(posedge CLK) //

begin

counter<=counter+1; //

if(counter==25'b1_0111_1101_0111_1000_0100_0000) //25M

// 1_0111_1101_0111_1000_0100_0000

begin

LED<=LED<<1;

counter<=0;

if(LED==8'b0000000)

LED<=8'b11111111;

end

end

endmodule

这里我们运用了“<<“这个移位运算符,至于这个运算符的用法,你可以参看夏老师的书31页,有比较详细的说明。当然,你也可以采用case语句,方法不一样,只要实现的功能一致就行——你可以比较一下两种方法代码的长度以及编译后占用的资源情况,看看有什么不一样的地方。在这里我就不多讲语法了,我着重讲的是实践。

中间有两行注释,这个是周立功那本书里写的(我参考了他的设计,呵呵)。我认为这两句是不能综合的,只能用于测试模块,相关的说明可以参看Verilog HDL的语法说明。所以我认为他书里写错了,于是我向夏老师求证,他也认同了我的看法。所以有时候还是不能尽信书。一般情况下,如果需要对寄存器进行初始化,需要加入reset信号。如果一定不能用reset信号,对FPGA来说综合后的电路应该上电就能复位。

4. 实验步骤

(1)打开Quartus II软件,进入集成开发环境,点击File->New project wizard..新建工程项目exp3,直接点击Finish。

(2)点击File->New..在该项目下新建Verilog HDL源程序文件exp3.v,输入上面的源程序代码并保存。

(3)选择所用的FPGA器件----EP1C3T144C8,以及进行一些配置。

选择配置器件,如果要下载程序到EPCS1的话。

选择不需要使用的IO功能。选择As inputs,tri-stated。

点击两次ok,回到主界面。

(4)为工程项目锁定引脚:(这里教大家一个新的办法,比较方便快捷)

首先建立一个TCL Script文件:点File->New…选择Other Files选项卡里面的Tcl Script File,如下图:

点击ok,输入下面的代码:

程序代码:

#Pin_Setup.tcl

# Setup pin setting

set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED"

set_global_assignment -name ENABLE_INIT_DONE_OUTPUT ON

set_location_assignment PIN_16 -to CLK

set_location_assignment PIN_97 -to LED\[0\]

set_location_assignment PIN_94 -to LED\[1\]

set_location_assignment PIN_91 -to LED\[2\]

set_location_assignment PIN_84 -to LED\[3\]

set_location_assignment PIN_82 -to LED\[4\]

set_location_assignment PIN_78 -to LED\[5\]

set_location_assignment PIN_76 -to LED\[6\]

set_location_assignment PIN_74 -to LED\[7\]

比较简单的代码,简单的讲解一下,第一行和第二行是注释,第四行的意思是设置不用的引脚为三态输入(这个前面其实我们已经做过了),第五行的意思是打开INIT_DONE输出。后面的几行分别是锁定CLK和8个LED的引脚。(如果想应用更多的东东,可以自己查阅一下相关的文档,我这里就是让你知道有这么一个东西,会用了就行,至于提高就是自己的事情咯,呵呵)。

保存这个文档(Pin_Setup.tcl),软件会自动把你加到项目里面(但是你关闭项目之后第二次打开又会没有,我也不知道是为什么,奇怪)。

然后点Tools->TCL Scripts…,出现下面这个界面:

选中你刚才建好的Tcl文件,点击Run。这个时候你可以在Quartus II软件下方的Message 框里面看到这么一个信息:Info: Successfully loaded and ran Tcl Script File "F:\VerilogHDL Exp\exp3\pin_setup.tcl""。你也可以确认一下是否正确分配了,分配的情况如下图:

怎么样,是不是快多了,不用点那么多次鼠标(鼠标的寿命又可以增加一点了,哈哈)。这个文件你可以适当修改用于别的项目,如果引脚一样也可以直接在别的项目中加入这个文件然后执行,可以省很多事情。如果只有几个引脚,一个一个锁定还就罢了,要是一个工程用到上百个引脚,那就要死人了。

其实Tcl脚本文件不仅仅是可以锁定引脚,还有其他很多的功能,比如(抄的是Quartus

的使用手册):

工程与分配功能

器件功能

高级器件功能

流程功能

时序功能

高级时序功能

Simulator 功能

报告功能

时序报告功能

反标功能

LogicLock 功能

Chip Editor 功能

其它功能

其他的功能我就不一一讲了,你可以参考以下的文档:

Quartus II Help 中的“Overview: Using Tcl Scripting”和“API Functions for Tcl”以及Altera 的Quartus II Handbook 第 2 卷“Tcl Scripting”:https://www.wendangku.net/doc/aa11136960.html,/literature/hb/qts/qts_qii52003.pdf,还有就是Quartus II Scripting Reference Manual:https://www.wendangku.net/doc/aa11136960.html,/literatur ... #083;criptRefMnl.pdf

(5)编译工程项目:点击Processing->Start Compilation。

(6)仿真:自己建立仿真文件检查自己的设计是否正确。

(7)下载目标文件到板子上:点击Tools->Programmer,选中Jtag模式,并且选中目标文件,然后点Start。

很快就完成了第三个实验,是不是觉得有所收获?没有?——那我就太失败咯。

你也可以试着别的花样来点亮LED,比如,只有一个灯亮的流水灯,亮过去之后又亮回来等等,就看你的想象力了,通过自己写程序更能有成就感,而且还能把书本的知识用到实际中,何乐而不为呢?是吧?

1. 实验任务

让实验板上的8个LED实现流水灯的功能。通过这个实验,进一步掌握采用计数与判断的方式来实现分频的Verilog HDL的编程方法以及移位运算符的使用。

2. 实验环境

硬件实验环境为艾米电子工作室型号EP2C8Q208C8增强版开发套件。

软件实验环境为Quartus II 8.1开发软件。

3. 实验原理

流水灯,顾名思义就是让LED象水一样的点亮。如果把流水做慢动作播放,可以想象到其实就是移动,即:把水块不断地向同一方向移动,而原来的水块保持不动,就形成了流水。同样,如果使得最左边的灯先亮;然后,通过移位,在其右侧的灯,由左向右依次点亮,而已经亮的灯又不灭,便形成了向右的流水灯。初始状态时,8个灯都不亮。每来一个时钟脉冲CLK,计数器就加1。每当判断出计数器中的数值达到25000000时,就会点亮一个灯,并进行移位。FPGA输出的数据就应该首先是10000000,隔1秒钟变成11000000……一直变化到11111111,这样,依次点亮所有的灯,就形成了流水灯。而当8个灯都点亮时,需要一个操作使得所有的灯恢复为初始状态,即:灯都不亮。然后,再一次流水即可。如果是右移位,就出现向右流水的现象;反之,向左流水。

4. 实验程序

module ledwater(clk,led); // 模块名及端口参数

output [7:0] led; // 输出端口定义

input clk; // 输入端口定义,50M时钟

reg[8:0] led_out; // 变量led_out定义为寄存器型

reg[8:0] led_out1; // 变量led_out1定义为寄存器型

reg[25:0]buffer; // 中间变量buffer定义为寄存器型

always@(posedge clk)

begin

buffer=buffer+1;

if (buffer==26'd2*******) // 判别buffer数值为25000000时,做输出处理

begin

led_out=led_out<<1; // led向左移位,空闲位自动添0补位

if(led_out==9'b000000000)

led_out=9'b111111111;

led_out1=~led_out; //取反输出

end

end

assign led="led"_out1[7:0];

endmodule

5. 实验步骤

(1)建立新工程项目:

打开Quartus II软件,进入集成开发环境,点击File→New project wizard建立一个工程项目ledwater。

(2)建立文本编辑文件:

点击File→New在该项目下新建Verilog HDL源程序文件ledwater.v,输入试验程序中的源程序代码保存后选择工具栏中的按钮启动编译,若在编译中发现错误,则找出并更正错误,

直到编译成功为止。

(3)选择器件型号及引脚的其他设置:

选择所用的FPGA器件→EP2C8Q208C8,以及进行一些配置。选择配置器件EPCS4,设置不需要使用的IO功能为As inputs,tri-stated。点击两次ok,回到主界面。

(4)配置FPGA引脚:

在Quartus II软件主页面下,选择Assignments→Pins或选择工具栏上按钮,配置led[0]---led[7]以及clk的引脚。

上述配置引脚的方法适合引脚比较少的项目,对于引脚比较多的工程项目,分配起来就比较麻烦了,下面介绍一种方便快捷的引脚分配方法。

a. 首先建立一个TCL Script文件:点File→New选择Design Files选项卡里面的Tcl Script File,如下图所示:

b.点击ok,输入下面的代码:

#Pin_Setup.tcl

# Setup pin setting

set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED"

set_global_assignment -name ENABLE_INIT_DONE_OUTPUT ON

set_location_assignment PIN_23 -to clk

set_location_assignment PIN_75 -to led[0]

set_location_assignment PIN_76 -to led[1]

set_location_assignment PIN_89 -to led[2]

set_location_assignment PIN_94 -to led[3]

set_location_assignment PIN_92 -to led[4]

set_location_assignment PIN_97 -to led[5]

set_location_assignment PIN_102 -to led[6]

set_location_assignment PIN_101 -to led[7]

比较简单的代码,简单的讲解一下,第一行和第二行是注释,第四行的意思是设置不用的引脚为三态输入,第五行的意思是打开INIT_DONE输出。后面的几行分别是锁定clk和8个led 的引脚。

c. 在Quartus II主界面中选择File→Save As保存这个文档,软件会自动把它加到项目里面。

d. 在Quartus II主界面中选择点Tools->TCL Scripts...,出现下图所示这个界面:

e. 选中你刚才建好的Tcl文件,点击Run。

f. 你可以选择Assignments→Pins或选择工具栏上按钮确认一下是否正确分配了,分配的情况如下图:

怎么样这种方法是不是比以前的方法快多了!这个文件你可以适当修改用于别的项目,如果引脚一样也可以直接在别的项目中加入这个文件然后执行,可以省很多事情。

(5)编译工程项目:

在Quartus II主页面下,选择Processing —Start Compilation或点击工具栏上的按钮启动编译,直到出现“Full Compilation Report”对话框,点击OK即可。

(6)波形仿真:由于本次试验比较简单,波形仿真将在后面实验详细讲解。

(7)下载设计程序到目标FPGA

6. 实验现象

经过前两个实验的训练,第三个实验应该很轻松地就做完了吧!看到实验板上LED实验了流水灯的功能,你是否掌握了移位运算符的使用,你可以试着自己编写其他花样的流水灯,比如左流水或其他花样的流水灯,这就要看你的想象力了。

艾米电子FPGA入门系列实验教程——实验三流水灯下载

实验三、Verilog之Johnson计数器

所谓Johnson计数器,其实说白了无非就是复杂一点的流水灯实验,不过是加上了按键控制,然后流水灯的方向在按键的控制下进行。关于按键消抖部分,建议先学习按键消抖部分,然后再进行这个部分的学习。

实验说明:本示例是带停止控制的双向4bit Johnson 计数器示例,可以通过LED灯直观的在开发板上进行演示。

sw2: 按键sw2 控制向左移动

sw3: 按键sw3 控制向右移动

sw1: 按键sw1 第一次按下时将停止移动,再次按下时就会恢复移动

代码如下:

module johnson(clk,rst_n,key1,key2,key3,led1,led2,led3,led4);

input clk; //主时钟,50MHz

input rst_n; //低电平复位

input key1,key2,key3; // 按键接口

output led1,led2,led3,led4; // LED等接口

//------------------------------------

reg[23:0] delay; //延时计数器

always @ (posedge clk or negedge rst_n)

if(!rst_n) delay <= 0;

else delay <= delay+1; //不断计数,周期为20ms

reg[2:0] key_value; //键值寄存器

always @ (posedge clk or negedge rst_n)

if(!rst_n) key_value <= 3'b111;

else if(delay == 24'hffffff) key_value <= {key3,key2,key1}; //delay 20ms,锁定键值

//-------------------------------------

reg[2:0] key_value_r;

always @ (posedge clk or negedge rst_n)

if(!rst_n) key_value_r <= 3'b111;

else key_value_r <= key_value;

wire[2:0] key_change; //判定前后20ms的键值是否发生了改变,若是,则key _change置高

assign key_change = key_value_r & (~key_value); //check key_value negedge per clk

//------------------------------------

reg stop_start,left_right; //流水灯控制位

always @ (posedge clk or negedge rst_n)

if(!rst_n) begin

stop_start <= 1;

left_right <= 1;

end

else

if(key_change[2]) stop_start <= ~stop_start; //开始结束控制位

else if(key_change[1]) left_right <= 1; //流水灯方向控制

else if(key_change[0]) left_right <= 0; //流水灯方向控制

//-------------------------------------

reg[3:0] led_value_r;// LED值寄存器

always @ (posedge clk or negedge rst_n)

if(!rst_n) led_value_r <= 4'b1110;

else if(delay == 24'h3fffff && stop_start) //流水灯控制

case (left_right) //方向控制

1: led_value_r <= {led_value_r[2:0],led_value_r[3]}; //右移

0: led_value_r <= {led_value_r[0],led_value_r[3:1]}; //左移

default: ;

endcase

assign {led4,led2,led3,led1} = led_value_r;

endmodule

【代码-Verilog】交通灯控制器

/**********************************************************/

/*MODULE: raffic_controller */

/*FILE NAME: raffic_controller.v */

/*VERSION: v1.0 */

/*DATE: 2009-06-10 21:30 */

/*AUTHOR: ht5815@https://www.wendangku.net/doc/aa11136960.html, */

/**********************************************************/

/****************************************************************************** ****************/

/* 交通灯控制器:用于主干道与?道公路的交叉路口,要求是优先保证主干道的畅通. */

/*设计要求: */

/* (1)平时处于"主干道绿灯,?道红灯"状态,只有在?道有车辆要穿过主干道时,才将交通灯切*/

/* 向"主干道红灯,?道绿灯",一旦?道无车辆通过路口,交通灯又回到"主干道绿灯,?道红灯"的状态. */

/* 当?干道连续有车通过、主干道无车通过时保持"主干道红灯,?道绿灯"状态。*/

/* (2)主干道每次通行的时间60秒,?路每次通行的时间20秒,而这两个状态交换过程中出现*/

/* "主黄、?红"和"主红,?黄"的状态,持续时间都为4秒*/

/****************************************************************************** ****************/

/*********************************************************/

/*状态| 主干道| ?干道| 时间/S */

/*——————————————————————————— */

/*state0 |绿灯亮,允许通行|红灯亮,禁止通行| 60s */

/*state1 |黄灯亮,停车|红灯亮,禁止通行| 4s */

/*state2 |红灯亮,禁止通行|绿灯亮,允许通行| 20s */

/*state3 |红灯亮,禁止通行|黄灯亮,停车| 4s */

/*********************************************************/

module traffic_controller(clk_1Hz,reset,a_busy,b_busy,a_counter,b_counter,

a_red,a_green,a_yellow,b_red,b_green,b_yellow);

input clk_1Hz,reset,a_busy,b_busy;

output[7:0] a_counter,b_counter; /*主干道,?干道计时显示*/

output a_red,a_green,a_yellow,b_red,b_green,b_yellow;

reg a_red,a_green,a_yellow,b_red,b_green,b_yellow;

reg[7:0] a_counter,b_counter;

reg[1:0] state;

parameter state0=2'b00,state1=2'b01,state2=2'b10,state3=2'b11;

/****************************************************************************** ****************/

always@(posedge clk_1Hz or posedge reset)

begin

if(reset) /*复位,计时器清零,两路都显示红灯*/

begin

a_counter<=0;

b_counter<=0;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b100100;

end

else begin

if(a_counter==0||b_counter==0)

case(state)

state0: begin

if(b_busy)

begin

state<=state1; /*主干道黄灯、?干道红灯,4秒*/

a_counter<=8'h03;

b_counter<=8'h03;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b001100;

end

else begin

state<=state0; /*主干道绿灯、?干道红灯,60秒*/

a_counter<=8'h59;

b_counter<=8'h63;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b010100;

end

end

state1: begin

state<=state2; /*主干道红灯、?干道绿灯,20秒*/

a_counter<=8'h23;

b_counter<=8'h19;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b100010;

end

state2: begin

if(a_busy)

begin

state<=state3;

b_counter<=8'h03;

a_counter<=8'h03;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b100001;

end

else if(b_busy)

begin

state<=state2;

a_counter<=8'h23;

b_counter<=8'h19;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b100010;

end

else begin

state<=state3; /*主干道红灯、?干道黄灯,4秒*/

b_counter<=8'h03;

a_counter<=8'h03;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b100001;

end

end

state3: begin

state<=state0;

a_counter<=8'h59;

b_counter<=8'h63;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b010100;

end

default:begin

a_counter<=8'h59;

b_counter<=8'h63;

state<=state0;

{a_red,a_green,a_yellow,b_red,b_green,b_yellow}<=6'b010100;

end

endcase

/**************************************************/

/*计时显示*/

else

begin

if(a_counter[3:0]==0)

begin

a_counter[7:4]<=a_counter[7:4]-1;

a_counter[3:0]<=9;

end

else a_counter[3:0]<=a_counter[3:0]-1;

if(b_counter[3:0]==0)

begin

b_counter[7:4]<=b_counter[7:4]-1;

b_counter[3:0]<=9;

end

else b_counter[3:0]<=b_counter[3:0]-1;

end

end

/****************************************************************************** ****************/

Endmodule

数字频率计(测试成功)

/*测试环境:quatersII7.2 FPGA:ED2开发版GPIO0_0 外接频率输入

*/

module frequency (clk_x,clk,segdat1,segdat2,segdat3,segdat4,segdat5,segdat6,segdat7,segdat8);

input clk,clk_x;

output segdat1,segdat2,segdat3,segdat4,segdat5,segdat6,segdat7,segdat8;

reg [6:0] segdat1,segdat2,segdat3,segdat4,segdat5,segdat6,segdat7,segdat8;

reg [3:0] dispdat1,dispdat2,dispdat3,dispdat4;

reg [24:0] count;

reg [15:0] fosc,fosc_flash;

reg second;

reg flag;

initial

begin

segdat5=7'b1111111;

segdat6=7'b1111111;

segdat7=7'b1111111;

segdat8=7'b1111111;

flag=1'b0;

end

////////////////////////////jiang shi zhong fen ping cheng 1 HZ////////////////////////////////////

always @ (posedge clk)

begin

count=count+1;

if(count==25'd2*******)

begin

count=25'b0000000000000000000000000;

second=~second;

end

end

///////////////////////display////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////

/*

/////////////////////////jiang ping lv de mei yi wei zhi fu gei xiang ying de shu chu guan jiao//////////////////////////////////////////////////////

always @(count[11:10])

begin

case(count[11:10])

2'b00: segdat1=fosc[3:0];

2'b01: segdat2=fosc[7:4];

2'b10: segdat3=fosc[11:8];

2'b11: segdat4=fosc[15:12];

endcase

end

*/

/////////////////jiang shu chu ping lv de zhi fu gei wei xuan chu ji cun qi///////////////////////////////////////////

always @(count[11:10])

begin

case(count[11:10])

2'b00: dispdat1=fosc[3:0];

2'b01: dispdat2=fosc[7:4];

2'b10: dispdat3=fosc[11:8];

2'b11: dispdat4=fosc[15:12];

endcase

end

//////////////////////yong wei xuan shu chu ji cun qi kong zhi segdat1 shu ma guan de ju ti shu chu zhi////////////////////////////////////////////////////

////////////////////////////////di yi ge shu ma guan de xian shi///////////////////////////// always @(dispdat1)

begin

case(dispdat1)

4'h0: segdat1=7'b1000000;//0

4'h1: segdat1=7'b1111001;//1

4'h2: segdat1=7'b0100100;//2

4'h3: segdat1=7'b0110000;//3

4'h4: segdat1=7'b0011001;//4

4'h5: segdat1=7'b0010010;//5

4'h6: segdat1=7'b0000010;//6

4'h7: segdat1=7'b1111000;//7

4'h8: segdat1=7'b0000000;//8

4'h9: segdat1=7'b0010000;//9

endcase

end

////////////////////////////////di er ge shu ma guan de xian shi///////////////////////// always @(dispdat2)

begin

case(dispdat2)

4'h0: segdat2=7'b1000000;//0

4'h1: segdat2=7'b1111001;//1

4'h2: segdat2=7'b0100100;//2

4'h3: segdat2=7'b0110000;//3

4'h4: segdat2=7'b0011001;//4

4'h5: segdat2=7'b0010010;//5

4'h6: segdat2=7'b0000010;//6

4'h7: segdat2=7'b1111000;//7

4'h8: segdat2=7'b0000000;//8

4'h9: segdat2=7'b0010000;//9

endcase

end

/////////////////////di san ge shu ma guan de xian shi///////////////////////// always @(dispdat3)

begin

case(dispdat3)

4'h0: segdat3=7'b1000000;//0

4'h1: segdat3=7'b1111001;//1

4'h2: segdat3=7'b0100100;//2

4'h3: segdat3=7'b0110000;//3

4'h4: segdat3=7'b0011001;//4

4'h5: segdat3=7'b0010010;//5

4'h6: segdat3=7'b0000010;//6

4'h7: segdat3=7'b1111000;//7

4'h8: segdat3=7'b0000000;//8

4'h9: segdat3=7'b0010000;//9

endcase

end

//////////////////////di si ge shu ma guan de xian shi/////////////////////////

always @(dispdat4)

begin

case(dispdat4)

4'h0: segdat4=7'b1000000;//0

4'h1: segdat4=7'b1111001;//1

4'h2: segdat4=7'b0100100;//2

4'h3: segdat4=7'b0110000;//3

4'h4: segdat4=7'b0011001;//4

4'h5: segdat4=7'b0010010;//5

4'h6: segdat4=7'b0000010;//6

4'h7: segdat4=7'b1111000;//7

4'h8: segdat4=7'b0000000;//8

4'h9: segdat4=7'b0010000;//9

endcase

end

/*

always

begin

fosc[3:0]=4'd0;

end

*/

//ce ding wei zhi xin hao clk_x de ping lv ,bing jiang qi zhi chuan gei fosc_flash////////////

always @ (posedge clk_x)

begin

if(second)

begin

flag=1;

fosc_flash[3:0]=fosc_flash[3:0]+1;

if(fosc_flash[3:0]>4'd9)

begin

fosc_flash[3:0]=4'd0;

fosc_flash[7:4]=fosc_flash[7:4]+1;

if(fosc_flash[7:4]>4'd9)

begin

fosc_flash[7:4]=4'd0;

fosc_flash[11:8]=fosc_flash[11:8]+1;

if(fosc_flash[11:8]>4'd9)

begin

fosc_flash[11:8]=4'd0;

fosc_flash[15:12]=fosc_flash[15:12]+1;

if(fosc_flash[15:12]>4'd9)

fosc_flash[15:12]=4'd0;

end

end

end

end

else if(flag)

begin

//if(flag)

begin

flag=0;

fosc[15:0]=fosc_flash[15:0];

fosc_flash[15:0]=16'h0;

end

end

end

endmodule

/*心得与体会

1、使用数码管时,要定义一个输出端口,若是七段数码管的话就定义输出端口7位,同时定义一个段码寄存器,先将要输出的值赋给段码寄存器,用case语句将要输出的值赋给输出管脚。(注意:实际上,段码寄存器的值和输出管脚的值是相等的,这里只是用了一种间接的方式将要输出的值显示出来)

如:

always @(count[11:10])

begin

case(count[11:10])

2'b00: dispdat1=fosc[3:0];

2'b01: dispdat2=fosc[7:4];

2'b10: dispdat3=fosc[11:8];

2'b11: dispdat4=fosc[15:12];

endcase

end

always @(dispdat1)

begin

case(dispdat1)

4'h0: segdat1=7'b1000000;//0

4'h1: segdat1=7'b1111001;//1

4'h2: segdat1=7'b0100100;//2

4'h3: segdat1=7'b0110000;//3

4'h4: segdat1=7'b0011001;//4

4'h5: segdat1=7'b0010010;//5

4'h6: segdat1=7'b0000010;//6

4'h7: segdat1=7'b1111000;//7

4'h8: segdat1=7'b0000000;//8

4'h9: segdat1=7'b0010000;//9

endcase

end

上面的程序中时将检测到的值先赋给段码寄存器(如dispdat1,dispdat2...),再将段码寄存器的值赋给相应的书出管脚(如segdat1,segdat2...).这里用到的是case语句,在c语言里面用的是一个数组就可以很容易就实现。应注意次方面的技巧。

2、注意以下习程序的技巧:

always @(count[11:10])

begin

case(count[11:10])

2'b00: segdat1=fosc[3:0];

2'b01: segdat2=fosc[7:4];

2'b10: segdat3=fosc[11:8];

2'b11: segdat4=fosc[15:12];

endcase

end

上面的这段程序有一点向单片机里面的动态扫描,所不同的是,扫描的值是通过计数器count极短的跳变时间里面里完成的。这种语句使用得相当的广泛。“always @(count[11:10])

*/

Verilog HDL 4*4矩阵键盘扫描程序

硬件电路图如下:

1 module key (clk, //50MHZ

reset, row, //行

col, //列

key_value //键值

);

input clk,reset;

input [3:0] row;

output [3:0] col;

output [3:0] key_value;

reg [3:0] col;

reg [3:0] key_value;

reg [5:0] count;//delay_20ms

reg [2:0] state; //状态标志

reg key_flag; //按键标志位

reg clk_500khz; //500KHZ时钟信号

reg [3:0] col_reg; //寄存扫描列值

reg [3:0] row_reg; //寄存扫描行值

always @(posedge clk or negedge reset)

if(!reset) begin clk_500khz<=0; count<=0; end

else

begin

if(count>=50) begin clk_500khz<=~clk_500khz;count<=0;end

else count<=count+1;

end

always @(posedge clk_500khz or negedge reset)

if(!reset) begin col<=4'b0000;state<=0;end

else

begin

case (state)

0:

begin

col[3:0]<=4'b0000;

key_flag<=1'b0;

if(row[3:0]!=4'b1111) begin state<=1;col[3:0]<=4'b1110;end //有键按下,扫描第一行

相关文档
相关文档 最新文档