verilog_串口实现
概述: 先了解串口的基础知识:
串口是怎样传数据的
什么是波特率,波特率怎么计算
说明: 通过Verilog编写串口,通过逻辑分析仪与串口模块的对接来进一步了解串口的应用。
文章目录
1.什么是波特率,波特率怎么计算
概述:
☆简而言之,串口传输的波特率即为每秒钟传输二进制的位数。
☆脱离枯燥乏味的文字描述,我们用波形和数字来看看波特率是什么吧☟。
☆说明:系统时钟50M,波特率115200。
1.1基础知识:
因 | 果 |
---|---|
系统时钟-50M | 时钟周期 |
假设1个时钟周期可以计数1次(其实FPGA就是这样) | 50M时钟1s计数50 000 000个 |
系统时钟-50M | 计1个数需要 s |
波特率-115200 | 1s传输二进制的位数115200bit |
波特率-115200 | 传输1bit需要 1/115200s=8.68us |
50M系统时钟------波特率为115200 | 传输1bit需要计数 |
以上重点是推导出50M系统时钟—波特率为115200条件下传输1bit需要计数个数为434。
1.2串口传输格式
●我们通常用的串口传输格式为:1bit起始位+8bit数据位+1bit停止位(无奇偶校验位),如下图所示:
所以传输1Byte数据串口需要传输10bit数据。上面计算得传输1Bit需要的时间为8.68us,则传输1Byte需要时间为8.68*10=86.8us。
1.3深入理解波特率
由基础知识知50M系统时钟—波特率为115200条件下传输1bit需要计数个数为434。那么1Byte(串口传输格式为:1bit起始位+8bit数据位+1bit停止位)是不是循环计数10次434就可以传输完毕。
直接上图:图中描述了1Byte数据传输的示意图,重点都在图里!!!。
✍什么时候去采样串口线上的数据呢?
★观察上图,Buad_Flag信号(通道2)表示了传输1Bit传输的间隔,每遇到1个Buad_Flag=1的信号,数据线上切换1次数据,所以两个Buad_Flag=1之间的数据是稳定的数据,根据抽样定理是不是应该在两个Buad_Flag=1信号的中间去采样数据呢,其实就是在1bit数据持续期间的中间点采样,才能得到最稳定的数据。见下图,重点都在图里!!!
★图中序号①-⑩分别为10bit数据的采样点,采样点处提取数据为1010_1010(0xAA)。
★★★至此,从下往上再看一遍,就明白了我们所熟悉的波特率(115200/9600/…)怎么来的。
2.串口是怎样传输数据的
➹通过逻辑分析仪捕捉串口传输的数据来了解串口传输数据的实质。
串行接口简称为串口,串行接口 (Serial Interface)是指数据一位一位地顺序传送。实现双向通信就需要一对传输线,即TX与RX线。
电路连接方式:
串口如果要实现双向传输,则设备1与设备2,TX与RX要交叉相连。
2.1串口数据解析
利用电脑端的串口助手通过CH340串口模块将数据0x55发送出去,并通过逻辑分析仪来捕捉数据。下图为串口发送的数据,是以十六进制(hex)形式发送的。
逻辑分析仪捕捉数据:
我们看到逻辑分析仪成功将数据0x55捕捉到。接下来看串口的数据构成是怎样的。
查阅资料,串口传输一帧数据如下图所示:
所谓串口的一帧数据即串行的发送一次数据(比如0x55(0101_0101))时TX数据线上的电平变化。由上图可知串口一帧数据的构成为:起始位(1bit)+数据(8bit)+奇偶校验位+停止位(1bit),8bit数据传输的方式为先低位(LSB)再高位(MSB)即通过(D0_D1_D2_D3_D4_D5_D6_D7)的顺序将数据依次放置在TX数据线上。我们再看我们所用的串口助手:
我们的设置为传输数据位为8bit,检验位为0bit即没有校验位,停止位为1bit。所以我们串口一帧数据的构成为:起始位(1bit)+数据(8bit)+停止位(1bit),所以串口一帧数据的传输单位为10bit,平时我们所说的串口传输单位为1Byte即8bit是指传输的有效数据,即起始位(1bit)+数据(8bit)+停止位(1bit)中的8bit数据,那为什么要多此一举的在收尾处各加1bit的数据呢,其实是为了接收设备能去正确的接收到8bit的有效数据,起始位相当于一帧数据的帧头,停止位相当于一帧数据的帧尾。
2.2起始位与停止位
起始位: 数据线TX由高电平变为低电平。
停止位: 数据线TX由低电平变为高电平。
起始位和停止位作用:
如果接收设备检测到数据线由高电平变为低电平,就是接收到了来自发送设备的起始信号,表示开始数据的传输。如果接收设备检测到数据线由低电平变为高电平,就是接收到了来自发送设备的停止信号,表示一帧数据的结束,通过以上特点接收设备就可以将中间的8bit有效数据解析出来,这样就完成了一帧数据的传输。
解析逻辑分析仪捕捉的数据
由以上分析知串口传输一帧数据构成:起始位(1bit)+数据(8bit)+停止位(1bit)。
解析逻辑分析仪获取的数据:
通道一:TX数据线
通道二:数据解析
通过通道一可以观察出一帧数据的格式确实为:起始位(1bit)+数据(8bit)+停止位(1bit)。中间8bit数据是通过(D0-D7:1010_1010)的顺序发送的,通过接收设备解析(高字节_低字节)为(D7-D0:0101_0101)即0x55。以上就为串口一帧数据的传输。
------所谓的波特率-----
进一步观察逻辑分析仪:
由标号①和②知1bit数据的传输时间为8.667us,那传输速率不就是
其实就是115200bit/s。再看看我们串口助手设置的波特率就为115200,这样是不是明白波特率是什么了,其实不就是1s传输115200bit数据。
3.verilog串口的实现
经过上面的分析我们要明白:
● (1)在时钟为50M时,波特率设置为115200时,发送1bit数据,需要计数个数为434(时间为8.68us)。
● (2)串口传输一字节数据的数据格式为:起始位(1bit)+数据(8bit)+停止位(1bit)。
● (3)串口传输数据:先发送低位,后发送高位。
● (4)串口数据线在空闲时默认为高电平。
3.1 verilog实现代码:
实现波特率在115200下串口的发送,发送数据为0xc5(0101_1011),则串口发送数据的格式如下图所示:
代码:
//Terry-M
//-------
//波特率115200 传输1bit需要计数434
//_起始位_8bit数据_停止位_
//-------
module uart
(
//输入
input CLK_50M, //系统时钟
input RST_N, //复位
//输出
output reg tx_flag, //为了理解所引出的信号(在该信号置位的时候,串口TX数据线切换数据)
output reg uart_tx //串口TX引脚
);
//产生波特率所需要的计数
parameter cnt_max = 9'd434;
parameter cnt_half = 9'd217;
parameter tx_data = 8'h5b; //0101_1011
reg[8:0] bps_cnt;
//起始信号和停止信号
parameter start_signal = 1'b0;
parameter stop_signal = 1'b1;
//状态机,传输10bit的状态
reg[7:0] tx_state;
parameter tx_start = 8'b0111_1111;
parameter tx_d0 = 8'b0000_0001;
parameter tx_d1 = 8'b0000_0010;
parameter tx_d2 = 8'b0000_0100;
parameter tx_d3 = 8'b0000_1000;
parameter tx_d4 = 8'b0001_0000;
parameter tx_d5 = 8'b0010_0000;
parameter tx_d6 = 8'b0100_0000;
parameter tx_d7 = 8'b1000_0000;
parameter tx_stop = 8'b1111_1110;
//产生波特率,tx_flag=1为数据发送点
always@(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
bps_cnt <= 9'd0;
else if(bps_cnt == cnt_max)
bps_cnt <= 9'd0;
else
bps_cnt <= bps_cnt + 9'd1;
end
always@(bps_cnt)
begin
if(bps_cnt == cnt_half)
tx_flag <= 1'b1;
else
tx_flag <= 1'b0;
end
//发送数据 先发送低位再发送高位
always@(posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
begin
uart_tx <= 1'b1;
tx_state <= tx_start;
end
else if(tx_flag == 1) //数据切换点
begin
case(tx_state)
tx_start: begin uart_tx <= start_signal; tx_state <=tx_d0;end //起始位
tx_d0: begin uart_tx <= tx_data[0]; tx_state <=tx_d1;end //D7
tx_d1: begin uart_tx <= tx_data[1]; tx_state <=tx_d2;end //D6
tx_d2: begin uart_tx <= tx_data[2]; tx_state <=tx_d3;end //D5
tx_d3: begin uart_tx <= tx_data[3]; tx_state <=tx_d4;end //D4
tx_d4: begin uart_tx <= tx_data[4]; tx_state <=tx_d5;end //D3
tx_d5: begin uart_tx <= tx_data[5]; tx_state <=tx_d6;end //D2
tx_d6: begin uart_tx <= tx_data[6]; tx_state <=tx_d7;end //D1
tx_d7: begin uart_tx <= tx_data[7]; tx_state <=tx_stop;end //停止位
tx_stop: begin uart_tx <= 1'b1; tx_state <=tx_start; end
default: uart_tx <= start_signal;
endcase
end
else
uart_tx <= uart_tx;
end
endmodule
3.2 SignalTap Ⅱ对FPGA内部信号进行逻辑分析
借助SignalTap Ⅱ软件对FPGA内置逻辑分析等如下:
3.3 通过逻辑分析仪解析数据校验数据
将FPGA的TX引脚接至逻辑分析仪获取以下波形:
逻辑分析仪解析数据为0x5B,数据正确。
3.4 与串口模块对接
通过FPGA的TX引脚连接CH340模块RX引脚,电脑串口助手接收数据如下:
接收数据为0x5B,数据正确。
★★★如有错误,欢迎指导!