目录
1.蓝牙模块介绍
2.UART介绍
3.Verilog代码:
3.1Uart_RX模块:
3.2 分频模块:
3.3 Uart驱动模块
3.4 Uart控制模块
4. 总览
1.蓝牙模块介绍
我使用的是JDY-31蓝牙模块,在连线中,要注意RX-TX,TX-RX。
即FPGA约束的TX对应蓝牙模块的RX,约束的RX对应蓝牙模块的TX。
2.UART介绍
蓝牙模块使用UART串口通信协议,具体介绍如下:
UART(通用异步收发器)是一种常见的串口通信协议。
UART协议的主要特点如下:
-
异步通信:UART使用异步通信方式,不需要时钟同步信号。数据的传输以字符为单位,每个字符由起始位、数据位、校验位(可选)和停止位组成。
-
数据格式:UART可以支持不同的数据格式。常见的数据位数包括5位、6位、7位和8位,常见的停止位数为1位或2位,常见的校验位有奇校验、偶校验和无校验。
-
波特率:波特率是指每秒钟传输的比特数。UART支持不同的波特率,常见的波特率有9600、115200等。发送和接收的设备必须以相同的波特率进行通信。
-
帧同步:UART通过起始位和停止位来确定数据帧的边界。起始位用于标识数据传输的开始,停止位用于标识数据传输的结束。
-
单工或半双工通信:UART通信可以是单向的(只有发送或只有接收)或半双工的(同时具有发送和接收功能)。
232通信时序图如下:
3.Verilog代码:
具体Verilog的实现代码如下:
3.1顶层模块:
module rs232(
input wire clk,
input wire rst_n,
input wire rx,
output wire tx
);
wire rx_flag;
wire [7:0] rx_data;
wire [7:0] tx_data;
Uart_TX uart_tx(
.clk(clk),
.rst_n(rst_n),
.data(rx_data),
.start_flag(rx_flag),
.tx(tx)
);
Uart_RX uart_rx(
.clk(clk),
.rst_n(rst_n),
.rx(rx),
.rx_data(rx_data),
.rx_flag(rx_flag)
);
endmodule
这段代码是RS232顶层模块。
其中包含一个发送器(Uart_TX
)和一个接收器(Uart_RX
)。实现了上位机发送信息后,FPGA将上位机的信息的返回。
3.2 Uart_TX模块:
`timescale 1ns / 1ps
module Uart_TX(
input wire clk,
input wire rst_n,
input wire [7:0] data,
input wire start_flag,
output wire tx
);
/******************内部变量**********************/
parameter N=13021; //N=系统时钟频率/波特率;f=125Mhz,baud=9600。表示N个系统时钟一个数据位
reg work_en;//工作使能
reg [31:0] baud_cnt;//波特计数器
reg bit_flag;//比特标志
reg [3:0] bit_cnt;//数据位计数,0-8
reg tx_reg;
assign tx=tx_reg;
/******************工作使能**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
work_en<=0;
else if(start_flag==1)//开始迟滞一个clk,工作使能
work_en<=1;
else if((bit_cnt==4'd9)&&(bit_flag==1))
work_en<=0;
else
work_en<=work_en;
end
/*******************波特计数器**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
baud_cnt<=0;
else if((baud_cnt==N-1)||(work_en==0))
baud_cnt<=0;
else if(work_en==1)
baud_cnt<=baud_cnt+1;
end
/*******************比特标志**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
bit_flag<=0;
else if(baud_cnt==1)
bit_flag<=1;
else
bit_flag<=0;
end
/*******************数据位计数**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
bit_cnt<=0;
else if((bit_cnt==4'd9)&&(bit_flag==1))
bit_cnt<=0;
else if(bit_flag==1)
bit_cnt<=bit_cnt+1;
end
/*******************数据输出**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
tx_reg<=1;
else if(bit_flag==1)
case(bit_cnt)
0:tx_reg<=0;
1:tx_reg<=data[0];
2:tx_reg<=data[1];
3:tx_reg<=data[2];
4:tx_reg<=data[3];
5:tx_reg<=data[4];
6:tx_reg<=data[5];
7:tx_reg<=data[6];
8:tx_reg<=data[7];
9:tx_reg<=1;
default:tx_reg<=1;
endcase
end
endmodule
首先根据系统时钟和波特率计算出N(我的FPGA是125Mhz,需要波特率9600)。
之后根据RS232的时序图写出各个模块,即可实现串口发送。
3.3 Uart_RX模块
`timescale 1ns / 1ps
module Uart_RX(
input wire clk,
input wire rst_n,
input wire rx,
output reg [7:0] rx_data,
output reg rx_flag
);
/******************内部变量**********************/
parameter N=13021; //N=系统时钟频率/波特率;f=125Mhz,baud=9600。表示N个系统时钟一个数据位
reg rx_reg1;//打排数据
reg rx_reg2;//打排数据
reg rx_reg3;//打排数据
reg start_flag;//起始标志
reg work_en;//工作使能
reg [31:0] baud_cnt;//波特计数器
reg bit_flag;//比特标志
reg [3:0] bit_cnt;//数据位计数,0-8
reg [7:0] rx_data_reg;//数据寄存器
reg rx_flag_reg;//数据标识符寄存器
/*******************数据打拍**********************/
//数据打拍,避免亚稳态
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rx_reg1<=1;
else
rx_reg1<=rx;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rx_reg2<=1;
else
rx_reg2<=rx_reg1;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n==0)
rx_reg3<=1;
else
rx_reg3<=rx_reg2;
end
/*******************起始标志**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
start_flag<=0;
else if((rx_reg3==1)&&(rx_reg2==0)&&(work_en==0))//迟滞reg3一个clk
start_flag<=1;
else
start_flag<=0;
end
/*******************工作使能**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
work_en<=0;
else if(start_flag==1)//开始迟滞一个clk,工作使能
work_en<=1;
else if((bit_cnt==8)&&(bit_flag==1))
work_en<=0;
else
work_en<=work_en;
end
/*******************波特计数器**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
baud_cnt<=0;
else if((baud_cnt==N-1)||(work_en==0))
baud_cnt<=0;
else
baud_cnt<=baud_cnt+1;
end
/*******************比特标志**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
bit_flag<=0;
else if(baud_cnt==(N/2-1))
bit_flag<=1;
else
bit_flag<=0;
end
/*******************数据位计数**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
bit_cnt<=0;
else if((bit_cnt==8)&&(bit_flag==1))
bit_cnt<=0;
else if(bit_flag==1)
bit_cnt<=bit_cnt+1;
end
/*******************数据寄存器**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rx_data_reg<=0;
else if((bit_cnt>=1)&&(bit_cnt<=8)&&(bit_flag==1))
rx_data_reg<={rx_reg3,rx_data_reg[7:1]};
end
/*******************数据标识符寄存器**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rx_flag_reg<=0;
else if((bit_cnt==8)&&(bit_flag==1))
rx_flag_reg<=1;
else
rx_flag_reg<=0;
end
/*******************数据输出**********************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rx_data<=0;
else if(rx_flag_reg==1)
rx_data<=rx_data_reg;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
rx_flag<=0;
else
rx_flag<=rx_flag_reg;
end
endmodule
依然是首先计算N,之后根据时序图实现。
4. 总览
效果如下:
具体结构如下:文章来源:https://www.toymoban.com/news/detail-752733.html
文章来源地址https://www.toymoban.com/news/detail-752733.html
到了这里,关于5—基于FPGA(ZYNQ-Z2)的多功能小车—软件设计—蓝牙串口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!