赞
踩
目录
我使用的是JDY-31蓝牙模块,在连线中,要注意RX-TX,TX-RX。
即FPGA约束的TX对应蓝牙模块的RX,约束的RX对应蓝牙模块的TX。
蓝牙模块使用UART串口通信协议,具体介绍如下:
UART(通用异步收发器)是一种常见的串口通信协议。
UART协议的主要特点如下:
异步通信:UART使用异步通信方式,不需要时钟同步信号。数据的传输以字符为单位,每个字符由起始位、数据位、校验位(可选)和停止位组成。
数据格式:UART可以支持不同的数据格式。常见的数据位数包括5位、6位、7位和8位,常见的停止位数为1位或2位,常见的校验位有奇校验、偶校验和无校验。
波特率:波特率是指每秒钟传输的比特数。UART支持不同的波特率,常见的波特率有9600、115200等。发送和接收的设备必须以相同的波特率进行通信。
帧同步:UART通过起始位和停止位来确定数据帧的边界。起始位用于标识数据传输的开始,停止位用于标识数据传输的结束。
单工或半双工通信:UART通信可以是单向的(只有发送或只有接收)或半双工的(同时具有发送和接收功能)。
232通信时序图如下:
具体Verilog的实现代码如下:
- 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将上位机的信息的返回。
- `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的时序图写出各个模块,即可实现串口发送。
- `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,之后根据时序图实现。
效果如下:
具体结构如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。