UART
1、理论部分
-
UART全称为通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)。异步的意思是指发送模块和接收模块之间没有同步时钟来同步数据,因此需要发送和接收模块提前约定好传输的速率。特点是通信线路简单,但传输速率低、传输距离有限。
-
数据传输速率以波特(baud)为单位,指每秒钟能传输的bit的个数。波特率115200即代表每秒钟最多传115200bit,则每bit需要维持的时间为1/115200s≈8.7us
-
常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和115200。因为起始位、停止位的存在,实际传输速率不等于波特率。
-
包格式
-
空闲状态总线处于高电平,当数据开始发送时,发送端将总线拉低作为起始位。然后发送数据位,数据位位宽可变。先发送最低位再发送最高位。
-
停止位是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备之间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟的机会。停止位个数越多,数据传输越稳定,但是数据传输速度也越慢
2、思路
发送模块
输入:clk、rst_n、tx_data[7:0]、data_valid
输出: tx
使用计数器按照约定的波特率产生脉冲,代码中baud_pulse相当于分频后的时钟上升沿。在data_valid为高电平时,将输入的数据载入缓存寄存器。将baud_pulse作为状态机的跳变条件,在不同的寄存器状态分别对信号进行描述。
代码中baud_valid相当于一个门控时钟,可以使模块只在数据信号有效时工作,降低功耗。
接收模块
待定
3、实现
发送模块
代码
module uart_tx
#(
parameter CLK_FRE = 50 ,
parameter BAUD_RATE = 115200
)(
input clk ,
input rst_n ,
input [7:0] tx_data ,
input data_valid ,
output reg tx
);
//define for count
localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE ;
reg baud_valid ;
reg [15:0] baud_cnt ;
reg baud_pulse ;
//define for FSM
localparam IDLE = 2'b00 ;
localparam START = 2'b01 ;
localparam SEND_BYTE = 2'b10 ;
localparam STOP = 2'b11 ;
reg [1:0] state,next_state ;
reg [2:0] bit_cnt ;
reg [7:0] tx_data_temp ;
//baud rate counter
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
baud_cnt <= 16'd0;
else if(!baud_valid)
baud_cnt <= 16'd0;
else if(baud_cnt == CYCLE - 1)
baud_cnt <= 16'd0;
else
baud_cnt <= baud_cnt + 1;
end
// registe the posedge of baud pulse
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
baud_pulse <= 0;
else if(baud_cnt == CYCLE/2 -1)
baud_pulse <= 1'b1 ;
else
baud_pulse <= 1'b0 ;
end
//FSM
always @(*)
begin
case (state)
IDLE : next_state = START ;
START: next_state = SEND_BYTE ;
SEND_BYTE : next_state = (bit_cnt == 3'd7) ? STOP : SEND_BYTE ;
STOP : next_state = IDLE ;
default: next_state = IDLE ;
endcase
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
state <= IDLE ;
else if(!baud_valid)
state <= IDLE ;
else if(baud_valid && baud_pulse)
state <= next_state ;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
baud_valid <= 1'b0 ;
tx_data_temp <= 8'd0;
tx <= 1'b1 ;
end
else
begin
case (state)
IDLE :
begin
tx <= 1'b1 ;
bit_cnt <= 3'd0 ;
if(data_valid)
begin
tx_data_temp <= tx_data ;
baud_valid <= 1'b1 ;
end
end
START:
begin
if(baud_pulse)
tx <= 1'b0;
end
SEND_BYTE :
begin
if(baud_pulse)
begin
bit_cnt <= bit_cnt + 1 ;
tx <= tx_data_temp[0] ;
tx_data_temp <= {1'b0,tx_data_temp[7:1]};
//tx_data_temp <= {tx_data_temp[6:0],1'b0};
end
end
STOP :
begin
if(baud_pulse)
begin
tx <= 1'b1;
baud_valid <= 1'b0;
end
end
default: ;
endcase
end
end
endmodule
仿真结果
测试用例8’b01100110 8‘b01011010
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】