FPGA学习笔记--低速通信协议串口

一、串口简介

串口作为三大低速通信协议(UART、IIC、SPI)之一,是异步通信全双工协议,因此没有时钟信号线,接收方并不知道数据什么时候会到达,双方收发端都有各自的时钟。

如果要实现串口直连通信,需要将通信双方的RS232接口(图1)连上,再通过约束协议通信。

如今的电脑主板、开发板已废弃RS232接口,全部改用USB口。因此,通信图例如下:

常用的USB--UART转换芯片有CH340、FT2232、CP2102等,要想让个人电脑串口识别到开发板串口,需要使用特定的串口通信软件,下载安装对应转换芯片的驱动。

二、串口通信时序

串口通信,以帧作为通信的单位。字符帧里面包含起始位(必须为1'b0),数据位(根据设置可为8位或者7位),校验位(根据设置可为奇校验、偶校验、不校验),停止位(必须为1'b1)

注意串口发送接收的数据位中,低位数据在前,高位数据在后。

数据位

校验位

字符帧 总位数

7位

奇校验

10位

7位

偶校验

10位

7位

不校验

9位

8位

奇校验

11位

8位

偶校验

11位

8位

不校验

10位

三、串口各模块设计

  1. 波特(以波特率9600为例解释串口通信的频率)

①要使双方正常串口通信,需要相同的波特率,相同的数据宽度、奇偶校验位相同。

②FPGA接收串口发来的数据,并将其由串行数据转为并行数据,存储在寄存器中。而每1bit数据的持续时间为1波特,FPGA只需要在1波特时间内提取一次数据,可选在二分之一波特时间点提取。

  1. 亚稳态

串口通信中,rx信号线的变化不受FPGA的控制(此时FPGA是接收方)。而我们判断起始位信号到来的根据是rx下降沿,那么万一rx变化的下降沿,刚好是在FPGA时钟信号CLK上升沿时呢?如图:

rx在sys_clk上升沿的建立时间 Tsu(指触发器的时钟信号上升沿到来以前,数据稳定不变的最小时间)和保持时间 Th(指触发器的时钟信号上升沿到来以后,数据稳定不变的最小时间)中变化了,此时FPGA采集到的信号就是不稳定的振荡0或者1。这是异步通信的弊病。

解决该问题,可使用“打两拍法”:将rx信号传到rx_reg1再传到rx_reg2再传到rx_reg3,再判断下降沿。

这种方法,虽然会让下降沿判断延后了3个时钟周期,但是精确度提高到99%。这样可能会导致漏采样问题(因为是在FPGA时钟上升沿捕捉的信号,20ns采样一次rx,如果rx的传输时钟频率比CLK快,就有一些收不到),但是串口是低速信号,所以不用担心。

//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;

//rx_reg2:第二级寄存器,寄存器空闲状态复位为 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;

//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;

//start_nedge:检测到下降沿时 start_nedge 产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((~rx_reg2) && (rx_reg3))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;

  1. 状态机

状态机可按照下面格式来完成,包括时序逻辑电路与组合逻辑电路

always @(*) begin
// State transition logic
end

always @(posedge clk, posedge reset) begin
// State flip-flops with asynchronous reset
end

  1. 移位寄存器

移位寄存器在串并转换上发挥着巨大的作用。

移位寄存器包括循环移位寄存器、算术移位寄存器两种

比如对于 reg [99:0]q;
循环左移1位:q <= {q[98:0], q[99]};
循环右移1位:q <= {q[0], q[99:1]};
算术左移1位:q <= {q[98:0], 1'b0}; // 算术左移,右端自动补0
算术右移1位:q <= {q[99], q[99:1]}; //算术右移(正数最高位为0,负数为1)左端自动补充符号位
算术右移8位:q <= { { 8{q[99]} } , q[98:8]}

5.串口收取端rx设计

网上有很多成熟的设计,复制粘贴即可。

6.串口发送端tx设计

网上有很多成熟的设计,复制粘贴即可。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值