名称:UART 串口控制 12 路 IO 输出 Verilog Vivado
软件:Vivado
语言:Verilog
功能介绍
本设计实现了一个基于 UART 串口接收的多路 IO 控制模块,核心功能是通过串口输入 16 位控制数据,直接驱动 12 路输出口状态变化。系统上电后即可通过外部串口持续下发控制字,完成对 CH1_IO1 到 CH1_IO12 的独立控制,适合做板级外设联动、继电器控制、状态指示和简单工业接口扩展。
设计中将串口接收到的 8 位数据分两次拼接为 16 位控制字,前 8 位与后 8 位按顺序写入内部寄存器,再将低 12 位分别映射到 12 个输出通道。这样的结构使得控制方式直接清晰,既便于软件端发送固定控制帧,也便于后续扩展更多通道或增加握手协议。
工程以 Vivado 为开发环境,顶层模块清晰,逻辑简单,适合做串口控制类 FPGA 入门项目,也适合需要快速搭建可下载验证的 IO 控制原型。
运行环境
语言:Verilog
开发软件:Vivado
输入时钟:50MHz 系统时钟
接口形式:UART 串口接收、12 路并行 IO 输出
工程类型:可综合、可实现、可生成比特流的 FPGA 设计
设计思路
整体思路围绕“串口接收数据 -> 组装控制字 -> 输出到多路 IO”展开。顶层模块 `CPCI_IO_test` 负责完成输入输出定义、串口接收实例化以及控制位映射;串口接收部分由 `uart_rx_module` 完成,外部只需提供 `clk_50M` 和 `M_RX` 即可工作。
串口数据进入后,模块并不是直接用单个字节控制全部输出,而是通过 `receive_dataHL` 标志位分两步接收。第一次有效接收时把 8 位数据写入 `receive_data[15:8]`,第二次有效接收时写入 `receive_data[7:0]`,这样就形成一个完整的 16 位控制字。该方式的优点是结构简单、资源开销小,软件端发送也很方便,只要按顺序发送两个字节即可完成整组控制。
控制字形成后,低 12 位分别分配给 `CH1_IO1` 到 `CH1_IO12`。这种映射方式直观,便于将串口命令与板上开关量、继电器、LED 或其他外设一一对应。设计没有引入多余状态机和复杂协议,目标非常明确,就是用最少的逻辑实现稳定的串口多路控制。
模块结构
工程主要包含两个核心模块。
`CPCI_IO_test`:顶层控制模块,负责接收 50MHz 时钟和串口输入,实例化串口接收单元,并将接收到的 16 位控制数据映射到 12 路输出口。
`uart_rx_module`:串口接收模块,输出 `data_receive_en` 和 `data_receive`,为顶层提供字节级接收结果。
顶层内部还定义了 `receive_dataHL` 和 `receive_data` 两个关键寄存器,用于完成两字节拼接。最终 `CH1_IO1` 到 `CH1_IO12` 直接由控制位驱动,结构层次少,调试路径清晰。
开发板验证
工程提供了明确的管脚约束文件,并已完成 Vivado 综合、实现与比特流生成流程,具备上板验证条件。顶层将串口接收数据映射到 12 路 IO 输出,适合配合对应硬件接口进行实际联调与功能验证。
仿真图/仿真说明/设计文档图片
工程包含综合、实现、时序、功耗、资源利用率等报告文件,可用于查看设计收敛情况和约束结果;同时配套有管脚约束文件,便于进行板级连线和下载验证。
部分代码
以下展示顶层模块 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)
);
wire ctrl_io_1;
wire ctrl_io_2;
wire ctrl_io_3;
wire ctrl_io_4;
wire ctrl_io_5;
wire ctrl_io_6;
wire ctrl_io_7;
wire ctrl_io_8;
wire ctrl_io_9;
wire ctrl_io_10;
wire ctrl_io_11;
wire ctrl_io_12;
//16'h0001,0002,0004,0008,0010,0020,0040,0080,0100,0200,0400,0800对应继电器开
reg receive_dataHL=0;//指示接收到的是高8位还是低8位,0表示高位,1表示低位
reg [15:0] receive_data=16'd0;
always@(posedge clk_50M)
if(receive_dataHL==0)//0表示高位,1表示低位
if(data_receive_en==1)begin
receive_data[15:8]<=data_receive;
receive_dataHL<=1;
end
else
;
else//1表示高位,0表示低位
if(data_receive_en==1)begin
receive_data[7:0]<=data_receive;
receive_dataHL<=0;
end
else
;
assign ctrl_io_1=receive_data[0];
assign ctrl_io_2=receive_data[1];
assign ctrl_io_3=receive_data[2];
assign ctrl_io_4=receive_data[3];
assign ctrl_io_5=receive_data[4];
assign ctrl_io_6=receive_data[5];
assign ctrl_io_7=receive_data[6];
assign ctrl_io_8=receive_data[7];
assign ctrl_io_9=receive_data[8];
assign ctrl_io_10=receive_data[9];
assign ctrl_io_11=receive_data[10];
assign ctrl_io_12=receive_data[11];
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;
assign CH1_IO6=ctrl_io_6;
assign CH1_IO7=ctrl_io_7;
assign CH1_IO8=ctrl_io_8;
assign CH1_IO9=ctrl_io_9;
assign CH1_IO10=ctrl_io_10;
assign CH1_IO11=ctrl_io_11;
assign CH1_IO12=ctrl_io_12;
endmodule
代码获取:点击来源:www.hdlcode.com
83