• 方案介绍
  • 相关推荐
申请入驻 产业图谱

CPCI 串口 IO 控制 FPGA 设计 Verilog Vivado

07/08 08:41
96
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

名称:CPCI 串口 IO 控制 FPGA 设计 Verilog Vivado

软件:Vivado

语言:Verilog

功能介绍

本设计实现了一个基于 CPCI 场景的串口 IO 控制 FPGA 工程,顶层模块为 CPCI_IO_test,使用 50MHz 时钟作为系统工作时钟,通过 UART 接收端口 M_RX 接收上位机或外部串口设备发送的控制字节,并根据不同命令控制 12 路 CH1_IO 输出状态。

控制逻辑面向多路开关量输出应用,例如继电器通道、数字 IO 扩展、板卡通道测试等场景。代码中将 8\'h01 至 8\'h0C 作为 1 到 12 路输出置位命令,将 8\'h11 至 8\'h1C 作为对应输出清零命令,串口收到有效数据后即可改变相应输出寄存器状态。

整体结构清晰,串口接收与输出控制分离,便于学习 UART 接收模块在 FPGA 工程中的调用方式,也便于根据实际硬件将输出通道扩展、改名或接入后级驱动电路

运行环境

开发语言:Verilog

开发软件:Vivado

工程顶层:CPCI_IO_test

主要文件:CPCI_IO_test.v、uart_rx.v、PINS.xdc

时钟输入:clk_50M

串口输入:M_RX

输出通道:CH1_IO1 至 CH1_IO12

设计思路

设计采用“串口接收模块 + 命令译码 + 多路寄存器输出”的实现思路。uart_rx_module 负责完成串口接收,当接收到一个完整字节后输出 data_receive_en 有效标志,同时给出 8 位接收数据 data_receive。顶层模块只需要关注接收完成标志和数据值,不需要在输出控制部分重复处理串口采样细节。

在输出控制部分,每一路 CH1_IO 都对应一个独立的控制寄存器 ctrl_io_x。系统在 clk_50M 上升沿判断 data_receive_en,当接收数据等于该路开启命令时将寄存器置 1,当接收数据等于该路关闭命令时将寄存器清 0。最后通过 assign 将寄存器状态连接到对应输出端口。

这种写法的优点是通道关系直观,命令字与输出通道一一对应,调试时可以直接根据串口发送值判断目标 IO 的变化。对于需要修改命令表、增减输出路数或接入其他控制协议的项目,也可以在现有结构上继续扩展。

模块结构

CPCI_IO_test:工程顶层模块,连接 50MHz 时钟、串口接收输入和 12 路 CH1_IO 输出,完成串口数据到 IO 控制信号的转换。

uart_rx_module:串口接收模块,输出接收完成标志 data_receive_en 和 8 位接收数据 data_receive。

PINS.xdc:Vivado 管脚约束文件,用于约束时钟、串口输入和输出 IO 等硬件引脚

开发板验证

工程提供 Vivado 管脚约束文件 PINS.xdc,并已生成实现相关文件和 bitstream 文件,可用于实际 FPGA 硬件下载验证。约束文件覆盖工程端口的硬件管脚分配,适合作为 CPCI IO 控制板卡或相近 FPGA 平台的移植参考。

部分代码

以下展示顶层模块 CPCI_IO_test 的部分代码,完整源码请下载压缩包查看。

module CPCI_IO_test(
    input clk_50M,
    input M_RX,//串口接收数据
    
    output CH1_IO1,
    output CH1_IO2,
    output CH1_IO3,
    output CH1_IO4,
    output CH1_IO5,
    output CH1_IO6,
    output CH1_IO7,
    output CH1_IO8,
    output CH1_IO9,
    output CH1_IO10,
    output CH1_IO11,
    output CH1_IO12
    );

wire data_receive_en;
wire [7:0] data_receive;

uart_rx_module i_uart_rx_module(
.clk(clk_50M),
.rst_p(1\'b0),
.uart_rx(M_RX),
.data_receive_en(data_receive_en),
.data_receive(data_receive)
);

reg ctrl_io_1=0;
reg ctrl_io_2=0;
reg ctrl_io_3=0;
reg ctrl_io_4=0;
reg ctrl_io_5=0;
reg ctrl_io_6=0;
reg ctrl_io_7=0;
reg ctrl_io_8=0;
reg ctrl_io_9=0;
reg ctrl_io_10=0;
reg ctrl_io_11=0;
reg ctrl_io_12=0;
//8\'h01,02,03,04,05,06,07,08,09,0A,0B,0C对应继电器开
//8\'h11,12,13,14,15,16,17,18,19,1A,1B,1C对应继电器关
always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h01)
        ctrl_io_1<=1;
    else if(data_receive_en && data_receive==8\'h11)
        ctrl_io_1<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h02)
        ctrl_io_2<=1;
    else if(data_receive_en && data_receive==8\'h12)
        ctrl_io_2<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h03)
        ctrl_io_3<=1;
    else if(data_receive_en && data_receive==8\'h13)
        ctrl_io_3<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h04)
        ctrl_io_4<=1;
    else if(data_receive_en && data_receive==8\'h14)
        ctrl_io_4<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h05)
        ctrl_io_5<=1;
    else if(data_receive_en && data_receive==8\'h15)
        ctrl_io_5<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h06)
        ctrl_io_6<=1;
    else if(data_receive_en && data_receive==8\'h16)
        ctrl_io_6<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h07)
        ctrl_io_7<=1;
    else if(data_receive_en && data_receive==8\'h17)
        ctrl_io_7<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h08)
        ctrl_io_8<=1;
    else if(data_receive_en && data_receive==8\'h18)
        ctrl_io_8<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h09)
        ctrl_io_9<=1;
    else if(data_receive_en && data_receive==8\'h19)
        ctrl_io_9<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h0A)
        ctrl_io_10<=1;
    else if(data_receive_en && data_receive==8\'h1A)
        ctrl_io_10<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h0B)
        ctrl_io_11<=1;
    else if(data_receive_en && data_receive==8\'h1B)
        ctrl_io_11<=0;

always@(posedge clk_50M)
    if(data_receive_en && data_receive==8\'h0C)
        ctrl_io_12<=1;
    else if(data_receive_en && data_receive==8\'h1C)
        ctrl_io_12<=0;

assign CH1_IO1=ctrl_io_1;
assign CH1_IO2=ctrl_io_2;
assign CH1_IO3=ctrl_io_3;
assign CH1_IO4=ctrl_io_4;
assign CH1_IO5=ctrl_io_5;
// ... 以下代码略,完整源码请下载压缩包查看

代码文件(付费下载)

相关推荐