任务要求
通过串口向FPGA开发板发送指令以控制LED灯的工作状态。
工作状态要求:让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,有用户随机指定。8个状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择。
存在问题:由于实际板级运行时,当我们的Time值更新时,counter计数值已经大于该值,所以无法通过计数比较的方式清零,直到32位计满溢出后,才能正常的循环计数。
//解决方法:
if(counter >= Time - 1)
counter <= 0;
仿真波形
设计文件程序
module counter_led(
input Clk,
input Reset_n,
input [7:0] sel,
input [31:0] Time,
output reg Led
);
reg [31:0]counter;
always @(posedge Clk or negedge Reset_n) begin
if(!Reset_n)
counter <= 0;
else if(counter >= Time - 1)
counter <= 0;
else
counter <= counter + 1'd1;
end
reg [2:0]counter2;
always @(posedge Clk or negedge Reset_n) begin
if(!Reset_n)
counter2 <= 0;
else if(counter >= Time - 1)
counter2 <= counter2 + 1'b1;
end
always @(posedge Clk or negedge Reset_n) begin
if(!Reset_n)
Led <= 0;
else case(counter2)
0: Led <= sel[0];
1: Led <= sel[1];
2: Led <= sel[2];
3: Led <= sel[3];
4: Led <= sel[4];
5: Led <= sel[5];
6: Led <= sel[6];
7: Led <= sel[7];
default:Led <= Led;
endcase
end
endmodule
`timescale 1ns/1ns
module UART(
Clk,
Reset_N,
Baud_Set,
UART_RX,
Data,
Rx_Done
);
input Clk;
input Reset_N;
input [2:0]Baud_Set;
input UART_RX;
output reg [7:0]Data;
output reg Rx_Done;
reg [1:0]UART_RX_R;
always@(posedge Clk)begin
UART_RX_R[0] <= #1 UART_RX;
UART_RX_R[1] <= #1 UART_RX_R[0];
end
wire pedge_UART_RX;
wire nedge_UART_RX;
//上升沿检测
// assign pedge_UART_RX = ((UART_RX_R[0] == 1) && (UART_RX_R[1] == 0));
assign pedge_UART_RX = (UART_RX_R == 2'b01);
//下降沿检测
// assign nedge_UART_RX = ((UART_RX_R[0] == 0) && (UART_RX_R[1] == 1));
assign nedge_UART_RX = (UART_RX_R == 2'b10);
// Baud_Set BaudRate
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
//针对不同的波特率,计算相对应的时间长度
reg [17:0]bps_DR;
parameter Time = 32'd1000000000;
always@(*)
case(Baud_Set)
// 16:16倍采样
0: bps_DR = Time/9600/16/20 - 1;
1: bps_DR = Time/19200/16/20 - 1;
2: bps_DR = Time/38400/16/20 - 1;
3: bps_DR = Time/57600/16/20 - 1;
4: bps_DR = Time/115200/16/20 - 1;
default: bps_DR = Time/9600/16/20 - 1;
endcase
// 16段中心采样位置
wire bps_clk_16x;
assign bps_clk_16x = (div_cnt == bps_DR / 2);
reg RX_EN;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
RX_EN <= #1 0;
else if(nedge_UART_RX)
RX_EN <= #1 1;
else if(Rx_Done || (start_bit >= 4))
RX_EN <= #1 0;
// 每小分段计数器
reg [8:0]div_cnt;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
div_cnt <= #1 0;
else if(RX_EN)begin
if(div_cnt == bps_DR)
div_cnt <= #1 0;
else
div_cnt <= #1 div_cnt + 1'd1;
end
else
div_cnt <= #1 0;
// 每帧数据中160小段计数器
reg [7:0]bps_cnt;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
bps_cnt <= #1 0;
else if(RX_EN)begin
if(bps_clk_16x)begin
if(bps_cnt == 160)
bps_cnt <= #1 0;
else
bps_cnt <= #1 bps_cnt + 1'd1;
end
else
bps_cnt <= #1 bps_cnt;
end
else
bps_cnt <= #1 0;
// 二维寄存器 reg width name number
reg [2:0]r_data[7:0];
reg [2:0]start_bit;
reg [2:0]end_bit;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)begin
r_data[0] <= #1 0;
r_data[1] <= #1 0;
r_data[2] <= #1 0;
r_data[3] <= #1 0;
r_data[4] <= #1 0;
r_data[5] <= #1 0;
r_data[6] <= #1 0;
r_data[7] <= #1 0;
start_bit <= #1 0;
end_bit <= #1 0;
end
else if(bps_clk_16x)begin
case(bps_cnt)
0:begin
r_data[0] <= #1 0;
r_data[1] <= #1 0;
r_data[2] <= #1 0;
r_data[3] <= #1 0;
r_data[4] <= #1 0;
r_data[5] <= #1 0;
r_data[6] <= #1 0;
r_data[7] <= #1 0;
start_bit <= #1 0;
end_bit <= #1 0;
end
5,6,7,8,9,10,11: start_bit <= #1 start_bit + UART_RX;
21,22,23,24,25,26,27: r_data[0] <= #1 r_data[0] + UART_RX;
37,38,39,40,41,42,43: r_data[1] <= #1 r_data[1] + UART_RX;
53,54,55,56,57,58,59: r_data[2] <= #1 r_data[2] + UART_RX;
69,70,71,72,73,74,75: r_data[3] <= #1 r_data[3] + UART_RX;
85,86,87,88,89,90,91: r_data[4] <= #1 r_data[4] + UART_RX;
101,102,103,104,105,106,107: r_data[5] <= #1 r_data[5] + UART_RX;
117,118,119,120,121,122,123: r_data[6] <= #1 r_data[6] + UART_RX;
133,134,135,136,137,138,139: r_data[7] <= #1 r_data[7] + UART_RX;
149,150,151,152,153,154,155: end_bit <= #1 end_bit + UART_RX;
default:;
endcase
end
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
Data <= #1 0;
else if(bps_clk_16x && (bps_cnt == 159))begin
//Data[0] <= #1 r_data[0][2];
Data[0] <= #1 (r_data[0] >= 4)?1'b1:1'b0;
Data[1] <= #1 (r_data[1] >= 4)?1'b1:1'b0;
Data[2] <= #1 (r_data[2] >= 4)?1'b1:1'b0;
Data[3] <= #1 (r_data[3] >= 4)?1'b1:1'b0;
Data[4] <= #1 (r_data[4] >= 4)?1'b1:1'b0;
Data[5] <= #1 (r_data[5] >= 4)?1'b1:1'b0;
Data[6] <= #1 (r_data[6] >= 4)?1'b1:1'b0;
Data[7] <= #1 (r_data[7] >= 4)?1'b1:1'b0;
end
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
Rx_Done <= #1 0;
else if((div_cnt == bps_DR / 2) && (bps_cnt == 160))
Rx_Done <= #1 1;
else
Rx_Done <= #1 0;
endmodule
module UART_CMD(
Clk,
Reset_N,
Data,
Rx_Done,
Time,
Sel
);
input Clk;
input Reset_N;
input [7:0]Data;
input Rx_Done;
output reg [31:0]Time;
output reg [7:0]Sel;
//移位寄存器复位置零无意义可忽略
reg [7:0]Data_str[7:0];
always@(posedge Clk)
if(Rx_Done)begin
Data_str[0] <= Data_str[1];
Data_str[1] <= Data_str[2];
Data_str[2] <= Data_str[3];
Data_str[3] <= Data_str[4];
Data_str[4] <= Data_str[5];
Data_str[5] <= Data_str[6];
Data_str[6] <= Data_str[7];
Data_str[7] <= Data;
end
//滞后一个时钟周期
reg r_Rx_Done;
always@(posedge Clk)
r_Rx_Done <= Rx_Done;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)begin
Time <= 0;
Sel <= 0;
end
else if(r_Rx_Done)begin
if((Data_str[0] == 8'h55) && (Data_str[1] == 8'ha5) && (Data_str[7] == 8'hf0))begin
Time[7:0] <= Data_str[2];
Time[15:8] <= Data_str[3];
Time[23:16] <= Data_str[4];
Time[31:24] <= Data_str[5];
Sel <= Data_str[6];
end
end
endmodule
仿真文件程序
`timescale 1ns / 1ns
module UART_LED_tb();
reg Clk;
reg Reset_N;
reg UART_RX;
wire Led;
UART_LED UART_LED(
Clk,
Reset_N,
UART_RX,
Led
);
initial Clk <= 0;
always #10 Clk <= !Clk;
initial begin
Reset_N <= 0;UART_RX = 1;
#201;
Reset_N <= 1;
#200;
uart_tx_byte(8'h55);
#9000;
uart_tx_byte(8'ha5);
#9000;
uart_tx_byte(8'h12);
#9000;
uart_tx_byte(8'h34);
#9000;
uart_tx_byte(8'h56);
#9000;
uart_tx_byte(8'h78);
#9000;
uart_tx_byte(8'haa);
#9000;
uart_tx_byte(8'hf0);
#9000;
$stop;
end
task uart_tx_byte;
input [7:0]tx_data;
begin
UART_RX = 1;
#20;
UART_RX = 0;
#8680;
UART_RX = tx_data[0];
#8680;
UART_RX = tx_data[1];
#8680;
UART_RX = tx_data[2];
#8680;
UART_RX = tx_data[3];
#8680;
UART_RX = tx_data[4];
#8680;
UART_RX = tx_data[5];
#8680;
UART_RX = tx_data[6];
#8680;
UART_RX = tx_data[7];
#8680;
UART_RX = 1;
#8680;
end
endtask
endmodule
板级验证
UART发送成功后可以观察到LED灯以0.5s的频率闪烁