功能描述:
1.每隔3ms以115200波特率的速度发送一个遵循uart协议的数据。每次发送数据增大1(从0开始即可).
2.数据 来自数据采集器,每采集一个数据,发送一个脉冲告知串口,串口对这个数据进行发送。
学习:
1.在上一次底层设计中,我们把发送使能端send_en作为input,不能在底层为它赋值。但是我们在顶层新建一个模块,调用底层模块时,可以把send_en作为顶层的内部变量,这样子就可以赋值了。
2.如果触发条件是脉冲的,我们可以设计一个内部变量en,用脉冲把en置一,让它控制数据发送的使能。再用结束位置零。这样子在外部上看就起到了用脉冲触发的效果。
3.用顶层调用底层时(例化)在顶层中同样是设计逻辑,用到与底层同个变量时,顶层和底层的逻辑是并行执行的。只不过变量在两个地方的地位不一样,在底层中无法赋值的input,在顶层中可以作为 可赋值的reg。
4.可以用x=!x把x置为脉冲型。
5.调试的基本思路是:查看仿真波形,看哪个变量的波形不对劲,回到源码中找到该变量的逻辑语句进行分析。一般先看关键变量的波形,具体来说就是输出的波形是否与预期相符。再由输出推到与其联系的相关变量的逻辑。
6.最好每一个变量都用独立的always来描述逻辑变化。
- 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