(一)FPGA之串口通信(UART)
回到梦开始的地方,如今回过头来看串口协议,确实清晰了很多,但是奈何好记性不如烂笔头,我还是要重新记录一下学习的知识点,方便查找和学习。
波特率(Band Rate):
串口协议中很重要的一点就是波特率,波特率的概念是每秒钟传送码元的个数,就是一秒钟传输了几个二进制的个数,他的单位是Bit/s和bps两种。常见的串口速度有115200bps 9600bps等等,串口(RS232)的最大传输速率是 115200bps,表示一秒钟传输了115200个二进制 。
波特率和字节的关系
1GB=1024MB
1MB=1024KB
1KB=1024B(字节)
我们需要串口接收的数据数每秒512字节,串口的波特率是115200位/秒
波特率115200=115200(位/秒)
如果没有校验位,就应该除以10,得到的是每秒字节数:波特率115200=115200(位/秒)=11520(字节/秒)
再除以1024,就是每秒KB数:波特率115200=115200(位/秒)=11.25(KB/秒)也就是满足每秒可以接收512字节。
**在Verilog代码中,我们只需要理解计算这两个值就可以完成串口代码的梳理,**假设我们FPGA使用的是50MHZ的系统时钟 波特率使用的是9600bps 传输一个bit需要的时钟周期个数是50_000_000/9600个个数,得到个数之后再用这个个数乘以周期的时间便是传输1bit需要的时间50_000_000/9600*20便是1bit需要的时间。
Uart通信协议
1.串口通信的信号线只需要两条线就可以完成,TX和RX TX发送端 RX为接收端。
2.起始位,数据线从高变低,低有效为0,数据传输开始。
3.数据位,起始位传输之后便是数据位开始,一般为8位,传输时低位(LSB)在前,高位(MSB)在后。
4.校验位,校验位可以认为是一个特殊的数据位,通常使用的是奇偶校验,使用串口协议时通常取消奇偶校验位。
5.停止位,停止位高有效为1,他表示这一个个字节传输结束。
6.位时间,起始位、数据位、校验位的位宽度是一致的,停止位有0.5位、1位、1.5位格式,一般为1位。
7.空闲位,持续的高电平。
7.帧:从起始位开始到停止位结束的时间间隔称之为一帧。

接受模块
首先约定波特率为9600(可变),无校验位
将数据线打两拍,防止亚稳态并捕获其的下降沿信号(起始位0)
检测到下降沿后拉高数据传输标志,意味着数据开始接收;并在传输第九个数据(终止位1)的正中(数据比较稳定)将数据传输标志拉低,意味着数据接收完成
对时钟进行计数,每一个周期(在设定波特率条件下传输一位所需要的时间)对数据线进行采样并将数据寄存,同时记录传输个数(记录当前共接收了多少个数据)
接收到第九个数据(终止位1)后,拉高接收完成标志位
————————————————
module uart_rx(
input sys_clk, //50M系统时钟
input sys_rst_n, //系统复位
input uart_rxd, //接收数据线
output reg uart_rx_done, //数据接收完成标志
output reg [7:0]uart_rx_data //接收到的数据
);
//常量化波特率,可更改
parameter BPS=9600; //波特率9600bps,可更改
parameter SYS_CLK_FRE=50_000_000; //50M系统时钟
localparam BPS_CNT=SYS_CLK_FRE/BPS; //传输一位数据所需要的时钟个数
reg uart_rx_d0; //寄存1拍
reg uart_rx_d1; //寄存2拍
reg [15:0] clk_cnt; //时钟计数器
reg [3:0] rx_cnt; //接收计数器
reg rx_flag; //接收标志位
reg [7:0] uart_rx_data_reg; //数据寄存
wire neg_uart_rx_data; //数据的下降沿
assign neg_uart_rx_data=uart_rx_d1 & (~uart_rx_d0); //捕获数据线的下降沿,用来标志数据传输开始
//将数据线打两拍,作用1:同步不同时钟域信号,防止亚稳态;作用2:用以捕获下降沿
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
uart_rx_d0<=1'b0;
uart_rx_d1<=1'b0;
end
else begin
uart_rx_d0<=uart_rxd;
uart_rx_d1<=uart_rx_d0;
end
end
//捕获到数据下降沿(起始位0)后,拉高传输开始标志位,并在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
rx_flag<=1'b0;
else begin
if(neg_uart_rx_data)
rx_flag<=1'b1;
else if((rx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2))//在第9个数据(终止位)的传输过程正中(数据比较稳定)再将传输开始标志位拉低,标志传输结束
rx_flag<=1'b0;
else
rx_flag<=rx_flag;
end
end
//时钟每计数一个BPS_CNT(传输一位数据所需要的时钟个数),即将数据计数器加1,并清零时钟计数器
always@(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
rx_cnt<=4'd0;
clk_cnt<=16'd0;
end
else if(rx_flag)begin
if(clk_cnt<BPS_CNT-1'b1)begin
clk_cnt<=clk_cnt+1'b1;
rx_cnt<=rx_cnt;
end
else begin
clk_cnt<

本文详细介绍了FPGA如何实现UART串口通信,包括波特率的计算、串口协议的各个组成部分,以及Verilog代码实现的接收和发送模块。通过实例展示了如何在50MHz系统时钟下,处理9600bps波特率的数据传输,包括起始位、数据位、校验位和停止位的识别与处理。同时,提供了仿真代码以验证设计的正确性。
最低0.47元/天 解锁文章
27万+

被折叠的 条评论
为什么被折叠?



