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 //有键按下,扫描第一行