当前位置: 首页 > news >正文

打工人日报#202510012

打工人日报#20251012

知识点

UART

通过串口调试助手发送数据给开发版,UART 串口接收数据并将接收到的数据发送给上位机

uart_loopback.v

// UART环回测试模块
// 功能:将UART接收端收到的数据直接通过发送端回传,实现数据环回功能
module uart_loopback(input       sys_clk,        // 外部50MHz时钟信号input       sys_rst_n,      // 外部复位信号,低电平有效// UART接口信号input       uart_rxd,       // UART接收端口output      uart_txd        // UART发送端口
);// 参数定义
parameter   CLK_FREQ    = 50000000;   // 系统时钟频率,单位:Hz
parameter   UART_BPS    = 115200;     // UART通信波特率// 内部连线定义
wire        uart_rx_done;     // UART接收完成标志(高电平有效)
wire [7:0]  uart_rx_data;     // UART接收的数据(8位)// *****************************************************
// ** 主逻辑
// *****************************************************// 例化UART接收模块
// 功能:将串行的UART接收信号(uart_rxd)转换为并行数据(uart_rx_data)
//       接收完成后输出接收完成标志(uart_rx_done)
uart_rx #(.CLK_FREQ   (CLK_FREQ),    // 传递系统时钟频率参数.UART_BPS   (UART_BPS)     // 传递UART波特率参数
) 
u_uart_rx(.clk        (sys_clk),     // 时钟输入.rst_n      (sys_rst_n),   // 复位输入(低电平有效).uart_rxd   (uart_rxd),    // UART接收信号输入.uart_rx_done(uart_rx_done),// 接收完成标志输出.uart_rx_data(uart_rx_data) // 接收数据输出(8位并行)
);// 例化UART发送模块
// 功能:将并行数据(uart_rx_data)转换为串行的UART发送信号(uart_txd)
//       当接收完成标志(uart_rx_done)有效时启动发送
uart_tx #(.CLK_FREQ   (CLK_FREQ),    // 传递系统时钟频率参数.UART_BPS   (UART_BPS)     // 传递UART波特率参数
) 
u_uart_tx(.clk        (sys_clk),     // 时钟输入.rst_n      (sys_rst_n),   // 复位输入(低电平有效).uart_tx_en (uart_rx_done),// 发送使能(使用接收完成标志作为触发信号).uart_tx_data(uart_rx_data),// 待发送数据(来自接收模块的输出).uart_txd   (uart_txd),    // UART发送信号输出.uart_tx_busy( )           // 发送忙标志(未使用,悬空)
);endmodule

uart_rx.v

 module uart_rx(input clk , //系统时钟input rst_n , //系统复位,低有效input uart_rxd , //UART 接收端口output reg uart_rx_done, //UART 接收完成信号output reg [7:0] uart_rx_data //UART 接收到的数据);//parameter defineparameter CLK_FREQ = 50000000; //系统时钟频率parameter UART_BPS = 115200 ; //串口波特率localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS; //为得到指定波特率,对系统时钟计数 BPS_CNT 次//reg definereg uart_rxd_d0;reg uart_rxd_d1;reg uart_rxd_d2;reg rx_flag ; //接收过程标志信号reg [3:0 ] rx_cnt ; //接收数据计数器reg [15:0] baud_cnt ; //波特率计数器reg [7:0 ] rx_data_t ; //接收数据寄存器//wire definewire start_en;//*****************************************************//** main code//*****************************************************//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号assign start_en = uart_rxd_d2 & (~uart_rxd_d1) & (~rx_flag);//针对异步信号的同步处理always @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_rxd_d0 <= 1'b0;uart_rxd_d1 <= 1'b0;uart_rxd_d2 <= 1'b0;endelse beginuart_rxd_d0 <= uart_rxd;uart_rxd_d1 <= uart_rxd_d0;uart_rxd_d2 <= uart_rxd_d1;endend//给接收标志赋值always @(posedge clk or negedge rst_n) beginif(!rst_n)rx_flag <= 1'b0;else if(start_en) //检测到起始位rx_flag <= 1'b1; //接收过程中,标志信号 rx_flag 拉高//在停止位一半的时候,即接收过程结束,标志信号 rx_flag 拉低else if((rx_cnt == 4'd9) && (baud_cnt == BAUD_CNT_MAX/2 - 1'b1))rx_flag <= 1'b0;elserx_flag <= rx_flag;end //波特率的计数器赋值always @(posedge clk or negedge rst_n) beginif(!rst_n)baud_cnt <= 16'd0;else if(rx_flag) begin //处于接收过程时,波特率计数器(baud_cnt)进行循环计数if(baud_cnt < BAUD_CNT_MAX - 1'b1)baud_cnt <= baud_cnt + 16'b1;elsebaud_cnt <= 16'd0; //计数达到一个波特率周期后清零end elsebaud_cnt <= 16'd0; //接收过程结束时计数器清零end//对接收数据计数器(rx_cnt)进行赋值always @(posedge clk or negedge rst_n) beginif(!rst_n)rx_cnt <= 4'd0;else if(rx_flag) begin //处于接收过程时 rx_cnt 才进行计数if(baud_cnt == BAUD_CNT_MAX - 1'b1) //当波特率计数器计数到一个波特率周期时rx_cnt <= rx_cnt + 1'b1; //接收数据计数器加 1elserx_cnt <= rx_cnt;endelserx_cnt <= 4'd0; //接收过程结束时计数器清零end //根据 rx_cnt 来寄存 rxd 端口的数据always @(posedge clk or negedge rst_n) beginif(!rst_n)rx_data_t <= 8'b0;else if(rx_flag) begin //系统处于接收过程时if(baud_cnt == BAUD_CNT_MAX/2 - 1'b1) begin //判断 baud_cnt 是否计数到数据位的中间case(rx_cnt)4'd1 : rx_data_t[0] <= uart_rxd_d2; //寄存数据的最低位4'd2 : rx_data_t[1] <= uart_rxd_d2;4'd3 : rx_data_t[2] <= uart_rxd_d2;4'd4 : rx_data_t[3] <= uart_rxd_d2;4'd5 : rx_data_t[4] <= uart_rxd_d2;4'd6 : rx_data_t[5] <= uart_rxd_d2;4'd7 : rx_data_t[6] <= uart_rxd_d2;4'd8 : rx_data_t[7] <= uart_rxd_d2; //寄存数据的高低位default : ;endcase endelserx_data_t <= rx_data_t;endelserx_data_t <= 8'b0;end //给接收完成信号和接收到的数据赋值always @(posedge clk or negedge rst_n) beginif(!rst_n) beginuart_rx_done <= 1'b0;uart_rx_data <= 8'b0;end//当接收数据计数器计数到停止位,且 baud_cnt 计数到停止位的中间时else if(rx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX/2 - 1'b1) beginuart_rx_done <= 1'b1 ; //拉高接收完成信号uart_rx_data <= rx_data_t; //并对 UART 接收到的数据进行赋值end else beginuart_rx_done <= 1'b0;uart_rx_data <= uart_rx_data;endendendmodule

uart_tx.v


module uart_tx(input clk ,         // 系统时钟信号input rst_n ,       // 系统复位信号,低电平有效input uart_tx_en ,  // UART发送使能信号(高电平有效)input [7:0] uart_tx_data, // 待发送的8位数据output reg uart_txd ,     // UART发送端口output reg uart_tx_busy   // 发送忙状态信号(高电平表示正在发送)
);// 参数定义
parameter CLK_FREQ = 50000000;  // 系统时钟频率(50MHz)
parameter UART_BPS = 115200 ;   // 串口波特率(115200bps)
localparam BAUD_CNT_MAX = CLK_FREQ / UART_BPS;  // 波特率计数最大值,用于将系统时钟分频为波特率时钟// 寄存器定义
reg [7:0] tx_data_t;  // 发送数据缓存寄存器,用于暂存待发送的8位数据
reg [3:0] tx_cnt ;     // 发送位计数器,记录当前发送的位序号(0~9,对应起始位到停止位)
reg [15:0] baud_cnt ;  // 波特率计数器,用于生成波特率时钟(每计数到BAUD_CNT_MAX完成一次波特率周期)// *****************************************************
// ** 主逻辑
// *****************************************************// 数据缓存与发送忙信号控制
always @(posedge clk or negedge rst_n) beginif(!rst_n) begin  // 复位状态tx_data_t <= 8'b0;       // 清空数据缓存uart_tx_busy <= 1'b0;    // 复位时不处于发送状态end// 发送使能有效时,锁存输入数据并置高忙信号else if(uart_tx_en) begintx_data_t <= uart_tx_data;  // 锁存待发送的数据uart_tx_busy <= 1'b1;      // 标记为发送忙end// 发送完成条件:当发送到停止位(tx_cnt=9),且波特率计数接近结束(预留一小段时间确保信号稳定)else if(tx_cnt == 4'd9 && baud_cnt == BAUD_CNT_MAX - BAUD_CNT_MAX/16) begintx_data_t <= 8'b0;         // 清空数据缓存uart_tx_busy <= 1'b0;      // 标记为发送完成,清除忙信号end// 其他情况保持当前状态else begintx_data_t <= tx_data_t;uart_tx_busy <= uart_tx_busy;end
end// 波特率时钟生成(分频逻辑)
always @(posedge clk or negedge rst_n) beginif(!rst_n)baud_cnt <= 16'd0;  // 复位时计数器清零// 发送忙时,波特率计数器递增,生成波特率时钟else if(uart_tx_busy) beginif(baud_cnt < BAUD_CNT_MAX - 1'b1)baud_cnt <= baud_cnt + 16'b1;  // 未计数到最大值时,继续递增elsebaud_cnt <= 16'd0;  // 计数到最大值后清零,完成一个波特率周期end elsebaud_cnt <= 16'd0;  // 发送空闲时,计数器清零
end// 发送位计数控制(按位发送:起始位→8位数据位→停止位)
always @(posedge clk or negedge rst_n) beginif(!rst_n)tx_cnt <= 4'd0;  // 复位时计数清零else if(uart_tx_busy) begin  // 发送忙时,才进行位计数// 每完成一个波特率周期(baud_cnt计数到最大值),切换到下一位if(baud_cnt == BAUD_CNT_MAX - 1'b1)tx_cnt <= tx_cnt + 1'b1;elsetx_cnt <= tx_cnt;  // 未完成当前波特率周期时,保持当前位endelsetx_cnt <= 4'd0;  // 发送空闲时,计数清零
end// 发送数据输出(按UART协议生成信号)
always @(posedge clk or negedge rst_n) beginif(!rst_n)uart_txd <= 1'b1;  // 复位时,发送端口处于空闲状态(高电平)else if(uart_tx_busy) begin  // 发送忙时,按位输出信号case(tx_cnt)4'd0 : uart_txd <= 1'b0 ; // 起始位(低电平)4'd1 : uart_txd <= tx_data_t[0]; // 数据位0(最低位)4'd2 : uart_txd <= tx_data_t[1]; // 数据位14'd3 : uart_txd <= tx_data_t[2]; // 数据位24'd4 : uart_txd <= tx_data_t[3]; // 数据位34'd5 : uart_txd <= tx_data_t[4]; // 数据位44'd6 : uart_txd <= tx_data_t[5]; // 数据位54'd7 : uart_txd <= tx_data_t[6]; // 数据位64'd8 : uart_txd <= tx_data_t[7]; // 数据位7(最高位)4'd9 : uart_txd <= 1'b1 ; // 停止位(高电平)default : uart_txd <= 1'b1;endcaseendelseuart_txd <= 1'b1;  // 发送空闲时,端口处于空闲状态(高电平)
endendmodule

tb_uart_loopback.v

`timescale 1ns/1ns //浠跨湡鐨勫崟浣�/浠跨湡鐨勭簿搴�module tb_uart_loopback();//parameter define
parameter CLK_PERIOD = 20;//鏃堕挓鍛ㄦ湡涓� 20ns//reg define
reg sys_clk ; //鏃堕挓淇″彿reg sys_rst_n; //澶嶄綅淇″彿reg uart_rxd ; //UART 鎺ユ敹绔彛//wire definewire uart_txd ; //UART 鍙戦�佺鍙�//*****************************************************//** main code//*****************************************************//鍙戦�� 8'h55 8'b0101_0101initial beginsys_clk <= 1'b0;sys_rst_n <= 1'b0;uart_rxd <= 1'b1;#200sys_rst_n <= 1'b1; #1000uart_rxd <= 1'b0; //璧峰浣�#8680uart_rxd <= 1'b1; //D0#8680uart_rxd <= 1'b0; //D1#8680uart_rxd <= 1'b1; //D2#8680uart_rxd <= 1'b0; //D3#8680uart_rxd <= 1'b1; //D4#8680uart_rxd <= 1'b0; //D5#8680uart_rxd <= 1'b1; //D6#8680uart_rxd <= 1'b0; //D7 #8680uart_rxd <= 1'b1; //鍋滄浣�#8680uart_rxd <= 1'b1; //绌洪棽鐘舵�� end//50Mhz 鐨勬椂閽燂紝鍛ㄦ湡鍒欎负 1/50Mhz=20ns,鎵�浠ユ瘡 10ns锛岀數骞冲彇鍙嶄竴娆�always #(CLK_PERIOD/2) sys_clk = ~sys_clk;//渚嬪寲椤跺眰妯″潡uart_loopback u_uart_loopback(.sys_clk (sys_clk ),.sys_rst_n (sys_rst_n),.uart_rxd (uart_rxd ),.uart_txd (uart_txd ));endmodule

阅读

《杀死一只知更鸟知》
第十七章
在这里插入图片描述

http://www.dtcms.com/a/478773.html

相关文章:

  • 网站备案 做网站东莞有互联网企业吗
  • 涪城移动网站建设如何自己学建设网站
  • codeforces round1057(div2)AB题解
  • 【ADS】【python基础】jupyter notebook环境极简搭建
  • 【办公类-115-05】20250920职称资料上传04——PDF和PDF合并PDF、图片和PDF合并PDF(十三五PDF+十四五图片)
  • MySQL分库分表方案及优缺点分析
  • 存储引擎(MySQL体系结构、InnoDB、MyISAM、Memory区别及特点、存储引擎的选择方案)
  • 星外网站开发苏州网络推广
  • 怎么做网站横幅建设工程协会网站查询系统
  • 1NumPy 常用代码示例
  • 【工业场景】用YOLOv8实现行人识别
  • 新手玩Go协程的一些小坑
  • STM32的VDD和VSS,VDDA和VSSA,REF+与REF-。
  • 基于STM32的智能门禁系统(论文+源码)
  • 新乡网站建设价格怎么做网站模块
  • 中小企业建设网站补贴企业网站推广的重要性
  • 信息比率诊断工具开发量化评估ETF网格择时能力有效性
  • 栏位索引超过许可范围:4,栏位数:3。; nested exception is org.postgresql.util.PSQLException
  • 厦门网站建设哪家强徐州58同城网
  • 如何进行新产品的推广网站seo技术
  • Dioxus状态管理
  • 微调高级推理大模型(COT)的综合指南:从理论到实践
  • 做美食分享网站源码wordpress网址一大串
  • 深圳做网站的人百度竞价点击软件奔奔
  • uniapp学习【整体实践】
  • Rabbitmq如何避免消息丢失
  • 建设一个朋友的网站工商局注册公司网站
  • wap网站建设免费关于网站建设费用的报告
  • asp网站开发实训报告亚马逊开店需要什么条件
  • cms管理手机网站制作网站的页面设计怎么做