一、如何隔10ms发送8bit的数据 , 让led实现这8bit的数据
1. 想实现的led样式
想要让一个led灯每隔10ms就重新按照 1010_1010 流一遍。其中 1 代表高电平,0 代表低电平。右边是低位,左边是高位。也就是先灭,再亮,再灭,再亮…直到亮完最后一位。这个过程包含在10ms内,10ms一到,重新发数据,然后先灭,再亮,再灭,再亮…直到亮完最后一位…一直重复。
2. 具体数据怎么发,其中的时间怎么定
2.1 一组数据的存储
1个 led 要实现完一组的 1010_1010 ,也就是先亮0,隔一点时间再亮1,再隔一点时间亮0(这样的描述对应1010_1010),中间的间隔时间,可以是1ms,这个正好符合人眼习惯。为了准备 1ms ,这里设置了一个定时器 cnt ,从0加到1ms,到时间了就切换下一个led的亮灭状态。对led的赋值可以选择隔1ms,重新给led赋值,如果这样做,会让一组数据只传输一遍就停止了。
2.2 定时循环传数据
也可以把1个字节的数据存在数组里面,1ms切换一个元素。用序号来取数组里面的值,序号先是0,1ms之后+1,直到序号是7的时候,重新清零,继续加,继续清零。这样就可以循环取8位里的每一位值了。为了取完8个bit,这里装一个2级计数器 cnt2,来记取数据的序号。项目想要达到的效果是隔10ms发一次数据,那led亮完最后一位的时候,消耗了7ms,要等待3ms再重新发数据。可以选择写一个3ms计数器,不过还是引入一个En使能信号吧。
2.3 如何理解En信号
在En信号拉高的时候,允许传数据,cnt 和 cnt2 可以计数;En失能的时候 ,不传数据,所以cnt 和 cnt2 通通不计数。这样一旦一组数据传完,就停止传数据,直到10ms到了再传下一组数据。这样想的话,可能还需要创建一个10ms 计数器 cnt_10ms ,cnt_10ms为0的时候,En信号拉高;传输完成En信号拉低。其中无论En信号是否使能,这个计数器都不受影响。
2.4 En信号的疑问
En信号的拉高拉低,不是依靠简单的时间划分:前7ms使能,后3ms失能——这样的做法相当于直接写一个3ms计数器。
En信号的拉高拉低是依靠判断 “ 数据是否传输完成 ” 来控制的。这样,万一之后传完一组数据花费的时间,不是7ms,而是任何其他的时间,也不用依靠更改后面的3ms来控制En信号了,继而凑成10ms。
二、代码
1. 设计代码
module Q6(
input sys_clk ,
input rst_n ,
input [7:0] ctrl ,
input [31:0] time_ctrl ,
output reg led
);
//---------------计数的变量--------------------//
parameter time_10ms=500_000;
reg [31:0] cnt;//基本计时器
reg [3:0] cnt2;//想要传输的数字传到第几位了,记序号
reg [18:0] cnt_10ms;//每10ms传输一次8位数据
reg En;
//-----------------基本时钟--------------------///
always@(posedge sys_clk)
if(!rst_n)
cnt<=0;
else if(En)begin
if (cnt==time_ctrl-1)
cnt<=0;
else
cnt<=cnt+1;
end
else
cnt<=0;
//--------------------2级时钟--------------------
always@(posedge sys_clk)
if(!rst_n)
cnt2<=0;
else if(En)begin
if(cnt==time_ctrl-1)
cnt2<=cnt2+1; end
else//(!En)
cnt2<=0;
//10ms时钟/
always@(posedge sys_clk)
if(!rst_n)
cnt_10ms<=0;
else if(cnt_10ms==time_10ms-1)
cnt_10ms<=0;
else
cnt_10ms<=cnt_10ms+1;
//--------------------En使能信号--------------------///
always@(posedge sys_clk)
if(!rst_n)
En<=0;
else if(cnt_10ms==0)
En<=1;
else if(cnt2==7 && cnt==time_ctrl-1)
En<=0;
else
En<=En;
//--------------------LED----------------------------
always@(posedge sys_clk)
if(!rst_n)
led<=1'b0;
else
case(cnt2)
0:led<=ctrl[0];
1:led<=ctrl[1];
2:led<=ctrl[2];
3:led<=ctrl[3];
4:led<=ctrl[4];
5:led<=ctrl[5];
6:led<=ctrl[6];
7:led<=ctrl[7];
default:led<=0;
endcase
endmodule
2. 测试代码
`timescale 1ns / 1ps
module tb;
//-------------------例化-------------------//
reg sys_clk ;
reg rst_n ;
reg [7:0] ctrl ;
reg [31:0] time_ctrl ;
wire led ;
Q6 q6(
. sys_clk (sys_clk ) ,
. rst_n (rst_n ) ,
. ctrl (ctrl ) ,
. time_ctrl (time_ctrl) ,
. led (led )
);
//-------------------时钟-------------------///
initial begin
sys_clk=0;
forever #10 sys_clk=~sys_clk;
end
//-------------------复位-------------------//
initial begin
rst_n=0;
#50 rst_n=1;
end
//-------------------ctrl 传输的数据-------------------///
initial begin
ctrl=8'd0;
#100 ctrl=8'b1010_1010;//波形是先低位再高位---0101_0101----
end
//-------------------time_ctrl 想要隔多久变化下一个灯-------------//
initial begin
time_ctrl=32'd0;
#120 time_ctrl=32'd250_00;//10ms(500_000) 发送一次数据,这里设置每个数据隔10ms的 1/20(250_00)继续发送下一个数据
end
endmodule
3. 仿真图
-------------p1---------------------En信号的一个周期确实是10ms
------------p2------------------我这里1bit 与 1 bit之间的时间间隔是 0.5 ms