RS232串口与RS485串口的verilog实现

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

目录

1. RS232通信原理

2. RS485通信原理

3. RS232与RS485主要区别

4. RS232与RS485优缺点分析

5.Verilog实现代码


1. RS232通信原理

     RS232是一种全双工串行通信标准,最早由电子工业协会(EIA)在1962年发布,后经多次修订。它采用单端信号传输,使用两根线(TX 和 RX)实现双向通信。RS232的电平标准与TTL/CMOS 不同:

逻辑1(MARK):-3V至-15V

逻辑0(SPACE):+3V至+15V

       这种负逻辑和较大的电压摆幅使得RS232能够抵抗一定的噪声干扰,但也限制了其传输距离(通常不超过 15 米)和传输速率(最高约20kbps)。RS232通常用于近距离设备通信,如计算机与调制解调器、打印机或工业设备的连接。

2. RS485通信原理

       RS485是一种半双工串行通信标准,由TIA/EIA-485-A标准定义。它采用差分信号传输,使用两根线(A和B)实现多点通信。RS485的电平标准:

逻辑1:A-B < -200mV

逻辑0:A-B > +200mV

       差分信号传输使得RS485具有更强的抗干扰能力,支持更远的传输距离(最长1200米)和更高的传输速率(最高10Mbps,距离与速率成反比)。RS485支持多节点通信(最多32个节点),因此常用于工业自动化、楼宇控制等需要长距离和多设备通信的场景。

3. RS232与RS485主要区别

特性RS232RS485
信号类型单端差分
通信方式全双工(两根线)半双工(两根线)
电平标准-3V~-15V (逻辑 1),+3V~+15V (逻辑 0)A-B <-200mV (逻辑 1),A-B > +200mV (逻辑 0)
传输距离最大 15 米最大 1200 米(9600bps 时)
传输速率最高 20kbps最高 10Mbps(短距离)
节点数量点对点最多 32 个节点
抗干扰能力较弱
线缆要求普通双绞屏蔽线特性阻抗 120Ω 的差分屏蔽线

4. RS232与RS485优缺点分析

RS232的优点

  • 实现简单,只需两根信号线(TX/RX)
  • 历史悠久,兼容性好,大多数设备支持
  • 适合近距离、低速率通信

RS232的缺点

  • 传输距离短
  • 抗干扰能力弱
  • 不支持多节点通信
  • 电平转换复杂(需专用芯片如MAX232)

RS485的优点

  • 传输距离远
  • 抗干扰能力强
  • 支持多节点通信
  • 功耗低
  • 传输速率高

RS485的缺点

  • 半双工通信,需要控制信号切换发送/接收模式
  • 布线要求高(需使用差分线)
  • 需额外的收发器芯片(如MAX485)
  • 设计复杂度较高(需处理总线竞争问题)

5.Verilog实现代码

RS232实现代码
// RS232 UART模块 - 实现基本的发送和接收功能
module rs232_uart (
    input wire clk,            // 系统时钟
    input wire rst_n,          // 复位信号,低电平有效
    input wire [7:0] tx_data,  // 发送数据
    input wire tx_en,          // 发送使能
    output reg tx_done,        // 发送完成标志
    output reg tx,             // 发送数据线
    input wire rx,             // 接收数据线
    output reg [7:0] rx_data,  // 接收数据
    output reg rx_done         // 接收完成标志
);

    // 参数定义
    parameter BAUD_RATE = 9600;          // 波特率
    parameter CLK_FREQ = 50_000_000;     // 系统时钟频率
    parameter BAUD_DIV = CLK_FREQ / BAUD_RATE;  // 波特率分频系数
    
    // 内部信号定义
    reg [15:0] baud_cnt;                 // 波特率计数器
    reg baud_tick;                       // 波特率时钟脉冲
    reg [3:0] tx_state, rx_state;        // 发送/接收状态机
    reg [3:0] tx_bit_cnt, rx_bit_cnt;    // 发送/接收位计数器
    reg [7:0] tx_buffer;                 // 发送数据缓冲区
    reg rx_d1, rx_d2;                    // 接收信号同步寄存器
    
    // 波特率发生器
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            baud_cnt <= 16'd0;
            baud_tick <= 1'b0;
        end
        else begin
            if (baud_cnt >= BAUD_DIV - 1) begin
                baud_cnt <= 16'd0;
                baud_tick <= 1'b1;
            end
            else begin
                baud_cnt <= baud_cnt + 1'b1;
                baud_tick <= 1'b0;
            end
        end
    end
    
    // 发送状态机
    localparam TX_IDLE = 4'd0;
    localparam TX_START = 4'd1;
    localparam TX_DATA = 4'd2;
    localparam TX_STOP = 4'd3;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            tx_state <= TX_IDLE;
            tx <= 1'b1;           // 空闲状态为高电平
            tx_bit_cnt <= 4'd0;
            tx_done <= 1'b0;
        end
        else begin
            case (tx_state)
                TX_IDLE: begin
                    tx_done <= 1'b0;
                    if (tx_en) begin
                        tx_buffer <= tx_data;
                        tx_state <= TX_START;
                    end
                    else begin
                        tx_state <= TX_IDLE;
                    end
                end
                
                TX_START: begin
                    if (baud_tick) begin
                        tx <= 1'b0;          // 发送起始位(低电平)
                        tx_state <= TX_DATA;
                        tx_bit_cnt <= 4'd0;
                    end
                end
                
                TX_DATA: begin
                    if (baud_tick) begin
                        tx <= tx_buffer[tx_bit_cnt];
                        if (tx_bit_cnt >= 4'd7) begin
                            tx_state <= TX_STOP;
                        end
                        else begin
                            tx_bit_cnt <= tx_bit_cnt + 1'b1;
                        end
                    end
                end
                
                TX_STOP: begin
                    if (baud_tick) begin
                        tx <= 1'b1;          // 发送停止位(高电平)
                        tx_done <= 1'b1;     // 发送完成
                        tx_state <= TX_IDLE;
                    end
                end
                
                default: tx_state <= TX_IDLE;
            endcase
        end
    end
    
    // 接收信号同步(消除亚稳态)
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            rx_d1 <= 1'b1;
            rx_d2 <= 1'b1;
        end
        else begin
            rx_d1 <= rx;
            rx_d2 <= rx_d1;
        end
    end
    
    // 接收状态机
    localparam RX_IDLE = 4'd0;
    localparam RX_START = 4'd1;
    localparam RX_DATA = 4'd2;
    localparam RX_STOP = 4'd3;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            rx_state <= RX_IDLE;
            rx_bit_cnt <= 4'd0;
            rx_done <= 1'b0;
            rx_data <= 8'd0;
        end
        else begin
            case (rx_state)
                RX_IDLE: begin
                    rx_done <= 1'b0;
                    if (rx_d2 == 1'b0) begin  // 检测到起始位
                        rx_state <= RX_START;
                    end
                end
                
                RX_START: begin
                    if (baud_tick) begin
                        // 确认起始位中点
                        if (rx_d2 == 1'b0) begin
                            rx_state <= RX_DATA;
                            rx_bit_cnt <= 4'd0;
                        end
                        else begin
                            rx_state <= RX_IDLE;
                        end
                    end
                end
                
                RX_DATA: begin
                    if (baud_tick) begin
                        // 在每个数据位的中点采样
                        rx_data[rx_bit_cnt] <= rx_d2;
                        if (rx_bit_cnt >= 4'd7) begin
                            rx_state <= RX_STOP;
                        end
                        else begin
                            rx_bit_cnt <= rx_bit_cnt + 1'b1;
                        end
                    end
                end
                
                RX_STOP: begin
                    if (baud_tick) begin
                        if (rx_d2 == 1'b1) begin  // 确认停止位
                            rx_done <= 1'b1;       // 接收完成
                        end
                        rx_state <= RX_IDLE;
                    end
                end
                
                default: rx_state <= RX_IDLE;
            endcase
        end
    end
    
endmodule

RS485实现代码

// RS485 UART模块 - 基于RS232 UART,增加方向控制
module rs485_uart (
    input wire clk,            // 系统时钟
    input wire rst_n,          // 复位信号,低电平有效
    input wire [7:0] tx_data,  // 发送数据
    input wire tx_en,          // 发送使能
    output reg tx_done,        // 发送完成标志
    input wire rx,             // 接收数据线
    output reg [7:0] rx_data,  // 接收数据
    output reg rx_done,        // 接收完成标志
    output reg rs485_dir       // RS485方向控制信号,1为发送,0为接收
);

    // 内部信号定义
    wire tx_internal;          // 内部发送信号
    reg tx_en_internal;        // 内部发送使能
    reg [1:0] state;           // 状态机状态
    
    // 实例化RS232 UART核心模块
    rs232_uart uart_core (
        .clk(clk),
        .rst_n(rst_n),
        .tx_data(tx_data),
        .tx_en(tx_en_internal),
        .tx_done(tx_done),
        .tx(tx_internal),
        .rx(rx),
        .rx_data(rx_data),
        .rx_done(rx_done)
    );
    
    // RS485方向控制状态机
    localparam IDLE = 2'd0;
    localparam TX_PREPARE = 2'd1;
    localparam TX_ACTIVE = 2'd2;
    localparam RX_READY = 2'd3;
    
    reg [7:0] delay_cnt;       // 延时计数器
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= IDLE;
            rs485_dir <= 1'b0; // 默认处于接收状态
            tx_en_internal <= 1'b0;
            delay_cnt <= 8'd0;
        end
        else begin
            case (state)
                IDLE: begin
                    rs485_dir <= 1'b0;     // 保持接收状态
                    tx_en_internal <= 1'b0;
                    if (tx_en) begin
                        state <= TX_PREPARE;
                        delay_cnt <= 8'd0;
                    end
                end
                
                TX_PREPARE: begin
                    rs485_dir <= 1'b1;     // 切换到发送状态
                    delay_cnt <= delay_cnt + 1'b1;
                    // 等待一段时间确保RS485收发器完成切换
                    if (delay_cnt >= 8'd10) begin
                        tx_en_internal <= 1'b1;  // 启动发送
                        state <= TX_ACTIVE;
                    end
                end
                
                TX_ACTIVE: begin
                    tx_en_internal <= 1'b1;  // 保持发送使能
                    if (tx_done) begin
                        tx_en_internal <= 1'b0;
                        delay_cnt <= 8'd0;
                        state <= RX_READY;
                    end
                end
                
                RX_READY: begin
                    rs485_dir <= 1'b0;     // 切换回接收状态
                    delay_cnt <= delay_cnt + 1'b1;
                    // 等待一段时间确保RS485收发器完成切换
                    if (delay_cnt >= 8'd10) begin
                        state <= IDLE;
                    end
                end
                
                default: state <= IDLE;
            endcase
        end
    end
    
    // RS485差分输出(实际应用中需连接到RS485收发器)
    // 此处仅为示意,实际硬件连接需要使用如MAX485等芯片
    // RS485_A <= tx_internal;
    // RS485_B <= ~tx_internal;
    
endmodule

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpga和matlab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值