在当今的电子系统中,需要板内、板间或下位机与上位机之间进行数据的发送与接收,需要双方共同遵循一定的通信协议来保证数据传输的正确性。常见的协议有UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)、IIC(继承电路总线)、SPI(串行外围总线)、USB2.0/3.0(通用串行总线)以及Ethernet(以太网)等。最为基础的是UART。
UART在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据,可以实现全双工传输和接收。UART是异步串行通信的总称。RS232、RS449、RS423、RS422和RS485等,是对应各种异步串行通信口的接口标准和总线标准,他们规定了通信口的电器特性、传输速率、连接特性和接口的机械特性等内容。
在RS-232标准中,一个完整的字节包括一位起始位、8位数据位、一位停止位总共十位数据来算,要想完整的实现这十位数据的发送,需要11个波特率时钟脉冲,第1个脉冲标记一次传输的起始,第11个脉冲标记一次传输的结束。
BPS_CLK信号的第一个上升沿到来时,字节发送模块开始发送起始位,接下来的2到9个上升沿,发送8个数据位,第10个上升沿到第11个上升沿为停止位的发送。
本节要学习UART通信的原理及硬件电路设计,使用FPGA实现UART通信中的数据发送部分设计。在仿真验证时除进行正常的功能仿真以外,使用ISSP进行板级验证,具体方法是:输入需要通过串口发送出去的数据,通过按下AC620开发板上的按键来控制FPGA将待发送的数据发送出去,在串口助手中查看PC端接收到的数据。
串口发送模块包含两个主要组件:发送波特率生成模块;数据发送模块。将BPS_CLK信号与对应位对应起来。
下图中的逻辑电路图相对应的代码,这个电路结构是有优先级的,若Send_En为1,就不会执行else if和else语句了。
(1)这个模块的设计是为了模块的复用性。当需要不同的波特率时,只需设置不同的波特率时钟计数器的计数值,使用查找表即可实现。
reg [15:0]bps_DR;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_DR <= 16'd5207;
else begin
case(baud_set)
0:bps_DR <= 16'd5207;
1:bps_DR <= 16'd2603;
2:bps_DR <= 16'd1301;
3:bps_DR <= 16'd867;
4:bps_DR <= 16'd433;
default:bps_DR <= 16'd5207;
endcase
end
(2)计数器模块,注意有个使能端
reg [15:0]div_cnt;
reg en_cnt;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
div_cnt <= 16'd0;
else if(en_cnt)
begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
(3)产生bps_clk
reg bps_clk;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0
(4)计数到11
reg [3:0]bps_cnt;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_cnt <= 4'd0;
else if(clr)
bps_cnt <= 4'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
(4)tx_done信号的生成
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Tx_done <= 1'b0;
else if(bps_cnt == 4'd11)
Tx_done <= 1'b1;
else
Tx_done <= 1'b0;
(5)数据传输
//在发送数据的过程中,必须保证数据是稳定的
//一旦检测到发送使能信号,将待发送数据寄存起来,使用一个寄存器寄存daya_byte信号
reg [7:0]r_data_byte;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
r_data_byte <= 8'd0;
else if(Send_en)
r_data_byte <= data_byte;
else
r_data_byte <= 8'd0
localparam START_BITE = 1'b0;
localparam STOP_BIT = 1'b1;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rs232_Tx <= 1'b1;
else
begin
case(bps_cnt)
0:Rs232_Tx <= 1'b1;
1:Rs232_Tx <= START_BITE;
2:Rs232_Tx <= r_data_byte[0];
3:Rs232_Tx <= r_data_byte[1];
4:Rs232_Tx <= r_data_byte[2];
5:Rs232_Tx <= r_data_byte[3];
6:Rs232_Tx <= r_data_byte[4];
7:Rs232_Tx <= r_data_byte[5];
8:Rs232_Tx <= r_data_byte[6];
9:Rs232_Tx <= r_data_byte[7];
10:Rs232_Tx <= STOP_BIT;
default: Rs232_Tx <= 1'b1;
endcase
end
(6)
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
uart_state <= 1'b0;
else if(send_en)
uart_state <= 1'b1;
else if(Tx_done)
uart_state <= 1'b0;
else
uart_state <= uart_state;