FPGA 串口与HC05蓝牙模块通信

介绍

关于接线:HC-05蓝牙模块一共有6个引脚,但经过我查阅资料以及自己的实操,实际上只需要用到中间的4个引脚即可(即RXD,TXD,GND,VCC)。需要注意的是,蓝牙模块的RXD引脚需要接单片机的TXD引脚,同样,蓝牙模块的TXD引脚需要接单片机的RXD引脚!也就是RXD--TXD,TXD--RXD,VCC--5V,GND--GND(注:HC-05模块的TX对于FPGA来说是 RX)

FPGA代码

bash 复制代码
//
// Company: 武汉芯路恒科技有限公司
// Engineer: 小梅哥团队
// Web: www.corecourse.cn
// 
// Create Date: 2020/07/20 00:00:00
// Design Name: uart_rx
// Module Name: uart_byte_rx
// Project Name: uart_rx
// Description: 串口接收模块
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module uart_byte_rx(
	clk,
	reset_n,

	baud_set,
	uart_rx,

	data_byte,
	rx_done
);
	wire reset=~reset_n;

	input clk;    //模块全局时钟输入,50M
	input reset_n;   //复位信号输入,低有效

	input [2:0]baud_set;  //波特率设置
	input uart_rx;   //串口输入信号
	
	output [7:0]data_byte; //串口接收的1byte数据
	output rx_done;   //1byte数据接收完成标志
	
	reg [7:0]data_byte;
	reg rx_done;
	reg uart_rx_sync1;   //同步寄存器
	reg uart_rx_sync2;   //同步寄存器

	reg uart_rx_reg1;    //数据寄存器
	reg uart_rx_reg2;    //数据寄存器

	reg [15:0]bps_DR;    //分频计数最大值	
	reg [15:0]div_cnt;   //分频计数器
	reg bps_clk;   //波特率时钟	
	reg [7:0] bps_cnt;   //波特率时钟计数器	
	reg uart_state;//接收数据状态

	wire uart_rx_nedge;  

	reg [2:0]START_BIT;
	reg [2:0]STOP_BIT;
	reg [2:0]data_byte_pre [7:0];

	//同步串行输入信号,消除亚稳态
	always@(posedge clk or posedge reset)
	if(reset)begin
		uart_rx_sync1 <= 1'b0;
		uart_rx_sync2 <= 1'b0;	
	end
	else begin
		uart_rx_sync1 <= uart_rx;
		uart_rx_sync2 <= uart_rx_sync1;	
	end
	
	//数据寄存器
	always@(posedge clk or posedge reset)
	if(reset)begin
		uart_rx_reg1 <= 1'b0;
		uart_rx_reg2 <= 1'b0;	
	end
	else begin
		uart_rx_reg1 <= uart_rx_sync2;
		uart_rx_reg2 <= uart_rx_reg1;	
	end
	
  //下降沿检测
	assign uart_rx_nedge = !uart_rx_reg1 & uart_rx_reg2;
	
	always@(posedge clk or posedge reset)
	if(reset)
		bps_DR <= 16'd324;
	else begin
		case(baud_set)
			0:bps_DR <= 16'd324;
			1:bps_DR <= 16'd162;
			2:bps_DR <= 16'd80;
			3:bps_DR <= 16'd53;
			4:bps_DR <= 16'd26;
			default:bps_DR <= 16'd324;			
		endcase
	end
	
	//counter
	always@(posedge clk or posedge reset)
	if(reset)
		div_cnt <= 16'd0;
	else if(uart_state)begin
		if(div_cnt == bps_DR)
			div_cnt <= 16'd0;
		else
			div_cnt <= div_cnt + 1'b1;
	end
	else
		div_cnt <= 16'd0;
		
	// bps_clk gen
	always@(posedge clk or posedge reset)
	if(reset)
		bps_clk <= 1'b0;
	else if(div_cnt == 16'd1)
		bps_clk <= 1'b1;
	else
		bps_clk <= 1'b0;
	
	//bps counter
	always@(posedge clk or posedge reset)
	if(reset)	
		bps_cnt <= 8'd0;
	else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && (START_BIT > 2)))
		bps_cnt <= 8'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;

	always@(posedge clk or posedge reset)
	if(reset)
		rx_done <= 1'b0;
	else if(bps_cnt == 8'd159)
		rx_done <= 1'b1;
	else
		rx_done <= 1'b0;		
		
	always@(posedge clk or posedge reset)
	if(reset)begin
		START_BIT <= 3'd0;
		data_byte_pre[0] <= 3'd0;
		data_byte_pre[1] <= 3'd0;
		data_byte_pre[2] <= 3'd0;
		data_byte_pre[3] <= 3'd0;
		data_byte_pre[4] <= 3'd0;
		data_byte_pre[5] <= 3'd0;
		data_byte_pre[6] <= 3'd0;
		data_byte_pre[7] <= 3'd0;
		STOP_BIT <= 3'd0;
	end
	else if(bps_clk)begin
		case(bps_cnt)
			0:begin
        START_BIT <= 3'd0;
        data_byte_pre[0] <= 3'd0;
        data_byte_pre[1] <= 3'd0;
        data_byte_pre[2] <= 3'd0;
        data_byte_pre[3] <= 3'd0;
        data_byte_pre[4] <= 3'd0;
        data_byte_pre[5] <= 3'd0;
        data_byte_pre[6] <= 3'd0;
        data_byte_pre[7] <= 3'd0;
        STOP_BIT <= 3'd0;			
      end
			6 ,7 ,8 ,9 ,10,11:START_BIT <= START_BIT + uart_rx_sync2;
			22,23,24,25,26,27:data_byte_pre[0] <= data_byte_pre[0] + uart_rx_sync2;
			38,39,40,41,42,43:data_byte_pre[1] <= data_byte_pre[1] + uart_rx_sync2;
			54,55,56,57,58,59:data_byte_pre[2] <= data_byte_pre[2] + uart_rx_sync2;
			70,71,72,73,74,75:data_byte_pre[3] <= data_byte_pre[3] + uart_rx_sync2;
			86,87,88,89,90,91:data_byte_pre[4] <= data_byte_pre[4] + uart_rx_sync2;
			102,103,104,105,106,107:data_byte_pre[5] <= data_byte_pre[5] + uart_rx_sync2;
			118,119,120,121,122,123:data_byte_pre[6] <= data_byte_pre[6] + uart_rx_sync2;
			134,135,136,137,138,139:data_byte_pre[7] <= data_byte_pre[7] + uart_rx_sync2;
			150,151,152,153,154,155:STOP_BIT <= STOP_BIT + uart_rx_sync2;
			default:
      begin
        START_BIT <= START_BIT;
        data_byte_pre[0] <= data_byte_pre[0];
        data_byte_pre[1] <= data_byte_pre[1];
        data_byte_pre[2] <= data_byte_pre[2];
        data_byte_pre[3] <= data_byte_pre[3];
        data_byte_pre[4] <= data_byte_pre[4];
        data_byte_pre[5] <= data_byte_pre[5];
        data_byte_pre[6] <= data_byte_pre[6];
        data_byte_pre[7] <= data_byte_pre[7];
        STOP_BIT <= STOP_BIT;
      end
		endcase
	end

	always@(posedge clk or posedge reset)
	if(reset)
		data_byte <= 8'd0;
	else if(bps_cnt == 8'd159)begin
		data_byte[0] <= data_byte_pre[0][2];
		data_byte[1] <= data_byte_pre[1][2];
		data_byte[2] <= data_byte_pre[2][2];
		data_byte[3] <= data_byte_pre[3][2];
		data_byte[4] <= data_byte_pre[4][2];
		data_byte[5] <= data_byte_pre[5][2];
		data_byte[6] <= data_byte_pre[6][2];
		data_byte[7] <= data_byte_pre[7][2];
	end	
	
	always@(posedge clk or posedge reset)
	if(reset)
		uart_state <= 1'b0;
	else if(uart_rx_nedge)
		uart_state <= 1'b1;
	else if(rx_done || (bps_cnt == 8'd12 && (START_BIT > 2)) || (bps_cnt == 8'd155 && (STOP_BIT < 3)))
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;		

endmodule
bash 复制代码
//
// Company: 武汉芯路恒科技有限公司
// Engineer: 小梅哥团队
// Web: www.corecourse.cn
// 
// Create Date: 2020/07/20 00:00:00
// Design Name: uart_tx
// Module Name: uart_byte_tx
// Project Name: uart_tx
// Description: 串口发送模块
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module uart_byte_tx(
	clk,
	reset_n,
  
	data_byte,
	send_en,   
	baud_set,  
	
	uart_tx,  
	tx_done,   
	uart_state 
);

	input clk ;    //模块全局时钟输入,50M
	input reset_n;    //复位信号输入,低有效
	input [7:0]data_byte;  //待传输8bit数据
	input send_en;    //发送使能
	input [2:0]baud_set;   //波特率设置
	
	output reg uart_tx;    //串口输出信号
	output reg tx_done;    //1byte数据发送完成标志
	output reg uart_state; //发送数据状态
	
	wire reset=~reset_n;
	localparam START_BIT = 1'b0;
	localparam STOP_BIT = 1'b1; 
	
	reg bps_clk;	     //波特率时钟	
	reg [15:0]div_cnt;      //分频计数器	
	reg [15:0]bps_DR;       //分频计数最大值	
	reg [3:0]bps_cnt;      //波特率时钟计数器	
	reg [7:0]data_byte_reg;//data_byte寄存后数据
	
	always@(posedge clk or posedge reset)
	if(reset)
		uart_state <= 1'b0;
	else if(send_en)
		uart_state <= 1'b1;
	else if(bps_cnt == 4'd11)
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;
	
	always@(posedge clk or posedge reset)
	if(reset)
		data_byte_reg <= 8'd0;
	else if(send_en)
		data_byte_reg <= data_byte;
	else
		data_byte_reg <= data_byte_reg;
	
	always@(posedge clk or posedge reset)
	if(reset)
		bps_DR <= 16'd5207;
	else begin
		case(baud_set)
			0:bps_DR <= 16'd5207;
			1:bps_DR <= 16'd2603;
			2:bps_DR <= 16'd1301;
			3:bps_DR <= 16'd867;
			4:bps_DR <= 16'd433;
			default:bps_DR <= 16'd5207;			
		endcase
	end	
	
	//counter
	always@(posedge clk or posedge reset)
	if(reset)
		div_cnt <= 16'd0;
	else if(uart_state)begin
		if(div_cnt == bps_DR)
			div_cnt <= 16'd0;
		else
			div_cnt <= div_cnt + 1'b1;
	end
	else
		div_cnt <= 16'd0;
	
	// bps_clk gen
	always@(posedge clk or posedge reset)
	if(reset)
		bps_clk <= 1'b0;
	else if(div_cnt == 16'd1)
		bps_clk <= 1'b1;
	else
		bps_clk <= 1'b0;
	
	//bps counter
	always@(posedge clk or posedge reset)
	if(reset)	
		bps_cnt <= 4'd0;
	else if(bps_cnt == 4'd11)
		bps_cnt <= 4'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;
		
	always@(posedge clk or posedge reset)
	if(reset)
		tx_done <= 1'b0;
	else if(bps_cnt == 4'd11)
		tx_done <= 1'b1;
	else
		tx_done <= 1'b0;
		
	always@(posedge clk or posedge reset)
	if(reset)
		uart_tx <= 1'b1;
	else begin
		case(bps_cnt)
			0:uart_tx <= 1'b1;
			1:uart_tx <= START_BIT;
			2:uart_tx <= data_byte_reg[0];
			3:uart_tx <= data_byte_reg[1];
			4:uart_tx <= data_byte_reg[2];
			5:uart_tx <= data_byte_reg[3];
			6:uart_tx <= data_byte_reg[4];
			7:uart_tx <= data_byte_reg[5];
			8:uart_tx <= data_byte_reg[6];
			9:uart_tx <= data_byte_reg[7];
			10:uart_tx <= STOP_BIT;
			default:uart_tx <= 1'b1;
		endcase
	end	

endmodule
bash 复制代码
module top(
		input					clk				,
		input					reset_n			,
		input key_in,
		input					hc05_rx			,
		input					uart_rx			,
		output				hc05_tx			,
		output				uart_tx			
);

wire [7:0]data;
wire  [7:0]rx_data;

reg send_en; 
wire key_flag;
wire key_state;


key_filter key_filter(
	.clk(clk),
	.reset_n(reset_n),

	.key_in(key_in),
	.key_flag(key_flag),
	.key_state(key_state)
);


always @ (posedge clk or negedge reset_n)
if (!reset_n)
	send_en <= 0;
else if (key_flag && (!key_state))
	send_en <= ~send_en;
else 
	send_en <= 0;	


uart_byte_tx tx_inst_hc05(
	.clk(clk),
	.reset_n(reset_n),
  
	.data_byte(data),
	.send_en(send_en),   
	.baud_set(0),  
	
	.uart_tx(hc05_tx),  
	.tx_done(),   
	.uart_state ()
);

uart_byte_tx tx_inst_uart(
	.clk(clk),
	.reset_n(reset_n),
  
	.data_byte(rx_data),
	.send_en(send_en),   
	.baud_set(0),  
	
	.uart_tx(uart_tx),  
	.tx_done(),   
	.uart_state ()
);

uart_byte_rx  rx_inst_hc05(
	.clk(clk),
	.reset_n(reset_n),

	.baud_set(0),
	.uart_rx(hc05_rx),

	.data_byte(rx_data),
	.rx_done()
);

uart_byte_rx  rx_inst_uart(
	.clk(clk),
	.reset_n(reset_n),

	.baud_set(0),
	.uart_rx(uart_rx),

	.data_byte(data),
	.rx_done()
);


endmodule 

实验现象

通过蓝牙助手发送了一个16进制的数据66.

同时通过串口助手发送了一个16进制的数据55。接着按下按键S0。

可以看到串口接收到蓝牙助手发过来的数据,蓝牙助手也就接收到串口发过来的数据

相关推荐
一条九漏鱼2 小时前
寄存器 reg
fpga开发
技术小白爱FPGA8 小时前
xilinx FPGA 平台实现数字信号 -- 低通滤波
fpga开发
Jack153027682799 小时前
高性能、低成本立体声音频模数转换器—— GC1808,支持掉电和时钟检测低功耗模式
单片机·嵌入式硬件·fpga开发·制造·蓝牙·家庭影院·麦克风阵列处理器
博览鸿蒙15 小时前
FPGA工程师成长四阶段
fpga开发
北城笑笑1 天前
FPGA 21 ,深入理解 Verilog 中的基数,以及二进制数与十进制数之间的关系( Verilog中的基数 )
fpga开发·fpga
Terasic友晶科技2 天前
第20篇 基于ARM A9处理器用汇编语言实现中断<二>
fpga开发·汇编语言·中断·de1-soc开发板
ThreeYear_s2 天前
OFDM接收机学习-第二章 符号同步模块FPGA的实现
学习·fpga开发
FPGA的花路3 天前
基于FPGA的多功能数字钟设计
fpga开发·多功能时钟
移知3 天前
备战春招—FPGA 2024年的面试题库
fpga开发·面试·职场和发展