做这个东西的目的是锻炼一下自己的编程能力以及系统思维能力
首先,清楚自己要干什么,正点原子大家应该都看过,系统框图是一个比较重要的东西,引导我们去设计和思考。
下面先给出系统框图:
模块划分好后,结构就比较清晰了,可以分成三个文件实现,一个是LED控制模块,一个是串口接收模块,还有一个是顶层模块。
串口接收模块
module uart_recv (input clk,input rst_n,input uart_rx,output reg [7:0] rx_data,output reg data_valid );reg [1:0] signal; wire falling_edge; always @ (posedge clk or negedge rst_n) beginif (!rst_n) beginsignal[0] <= 1'd0;signal[1] <= 1'd0;end else beginsignal[0] <= uart_rx;signal[1] <= signal[0];end endassign falling_edge = ~signal[0] & signal[1]; //检测下降沿reg rx_flag; always @ (posedge clk or negedge rst_n) beginif (!rst_n) beginrx_flag <= 1'd0;end else if (falling_edge) beginrx_flag <= 1'd1;end else if (data_cnt == 4'd8) beginrx_flag <= 1'd0;end else beginrx_flag <= rx_flag;end end//115200bps 8680ns接收一位数据 系统时钟50M 20ns 每计数434次接收一位数据 reg [8:0] cnt; always @ (posedge clk or negedge rst_n) beginif (!rst_n) begincnt <= 9'd0;end else if (rx_flag && cnt < 9'd434) begincnt <= cnt + 1;end else begincnt <= 9'd0;end endreg [7:0] data; reg [3:0] data_cnt; always @ (posedge clk or negedge rst_n) beginif (!rst_n) begindata <= 8'd0;data_cnt <= 4'd0;end else if (rx_flag && cnt == 9'd434) begindata <= {data[6:0],uart_rx};data_cnt <= data_cnt + 1;end else if (rx_flag) begindata <= data;data_cnt <= data_cnt;end elsedata <= 8'd0;data_cnt <= 4'd0;end endalways @ (posedge clk or negedge rst_n) beginif (!rst_n) beginrx_data <= 8'd0;data_valid <= 1'd0;end else if (data_cnt == 4'd8) beginrx_data <= data;data_valid <= 1'd1;end else beginrx_data <= 8'd0;data_valid <= 1'd0;end endendmodule
对该模块进行仿真测试
`timescale 1ns / 1psmodule uart_recv_tb;reg clk; reg rst_n; reg uart_rx; wire [7:0] rx_data; wire data_valid;// 实例化模块 uart_recv uut (.clk(clk),.rst_n(rst_n),.uart_rx(uart_rx),.rx_data(rx_data),.data_valid(data_valid) );// 时钟生成 initial beginclk = 1'b0;forever #10 clk = ~clk; // 50 MHz 时钟 end// 复位信号 initial beginrst_n = 1'b0;#50 rst_n = 1'b1; end// 模拟 UART 数据帧传输(起始位+8数据位+停止位) initial beginuart_rx = 1'b1; // 空闲状态// 发送起始位(低电平)#8680 uart_rx = 1'b0;// 发送数据位 (10101011)#8680 uart_rx = 1'b1;#8680 uart_rx = 1'b0;#8680 uart_rx = 1'b1;#8680 uart_rx = 1'b0;#8680 uart_rx = 1'b1;#8680 uart_rx = 1'b0;#8680 uart_rx = 1'b1;#8680 uart_rx = 1'b1;// 发送停止位(高电平)#8680 uart_rx = 1'b1;// 等待接收完成#50000 $finish; endendmodule
测试结果
检测到起始位:
读出数据正确,读有效信号拉高
LED控制模块
module led_control(input clk,input rst_n,input [7:0] data,input data_valid,output reg led );always @ (posedge clk or negedge rst_n) beginif (!rst_n) beginled <= 1'd0;end else if (data_valid && data == 8'h12) beginled <= 1'd1;end else if (data_valid && data == 8'h23) beginled <= 1'd0;end else beginled <= led;end endendmodule
顶层模块
module top(input clk,input rst_n,input uart_rx,output led);wire [7:0] data; wire data_valid;uart_recv u_uart_recv(.clk (clk),.rst_n (rst_n),.uart_rx (uart_rx),.rx_data (data),.data_valid (data_valid) );led_control u_led_control(.clk (clk),.rst_n (rst_n),.data (data),.data_valid (data_valid),.led (led) );ila_0 your_instance_name (.clk(clk), // input wire clk.probe0(led), // input wire [0:0] probe0 .probe1(data_valid), // input wire [0:0] probe1 .probe2(data) // input wire [7:0] probe2 );endmodule
综合仿真
仿真结果正确,串口发送12时led点亮,串口发送23时,led熄灭
上板测试结果与仿真一致