FPGA的UART信息回显

一、准备及目标

采用的元器件:T型口数据线2;总线1;USB Blaster1;FPGA板子1;HC-05蓝牙模块*1。
使用的软件:手机:蓝牙串口SPP;电脑:Quartus。
实现的目标:手机输入一段信息,通过蓝牙传递信息给FPGA,FPGA收到信息后,再将该信息通过蓝牙传递回手机。
如图:
在这里插入图片描述

二、为什么要写这么一篇文章

太菜了QAQ,好多网上的东西看不懂,理解了UART,但是找不到一个基于UART且读得懂的代码。所有我把我的东西放在这里,恳请广大网友批评指正的同时,也帮助一些像我一样菜的同学理解一下蓝牙的串口协议。

三、原理

1、UART(异步收发传输器)串口协议

(1)为什么需要UART串口协议?
信息的传递有串行(异步)和并行(同步)两种。同步传输快但需要的线多,异步需要的线少但传输慢。以异步进行信息传递的叫UART,把异步信息和同步信息进行转换的标准叫串口协议。这个标准保证传递的信息时正确的。
(2)UART串口协议的原理:
这个不赘述,找到两个很棒的资料:
1、这个是文字的,细的一批—— FPGA——UART Verilog程序设计
2、这个是bilibili的视频,很直观——【Electronoobs】UART-I2C-SPI 基本串行通信协议 1080P (中英字幕)

2、手机、蓝牙、FPGA

当我给FPGA装上蓝牙模块后,我会很自然的认为信息的传递发生在手机和FPGA之间,这么想会给编程带来一定阻力。这种想法需要纠正为信息的传递发生在蓝牙模块和FPGA之间:手机和蓝牙连接上后相当于一个整体,里面流通的信息是一致的,而对他们而言,FPGA才是外部。所以我需要把蓝牙模块的输出(tx)所连接的FPGA上的引脚定义为(rx),蓝牙模块的输出(rx)所连接的FPGA上的引脚定义为(tx),即蓝牙模块的输入是FPGA的输出,蓝牙模块的输出是FPGA的输入。

3、实物连接

这个不难:在这里插入图片描述

四、代码

代码很非常丑陋且基础,但毕竟自己写的,读得懂:

1、主模块:

module bluetooth(
	input sys_clk,
	input rx,
	output tx,
	output wire[1:0]led
);																				//sys_clk为系统板载时钟(50MHz),rx对应蓝牙模块的tx,tx对应蓝牙模块的rx;led是我设置来判断读入数据错没错的
	wire[7:0]message;															//message为读入的数据
	wire sig;																	//sig是读入的完成信号,下降沿表示读入完成,同时作为输出的开始信号
	
	uart_r uart_r_1(.clk(sys_clk),.rx(rx),.message(message),.over(sig));		//读入
	uart_t uart_t_1(.clk(sys_clk),.tx(tx),.message(message),.run(sig));			//输出
	
	assign led[0]=message[0];													//这两个看数据最后两位存的对不对的
	assign led[1]=message[1];
endmodule

2、输入模块:

module uart_r(
	input clk,
	input wire rx,
	output reg [7:0]message,
	output reg over=0
);                  									//clk为FPGA板载时钟(50MHz),rx为读入的串行信号,message为对应的并行信号,over的下降沿将表示读入转换完成
                                                
	reg [12:0]cnt_clk=0;								//需要一个量来数clk的个数,每5208个clk,对应0.104us,即波特率9600对应的1bit占用的时常
	reg [4:0]cnt_message=0;								//计数message的位数,表征传递进行到了第几位
	reg [7:0]message_mid=0;								//message的前体,在over的下降沿传递给message,避免传递没结束,message就有输出值了
	reg r_start=1;										//判断第一个0位,表示传递开始
	
	always @(posedge clk)
	begin
		if (rx==0&&r_start==1) begin
			cnt_clk<=cnt_clk+1;
			if (cnt_clk==2604&&rx==0) begin
				r_start<=0;
				cnt_clk<=0;
				cnt_message<=0;
				message_mid<=0;
			end
		end												//判断是否为开始位,是时开始计算clk,数2604下(0.5bit)即在开始位中间,开始读数
		else if (r_start==0) begin
			cnt_clk<=cnt_clk+1;
			if (cnt_clk==5208) begin 					//每5208个clk读一次
				message_mid[cnt_message]<=rx;
				cnt_message<=cnt_message+1;
				cnt_clk<=0;
			end												
			else if (cnt_message==8) begin				//读完第8位不读了
				if (cnt_clk==3000) begin				//在数据位第8位的中间往右走2604个clk进入终止位(默认无奇偶校验位),在终止位中(往右走3000个clk和5000个clk之间)输出一个over信号
					over<=1;
				end
				if (cnt_clk==5000) begin				//over下降沿,传递完成,message_mid赋值给message,所有信号还原
					over<=0;
					cnt_clk<=0;
					cnt_message<=0;
					r_start<=1;
					message<=message_mid;
					message_mid<=0;
				end
			end
		end												//开始读数,每5208个clk读一次
		else begin
			r_start<=1;
			over<=0;
		end
	end

endmodule

3、输出模块:

module uart_t(
	input wire [7:0]message,
	input clk,
	output reg tx=1,
	input wire run
	);																	//大致思路与输入类似,tx连接蓝牙的rx,注意run信号为开始信号,连接的输入的over信号

	reg [12:0]cnt_clk=0;
	reg [4:0]cnt_message=0;
	reg t_start=1;
	
	always @(posedge clk) begin
		if (run==1&&t_start==1) begin
			t_start<=0;
			cnt_clk<=0;
		end
		else if (run==0&&t_start==0&&cnt_message==0) begin				//在run的下降沿开始输出
			tx<=0;
			cnt_clk<=cnt_clk+1;
			if (cnt_clk==5208) begin
				tx<=message[cnt_message];
				cnt_clk<=0;
				cnt_message<=1;
				t_start<=0;
			end
		end
		else if (cnt_message>=1) begin
			cnt_clk<=cnt_clk+1;
			if (cnt_clk==5208) begin
				cnt_clk<=0;
				if (cnt_message==8) begin
					tx<=1;
					t_start<=1;
					cnt_message<=0;
				end
				else begin
					tx<=message[cnt_message];
					cnt_message<=cnt_message+1;
				end
			end
		end
		else begin
			tx=1;
		end
	end
endmodule

4、测试模块

`timescale 1ps/1ps
module testbench (
	output reg clk,
	output reg tx,
	input rx,
	input [1:0] led
);
	reg [23:0]i;
	initial
	begin
		clk=0;
		for(i=0;i<668900;i=i+1)#10	clk=~clk;
	end
	
	initial begin
		tx=1; #200000 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=1; #104200
		
		tx=0; #104200 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=1; #104200 
		tx=0; #104200 
		tx=0; #104200 
		tx=1; #104200
		tx=1;
	end
	
	bluetooth blue1(.sys_clk(clk),.tx(rx),.rx(tx),.led(led));
endmodule

5、仿真效果

在这里插入图片描述
一个小Tip,Add Waves之后课以通过这一排按钮重新加载波形:
在这里插入图片描述

  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值