一、設計思路
- led模塊的功能是指定時間,控制八個時間段的亮滅,兩個輸入信號,8位的ctr信號,32位的time信號
time信號的計算公式:時間(clk),例如,系統時鍾為50MHz,想要一段時間為1秒,則有time = 150*10^6; - 串口接收后如何對數據進程處理,將40bit的數據,輸入到led模塊?
- 引入校驗位,例如:只有輸入的前兩個字節為,0x20,0x21,輸入的后一個字節為0xCE,才為正確的數據
- 引入校驗位,例如:只有輸入的前兩個字節為,0x20,0x21,輸入的后一個字節為0xCE,才為正確的數據
二、串口接收以及仿真代碼
[https://www.cnblogs.com/cnlntr/p/12483495.html]
三、串口接收的數據處理模塊(定義與下一個模塊的通信協議)
module uart_tx_cmd(
clk ,
rst_n ,
rx_done ,
data ,
ctr ,
tim
);
parameter DATA_W = 8;
parameter CTR_W = 8;
parameter TIM_W = 32;
parameter CNTD_N = 8; //一串完整數據所包含字節的個數,兩個起始校驗字節+5個數據字節+1個終值校驗字節
parameter CNTD_W = 3; //字節計數器位寬
input clk;
input rst_n;
input rx_done;
input [DATA_W-1:0] data;
output [CTR_W-1:0] ctr;
output [TIM_W-1:0] tim;
reg [CTR_W-1:0] ctr;
reg [TIM_W-1:0] tim;
reg [CNTD_W-1:0] cnt_data;
wire add_cnt_data;
wire end_cnt_data;
//8個8位的寄存器,用來存放串口發送的完整數據
reg [7:0] data_save[7:0];
reg data_done;
//串口發送字節計數器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_data <= 0;
else if(add_cnt_data)begin
if(end_cnt_data)
cnt_data <= 0;
else
cnt_data <= cnt_data + 1'b1;
end
end
assign add_cnt_data = rx_done;
assign end_cnt_data = add_cnt_data && cnt_data == CNTD_N - 1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
data_save[0] <= 0;
data_save[1] <= 0;
data_save[2] <= 0;
data_save[3] <= 0;
data_save[4] <= 0;
data_save[5] <= 0;
data_save[6] <= 0;
data_save[7] <= 0;
end
else if(rx_done)
data_save[cnt_data] <= data;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
{ctr,tim} <= 40'b0;
else if(data_done && (data_save[0]== 8'h20 && data_save[1] == 8'h21 && data_save[7] == 8'hCE))begin
ctr <= data_save[2];
tim[7:0] <= data_save[6];
tim[15:8] <= data_save[5];
tim[23:16] <= data_save[4];
tim[31:24] <= data_save[3];
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data_done <= 0;
else if(end_cnt_data)
data_done <= 1;
else
data_done <= 0;
end
endmodule
四、led控制模塊
module led_beta4(
clk ,
rst_n ,
ctr ,
tim ,
led
);
parameter CNT_W = 27; //計數器位寬
parameter CTR_W = 8; //輸入控制信號位寬
parameter CNT1_W = 3; //控制信號計數器位寬
parameter TIM_W = 32; //時間位寬
input clk;
input rst_n;
input [CTR_W-1:0] ctr;
input [TIM_W-1:0] tim;
output led;
reg led;
reg [CNT_W-1:0] cnt;
wire add_cnt;
wire end_cnt;
reg [CNT1_W-1:0] cnt_ctr;
wire add_cnt_ctr;
wire end_cnt_ctr;
wire led_tmp;
//0.25s計數器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1'b1;
end
end
assign add_cnt = (tim >= 1);
assign end_cnt = add_cnt && cnt == tim - 1;
//8位控制信號計數器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_ctr <= 0;
else if(add_cnt_ctr)begin
if(end_cnt_ctr)
cnt_ctr <= 0;
else
cnt_ctr <= cnt_ctr + 1'b1;
end
end
assign add_cnt_ctr = end_cnt;
assign end_cnt_ctr = add_cnt_ctr && cnt_ctr == CTR_W - 1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
led <= 1;
else
led <= led_tmp;
end
assign led_tmp = ctr[cnt_ctr];
endmodule
五、頂層模塊
module uart_rx_ctrl_led(
clk ,
rst_n ,
led ,
uart_rx
);
input clk;
input rst_n;
input uart_rx;
output led;
wire led;
wire [31:0] tim;
wire [7:0] ctr;
wire [7:0] data;
wire rx_done;
led_beta4 led_beta4(
.clk (clk),
.rst_n (rst_n),
.ctr (ctr),
.tim (tim),
.led (led)
);
my_uart_rx my_uart_rx(
.rst_n (rst_n),
.clk (clk),
.uart_rx (uart_rx),
.baud_set (4'd4),
.data (data),
.rx_done (rx_done)
);
uart_tx_cmd uart_tx_cmd(
.clk (clk),
.rst_n (rst_n),
.rx_done (rx_done),
.data (data),
.ctr (ctr),
.tim (tim)
);
endmodule
六、仿真代碼
`timescale 1ns / 1ns
module uart_rx_ctrl_led_tb();
parameter CYCLE = 20;
reg clk ;
reg rst_n;
wire led;
reg uart_rx;
uart_rx_ctrl_led uart_rx_ctrl_led(
clk ,
rst_n ,
led ,
uart_rx
);
initial begin
clk = 1;
forever
#(CYCLE/2)
clk = ~clk;
end
initial begin
rst_n = 1;
#3
rst_n = 0;
#(10*CYCLE)
rst_n = 1;
end
initial begin
uart_rx = 1'b1;
@(posedge rst_n);
#(8*CYCLE);
uart_tx(8'h20);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'h21);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'hE8);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'h03);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'h00);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'h00);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'h00);
@(posedge uart_rx_ctrl_led.rx_done);
uart_tx(8'hCE);
@(posedge uart_rx_ctrl_led.rx_done);
#2000000;
$stop;
end
task uart_tx;
input [7:0] data_in;
begin
uart_rx = 1'b0;
#(5208*CYCLE);
uart_rx = data_in[0];
#(5208*CYCLE);
uart_rx = data_in[1];
#(5208*CYCLE);
uart_rx = data_in[2];
#(5208*CYCLE);
uart_rx = data_in[3];
#(5208*CYCLE);
uart_rx = data_in[4];
#(5208*CYCLE);
uart_rx = data_in[5];
#(5208*CYCLE);
uart_rx = data_in[6];
#(5208*CYCLE);
uart_rx = data_in[7];
#(5208*CYCLE);
uart_rx = 1'b1;
end
endtask
endmodule
七、小結
計數器問題
第一個代碼:加一條件為1,結束條件是由變量控制的,當變量tim輸入為0的時候就變成了,0-1 = FFFF FFFF FFFF FFFF
因此要改動為第二個代碼
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1'b1;
end
end
assign add_cnt = 1;
assign end_cnt = add_cnt && cnt == tim - 1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1'b1;
end
end
assign add_cnt = (tim >= 1);
assign end_cnt = add_cnt && cnt == tim - 1;