13. 串口接收模块的项目应用案例
1. 使用串口来控制LED灯工作状态
使用串口发送指令到FPGA开发板,来控制第7课中第4个实验的开发板上的LED灯的工作状态。
LED灯的工作状态:让LED灯按指定的亮灭模式亮灭,亮灭模式未知,由用户指定,8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景来选择。
1.1 原理如下

1.2 任务简化为:
如何使用串口接收8个字节的数据,判断并输出其中的数据。
2. 写设计代码,仿真代码并仿真
2.1 设计代码(重要)
1.在完成uart_cmd解析数据模块时,要掌握移位寄存器的使用,以及延后一拍判定的方法
2.修改了uart_byte_rx1串口接收模块代码,修改了rx_data八位数据接收条件,原先是发送了在出现tx_done信号后得到输出八位数据,这样会导致我们在后续模块通过tx_done信号接收数据时接收的是前一个八位数据。现在改为了tx_done信号出现时,八位数据已准备输出了。
3.修改了counter_led灯模块代码
module uart_rx_ctrl_led(clk,rstn,uart_rx,blaud_set,led
);input clk;input rstn;input uart_rx;input [2:0]blaud_set;output led;wire [7:0]data;wire rx_done;wire [7:0] ctrl;wire [31:0] times;uart_byte_rx1 uart_byte_rx1_inst(.clk(clk),.rstn(rstn),.blaud_set(blaud_set),.uart_rx(uart_rx),.data(data),.rx_done(rx_done));uart_cmd uart_cmd_inst(.clk(clk),.rstn(rstn),.rx_data(data),.rx_done(rx_done),.ctrl(ctrl),.times(times));counter_led4 counter_led4_inst(.clk(clk),.rstn(rstn),.ctrl(ctrl),.times(times),.led(led));endmodule
module uart_byte_rx1(clk,rstn,blaud_set,uart_rx,data,rx_done
);input clk;input rstn;input [2:0]blaud_set;input uart_rx;output reg [7:0] data;output rx_done;reg [8:0] bps_dr;always@(*)case(blaud_set)0:bps_dr = 1000000000/9600/16/20;1:bps_dr = 1000000000/19200/16/20;2:bps_dr = 1000000000/38400/16/20;3:bps_dr = 1000000000/57600/16/20;4:bps_dr = 1000000000/115200/16/20;default : bps_dr = 1000000000/9600/16/20;endcase//边沿信号检测reg [1:0] uart_rx_r; //用两位寄存器分别存储两个时间沿的uart_rx信号always@(posedge clk) beginuart_rx_r[0] <= uart_rx;uart_rx_r[1] <= uart_rx_r[0];end//将两位寄存器的值直接通过导线输出进行判断(不需要再使用寄存器)wire nedge_uart_rx; //掌握一下这个方法,之前一直使用的是寄存器//法一://assign nedge_uart_rx = ((uart_rx_r[0] == 0)&&(uart_rx_r == 1));//法二:assign nedge_uart_rx = (uart_rx_r == 2'b10);reg rx_en;always@(posedge clk or negedge rstn)if(!rstn)rx_en <= 0;else if(nedge_uart_rx)rx_en <= 1;else if(rx_done)rx_en <= 0;//周期计数器reg [8:0] div_cnt;always@(posedge clk or negedge rstn)if(!rstn)div_cnt <= 0;else if(rx_en) beginif(div_cnt == bps_dr - 1)div_cnt <= 0;elsediv_cnt <= div_cnt + 1'd1;endelsediv_cnt <= 0;wire [3:0]bps_clk_16x; //(一定要记得加位宽)采样信号,这种写法很灵活assign bps_clk_16x = bps_dr/2; //采样每一段的中点值,同时也可以用它来计数。//发送一字节的数据有需要十个数据位,每位数据有16个小段供采样,共160reg [7:0]bps_cnt;always@(posedge clk or negedge rstn)if(!rstn)bps_cnt <= 0;else if(rx_en) beginif(bps_cnt == 159)bps_cnt <= 0;else if(div_cnt ==bps_clk_16x)bps_cnt <= bps_cnt + 1'd1; endelse bps_cnt <= 0;reg[2:0] r_data[7:0];//二维数据,代表八个r_data,每个r_data有3位寄存器存储数值。reg[2:0] sta_data;reg[2:0] sto_data;always@(posedge clk or negedge rstn)if(!rstn)beginsta_data <= 0;sto_data <= 0;r_data[0] <= 0; //语法规定,二维数组赋值要分开赋值r_data[1] <= 0; r_data[2] <= 0;r_data[3] <= 0; r_data[4] <= 0; r_data[5] <= 0; r_data[6] <= 0; r_data[7] <= 0; endelse if(div_cnt == bps_clk_16x - 1)case(bps_cnt) //下面合在一起的写法是允许的0:beginr_data[0] <= 0; r_data[1] <= 0; r_data[2] <= 0;r_data[3] <= 0; r_data[4] <= 0; r_data[5] <= 0; r_data[6] <= 0; r_data[7] <= 0;end 5,6,7,8,9,10,11: sta_data <= sta_data + uart_rx;21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;149,150,151,152,153,154,155: sto_data <= sto_data + uart_rx;default:;endcase reg rx_done;always@(posedge clk or negedge rstn)if(!rstn)rx_done <= 0;else if(bps_cnt == 159) beginrx_done <= 1;endelserx_done <= 0;//数据接收完成后赋值给data输出always@(posedge clk or negedge rstn)if(!rstn)data <= 0;else if(bps_cnt == 159)begin //修改了之前的判定条件(重要)data[0] <= (r_data[0] >= 4 ) ? 1 : 0;data[1] <= (r_data[1] >= 4 ) ? 1 : 0;data[2] <= (r_data[2] >= 4 ) ? 1 : 0;data[3] <= (r_data[3] >= 4 ) ? 1 : 0;data[4] <= (r_data[4] >= 4 ) ? 1 : 0;data[5] <= (r_data[5] >= 4 ) ? 1 : 0;data[6] <= (r_data[6] >= 4 ) ? 1 : 0;data[7] <= (r_data[7] >= 4 ) ? 1 : 0;end// data[1] <= r_data[1][2]// 0:3'd000// 1:3'd001// 2:3'd010// 4:3'd100// 5:3'd101// 6:3'd110// 7:3'd111 利用第3位的区别给data赋值endmodule
module uart_cmd(clk,rstn,rx_data,rx_done,ctrl,times
);input clk;input rstn;input [7:0]rx_data;input rx_done;output reg[7:0]ctrl;output reg[31:0]times;reg [7:0] data_str[7:0];always@(posedge clk)if(rx_done)begindata_str[7] <= rx_data;data_str[6] <= data_str[7];data_str[5] <= data_str[6];data_str[4] <= data_str[5];data_str[3] <= data_str[4];data_str[2] <= data_str[3];data_str[1] <= data_str[2];data_str[0] <= data_str[1];end// 使判断并取数据的触发条件在存数据的后一拍
// reg r_rx_done;
// always@(posedge clk)
// if(rx_done)
// r_rx_done <= rx_done;reg r_rx_done;always@(posedge clk)if(rx_done)r_rx_done <= 1;else r_rx_done <= 0;always@(posedge clk or negedge rstn)if(!rstn)begintimes <= 0;ctrl <= 0;endelse if(r_rx_done)if((data_str[0] == 8'h55) && (data_str[1] == 8'hA5) && (data_str[7] == 8'hF0))begintimes[7:0] <= data_str[2];times[15:8] <= data_str[3];times[23:16] <= data_str[4];times[31:24] <= data_str[5];ctrl[7:0] <= data_str[6];endelse beginctrl <= ctrl;times <= times;end
endmodule
module counter_led4(clk,rstn,ctrl,times,led
);input clk;input rstn;input [7:0] ctrl; input [31:0] times; output reg led;reg[31:0] counter;always@(posedge clk or negedge rstn)if(!rstn)counter <= 0;
//为了防止times为0时减1会得到非常到的数值导致归0时间很长(重要)else if(counter >= times - 1'd1) counter <= 0;elsecounter <= counter + 1'd1;reg [2:0]counter2;always@(posedge clk or negedge rstn)if(!rstn)counter2 <= 0;else if(counter == times - 1'd1)counter2 <= counter2 + 1'd1;always@(posedge clk or negedge rstn)if(!rstn) led <= 0;else case(counter2)0 : led <= ctrl[0];1 : led <= ctrl[1];2 : led <= ctrl[2];3 : led <= ctrl[3];4 : led <= ctrl[4];5 : led <= ctrl[5];6 : led <= ctrl[6];7 : led <= ctrl[7];default : led <= led;endcaseendmodule
2.2 仿真代码
`timescale 1ns / 1psmodule uart_rx_ctrl_led_tb();reg clk;reg rstn;reg uart_rx;wire led;wire [2:0]blaud_set;assign blaud_set = 3'd4;uart_rx_ctrl_led uart_rx_ctrl_led_inst(.clk(clk),.rstn(rstn),.uart_rx(uart_rx),.blaud_set(blaud_set),.led(led));initial clk = 1;always #10 clk = ~clk;initial beginrstn = 0;uart_rx = 1;#201;rstn = 1;#200;uart_tx_byte(8'h55);#90000;uart_tx_byte(8'ha5);#90000;uart_tx_byte(8'h9a);#90000;uart_tx_byte(8'h78);#90000;uart_tx_byte(8'h56);#90000;uart_tx_byte(8'h34);#90000;uart_tx_byte(8'h21);#90000;uart_tx_byte(8'hf0);#90000;$stop;endtask uart_tx_byte;input [7:0] tx_data;beginuart_rx = 1;#20;uart_rx = 0;#8680;uart_rx = tx_data[0];#8680;uart_rx = tx_data[1];#8680;uart_rx = tx_data[2];#8680;uart_rx = tx_data[3];#8680;uart_rx = tx_data[4];#8680;uart_rx = tx_data[5];#8680;uart_rx = tx_data[6];#8680;uart_rx = tx_data[7];endendtaskendmodule
仿真波形

3. 调试(重要)
3.1 tx_done信号到来,data_str[]正确接收到了数据且符合协议,但times和ctrl却仍未0,并未产生正确输出。
通过波形分析原因



通过代码找分析原因

3.2 模块接口给错导致的错误

3.3 counter计数判定条件需要修改

4. 上板验证(通过串口调试助手发送数据)

相关文章:
13. 串口接收模块的项目应用案例
1. 使用串口来控制LED灯工作状态 使用串口发送指令到FPGA开发板,来控制第7课中第4个实验的开发板上的LED灯的工作状态。 LED灯的工作状态:让LED灯按指定的亮灭模式亮灭,亮灭模式未知,由用户指定,8个变化状态为一个循…...
Python re找到特定pattern并将此pattern重复n次
要找到字符串s中的数字,并将这些数字重复3次: import re s "abc123def456ghi789" # 找到所有的数字 numbers re.findall(r\d, s) # 重复每个数字3次 repeated_numbers [num * 3 for num in numbers] # 将重复的数字放回原位置 #…...
ChatGpt报错:We ran into an issue while authenticating you解决办法
在登录ChatGpt时报错:Oops!,We ran into an issue while authenticating you.(我们在验证您时遇到问题),记录一下解决过程。 完整报错: We ran into an issue while authenticating you. If this issue persists, please contact…...
如何从 iPhone 恢复已删除的视频:简单有效方法
无论您是在尝试释放空间时不小心删除了 iPhone 上的视频,还是在出厂时清空了手机,现在所有数据都消失了,都不要放弃。有一些方法可以恢复这些视频。 在本文中,我们将向您展示六种最有效的数据恢复方法,可以帮助您从 i…...
【python量化交易】qteasy使用教程02 - 获取和管理金融数据
qteasy教程2 - 获取并管理金融数据 qteasy教程2 - 获取并管理金融数据开始前的准备工作获取基础数据以及价格数据下载交易日历和基础数据查看股票和指数的基础数据下载沪市股票数据从本地获取股价数据生成K线图 数据类型的查找定期下载数据到本地回顾总结 qteasy教程2 - 获取并…...
数据库学习案例20240206-ORACLE NEW RAC agent and resource关系汇总。
1 集群架构图 整体集群架构图如下: 1 数据库启动顺序OHASD层面 操作系统进程init.ohasd run启动ohasd.bin init.ohasd run 集群自动启动是否被禁用 crsctl enable has/crsGIHOME所在文件系统是否被正常挂载。管道文件npohasd是否能够被访问, cd /var/t…...
TypeScript 入门
课程地址 ts 开发环境搭建 npm i -g typescript查看安装位置: $ npm root -g C:\Users\Daniel\AppData\Roaming\npm\node_modules创建 hello.ts: console.log("hello, ts");编译 ts 文件,得到 js 文件: $ tsc foo.…...
linux 磁盘相关操作
1.U盘接入虚拟机 (1)在插入u盘时,虚拟机会检测usb设备,在弹出窗口选择连接到虚拟机即可。 (2)或 直接在虚拟机--->可移动设备--->找到U盘---->连接 2.检测U盘是否被虚拟机识别 ls /dev/sd* 查…...
PyTorch: torch.max()函数详解
torch.max函数详解:基于PyTorch的深入探索 🌵文章目录🌵 🌳引言🌳🌳torch.max()函数简介🌳🌳torch.max()的返回值🌳🌳torch.max()的应用示例🌳&am…...
Rust基础拾遗--核心功能
Rust基础拾遗 前言1.所有权与移动1.1 所有权 2.引用3.特型与泛型简介3.1 使用特型3.2 特型对象3.3 泛型函数与类型参数 4.实用工具特型5.闭包 前言 通过Rust程序设计-第二版笔记的形式对Rust相关重点知识进行汇总,读者通读此系列文章就可以轻松的把该语言基础捡起来…...
MySQL:常用指令
MySQL官网 一、在Windows 系统 cmd窗口里执行的命令 启动:net start MySQL停止:net stop MySQL卸载:sc delete MySQL 二、在macOS系统终端里执行的命令 启动:mysql.server start停止:mysql.server stop重启:mysql.server restart 三、执行帮…...
Scrapy:Python中强大的网络爬虫框架
Scrapy:Python中强大的网络爬虫框架 在当今信息爆炸的时代,从互联网上获取数据已经成为许多应用程序的核心需求。Scrapy是一款基于Python的强大网络爬虫框架,它提供了一种灵活且高效的方式来提取、处理和存储互联网上的数据。本文将介绍Scrap…...
linux系统非关系型数据库redis的配置文件
redis配置文件 Redis的配置文件位于Redis安装目录下,文件名为redis.conf,配置项说明如下 Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no当Redis以守护进程方式运行时,Red…...
电力负荷预测 | 基于LSTM、TCN的电力负荷预测(Python)
文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力负荷预测 | 基于LSTM、TCN的电力负荷预测(Python) 源码设计 #------------------...
Java+SpringBoot实习管理系统探秘
✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…...
c入门第十六篇——学生成绩管理系统
师弟:“师兄,我最近构建了一个学生成绩管理系统,有空试用一下么?” 我:“好啊!” 一个简单的学生成绩管理系统,基本功能包括:添加学生信息、显示所有学生信息、按学号查找学生信息、…...
大文件上传如何做断点续传?
文章目录 一、是什么分片上传断点续传 二、实现思路三、使用场景小结 参考文献 一、是什么 不管怎样简单的需求,在量级达到一定层次时,都会变得异常复杂 文件上传简单,文件变大就复杂 上传大文件时,以下几个变量会影响我们的用…...
SpringCloud-Eureka原理分析
Eureka是Netflix开源的一款用于实现服务注册与发现的工具。在微服务架构中,服务的动态注册和发现是必不可少的组成部分,而Eureka正是为了解决这一问题而诞生的。 一、为何需要Eureka 在微服务架构中,服务之间的协同合作和高效通信是至关重要…...
LeetCode周赛——384
1.修改矩阵(模拟) class Solution { public:vector<vector<int>> modifiedMatrix(vector<vector<int>>& matrix) {int n matrix.size();int m matrix[0].size();vector<int> ans(m);for(int i 0; i < m; i)for(…...
C#,巴都万数列(Padonve Number)的算法与源代码
1 巴都万数列(Padovan Sequence) 巴都万数列(Padovan Sequence)是一个整数数列。 首数个值为1, 1, 1, 2, 2, 3, 4, 5, 7, 9, 12, 16, 21, 28, 37 ... 此数列以建筑师理察巴都万命名,他的论文Dom(1994年&a…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
