一、什么是UART以及UART的运用
在计算机的数据通信中,外设一般不能与计算机直接相连,它们之间的信息交换主要存在以下问题:
(1)速度不匹配。外设的工作速度和计算机的工作速度不一样,而且外设之间的工作速度差异也比较大。
(2)数据格式不匹配。不同的外设在进行信息存储和处理时的数据格式可能不同,例如最基本的数据格式可分为并行数据和串行数据。
(3)信息类型不匹配。不同的外设可能采用不同类型的型号,有些是模拟信号,有些是数字信号,因此采用的处理方式也不同。
为了解决外设和计算机之间的信息交换问题,即需要设计一个信息交换的中间环节——接口。UART控制器是最常用的接口。
通用异步收发器(Universal Asynchronotls Receiv—er/Transmitter,UART)是辅助计算机与串行设备之间的通信,作为RS 232通信接口的一个重要的部分,目前大部分的处理器都集成了UART。
二、UART的通信协议
由于数字图像亚像素在计算机中是用8位二进制表示,因此UART传输的有效数据位为8位。(资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。)传输线在空闲时为高电平,因此有效数据流的开始位设为0。接着传输8位有效数据位,先从最低位开始传送。
奇偶检验位可以设置为奇检验、偶校验或者不设置校验位,由于本系统使用的传输速率不高,为了加快开发进程,减少电路面积,因此没有设计奇偶检验模块,数据流中不设奇偶检验位。最后停止位为高电平。
由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。每个数据有16个时钟采样,取中间的采样值,以保证采样不会滑码或误吗。一般UART一帧的数据位数为8,这样即使每个数据有一个时钟的误差,接收端也能正确地采样到数据。
UART的接收数据时序为:当检测到数据的下降沿时,表明线路上有数据进行传输,这是计数器CNT开始计数,当计数器为24=16+8时,(对24的由来的理解,由于萌新,可能会理解错,忘提醒。16是采样起始位时所用的时钟数,由于采样时采集中间的信号,所以加8)采样的值为第0位数据;当计数器的值为40时,采样的值为第一位数据,依次类推,进行后面6个数据的采样。如果需要进行奇偶校验,则当计数器的值为152时,采样的值即为奇偶位;当计数器的值为168时,采样的值为“1”表示停止位,数据接收完成。
三、Verilog实现UART
实现电路图,参考的小梅哥FPGA的设计理念
module uart_tx( input clk ,//50M input rst_n , input [ 7: 0] data_byte , input send_en , input [ 3: 0] baud_set , output reg rs232_tx , output reg tx_done , output wire uart_state ); //======================================================================//************** Define Parameter and Internal Signals ***************** //======================================================================/ localparam BEGIN_BIT = 1‘b0 ; localparam STOP_BIT = 1‘b1 ; localparam DATA_BITS = 10 ; localparam BAUD_RATE_9600 = 5208 ; localparam BAUD_RATE_19200 = 2604 ; localparam BAUD_RATE_38400 = 1302 ; localparam BAUD_RATE_115200= 434 ; reg [12: 0] BAUD_RATE ; reg bps_clk ; reg [ 7: 0] data_byte_reg ; reg flag_send ; wire [10: 0] tx_data_temp ; reg [19: 0] cnt0 ; wire add_cnt0 ; wire end_cnt0 ; reg [ 3: 0] cnt1 ; wire add_cnt1 ; wire end_cnt1 ; //======================================================================//**************************** Main Code ******************************* //======================================================================/ //data_byte_reg,寄存data_byte always @(posedge clk or negedge rst_n)begin if(!rst_n)begin data_byte_reg <= 8‘d0; end else if(send_en)begin data_byte_reg <= data_byte; end end //BAUD_RATE always @(posedge clk or negedge rst_n)begin if(!rst_n)begin BAUD_RATE <= BAUD_RATE_9600; end else begin case(baud_set) 4‘d0: BAUD_RATE <= BAUD_RATE_9600; 4‘d1: BAUD_RATE <= BAUD_RATE_19200; 4‘d2: BAUD_RATE <= BAUD_RATE_38400; 4‘d3: BAUD_RATE <= BAUD_RATE_115200; default:BAUD_RATE <= BAUD_RATE_9600; endcase end end //flag_send always @(posedge clk or negedge rst_n)begin if(!rst_n)begin flag_send <= 1‘b0; end else if(send_en)begin flag_send <= 1‘b1; end else if(tx_done)begin flag_send <= 1‘b0; end end //cnt0 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt0 <= 0; end else if(add_cnt0)begin if(end_cnt0) cnt0 <= 0; else cnt0 <= cnt0 + 1; end else begin cnt0 <= 0; end end assign add_cnt0 = flag_send; assign end_cnt0 = add_cnt0 && cnt0 == BAUD_RATE-1; //cnt1 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt1 <= 0; end else if(add_cnt1)begin if(end_cnt1) cnt1 <= 0; else cnt1 <= cnt1 + 1; end end assign add_cnt1 = end_cnt0; assign end_cnt1 = add_cnt1 && cnt1 == DATA_BITS-1; //tx_done always @(posedge clk or negedge rst_n)begin if(!rst_n)begin tx_done <= 1‘b0; end else if(end_cnt1)begin tx_done <= 1‘b1; end else begin tx_done <= 1‘b0; end end //bps_clk always @(posedge clk or negedge rst_n)begin if(!rst_n)begin bps_clk <= 1‘b0; end else if(cnt0 == 1‘b1)begin bps_clk <= 1‘b1; end else begin bps_clk <= 1‘b0; end end //tx_data_temp assign tx_data_temp = {STOP_BIT, data_byte_reg, BEGIN_BIT }; //rs232_tx 串行发送数据 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin rs232_tx <= 1‘b1; end else if(flag_send && bps_clk)begin rs232_tx <= tx_data_temp[cnt1]; end else if(!flag_send)begin rs232_tx <= 1‘b1; end end //uart_state assign uart_state = flag_send; endmodule
供参考,如有错误欢迎留言探讨
原文:https://www.cnblogs.com/darlingsansan/p/13057592.html