前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

UART

作者头像
瓜大三哥
发布2020-05-29 11:01:00
1.2K0
发布2020-05-29 11:01:00
举报
文章被收录于专栏:瓜大三哥瓜大三哥

大家常说的serial、UART、RS232、串口等概念究竟是怎么回事?它们之间有何联系?有何区别?下面小编会与大家一起来学习。

UARTRS232 RS485 RS422区别RS232物理接口RS485物理接口RS422物理接口UART通信协议UART设计波特率产生模块发送模块接收模块顶层模块串口驱动下载

UART

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART。可以实现全双工接收发送,是异步串行通信的总称,不表示具体的协议。RS232、RS422、RS485等都属于UART,只是它们的接口协议、电气特性、传输速率和机械结构不同而已。

RS232 RS485 RS422区别

RS232物理接口

RS232是电子工业协会(Electronic Industries Association,EIA) 制定的异步传输标准接口,同时对应着电平标准和通信协议(时序),其电平标准:+3V~+15V对应0,-3V~-15V对应1。RS232 的逻辑电平和TTL不一样但是协议一样。

RS485物理接口

RS485是一种串口接口标准,为了长距离传输采用差分方式传输,传输的是差分信号,抗干扰能力比RS232强很多。两线压差为-(2~6)V表示0,两线压差为+(2~6)V表示1。

RS422物理接口

EIA-422(过去称为RS-422)是一系列的规定采用4线,全双工,差分传输,多点通信的数据传输协议。它采用平衡传输——单向/非可逆,有使能端或没有使能端的传输线。和RS-485不同的是EIA-422不允许出现多个发送端而只能有多个接受端。硬件构成上EIA-422 (RS-422)相当于两组EIA-485(RS-485),即两个半双工的EIA-485(RS-485)构成一个全双工的EIA-422(RS-422)。

小编总结了这几种接口之间的区别如下表

名称

RS232

RS485

RS422

电平

(+5~+15V)

-7~+12V

-7~+7V

速率

20Kbps

10Mbps

10Mbps

抗干扰性

抗噪声干扰性弱

抗干扰性强(差分传输)

抗干扰性强(差分传输)

传输距离

不超过50米

3000米

3000米

工作模式

全双工

半双工

全双工

参考链接?:https://blog.csdn.net/m0_38106923/article/details/98615747?ops_request_misc=&request_id=&biz_id=102&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3

参考链接?:https://blog.csdn.net/Bertfans/article/details/80027151?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158823917419725256756927%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.57652%2522%257D&request_id=158823917419725256756927&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-3

UART通信协议

UART通信的一帧一般由11到12位数据组成。1bit的起始位,检测为低电平表示数据开始传输;紧接着8bits的数据;然后是1bit的奇偶校验位,可以是奇校验或者偶校验;最后是1bit或2bits的停止位,必须为高电平,表示一个字符数据的传输结束。 波特率:此参数容易和比特率混淆,其实他们是有区别的。具体可以百度更清楚。但是我认为uart中的波特率就可以认为是比特率,即每秒传输的位数(bit)。一般选波特率都会有9600,19200,115200等选项。其实意思就是每秒传输这么多个比特位数(bit)。

  • 起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
  • 数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。一般情况下都选择8位而不选择7,因为这样能尽可能避免数据的丢失或者混乱。小端传输(即从LSB_D0端开始发送数据,而且是串行发送)。
  • 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
  • 停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
  • 空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。

UART设计

串口通信控制器的Verilog HDL实现(一) 顶层模块

串口通信控制器的Verilog HDL实现(二) 波特率发生器模块

串口通信控制器的Verilog HDL实现(三) 发送模块的Verilog HDL 实现

串口通信控制器的Verilog HDL实现(四) 接收模块的Verilog HDL 实现

波特率产生模块

波波特率表示数据传输的速率,单位bps,表示位每秒。比如9600bps就表示1s可以传输9600bits的数据。异步收发没有时钟打拍来控制数据的传输,就需要保证收发双方在波特率设置上的一致。确保接收数据的完整性。波特率发生器实际上是一个分频器,从给定的系统时钟频率得到要求的波特率。一般来讲,为了提高系统的容错性处理,要求波特率发生器的输出时钟为实际串口数据波特率的N倍,N可以取值为8、16、32、64等。在本设计中,取N为16,因此波特率发生器的输出号频率应改为9600*16=153.6kbps。由于串口速率较低,其16倍频率值也不高,因此在设计中,可以不要求波特率发生器输出信号的占空比为50%,在本例中,其占空比为1:325。设计中的波特率发生器的代码(baud_gen.v)如下所列。

代码语言:javascript
复制
module baud_gen(
clk_50MHz,rst_p,bclk
    );

 input clk_50MHz;
 input rst_p;
 output bclk;//153.60kbps
 reg bclk;
 reg [8:0]cnt;//50000000/153600=325.5 
always @(posedge clk_50MHz)
begin
    if(rst_p)
        begin
            cnt<=0;
            bclk<=0;
        end
    else
    begin
    if(cnt>324)
        begin
            cnt<=0;
            bclk<=1;
        end
    else
        begin
            cnt<=cnt+1;
            bclk<=0;
        end
    end
end 
endmodule

发送模块

由于波特率发生器产生的时钟信号bclk的频率为9600Hz的16倍,因此在发送器中,每16个bclk周期发送一个有效比特,发送数据格式严格按照串口数据帧来完成:首先是起始位(发送端口txd从逻辑1转化为逻辑0,并持续1/9600s),其次是8个有效数据比特(低位在前,高位在后),最后是一位停止位(没有添加校验位)。

代码语言:javascript
复制
module uart_tx(bclk,reset,tx_din,tx_cmd,tx_ready,txd);
 input bclk;
 input reset;
 input [7:0]tx_din;
 input tx_cmd;
 output tx_ready;
 output txd;
 reg tx_ready;
 parameter Lframe=8;
 parameter [2:0]s_idle=3'b000;
 parameter [2:0]s_start=3'b001;
 parameter [2:0]s_wait=3'b010;
 parameter [2:0]s_shift=3'b011;
 parameter [2:0]s_stop=3'b100;
 reg [2:0]state=s_idle;
 reg [3:0]cnt=0;
 reg [3:0]dcnt=0;
 reg txdt;
 assign txd=txdt;
 always @(posedge bclk or posedge reset)
 begin
    if(reset)
        begin
            state<=s_idle;
            cnt<=0;
            tx_ready<=0;
            txdt<=1'b1;
        end
    else
    begin
    case(state)
    s_idle:
    begin
        tx_ready<=1;
        cnt<=0;
        txdt<=1'b1;
        if(tx_cmd==1'b1)
            state<=s_start;
        else
            state<=s_idle;
        end
    s_start:
    begin
        tx_ready<=1'b0;
        txdt<=1'b0;//the start bit
        state<=s_wait;
    end
    s_wait:
    begin
        tx_ready<=1'b0;
        if(cnt>=4'b1110)
        begin
        cnt<=0;
        if(dcnt==Lframe)
            begin
                state<=s_stop;
                txdt<=1'b1;
                dcnt<=0;
            end
        else
            begin
                state<=s_shift;
                txdt<=txdt;
            end
        end
        else
            begin
                state<=s_shift;
                cnt<=cnt+1;
            end
        end
    s_shift:
        begin
            tx_ready<=1'b0;
            txdt<=tx_din[dcnt];
            dcnt<=dcnt+1;
            state<=s_wait;
        end
    s_stop:
        begin
            txdt<=1'b1;
            if(cnt>4'b1110)
                begin
                    tx_ready<=1'b1;
                    cnt<=0;
                    state<=s_idle;
                end
            else
                begin
                    state<=s_stop;
                    cnt<=cnt+1;
                end
        end
    endcase
    end
end
endmodule

接收模块

在接收系统中,起始状态和数据都需要依靠接收端检测得到,为了避免毛刺影响,能够得到正确的起始信号和有效数据,需要完成一个简单的最大似然判决,其方法如下:由于bclk信号的频率为9600Hz的16倍,则对于每个数据都会有16个样值,最终的采样比特值为出现次数超过8次的电平逻辑值。

代码语言:javascript
复制
module uart_rx(bclk,reset,rxd,rx_ready,rx_dout);
 input bclk;
 input reset;
 input rxd;
 output rx_ready;
 output [7:0]rx_dout;
 parameter [3:0]Lframe=9;
 parameter [2:0]s_idle=3'b000;
 parameter [2:0]s_sample=3'b010;
 parameter [2:0]s_stop=3'b100;
 reg rx_ready;
 reg [7:0]rx_doutmp=0;
 reg [2:0]state=s_idle;
 reg [3:0]cnt=0;
 reg [3:0]dcnt=0;
 reg [3:0]num=0;
 assign rx_dout=rx_doutmp;
 always @(posedge bclk or posedge reset)
 begin
    if(reset==1'b1)
        begin
            state<=s_idle;
            cnt<=0;
            dcnt<=0;
            num<=0;
            rx_doutmp<=0;
            rx_ready<=0;
        end
    else
    begin
        case(state)
        s_idle:
            begin
            rx_dout<=0;
            rx_ready<=1;
            dcnt<=0;
            if(cnt==4'b1111)
            begin
            cnt<=0;
            if(num>7)
                begin
                state<=s_sample;
                num<=0;
                end
            else
                begin
                state<=s_idle;
                num<=0;
                end
            end
            else
            begin
                cnt<=cnt+1;
                if(rxd==1'b0)
                    begin
                        num<=num+1;
                    end
                else
                    begin
                        num<=num;
                    end
                end
            end
        s_sample:
            begin
                rx_ready<=1'b0;
                if(dcnt==Lframe)
                    begin
                        state<=s_stop;
                    end
                else
                begin
                    if(cnt==4'b1111)
                    begin
                    dcnt<=dcnt+1;
                    cnt<=0;
                    if(num>7)
                        begin
                            num<=0;
                            rx_doutmp[dcnt]<=1;
                        end
                    else
                        begin
                            num<=0;
                            rx_doutmp[dcnt]<=0;
                        end
                    end
                    else
                    begin
                        cnt<=cnt+1;
                        if(rxd==1'b1)
                        begin
                            num<=num+1;
                        end
                        else
                        begin
                            num<=num;
                        end
                    end
                end
            end
        s_stop:
        begin
            rx_ready<=1'b1;
            if(cnt==4'b1111)
            begin
            cnt<=0;
            state<=s_idle;
            end
        else
            begin
            cnt<=cnt+1;
            end
        end
        endcase
    end
 end
endmodule

顶层模块

将上面三个模块连接起来即可。

代码语言:javascript
复制
module uart_top(sys_clk_50MHz,rst_p,txd,rxd,LED,button_n,button_s); 
 baud_gen u1(
.clk_50MHz(sys_clk_50MHz),
.rst_p(rst_p),
.bclk(bclk)
);

uart_tx u2(
.bclk(bclk),
.reset(rst_p),
.tx_din(din),
.tx_cmd(tx_cmd),
.tx_ready(tx_ready),
.txd(txd)
);

uart_rx u3(
.bclk(bclk),
.reset(rst_p),
.rxd(rxd),
.rx_out(rx_out),
.rx_ready(rx_ready)
);

endmodule

至此,小编讲解已经完成。

串口驱动下载

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 瓜大三哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • UART
  • RS232 RS485 RS422区别
    • RS232物理接口
      • RS485物理接口
        • RS422物理接口
        • UART通信协议
        • UART设计
          • 串口通信控制器的Verilog HDL实现(一) 顶层模块
            • 波特率产生模块
              • 发送模块
                • 接收模块
                  • 顶层模块
                  • 串口驱动下载
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档