功能描述:
1.每隔3ms以115200波特率的速度发送一个遵循uart协议的数据。每次发送数据增大1(从0开始即可).
2.数据 来自数据采集器,每采集一个数据,发送一个脉冲告知串口,串口对这个数据进行发送。
学习:
1.在上一次底层设计中,我们把发送使能端send_en作为input,不能在底层为它赋值。但是我们在顶层新建一个模块,调用底层模块时,可以把send_en作为顶层的内部变量,这样子就可以赋值了。
2.如果触发条件是脉冲的,我们可以设计一个内部变量en,用脉冲把en置一,让它控制数据发送的使能。再用结束位置零。这样子在外部上看就起到了用脉冲触发的效果。
3.用顶层调用底层时(例化)在顶层中同样是设计逻辑,用到与底层同个变量时,顶层和底层的逻辑是并行执行的。只不过变量在两个地方的地位不一样,在底层中无法赋值的input,在顶层中可以作为可赋值的reg。
4.可以用x=!x把x置为脉冲型。
5.调试的基本思路是:查看仿真波形,看哪个变量的波形不对劲,回到源码中找到该变量的逻辑语句进行分析。一般先看关键变量的波形,具体来说就是输出的波形是否与预期相符。再由输出推到与其联系的相关变量的逻辑。文章来源:https://www.toymoban.com/news/detail-480654.html
6.最好每一个变量都用独立的always来描述逻辑变化。文章来源地址https://www.toymoban.com/news/detail-480654.html
- 1
module uart_1( //设计输入 clk,//时钟 reset,//复位 data,//数据 send_en,//使能 baud_rate,//波特率 uart_tx,//串口输出 tx_done//结束信号 ); input clk; input reset; input [7:0]data; input send_en; input [2:0]baud_rate; output reg uart_tx; output reg tx_done; reg [17:0]bit_tim; //设计逻辑 //把波特率转化为一位的持续时间 //单位时间内通过信道传输的码元数称为码元传输速率,即波特率,码元/s,一个码元可能由多个位组成。而比特率即 ‘位/s’ always@(baud_rate) //在这里一个 码元由一位组成,所以波特率=比特率 begin case(baud_rate) //常见的串口传输波特率 3'd0 : bit_tim = 1000000000/300/20 ; //波特率为300 3'd1 : bit_tim = 1000000000/1200/20 ; //波特率为1200 3'd2 : bit_tim = 1000000000/2400/20 ; //波特率为2400 3'd3 : bit_tim = 1000000000/9600/20 ; //波特率为9600 3'd4 : bit_tim = 1000000000/19200/20 ; //波特率为19200 3'd5 : bit_tim = 1000000000/115200/20 ; //波特率为115200 default bit_tim = 1000000000/9600/20 ; //多余的寄存器位置放什么:默认速率 endcase end reg [17:0]counter1 ;//用来计数每一位的持续时间 always@(posedge clk or negedge reset) begin if(!reset)//复位清零 counter1 <=17'b0 ; else if (send_en )//使能端有效,计数 begin if( counter1 == bit_tim - 1'b1 )//位持续时间到达时归零 counter1 <= 17'b0 ; else counter1 <= counter1 + 1'b1 ;//位持续时间没达到时继续进行 end else counter1 <= 17'b0 ; //使能端无效时,清零 end reg [3:0]counter2 ; //输出第几位。如果忘了考虑归零,那么计数器会出现溢出归零,在这里是加到15然后归零 always@(posedge clk or negedge reset) begin if(!reset)//复位 counter2 <= 4'b0 ; else if ( send_en )//使能端有效 begin if(counter2 == 0)//消耗20ns,进入起始位。这个挺重要的,没有这个的话得消耗一位的时间进入起始位 counter2 <= counter2 +1'b1 ; else if( counter1 == bit_tim - 1'b1 )//开始进行位移 counter2 <= counter2 + 4'b1 ; else counter2 <= counter2 ; end else//使能端无效,归零,进入空闲位 counter2 <= 4'b0 ; end always@(posedge clk or negedge reset) begin if(!reset)//复位 begin uart_tx <= 4'b1 ; end else if ( send_en )//使能端有效,输出每一位 case(counter2) 0:begin uart_tx <= 1'b1 ; end//设定第一位为空闲位。没有空闲位的话,使能端无效时,counter停留在0,不能保持输出高电平(取决于要输出的数据),不符合要求。 1:uart_tx <= 1'b0 ;//起始位 2:uart_tx <= data[0] ; 3:uart_tx <= data[1] ; 4:uart_tx <= data[2] ; 5:uart_tx <= data[3] ; 6:uart_tx <= data[4] ; 7:uart_tx <= data[5] ; 8:uart_tx <= data[6] ; 9:uart_tx <= data[7] ; 10:uart_tx <= 1'b1 ;//结束位 11:begin uart_tx <= 1'b1 ; end//为了让结束位跑满,设置11,作为第11个点,定第十位长度。 default uart_tx <= 1'b1 ; endcase else uart_tx <= 1'b1 ; end always@(posedge clk or negedge reset) begin if(!reset)//复位清零 tx_done <= 1'b0 ; else if (send_en )//使能端有效 begin if( counter2 == 0 )// tx_done <= 1'b0 ; else if ( counter2 == 11 ) tx_done <= 1'b1 ; end else if (tx_done == 1'b1) tx_done <= 1'b0 ; end endmodule
module uart_2(//使能端信号为电平型 Clk, Reset, uart_tx ); input Clk ; input Reset ; reg [7:0]data ; reg send_en ; wire [2:0]baud_rate ; output wire uart_tx ; wire tx_done ; uart_1 uart_1_send( //设计输入 .clk(Clk),//时钟 .reset(Reset),//复位 .data(data),//数据 .send_en(send_en),//使能 .baud_rate(baud_rate),//波特率 .uart_tx(uart_tx),//串口输出 .tx_done(tx_done)//结束信号 ); assign baud_rate = 3'b101 ; reg [18:0]counter ; always@(posedge Clk or negedge Reset) begin if(!Reset)//复位清零 counter <= 1'd0 ; else if (counter == 19'd149000 )// counter <= 1'b0 ;// else counter <= counter + 1'b1 ; end always@(posedge Clk or negedge Reset) begin if(!Reset)//复位清零 send_en <= 1'd0 ; else if (counter == 19'd1 )// send_en <= 1'b1 ;// else if (tx_done == 1'b1 )// send_en <= 1'b0 ; end always@(posedge Clk or negedge Reset) begin if(!Reset)//复位清零 data <= 8'd0 ; else if (counter == 19'd149000 )// begin data <= data + 1'b1 ; end else data <= data ;// end endmodule
module uart_3(//使能端信号为脉冲型 Clk, Reset, send_pulse, data1, uart_tx ); input Clk ; input Reset ; input send_pulse ; input [7:0]data1 ; output wire uart_tx ; wire tx_done ; reg send_en ; wire [2:0]baud_rate ; wire [7:0]data ; uart_1_1 uart_1_1send( //设计输入 .clk(Clk),//时钟 .reset(Reset),//复位 .data(data),//数据 .send_en(send_en),//使能 .baud_rate(baud_rate),//波特率 .uart_tx(uart_tx),//串口输出 .tx_done(tx_done)//结束信号 ); assign baud_rate = 3'b101 ; assign data = data1 ; reg [18:0]counter ; always@(posedge Clk or negedge Reset) begin if(!Reset)//复位清零 counter <= 1'd0 ; else if (counter == 19'd149000 )// counter <= 1'b0 ;// else counter <= counter + 1'b1 ; end always@(posedge Clk or negedge Reset) begin if(!Reset)//复位清零 send_en <= 1'd0 ; else if (send_pulse == 1'd1 )// send_en <= 1'b1 ;// else if (tx_done == 1'b1 )// send_en <= 1'b0 ; end endmodule
`timescale 1ns / 1ns module uart_3_tb (); reg Clk ; reg Reset ; reg send_pulse; reg [7:0]data1 ; wire uart_tx ; uart_3 uart_3_sim( .Clk(Clk), .Reset(Reset), .send_pulse(send_pulse), .data1(data1), .uart_tx(uart_tx) ); initial Clk = 1 ; always #10 Clk = ! Clk ; initial begin Reset = 0 ; data1 = 8'b0 ; send_pulse = 1'b0 ; #201 ; Reset = 1 ; data1 = 8'b0110_1001 ; send_pulse = 1'b1 ; #20 send_pulse = !send_pulse ; #3100000 ; data1 = 8'b1001_1101 ; send_pulse = 1'b1 ; #20 send_pulse = !send_pulse ; #3100000 ; $stop ; end endmodule
到了这里,关于串口应用:发送数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!