【FPGA零基础学习之旅#14】串口发送字符串

🎉欢迎来到FPGA专栏~串口发送字符串


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    FPGQ2

CSDN

🎉 目录-串口发送字符串

  • 一、效果演示
  • 二、代码编写
  • 三、封装为模块
  • 四、其余项目
  • 五、后记

遇见未来

一、效果演示

🥝发送Hello:
hello

🥝发送数字字符并自增1:
adder1

🥝发送数字字符复位后从1开始发送:
adder2

二、代码编写

✨注:本篇文章需要使用到按键消抖模块串口发送模块(1byte)
按键消抖模块:【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)。
串口发送模块:【FPGA零基础学习之旅#13】串口发送模块设计与验证。

首先展示整体代码和RTL视图。

代码:uart_string_tx_top.v

module uart_string_tx_top(input	Clk,input 	Rst_n,input 	key_in,output 	uart_tx,output 	led
);reg 	send_en;reg 	[7:0]data_byte;reg 	[2:0]cnt;wire 	Tx_Done;wire 	key_flag;wire 	key_state;localparambyte1 = "H",byte2 = "E",byte3 = "L",byte4 = "L",byte5 = "O",byte6 = "\n";KeyFilter KeyFilter(.Clk(Clk),.Rst_n(Rst_n),.key_in(key_in),.key_flag(key_flag),.key_state(key_state));uart_byte_tx uart_byte_tx(.Clk(Clk),.Rst_n(Rst_n),.data_byte(data_byte),.send_en(send_en),.baud_set(3'd0),.uart_tx(uart_tx),.Tx_Done(Tx_Done),.uart_state(led));always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)cnt <= 1'b0;else if(Tx_Done)cnt <= cnt + 1'b1;else if(key_flag & !key_state)cnt <= 1'b0;else;endalways@(posedge Clk or negedge Rst_n)beginif(!Rst_n)send_en <= 1'b0;else if(key_flag & !key_state)send_en <= 1'b1;else if(Tx_Done & (cnt < 3'd5))send_en <= 1'b1;elsesend_en <= 1'b0;endalways@(*)begincase(cnt)3'd0:data_byte = byte1;3'd1:data_byte = byte2;3'd2:data_byte = byte3;3'd3:data_byte = byte4;3'd4:data_byte = byte5;3'd5:data_byte = byte6;default:data_byte = 0;endcaseendendmodule

RTL视图:

RTL1

🔸设计思路:
使用前文的串口发送模块(FPGA零基础学习之旅#13】串口发送模块设计与验证)一次只能发送1byte的数据,为了发送多比特的字符串数据,我们将字符串按照byte流发送出去即可。

🔸代码详解:
用于判断串口发送模块已发送完1byte数据:

always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)cnt <= 1'b0;else if(Tx_Done)cnt <= cnt + 1'b1;else if(key_flag & !key_state)cnt <= 1'b0;else;
end

用于开启或关闭串口发送模块的使能信号:

always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)send_en <= 1'b0;else if(key_flag & !key_state)send_en <= 1'b1;else if(Tx_Done & (cnt < 3'd5))send_en <= 1'b1;elsesend_en <= 1'b0;
end

通过查找表的方式将byte流发送出去:

always@(*)begincase(cnt)3'd0:data_byte = byte1;3'd1:data_byte = byte2;3'd2:data_byte = byte3;3'd3:data_byte = byte4;3'd4:data_byte = byte5;3'd5:data_byte = byte6;default:data_byte = 0;endcase
end

测试激励文件:

`timescale 1ns/1ns
`define clock_period 20module uart_string_tx_top_tb;reg Clk;reg Rst_n;reg press;wire key_in;wire uart_tx;wire led;uart_string_tx_top uart_string_tx_top0(.Clk(Clk),.Rst_n(Rst_n),.key_in(key_in),.uart_tx(uart_tx),.led(led));key_model key_model(.press(press),.key(key_in));initial Clk = 1;always#(`clock_period / 2) Clk = ~Clk;initial beginRst_n = 1'b0;press = 0;#(`clock_period*20 + 1);Rst_n = 1'b1;#(`clock_period*20 + 1);press = 1;#(`clock_period*20 + 1);press = 0;wait(uart_string_tx_top0.Tx_Done &(uart_string_tx_top0.cnt == 3'd5));#(`clock_period*2000000 + 1);#(`clock_period*20 + 1);press = 1;#(`clock_period*20 + 1);press = 0;wait(uart_string_tx_top0.Tx_Done &(uart_string_tx_top0.cnt == 3'd5));#(`clock_period*2000000 + 1);$stop;endendmodule

其中,仿真模型key_model:

`timescale 1ns/1nsmodule key_model(press,key);input press;output reg key;reg [15:0]myrand;initial beginkey = 1'b1;endalways@(posedge press)press_key;task press_key;begin//50次随机时间按下抖动repeat(50)beginmyrand = {$random}%65536;//0~65535#myrand key = ~key;endkey = 0;#25_000_000;//按下稳定//50次随机时间释放抖动repeat(50)beginmyrand = {$random}%65536;//0~65535#myrand key = ~key;endkey = 1;#25_000_000;//释放稳定endendtask	endmodule

关于上述仿真模型的基础讲解,见文章:【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)。

仿真结果:

仿真结果

三、封装为模块

将uart_string_tx_top中发送字符串“Hello”代码的部分封装为一个模块,只需要把设计部分中使用到的输入输出信号整理好即可。

Str_Hello.v:

module Str_Hello(input 				Clk,input 				Rst_n,input 				Tx_Done,input 				key_flag,input 				key_state,output reg 			send_en,output reg [7:0]	data_byte
);reg 	[2:0]cnt;localparambyte1 = "H",byte2 = "E",byte3 = "L",byte4 = "L",byte5 = "O",byte6 = "\n";always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)cnt <= 1'b0;else if(Tx_Done)cnt <= cnt + 1'b1;else if(key_flag & !key_state)cnt <= 1'b0;else;endalways@(posedge Clk or negedge Rst_n)beginif(!Rst_n)send_en <= 1'b0;else if(key_flag & !key_state)send_en <= 1'b1;else if(Tx_Done & (cnt < 3'd5))send_en <= 1'b1;elsesend_en <= 1'b0;endalways@(*)begincase(cnt)3'd0:data_byte = byte1;3'd1:data_byte = byte2;3'd2:data_byte = byte3;3'd3:data_byte = byte4;3'd4:data_byte = byte5;3'd5:data_byte = byte6;default:data_byte = 0;endcaseendendmodule

module Str_Hello的RTL视图:

RTLstr

将该模块例化到顶层模块中:

module uart_string_tx_top(input	Clk,input 	Rst_n,input 	key_in,output 	uart_tx,output 	led
);wire 	send_en;wire 	[7:0]data_byte;wire 	Tx_Done;wire 	key_flag;wire 	key_state;KeyFilter KeyFilter(.Clk(Clk),.Rst_n(Rst_n),.key_in(key_in),.key_flag(key_flag),.key_state(key_state));uart_byte_tx uart_byte_tx(.Clk(Clk),.Rst_n(Rst_n),.data_byte(data_byte),.send_en(send_en),.baud_set(3'd0),.uart_tx(uart_tx),.Tx_Done(Tx_Done),.uart_state(led));Str_Hello Str_Hello0(.Clk(Clk),.Rst_n(Rst_n),.Tx_Done(Tx_Done),.send_en(send_en),.key_flag(key_flag),.key_state(key_state),.data_byte(data_byte));endmodule

顶层模块的RTL视图:

RTLstr2

四、其余项目

以使用串口发送模块发送字符串的思路,编写一个模块:
按下一次按键,串口发送字符“0”;再按下一次按键,串口发送字符“1”;… ;再按下一次按键,串口发送字符“9”。且每一个数字字符为一行。

🔸实现思路:
当接收到一次按键信号之后,串口发送模块依次发送数字字符和一个换行符;同时,再接收到一次按键信号的同时,内部的计数器开始计数,一次按键信号获取后计数器增加1,用于判断发送的数字字符的大小。

🔸实现效果:
adder3
🔸先看RTL视图来理解思路:
ADDERRTL
通过RTL视图,可以看到串口发送模块的Tx_Done信号是作为反馈信号输入给Num_Adder模块的,该信号即用于判断一个byte数据发送的完成。当一个数字字符发送完成并返回Tx_Done信号之后,需要继续发送一个换行符。

module Num_Adder.v:

module Num_Adder(input 				Clk,input 				Rst_n,input 				key_flag,input 				key_state,input 				Tx_Done,output reg 			send_en,output reg [7:0]	Num_byte
);reg [3:0]cnt;reg [1:0]cnt_N;reg [7:0]Num_byte_r;//--------<发送数据的增加模块>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)cnt <= 4'd0;else if(key_flag & !key_state)cnt <= cnt + 1'd1;else if(cnt == 4'd10)cnt <= 4'd0;elsecnt <= cnt;end//--------<数据查找表>--------		always@(*)begincase(cnt)4'd1:Num_byte_r = "0";4'd2:Num_byte_r = "1";4'd3:Num_byte_r = "2";4'd4:Num_byte_r = "3";4'd5:Num_byte_r = "4";4'd6:Num_byte_r = "5";4'd7:Num_byte_r = "6";4'd8:Num_byte_r = "7";4'd9:Num_byte_r = "8";4'd10:Num_byte_r = "9";default:Num_byte_r = 0;endcaseend//--------<发送“\n”的计数器>--------	always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)cnt_N <= 2'd0;else if(Tx_Done)cnt_N <= cnt_N + 1'b1;else if(key_flag & !key_state)cnt_N <= 2'd0;else;end//--------<发送“\n”>--------	always@(*)begincase(cnt_N)2'd0:Num_byte = Num_byte_r;2'd1:Num_byte = "\n";default:Num_byte = 0;endcaseend//--------<发送模块使能信号的处理>--------		always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)send_en <= 1'b0;else if(key_flag & !key_state)send_en <= 1'b1;else if(Tx_Done & (cnt_N < 2'd2))send_en <= 1'b1;elsesend_en <= 1'b0;end	endmodule

module uart_NumAdder_tx_top.v:

module uart_NumAdder_tx_top(input	Clk,input 	Rst_n,input 	key_in,output 	uart_tx,output 	led
);wire [7:0]data_byte;wire 	key_flag;wire 	key_state;wire	Tx_Done;wire  send_en;KeyFilter KeyFilter(.Clk(Clk),.Rst_n(Rst_n),.key_in(key_in),.key_flag(key_flag),.key_state(key_state));Num_Adder Num_Adder0(.Clk(Clk),.Rst_n(Rst_n),.key_flag(key_flag),.key_state(key_state),.Tx_Done(Tx_Done),.send_en(send_en),.Num_byte(data_byte)	);uart_byte_tx uart_byte_tx(.Clk(Clk),.Rst_n(Rst_n),.data_byte(data_byte),.send_en(send_en),.baud_set(3'd0),.uart_tx(uart_tx),.Tx_Done(Tx_Done),.uart_state(led));endmodule

五、后记

我在我的每篇文章中都几乎放上设计的RTL视图,因为观察RTL视图,也是一种简单的debug方法。

在设计串口发送字符串的逻辑框架时,发现仿真一直出不来结果,直到我看了一眼RTL视图:
123
看了之后才发现是例化模块的时候,引脚绑定的大小写不一致导致的。

csdn

🧸结尾


  • ❤️ 感谢您的支持和鼓励! 😊🙏
  • 📜您可能感兴趣的内容:
  • 【FPGA零基础学习之旅#11】数码管动态扫描
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)
  • 【Arduino TinyGo】【最新】使用Go语言编写Arduino-环境搭建和点亮LED灯
  • 【全网首发开源教程】【Labview机器人仿真与控制】Labview与Solidworks多路支配关系-四足爬行机器人仿真与控制
    遇见未来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/151657.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑散热——液金散热

目录 1.简介 2.传统硅脂与液金导热区别 3.特点 4.优点 5.为什么液金技术名声不太好 6.使用方法 1.简介 凡是对于电脑基础硬件有所了解的人&#xff0c;都知道硅脂是如今高性能电脑设备中必不可少的东西。芯片表面和散热器接触面&#xff0c;虽然肉眼看上去是非常光滑的金属…

C (1094) : DS双向链表—前驱后继

Description 在双向链表中&#xff0c;A有一个指针指向了后继节点B&#xff0c;同时&#xff0c;B又有一个指向前驱节点A的指针。这样不仅能从链表头节点的位置遍历整个链表所有节点&#xff0c;也能从链表尾节点开始遍历所有节点。 对于给定的一列数据&#xff0c;按照给定的…

C#封装、继承和多态的用法详解

大家好&#xff0c;今天我们将来详细探讨一下C#中封装、继承和多态的用法。作为C#的三大面向对象的特性&#xff0c;这些概念对于程序员来说非常重要&#xff0c;因此我们将对每个特性进行详细的说明&#xff0c;并提供相应的示例代码。 目录 1. 封装&#xff08;Encapsulati…

ElementUI结合Vue完成主页的CUD(增删改)表单验证

目录 一、CUD ( 1 ) CU讲述 ( 2 ) 编写 1. CU 2. 删除 二、验证 前端整合代码 : 一、CUD 以下的代码基于我博客中的代码进行续写 : 使用ElementUI结合Vue导航菜单和后台数据分页查询 ( 1 ) CU讲述 在CRUD操作中&#xff0c;CU代表创建&#xff08;Create&#xff09…

我做了一个简易P图(参数图)分析软件

P图(即参数图&#xff0c;Parameter Diagram)&#xff0c;是一个结构化的工具&#xff0c;帮助大家对产品更好地进行分析。 典型P图格式 P图最好是和FMEA软件联动起来&#xff0c;如国可工软的FMEA软件有P图分析这个功能。 单纯的P图分析软件很少&#xff0c;为了方便做P图分…

Elasticsearch:多语言语义搜索

在此示例中&#xff0c;我们将使用多语言嵌入模型 multilingual-e5-base 对混合语言文档的 toy 数据集执行搜索。 使用这个模型&#xff0c;我们可以通过两种方式进行搜索&#xff1a; 跨语言&#xff0c;例如使用德语查询来查找英语文档在非英语语言中&#xff0c;例如使用德…

【C++】多线程的学习笔记(2)——白话文版(bushi

目录 前一篇 本章内容提要 使用mutex锁的原因 mutex锁的概念 mutex的使用教程 锁的声明以及命名 mutex的加锁以及解锁 例子 结果 注意 mutex的其他方式的锁介绍 lock_guard 介绍 例子 运行结果 adopt_lock参数 unique_lock 介绍 try_to_lock defer_lock re…

iOS开发 通过分析UMeng的错误详情解决crash问题

iOS开发 通过分析UMeng的错误详情解决crash问题 在项目中获取崩溃信息很重要。在iOS开发调试以及上线之后&#xff0c;程序经常会出现Crash问题。比较常见的第三方crash分析工具是使用友盟、百度、crashlytics等。第三方crash分析工具&#xff0c;甚至还带了符号化crash日志的…

设计模式 - 七大软件设计原则

目录 一、设计模式 1.1、软件设计原则 1.1.1、开闭原则 1.2.2、单一职责原则 1.2.3、里氏替换原则 1.2.4、迪米特原则 1.2.5、接口隔离原则 1.2.6、依赖倒转原则 1.2.7、合成/聚合复用原则 一、设计模式 1.1、软件设计原则 1.1.1、开闭原则 开闭原则&#xff1a;对扩…

Docker 日志管理 - ELK

Author&#xff1a;rab 目录 前言一、Docker 日志驱动二、ELK 套件部署三、Docker 容器日志采集3.1 部署 Filebeat3.2 配置 Filebeat3.3 验证采集数据3.4 Kibana 数据展示3.4.1 创建索引模式3.4.2 Kibana 查看日志 总结 前言 如何查看/管理 Docker 运行容器的日志&#xff1f;…

1.Linux入门基本指令

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 01.ls指令 02.pwd指令 03.cd指令 04.touch指令 05.mkdir指令(重要) 06.rmdir&&rm指令(重要) 07.man指令(重要) 08.cp指令(重要) 09.mv指令(重要) 10.cat指令 nano指令 echo指令 输出重定向 追加重…

当 FineReport 遇见 CnosDB

随着大数据和物联网应用的快速发展&#xff0c;时序数据库成为了一种关键的数据存储和分析工具。而 FineReport 作为一款流行的商业智能工具&#xff0c;与时序数据库 CnosDB 的集成可以为企业提供更强大的数据分析和可视化功能。本博客将介绍如何将 FineReport 与 CnosDB 集成…

架构师-软件工程习题选择题

架构师-软件工程习题选择题

SpringBoot-黑马程序员-学习笔记(一)

8.pom文件中的parent 我们使用普通maven项目导入依赖时&#xff0c;通常需要在导入依赖的时候指定版本号&#xff0c;而springboot项目不需要指定版本号&#xff0c;会根据当前springboot的版本来下载对应的最稳定的依赖版本。 点开pom文件会看到这个&#xff1a; 继承了一个…

【Redis】基础数据结构-简单动态字符串SDS

C语言字符串 char *str "redis"; // 可以不显式的添加\0&#xff0c;由编译器添加 char *str "redis\0"; // 也可以添加\0代表字符串结束C语言中使用char*字符数组表示字符串&#xff0c;‘\0’来标记一个字符串的结束&#xff0c;不过在使用的过程中我…

自动驾驶传感器技术

自动驾驶传感器技术是自动驾驶系统的关键组成部分&#xff0c;它使车辆能够感知并理解周围环境。本文将深入探讨自动驾驶传感器技术&#xff0c;包括常见类型、工作原理以及它们在自动驾驶中的作用。 1. 摄像头 摄像头的工作原理 摄像头是基于光学原理的传感器&#xff0c;其…

【数组】二分查找(减不减一,看初始化!)

一、力扣习题链接 704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 二、思路 这道题目的前提是数组为有序数组&#xff0c;同时题目还强调数组中无重复元素&#xff0c;因为一旦有重复元素&#xff0c;使用二分查找法返回的元素下标可能不是唯一的&#xff0c;这些都是…

防火墙-——iptables

目录 安全技术&#xff1a;&#xff08;市场上常见的防御&#xff09; 1.入侵检测机制 2.入侵防御 3.防火墙 4.防水墙 通信的五大要素和四要素 iptables 四个表 数据流程图 安装iptables iptables管理选项: 匹配条件 通用匹配规则 1.查看filter中的 INPUT表 2.清…

Docker中MySql容器的数据挂载

1.查看是否有数据卷 docker inspect mysql 说明&#xff1a;Name的值是随机生成的不是命令的。因此没有数据卷。 2. 目录挂载 说明&#xff1a;本地目录不允许简写&#xff1b;在执行docker runi命令时&#xff0c;使用-v本地目录&#xff1a;容器内目录可以完成本地目录挂载…

滴滴发布十一大数据:延边出行需求上涨280% 西部省份成旅游热点

今年十一假期适逢中秋佳节&#xff0c;在亲友团聚和长假出游的多重期盼下&#xff0c;超级黄金周展现强劲内需&#xff0c;带动多样化的消费趋势&#xff0c;出行热情也随之高涨。滴滴出行数据显示&#xff0c;打车需求相比去年同期上涨80%&#xff0c;高峰时段每分钟呼叫突破1…