FPGA实验—— 流水灯

发布时间 2023-03-25 18:01:58作者: CoderEnd

FPGA实验 流水灯

时钟频率与时钟周期计算

\[f=\frac{1}{T} \]

f是频率 T是周期  时钟周期的计算  1s=1000ms=1000000us=1000000000ns
对于100kHz=100000Hz  f= 1000000000/100000 =10000ns
	8MHz = 8000kHz=8000000Hz f=1000000000/8000000=125ns
时钟频率 时钟周期
100kHz 10_000ns
1MHz 1_000ns
8MHz 125ns
50MHz 20ns
100MHz 10ns
125MHz 8ns
150MHz 6.667ns
200MHz 5ns
led 流水灯 每隔0.2s 闪

20ns对应输入的时钟频率为50MHz (不同开发板,或者硬件设计可能有不同)

0.2s/20ns = 1000_0000

ppD9C5j.md.png

//计数器 counter:0-9999999 (10000000) 通过转换二进制 得到位宽
/*
计数器 counter 一般计数器都是从0开始,例如计数器要计数10000,则需要写成10000-1
计数器 counter-1
‭16b'0010_0111_0001_0000‬ = 16d'1_0000
*/
//‭1001_1000_1001_0110_1000_0000‬   位宽24  reg [23:0]  位宽N  reg [N-1:0]  
reg [23:0] counter;

//电路设计 高电平点亮,低电平熄灭

//计数器对系统时钟计数,计时0.2秒
always @(posedge sys_clk or negedge sys_rst_n) begin //检测时钟的上升沿和复位的下降沿
    if (!sys_rst_n)  //当sys_rst_n 处于复位状态时,计数器重置0  复位信号低有效
        counter <= 24'd0;
    else if (counter < 24'd1000_0000-1'b1) //计数器开始计数,从0-9999999,自加
        counter <= counter + 1'b1;
    else
        counter <= 24'd0;//计数器达到计数值,置0,
end


//通过移位寄存器控制IO口的高低电平,从而改变LED的显示状态
//0001->0010->0100->1000->0001
always @(posedge sys_clk or negedge sys_rst_n) begin //检测时钟的上升沿和复位的下降沿
    if (!sys_rst_n)   //当sys_rst_n 处于复位状态时,led1亮,置1
        led <= 4'b0001;
    else if(counter == 24'd1000_0000-1'b1) //当计数器计数到指定值时,进行操作
        led[3:0] <= {led[2:0],led[3]};  //把高位赋给低位进行交换
    else
        led <= led;
end

基本概念

1.1 原码

最高位为符号位,0表示正数,1表示负数。
例如:
X = 0b11 (3),四比特表示原码 = 0011(3) ;

X = - 0b11(-3) ,四比特表示原码 = 1011(11) ;

1.2 反码

最高位为符号位,0表示正数,1表示负数。

正数的反码等于本身,负数的反码除符号位外,各位取反:
例如:
X = 0b11 (3),四比特表示原码 = 0011(3),对应反码为 = 0011(3) ;

X = - 0b11(-3) ,四比特表示原码 = 1011(11),对应反码为 = 1100(12)  ;

1.3 补码

最高位为符号位,0表示正数,1表示负数。

正数的补码等于本身,负数的补码等于反码+1:
例如:
X = 0b11 (3),四比特表示原码 = 0011(3) 对应反码为 = 0011(3)  补码 = 0011(3) 

X = - 0b11(-3) ,四比特表示原码 = 1011(11) 对应反码为 = 1100(12)  补码 = 1101 

2. 运算符

2. 1 拼接运算符 “ {} ”

拼接操作是将小表达式合并形成大表达式的操作,其形式如下:

{ expr1, expr2, . . ., exprN} ; 
// 假设 Dbus = 8b'1101 1110 
// [7:0]是从高位到低位的排布
//[7:0] Dbus -->>{Dbus [7], Dbus [6], Dbus[5], Dbus[ 4 ] ,Dbus [3], Dbus [2], Dbus[1], Dbus[0]}
wire [7:0] Dbus; 
assign Dbus [7:4] = {Dbus [0], Dbus [1], Dbus[2], Dbus[ 3 ] } ; //->[0,1,1,1]
//[7:4]  = 4b'0101
/ /以反转的顺序将低端 4 位赋给高端 4 位。
assign Dbus = {Dbus [3:0], Dbus [ ] } ;
// Dbus [3:0] = 4b'1010  Dbus [ 7:4] = 4b'1101
//高 4 位与低 4 位交换

2.2 赋值

在一个always块中,阻塞型赋值语句操作完成后才允许其它语句执行,这样容易产生一个问题:当等号= 右端操作符在另一个always块中是左边变量时,两个赋值操作就是同时进行的!

非阻塞型赋值的操作符是<=,非阻塞型赋值语句的名称由来是因为非阻塞型赋值的操作在一个时刻开始是被赋予左端表达式,而在这一时刻结束时左端表达式才更新。在此过程中不影响其它赋值语句的操作。

非阻塞可以理解为并行执行,不考虑顺序,在always块语句执行完成后,才进行赋值。

在assign 语句中必须使用阻塞赋值。