最近一周因为疫情封控在家,整个人都快废了,天天躺。更新一下串口发送,串口单字节发送程序和串口单字节接收程序的区别不大,而且可以说更简单,因为接收的时候需要考虑传输线上的每个bit位在什么时间点采样,而发送不需要考虑。由于区别不大,就不做过多阐述了。在看完我上篇串口接收程序文章以及程序注释,再来看串口发送,思路就很清晰。其关键就是在发送每个bit位的过程中,把待发送字节的对应bit位赋值给tx线就行。程序注释没有串口接收程序的注释详细。
以下是手敲的代码,已经验证。
module uart_tx
#(parameter CLK_FRE=50_000_000,//系统频率
parameter BPS=115200//串口波特率
)
(
input sys_clk,
input sys_rst_n,
input [7:0] databyte,//待发送的字节
input tx_en,//发送使能信号,为高电平就启动发送
output reg tx,//串口发送线
output reg tx_done//发送完成信号
);
localparam CNT_MAX = CLK_FRE/BPS;//发送一个bit的计数值,计算过程参考串口接收程序注释
reg [29:0] cnt_clk;//对系统时钟进行计数
reg [3:0] bit_cnt;//对发送bit位进行计数
reg tx_state;//发送状态,为1正在发送,为0不在发送状态
//发送使能信号tx_en为高,就让发送状态为1,表示处于发送状态,在发送完成后清零
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
tx_state <= 1'b0;
else if(tx_en)
tx_state <= 1'b1;
else if(tx_done)
tx_state <= 1'b0;
else
tx_state <= tx_state;
end
//tx_state为1时,就启动cnt_clk,每当计数到CNT_MAX - 1时就清零,重新开始计数。tx_state为0时,cnt_clk不计数。
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt_clk <= 30'd0;
else if(tx_state)begin
if(cnt_clk == (CNT_MAX - 1))
cnt_clk <= 30'd0;
else
cnt_clk <= cnt_clk + 1'b1;
end
else
cnt_clk <= 30'd0;
end
//bit_cnt对已经发送bit位进行计数,每当bit_cnt等于9时就清零,0-9共十位表示一次发送完成。
//每当cnt_clk等于CNT_MAX - 1时,bit_cnt就加1
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
bit_cnt <= 4'd0;
else if(bit_cnt == 9)
bit_cnt <= 4'd0;
else if(cnt_clk == (CNT_MAX - 1))
bit_cnt <= bit_cnt + 1'b1;
else
bit_cnt <= bit_cnt;
end
//bit_cnt等于9时,一次发送完成,拉高tx_done,仅持续一个系统时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
tx_done <= 1'b0;
else if(bit_cnt == 9)
tx_done <= 1'b1;
else
tx_done <= 1'b0;
end
//根据bit_cnt的值,给tx赋值,比如bit_cnt=0,就是发送起始位0
//tx初始值赋值为1,因为串口空闲态为1
//bit_cnt如果产生其他意外值,tx就赋值为1,一般不会出现这种情况但是default情况下如果没有赋值tx的话,会产生警告,有latch
always@(*)begin
if(!sys_rst_n)
tx = 1'b1;
else if(tx_state)begin
case(bit_cnt)
0:tx = 1'b0;
1:tx = databyte[0];
2:tx = databyte[1];
3:tx = databyte[2];
4:tx = databyte[3];
5:tx = databyte[4];
6:tx = databyte[5];
7:tx = databyte[6];
8:tx = databyte[7];
9:tx = 1'b1;
default:tx = 1'b1;
endcase
end
else
tx <= 1'b1;
end
endmodule