手搓FPGA万用串口模块指南

fpga uart串口verilog波特率 奇偶 校验 可配置rs232 rs422 rs485代码 资料包清单: 1.uart_test:串口 Verilog altera工程代码,支持:波特率、校验位可配置,主时钟可配置。 2.uart说明书 3.quartus ii 13.0 :安装包及破解 注1:工程均带有激励testbench,工程安装好之后,仿真路径设置之后,打开,点击RTL Simulation即可开始仿真 注2:代码均为纯Verilog,没有IP 注3:可进行顶层应用指导 注4:给出的工程为quartus II 13.0,给出testbench代码,并且已经在电路板中验证过。

这年头玩FPGA不搞点串口协议都不好意思打招呼。今天要拆解的这套Verilog代码堪称串口界的瑞士军刀,支持RS232/422/485三协议通吃,波特率奇偶校验全可调。先看关键参数设置:

verilog 复制代码
parameter CLK_FREQ = 50_000_000;  // 主时钟50MHz
parameter BAUD_RATE = 115200;     // 波特率自由配
parameter PARITY = "ODD";         // 校验位:NONE/EVEN/ODD
parameter DATA_WIDTH = 8;         // 数据位5~8可调

重点看波特率生成模块。这里用了相位累加器方案,比传统计数器方案更精准。核心代码截取:

verilog 复制代码
// 相位累加器实现波特率
always @(posedge clk) begin
    if(!rst_n) begin
        baud_cnt <= 0;
    end else begin
        baud_cnt <= baud_cnt + BAUD_DIV;
        if(baud_cnt >= CLK_FREQ) 
            baud_cnt <= baud_cnt - CLK_FREQ;
    end
end
assign baud_tick = (baud_cnt < BAUD_DIV); // 产生波特率脉冲

状态机设计是串口模块的灵魂。接收模块采用三级流水:

  1. 起始位检测
  2. 数据位采样
  3. 校验位验证

注意这个奇葩的亚稳态处理技巧:在数据位中间连续采样三次取众数。实测能有效对抗信号毛刺。

verilog 复制代码
// 三重采样抗干扰
always @(posedge clk) begin
    case(sample_cnt)
        2'd0: sample0 <= rxd_sync;
        2'd1: sample1 <= rxd_sync;
        2'd2: sample2 <= rxd_sync;
    endcase
end
assign data_bit = (sample0 & sample1) | (sample0 & sample2) | (sample1 & sample2);

测试环节更骚------直接用SystemVerilog写了个智能校验生成器。这坨代码会自动根据当前配置生成对应的测试序列:

verilog 复制代码
// 自动生成测试数据包
task generate_packet;
    input [7:0] data;
    begin
        // 生成起始位
        txd_ref = 0;
        #BIT_TIME;
        
        // 数据位
        for(int i=0; i<DATA_WIDTH; i++) begin
            txd_ref = data[i];
            #BIT_TIME;
        end
        
        // 奇偶校验位
        if(PARITY != "NONE") begin
            txd_ref = ^data; // 异或生成校验
            if(PARITY == "EVEN") txd_ref = ~txd_ref;
            #BIT_TIME;
        end
        
        // 停止位
        txd_ref = 1;
        #(BIT_TIME*1.5);
    end
endtask

实际部署时要注意RS485的方向控制,代码里用了三态门动态切换:

verilog 复制代码
assign rs485_tx = (tx_en) ? tx_data : 1'bz;
assign rs485_rx = (tx_en) ? 1'b1 : rs485_tx;

这套代码最妙的是顶层封装------通过宏定义切换协议类型。想用RS422就把下面这行注释取消:

verilog 复制代码
`define RS422_MODE  // 默认RS232,RS485需改硬件驱动

实测发现个骚操作:把波特率设成250k,用50MHz时钟居然能稳定跑,看来相位累加器的精度优势体现出来了。不过注意RS485长距离传输时建议适当降低波特率。

最后提醒:烧录前务必检查停止位设置。有次配置成1.5停止位结果把下位机搞崩了,后来发现是某国产芯片的硬件bug...(别问,问就是玄学)

相关推荐
SkylerHu5 天前
tornado+gunicorn部署设置max_body_size
python·tornado·gunicorn
Mr.小海17 天前
gunicorn和docker冲突吗
docker·容器·gunicorn
edward11101 个月前
Python编程入门从基础语法到实践应用
gunicorn
安岁的笔记本2 个月前
Flask/Django 生产部署:Gunicorn vs Nginx,Windows 与 Linux 实战指引
django·flask·gunicorn
Ice__Cai2 个月前
深入掌握 Flask 配置管理:从基础到高级实战
python·flask·gunicorn
S01d13r3 个月前
gunicorn + flask 处理高并发请求
python·flask·gunicorn
feihui4 个月前
记一次 Python 服务 TCE 实例进程异常退出排查
python·gunicorn
无影无踪的青蛙5 个月前
[Python][Flask][Gunicorn] 搭建一个服务器-初步-小白式教程 - 1
python·flask·gunicorn
zizle_lin6 个月前
优雅使用Gunicorn进程管理FastAPI
服务器·fastapi·gunicorn