原创 fpga学习日记17,第一个综合项目数字时钟

2013-8-31 10:37 1473 19 21 分类: FPGA/CPLD 文集: 数电,FPGA学习

本文分为两个部分

第一部分 verilog知识点简要回顾

第二部分 数字时钟设计

 

第一部分:verilog知识点回顾

1,数值表示方法
verilog支持两种格式的数值表示方法: 指明位宽的数字(sized number)和不指明位宽
的数字(unsized number)。

指明位宽的数字的表示形式为:’ ;
4’ b1001; //4 位宽的二进制数 1001
12’habc; // 12 位的十六进制数 abc
16’d255; //16 位十进制数

如果在数字说明中没有指定基数, 那么默认为十进制数; 如果没有指定位宽, 则默认的
位宽与仿真器、综合器使用的计算机有关(最小为 32 位)。举例如下:
23456; //32 位宽的十进制数 23456
’habc; // 32 位的十六进制数 abc

2,端口连接规则


 

1.jpg

3,向量
线网和寄存器类型的变量可以声明为向量(Vector)(位宽大于 1),如果声明中没有指定位
宽,则默认为标量(位宽为 1)。举例如下
wire a; //标量线网变量,默认
reg  [n-1:0]busA,busB; //声明 busA 和 busB 为 n 位宽寄存器变量,
reg  [0:n-1]busC;   //声明 busC 为 n 位宽的寄存器变量
wire  [n-1:0]busA,busB; //声明 busA 和 busB 为 n 位宽信号,
wire  [0:n-1]busC;   //声明 busC 为 n 位宽的信号

向量通过[high#:low#]或者[low#:high#]说明,方括号中左边数总是代表向量的最高有效
位(Most  Significant  Bit,  MSB),在上面的例子中,向量 busA 的最高有效位为第 n-1 位

,向量busC 的最高有效位为第 0 位。
1、向量域选择
对于上面例子中声明的向量,可以指定它的某一位或若干个相邻位。举例如下
busA[0]   //向量 busA 的第 0 位;
busA[2:0] //向量第 3 位;如果写成 busA[0:2]非法,高位应该写在范围说明的左侧;
busC[0:1] //向量 busC 的高 2 位;
2、可变的向量域选择
除了用常量指定向量域外, Verilog HDL 还允许指定可变的向量域选择。 这样使设计者可
以通过 for 循环动态地选取向量的各个域,下面是动态域选择的两个专用操作符
[ +: width]:  从起始位 starting_bit 开始递增,位宽为 width;
[ -: width]:  从起始位 starting_bit 开始递增,位宽为 width;

 

 

 

 

 

 

 

 

 

4,数组
在 Verilog  HDL 中允许声明 reg 以及 wire 类型向量以及标量的数组,对数组的维数没有
限制。 线网数组也可用于连接连接实例的端口, 数组中的每个元素可以作为变量或者向量使
用。
reg [4:0]port_id[0:7] //由 8 个 5 位宽的向量组成的数组,数组的每个元素为 5 位宽变量

5   always语句

always@([sensitivity_list])
begin [optional_block_name]
[optional local variable declaration];
[procedural statement];
[procedural statement];
end
[sensitivity_list]称为敏感列表, 敏感列表是可选的, 有时也被称为事件控制表达式(event
control expression)。
规则
always 只能赋值寄存器reg integer real time realtime 类型
• 启动仿真时所有always 都开始执行而且在仿真过程中持续执行当到达always 的最后一条

从仿真角度讲, 敏感信号值发生改变, always 块会对其改变做出
响应,即顺序执行 always 块中的所有语句。always 块如果包含多条语句,则需要将多个语句置于 begin 和 end 之间。如果只有 1 条语句,则可以省略 begin 和 end。注意:出于代码
可维护性的考虑,建议只有一条语句时也使用 begin 和 end。
举例如下:
//电平敏感的敏感列表
always@(a or b or c)    //always 块描述的组合逻辑电路的输入为 a,b 和 c。
always@(a, b, c)       //另外一种形式的敏感列表, 敏感列表包含多个信号时可以采//
用关键字 or 分割,也可以采用逗号(;)分割;
always@*               //另外一种形式的敏感列表,表示 always 块中所有赋值表达式
//中的所有变量都是敏感信号。

 

6,阻塞与非阻塞
过程赋值语句只能出现在 always 块或者 initial 块中,分为两种类型:阻塞赋值(blocking
assignment)和非阻塞赋值(non-blocking assignment)。其基本语法如下:
[variable_name1] = expression1;    阻塞赋值语句
[variable_name2] <= expression2;   非阻塞赋值语句
阻塞赋值语句中, 赋值表达式首先被计算, 之后将计算结果赋值给左侧变量。 此过程连续执行,在完成赋值前不能执行其后的其它任何语句(该赋值语句的执行“阻塞”其后其它语句的执行),其行为非常类似 C 语言中变量赋值过程。
无论是阻塞赋值还是非阻塞赋值都只能对寄存器类型(reg)的变量赋值。这里需要强调:虽然过程赋值语句只能对寄存器类型的变量赋值, 并不代表最终的综合结果一定包含寄存器。
非阻塞赋值语句执行时, 首先计算表达式的值, 但并不会立即将表达式的值赋予左侧变量,赋值操作会在 always 块所有语句执行完成之后再将表达式的值赋予左侧变量(赋值过程并不会“阻塞”其后的其它语句的执行)。
对于 Verilog  HDL 的初学者,阻塞赋值语句和非阻塞语句的使用非常困难。如果不能理
解二者的区别往往导致最终的电路出现竞争和冒险。 这里给出 2 条经验规则(rules of thumb):
  组合逻辑描述中使用阻塞赋值语句;
  时序电路的描述中使用非阻塞赋值语句;

 

7,if else
//类型 1:只有 if 子句,不包含 else 分支
if(expression)
 begin       //expression 为真时,执行
 true_statement1;
 true_statement2;
 …
 end
//类型2
if(expression)
 begin       //expression 为真时,执行
 true_statement1;
 true_statement2;
 …
 end

else
 begin       //expression 为假时,执行
 false_statement1;
 false_statement2;
 …
 end

举例
always @*
if (en==1'b0)         //等价于 if(~en)
y = 4'b0000;
else if (a==2'b00)
y = 4'b0001;
else if (a==2'b01)
y = 4'b0010;
else if (a==2'b10)
y = 4'b0100;
else
y = 4'b1000;

8,case 语句语法
case (case_expression)
alternative1:
begin
procedural_statement11;
procedural_statement12;

end
alternative2:
begin
procedural_statement21;
procedural_statement22;

end

alternativen:
begin
procedural_statementn1;
procedural_statementn2;

end
default:
begin
procedural_statement_1;
procedural_statement_2;

end
endcase
举例
always@*
begin
case(s)
2'b00: y=a;
2'b01: y=b;
2'b10: y=c;
2'b11: y=d;
default: y=8'bxxxxxxxx;
endcase

end

 

第二部分:数字时钟设计

设计思路

1,首先我们要让代表秒的led每秒闪烁一次

所以我们要设计一个2hz 的时钟来提供led闪烁

2,其次我们设计三个计数器 周期分别是60 60 24代表秒 分 时 计数满后向相邻计数器进1

3,数码管驱动程序每ms把计数器数据显示到数码管上即可

第二部分数字时钟设的

1,制作2hz时钟驱动led每秒亮一次

//****************************************Copyright (c)***************************
//
//file name:myclock.v
//作用:产生1HZ时钟 并驱动LED1秒亮一次
//
// ----------------------------------------------------
//
//by:wenzer
//date:2013-08-30
//version:v0.01
//Descriptions:        The original version
//
//*********************************************************************************
module myclock(
   input   sys_clk_50m,
   input   sys_rst_n,
   output reg [7:0]   LED);
   
   reg   [16:0] div_cnt_ms;
   reg   [16:0] div_cnt_500ms;
   reg    clk_ms;
   reg    clk_500ms;
   
   // 50M = 20ns , 20ns * 25000 *2 ~= 1ms
always @(posedge sys_clk_50m or negedge sys_rst_n) begin
       if (sys_rst_n ==1'b0)  
           div_cnt_ms <= 17'b0;
       else if (div_cnt_ms >= 17'd25000)
                   div_cnt_ms <= 17'b0;
               else
                   div_cnt_ms <= div_cnt_ms + 17'b1;
end

always @(posedge sys_clk_50m or negedge sys_rst_n) begin
       if (sys_rst_n ==1'b0)  
           clk_ms <=   1'b0;
       else if ( div_cnt_ms == 17'b0 )
          clk_ms <=  ~clk_ms ;
       else ;
end

always @(posedge clk_ms or negedge sys_rst_n) begin
       if (sys_rst_n ==1'b0)  
           div_cnt_500ms <=  17'b0;
       else
           if (div_cnt_500ms >= 17'd250)
                   div_cnt_500ms <=   17'b0;
               else
                   div_cnt_500ms <=  div_cnt_500ms + 17'b1;
end

always @(posedge clk_ms or negedge sys_rst_n) begin
       if (sys_rst_n ==1'b0)  
           clk_500ms <=  1'b0;
       else if ( div_cnt_500ms == 17'd250 )begin
           clk_500ms <=  ~clk_500ms ;

               end
end

always @(posedge clk_500ms) begin

               LED = ~LED ;              
end

endmodule

2,实现三个计数器  周期分别为24小时   60分  60秒

60=11 1100  6位

24= 1 1000  5位

//
//秒计数器
//
always @(posedge clk_sec or negedge sys_rst_n) begin

       if (sys_rst_n ==1'b0)  
           cnt_sec <=  6'b0;
       else if (cnt_sec>= 6'd60 )
                       cnt_sec=6'b0;
               else
                       cnt_sec=cnt_sec+6'b1;
end
//
//分计数器
//
always @(posedge clk_sec or negedge sys_rst_n) begin

       if (sys_rst_n ==1'b0)  
           cnt_min <=  6'b0;
       else if (cnt_min>=6'd60)
                       cnt_min=6'b0;
               else if(cnt_sec>=6'd60)
                       cnt_min=cnt_min+6'b1;
end
//
//小时计数器
//
always @(posedge clk_sec or negedge sys_rst_n) begin

       if (sys_rst_n ==1'b0)  
           cnt_hor <=  6'd12;
       else if (cnt_min>= 6'd60)
                   cnt_hor=cnt_hor+6'b1;
                   else if (cnt_hor>= 6'd24)begin
                           cnt_hor=6'b0;
                               end
                             
end

 

3,实现每秒把计数器数据显示到数码管  可参考此设计思想

 

 

11.jpg

 

 目前目测

 

 

 

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

2005jiangxu_694877046 2015-3-11 08:54

原来如此,谢谢分享!

liang890319_284707880 2013-9-2 08:00

还有很多困惑的地方需要学习呢

用户961355 2013-8-31 15:19

楼主十几天就学到这个程度,厉害。
相关推荐阅读
liang890319_284707880 2016-03-22 11:41
[博客大赛]我在搞嵌入式 我有罪
  我在搞嵌入式 我有罪 做嵌入式也有几年了 刚学习的时候书上说嵌入式的定义是以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计...
liang890319_284707880 2015-10-22 11:57
帕萨特迈腾蒙迪欧哪个好
氵灬清风灬说:太小了,没法穿了,懒得换了 junyao00022说:............................... jd272475byp说:宝贝收到啦,衣服质量非常不错,...
liang890319_284707880 2015-10-22 11:56
二手荣威550和二手起亚k2哪个好
二手荣威550和二手起亚k2哪个好   风之乞说:衣服挺好的,就是偏小,已经更换了 梦里水乡0609说:不错 很好  不了不错  赞 四灵之首说:衣服质量不错,韵达快递不行~ ...
liang890319_284707880 2015-10-22 11:55
澳大利亚深海鱼油哪个牌子好
hgjfhgj说:不错  价格便宜  款式不错  开始买中码小了一点  免费给换的  好店家 小杰c子说:非常合适。也很有气质 天佑945说:还可以,性价比高。。。。。。。。。。 Ab...
liang890319_284707880 2015-10-19 11:03
常用DDR sdram和Flash型号
  以下是代码片段: http://blog.csdn.net/myarrow/article/details/7854863   主要是三星 现代 ...
liang890319_284707880 2013-09-29 17:00
ROM FLASH RAM
EPROM、EEPROM、FLASH的总结性区别   http://xdc0363.blog.163.com/blog/static/11546200220...
EE直播间
更多
我要评论
2
19
关闭 站长推荐上一条 /3 下一条