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]; endmodule2、輸入模塊:
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)beginif (rx==0&&r_start==1) begincnt_clk<=cnt_clk+1;if (cnt_clk==2604&&rx==0) beginr_start<=0;cnt_clk<=0;cnt_message<=0;message_mid<=0;endend //判斷是否為開始位,是時開始計算clk,數2604下(0.5bit)即在開始位中間,開始讀數else if (r_start==0) begincnt_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;endif (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;endendend //開始讀數,每5208個clk讀一次else beginr_start<=1;over<=0;endendendmodule3、輸出模塊:
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) beginif (run==1&&t_start==1) begint_start<=0;cnt_clk<=0;endelse if (run==0&&t_start==0&&cnt_message==0) begin //在run的下降沿開始輸出tx<=0;cnt_clk<=cnt_clk+1;if (cnt_clk==5208) begintx<=message[cnt_message];cnt_clk<=0;cnt_message<=1;t_start<=0;endendelse if (cnt_message>=1) begincnt_clk<=cnt_clk+1;if (cnt_clk==5208) begincnt_clk<=0;if (cnt_message==8) begintx<=1;t_start<=1;cnt_message<=0;endelse begintx<=message[cnt_message];cnt_message<=cnt_message+1;endendendelse begintx=1;endend endmodule4、測試模塊
`timescale 1ps/1ps module testbench (output reg clk,output reg tx,input rx,input [1:0] led );reg [23:0]i;initialbeginclk=0;for(i=0;i<668900;i=i+1)#10 clk=~clk;endinitial begintx=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; #104200tx=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; #104200tx=1;endbluetooth blue1(.sys_clk(clk),.tx(rx),.rx(tx),.led(led)); endmodule5、仿真效果
一個小Tip,Add Waves之后課以通過這一排按鈕重新加載波形:
總結
以上是生活随笔為你收集整理的FPGA的UART信息回显的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: qrcode的使用方法
- 下一篇: 报错(SQLite 3.8.3 or l