FPGA自定义UART传输(包含:matlab数据拆分)
生活随笔
收集整理的這篇文章主要介紹了
FPGA自定义UART传输(包含:matlab数据拆分)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
引言:本程序是在工程實踐中寫的模塊,經驗證,可靠。由于大多書本上講的都是僅僅傳輸1個數據,然后根據這個數據亮燈。這種在工程中幾乎用不上工程實際中,往往我們需要根據地址不同,傳給不同的寄存器,從而控制比如脈沖寬度,長度,延時,個數等功能。
由于我們需要在testbench中算出每一幀的檢驗和,所以我們用了matlab來進行數據拆分,從而計算校驗和。如果手工算也可以,但幀數過多后,相當麻煩,而且易錯。
此處,先把matlab代碼上傳
#matlab數據拆分代碼(獲得檢驗值)
clc; clear; add='18' ;%地址,16進制 data0=16;%輸入十進制的16bit數據add_dec=uint8(hex2dec(add));data1=uint16(data0);%輸入16bit data1_bit=dec2bin(data1); %輸入數據二進制格式 data2unit8=uint8(zeros([1 2]));%存儲2個8位數據的數組 data2unit8(1)=bitand(data1,255);%低8位 data2unit8(2)=bitand(bitshift(data1,-8),255);%高8位 data_low8bit=dec2hex(data2unit8(1));%低8位的數據16進制 data_high8bit=dec2hex(data2unit8(2));%高8位的數據16進制數據 output1=bitxor(add_dec,data2unit8(1)); check_sum=bitxor(output1,data2unit8(2));%得到校驗和 check_sum_hex=dec2hex(check_sum);%得到校驗和的16進制形式#UART代碼
接收頂層模塊
`timescale 1ns / 1psmodule uart_rx_core #(parameter BAUD_RATE = 115_200, // Baud rateparameter CLOCK_RATE = 50_000_000 // Clock rate)(input clk,input rx_en, // 接收使能input rx_pin, // 數據輸入管腳output [ 7:0] addr, // 接收的32bit數據output [15:0] data, // 接收的32bit數據output valid // 一次數據協議解碼成功);wire [ 7:0] rx_data; // 接收的8 bit數據wire rx_done; // 數據接收完畢,產生一個高脈沖uart_rx_module #(.BAUD_RATE ( BAUD_RATE ), // Baud rate.CLOCK_RATE ( CLOCK_RATE ) // Clock rate) Uuart_rx (.clk( clk ),.rx_en( rx_en ), // 接收使能.rx_pin( rx_pin ), // 數據輸入管腳.rx_data( rx_data ), // 每次接收的8 bit數據.rx_done( rx_done ) // 數據接收完畢,產生一個高脈沖);uart_decode_module Uuart_decode (.clk( clk ),.rx_data( rx_data ), // 接收的8 bit數據.rx_done( rx_done ), // 數據接收完畢,產生一個高脈沖.addr( addr ), // 地址碼.data( data ), // 數據組.valid( valid ) // 一次數據協議解碼成功);endmodule`timescale 1ns / 1psmodule uart_rx_module #(parameter BAUD_RATE = 115_200, // Baud rateparameter CLOCK_RATE = 50_000_000 // Clock rate)(input clk,input rx_en, // 接收使能input rx_pin, // 數據輸入管腳output [ 7:0] rx_data, // 接收的8 bit數據output rx_done // 數據接收完畢,產生一個高脈沖);/* 產生波特率采樣時鐘 --------------------------------------------------- */wire baud_clk; // 波特率采樣時鐘wire en_baud_gene; // 使能波特率采樣時鐘baud_gene_module #(.BAUD_RATE ( BAUD_RATE ), // Baud rate.CLOCK_RATE ( CLOCK_RATE ) // Clock rate) Urx_baud_gene (.clk( clk ),.en( en_baud_gene ), // 計數使能,高電平時波特率發生器才工作.baud_clk( baud_clk ) // 波特率采樣時鐘輸出);/* ---------------------------------------------------------------------- *//* rx_pin下降沿檢測 ----------------------------------------------------- */reg [1:0] rx_pin_r = 1'b0;always @ (posedge clk)rx_pin_r <= {rx_pin_r[0:0], rx_pin};wire rx_pin_fall = (!rx_pin_r[0]) & rx_pin_r[1];// 下降沿檢測wire rx_start = rx_pin_fall;/* ---------------------------------------------------------------------- *//* 串口接收控制 --------------------------------------------------------- */reg en_baud_r = 1'b0;//Li:接收數據使能區域reg [ 7:0] rx_data_r = 8'b0;reg rx_done_r = 1'b0;reg [ 3:0] rx_ii = 4'b0;/* 接收數據格式:1位起始位,8位數據位,1位停止位,其中起始位為0;無校驗位;停止位為1 */always @ (posedge clk)if (rx_en) // 當rx_en被拉高時開始工作case (rx_ii) // 每個baud_clk接收一位數據4'd0 : // 開始信號,有數據發送過來,準備接收------//Li:啟動if (rx_start) begin en_baud_r <= 1'b1; rx_done_r <= 1'b0; rx_ii <= rx_ii + 1'b1; //Li:剛開始的下降沿啟動end4'd1 : // 接收起始位if (baud_clk) begin en_baud_r <= 1'b1; rx_done_r <= 1'b0; rx_ii <= rx_ii + 1'b1; end4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8, 4'd9 :// 將rx_pin的值保存到rx_data_r中,從最低位到最高位; LSB first defaultif (baud_clk) begin en_baud_r <= 1'b1; rx_data_r[rx_ii-2] <= rx_pin; rx_done_r <= 1'b0; rx_ii <= rx_ii + 1'b1; end4'd10 : // 接收停止位,無校驗位,如果沒有什么特別需求,可直接忽略if (baud_clk) begin en_baud_r <= 1'b0; rx_done_r <= 1'b1; rx_ii <= rx_ii + 1'b1; end4'd11 : // 產生一個時鐘周期的高脈沖rx_done_r,表示數據接收完畢begin en_baud_r <= 1'b0; rx_done_r <= 1'b0; rx_ii <= 4'd0; enddefault: ;endcaseelse beginen_baud_r <= 1'b0; rx_data_r <= 8'd0; rx_done_r <= 1'b0; rx_ii <= 4'd0; endassign en_baud_gene = en_baud_r;/* ---------------------------------------------------------------------- */assign rx_data = rx_data_r;assign rx_done = rx_done_r;endmodule
`timescale 1ns / 1ps /*-------------------------------------------------------------------------------------* 串口波特率產生*----------------------------------------------------------------------------------*/ module baud_gene_module #(parameter BAUD_RATE = 115_200, // Baud rateparameter CLOCK_RATE = 50_000_000 // Clock rate)(input clk,input en, // 計數使能,高電平時波特率發生器才工作output baud_clk // 波特率采樣時鐘輸出);/* 以下函數供Verilog使用,Verilog_2005和SystemVerilog有"$clog2"函數 */function integer clog2(input integer value);beginvalue = value-1;for (clog2=0; value>0; clog2=clog2+1)value = value>>1;endendfunction// 分頻計數DIVIDER = 時鐘CLOCK_RATE / 波特率BAUD_RATE,并取整// (所以整除之前先加波特率BAUD_RATE的一半)localparam DIVIDER = (CLOCK_RATE+BAUD_RATE/2) / BAUD_RATE;// 計數器的值localparam BAUD_VALUE = DIVIDER - 1;localparam BAUD_HALF = BAUD_VALUE/2 - 1;// 計數器位寬計算localparam CNT_WID = clog2(DIVIDER);reg [CNT_WID-1:0] baud_cnt = BAUD_VALUE;always @ (posedge clk)if (baud_cnt==BAUD_VALUE)baud_cnt <= {CNT_WID{1'b0}};else if (en)baud_cnt <= baud_cnt + 1'b1;elsebaud_cnt <= {CNT_WID{1'b0}};assign baud_clk = (baud_cnt==BAUD_HALF) ? 1'b1 : 1'b0;endmodule
`timescale 1ns / 1psmodule uart_decode_module(input clk,input [ 7:0] rx_data, // 接收的8 bit數據input rx_done, // 數據接收完畢,產生一個高脈沖output [ 7:0] addr, // 地址碼output [15:0] data, // 數據組output valid // 一次數據協議解碼成功);/* 有限狀態機,三過程塊建模風格 ********************************************/// 狀態編碼localparam FRAME_HEAD = 4'd0, // 幀頭(1byte)CMD_ADDR = 4'd1, // 地址(1byte)CMD_DATA0 = 4'd2, // 數據(2byte)CMD_DATA1 = 4'd3,CHECK_SUM = 4'd4, // 校驗(1byte,異或和)FRAME_TAIL = 4'd5, // 幀尾(1byte)DONE = 4'd6; // 本幀接收結束reg [ 3:0] now_state = FRAME_HEAD, next_state = FRAME_HEAD;reg [ 7:0] rx_data_r = 8'd0;reg rx_done_r = 1'b0;//reg data_number='d0;// 1.實現狀態轉換always @ (posedge clk) begin//: trans_staterx_data_r <= rx_data;rx_done_r <= rx_done;if (rx_done_r || now_state==DONE)now_state <= next_state;end//: trans_statereg [ 7:0] check_sum;// 2.產生下一個狀態always @ (*) begin//: set_next_statecheck_sum = addr ^ data[ 7: 0]^data[15: 8];// next_state = now_state; // 下面分支的缺省狀態case (now_state)FRAME_HEAD : if(rx_data_r == 8'hF1) next_state = CMD_ADDR;else next_state = FRAME_HEAD;CMD_ADDR : next_state = CMD_DATA0;CMD_DATA0 : next_state = CMD_DATA1;CMD_DATA1 : next_state = CHECK_SUM;CHECK_SUM : if(rx_data_r == check_sum) next_state = FRAME_TAIL;else next_state = FRAME_HEAD;FRAME_TAIL : if(rx_data_r == 8'hF2) next_state = DONE;else next_state = FRAME_HEAD;DONE : next_state = FRAME_HEAD;default : next_state = FRAME_HEAD;endcaseend//: set_next_state// 3.產生狀態機的輸出值reg [ 7:0] addr_r = 8'd0;reg [32:0] data_r = 32'd0;reg valid_r = 1'b0;reg valid_r_r = 1'b0;always @ (posedge clk) begincase (now_state)FRAME_HEAD : valid_r <= 1'b0;CMD_ADDR : begin valid_r <= 1'b0; addr_r <= rx_data_r; endCMD_DATA0 : begin valid_r <= 1'b0; data_r[7:0] <= rx_data_r; endCMD_DATA1 : begin valid_r <= 1'b0; data_r[15:8] <= rx_data_r; endCHECK_SUM : valid_r <= 1'b0;FRAME_TAIL : valid_r <= 1'b0;DONE : valid_r <= 1'b1;// data_number<=data_number+1; default : ;endcaseend//: set_out_stateassign addr = addr_r;assign data = data_r;always @ (posedge clk)beginvalid_r_r<=valid_r;endassign valid = valid_r_r;endmodule
#心得體會:
matlab中16進制是沒法直接表示的,我嘗試a=0x7 這樣賦值是不行的。16進制必須是字符形式a=‘0x7’,如果要參與運算,請轉換為10進制來參與運算。
注意即使check_sum沒錯,也許測試文件里幀頭這些錯誤也可能。
最終效果:
自定義uart,一共24幀。控制24個變量參數。
總結
以上是生活随笔為你收集整理的FPGA自定义UART传输(包含:matlab数据拆分)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: verilog基础--sign表达式
- 下一篇: verilog一些小知识点注意事项集合