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

这篇具有很好参考价值的文章主要介绍了【FPGA零基础学习之旅#14】串口发送字符串。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

一、效果演示

🥝发送Hello:
【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

🥝发送数字字符并自增1:
【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

🥝发送数字字符复位后从1开始发送:
【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

二、代码编写

✨注:本篇文章需要使用到按键消抖模块串口发送模块(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;
	
	localparam
		byte1 = "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)begin
		if(!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)begin
		if(!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;
		else
			send_en <= 1'b0;
	end

	always@(*)begin
		case(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

endmodule

RTL视图:

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

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

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

always@(posedge Clk or negedge Rst_n)begin
	if(!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)begin
	if(!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;
	else
		send_en <= 1'b0;
end

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

always@(*)begin
	case(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 20

module 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 begin
		Rst_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;
	end

endmodule

其中,仿真模型key_model:

`timescale 1ns/1ns

module key_model(press,key);
	
	input press;
	output reg key;
	
	reg [15:0]myrand;
	
	initial begin
		key = 1'b1;
	end
	
	always@(posedge press)
		press_key;
	
	task press_key;
		begin
			//50次随机时间按下抖动
			repeat(50)begin
				myrand = {$random}%65536;//0~65535
				#myrand key = ~key;
			end
			key = 0;
			#25_000_000;//按下稳定
			
			//50次随机时间释放抖动
			repeat(50)begin
				myrand = {$random}%65536;//0~65535
				#myrand key = ~key;
			end
			key = 1;
			#25_000_000;//释放稳定
		end
	endtask	

endmodule

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

仿真结果:

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

三、封装为模块

将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;
	
	localparam
		byte1 = "H",
		byte2 = "E",
		byte3 = "L",
		byte4 = "L",
		byte5 = "O",
		byte6 = "\n";
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!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)begin
		if(!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;
		else
			send_en <= 1'b0;
	end

	always@(*)begin
		case(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

endmodule

module Str_Hello的RTL视图:

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

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

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视图:

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

四、其余项目

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

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

🔸实现效果:
【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串
🔸先看RTL视图来理解思路:
【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串
通过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)begin
		if(!Rst_n)
			cnt <= 4'd0;
		else if(key_flag & !key_state)
			cnt <= cnt + 1'd1;
		else if(cnt == 4'd10)
			cnt <= 4'd0;
		else
			cnt <= cnt;
	end

//--------<数据查找表>--------		
	always@(*)begin
		case(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;
		endcase
	end

//--------<发送“\n”的计数器>--------	
	always@(posedge Clk or negedge Rst_n)begin
		if(!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@(*)begin
		case(cnt_N)
			2'd0:Num_byte = Num_byte_r;
			2'd1:Num_byte = "\n";
			default:Num_byte = 0;
		endcase
	end

//--------<发送模块使能信号的处理>--------		
	always@(posedge Clk or negedge Rst_n)begin
		if(!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;
		else
			send_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视图:
【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串
看了之后才发现是例化模块的时候,引脚绑定的大小写不一致导致的。

【FPGA零基础学习之旅#14】串口发送字符串,FPGA学习之旅,fpga开发,学习,Verilog HDL,串口通信,字符串

🧸结尾文章来源地址https://www.toymoban.com/news/detail-715176.html


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

到了这里,关于【FPGA零基础学习之旅#14】串口发送字符串的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32串口发送字符、字符串(标准库)

    目录 一 芯片概述  二 代码编写 2.1 以串口2为例配置初始化代码 2.2 发送自定义长度的字符串 2.3 发送单个字符 2.4 自定义printf函数 三 完整代码 3.1 usart2.c 3.2 usart2.h 3.3 while(1) 本文以stm32f103c8t6系列芯片为例,使用自定义函数发送串口数据。 PA2为TX引脚,PA3为RX引脚 第一个变量

    2024年04月15日
    浏览(47)
  • STM32串口发送字符串

    在STM32串口学习中,串口发送字符串是必不可少的,但是 在学习过程中可能会遇到下面这个问题,就由我来给大家分享一下吧。 下面是封装的串口发送字符串的函数: 在mian.c文件中我们运行代码不会报错,但是我们可以看到Usart_SendString函数打印字符串时会出现警告。 当我们

    2024年02月12日
    浏览(41)
  • 【个人笔记】51单片机串口通信的字符串接收和发送,串口通信调节数码管显示时钟(串口通信,定时器,数码管)

           目的:利用PROTUES仿真软件、串口调试助手、虚拟串口,搭建单片机与PC通信仿真平台,熟悉单片机串口的配置及与PC机的通信方法;尝试制定通信协议,单片机根据通信协议解析接收到的内容,并根据接收的指令执行相应的操作。 基本功能: 1.时分秒的动态显示。

    2024年02月11日
    浏览(63)
  • 基于STM32F1以及STM32CubeMx实现串口中断通讯(字符串发送与接收)

    首先选好自己的板子并打开软件设置,本实验基于STM32F103ZET6实现,打开软件后如图: 打开外部高速晶振,然后接着配置时钟: 将时钟频率修改为72MHz,接着设置接线方式为SW 接下来需要使用串口中断通讯,打开我们的串口设置并打开中断 这里波特率设置为115200,数据位为

    2024年02月09日
    浏览(47)
  • FPGA学习笔记(三)——串口通信之发送数据(调试过程)

    本学习笔记主要参考小梅哥B站教学视频,网址如下: https://www.bilibili.com/video/BV1va411c7Dz?p=1 使用的编译器为Vivado,HDL语言为verilog 一、串口通信之发送数据 原理 设计代码 测试代码 仿真结果 发现Send_en拉高之前,uart_tx就置为0了,不符合常理。 转到第二个发送信号处,发现Send

    2023年04月09日
    浏览(43)
  • MSP432学习笔记10:串口接收字符串命令并执行任务

    今日终于得以继续我的MSP432电赛速通之路: 串口通信是单片机需要学习深入的一个很重要的板块,通过串口,我们可以实现许多数据收发与调试工作,可谓是非常方便快捷。 今日就跟随我的脚步,逐步扎实地学习 如何编程MSP432串口接收字符串命令 ,并使其执行一些任务,

    2024年02月10日
    浏览(78)
  • 嵌入式学习笔记——STM32的USART收发字符串及串口中断

    上一篇中,介绍了串口收发相关的寄存器,通过代码实现了一个字节的收发,本文接着上面的内容,通过功能函数实现字符串的收发,然后引入中断解决收发过程中while()死等的问题。 根据昨天的字符发送函数,只需要稍作修改即可实现发送函数了,一个字符串的结尾会有一

    2024年02月03日
    浏览(79)
  • 【FPGA零基础学习之旅#9】状态机基础知识

    🎉欢迎来到FPGA专栏~状态机基础知识 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🔸 Hello状态机例程 : RTL视图: 状态

    2024年02月16日
    浏览(46)
  • 【FPGA零基础学习之旅#11】数码管动态扫描

    🎉欢迎来到FPGA专栏~数码管动态扫描 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🥝 Spirit_V2开发板按键控制数码管:

    2024年02月11日
    浏览(40)
  • 【FPGA零基础学习之旅#7】BCD计数器设计

    🎉欢迎来到FPGA专栏~BCD计数器设计 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 顶层模块中的BCD模块级联: Verilog实现

    2024年02月08日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包