歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

基於FPGA的UART設計

概念 UART即數據按一定頻率串行輸出的通信方式,可分為同步串口通信和異步串口通信兩種。在 UA RT 中,數據位是以字符為傳送單位,數據
的前、後要有起始位、停止位,另外可以在停止位的前面加上一個比特(bit)的校驗位。其幀格式如下圖所示:

基於FPGA的UART設計 - 毛~ - 我的博客

其基 本 特 點是:
① 在 信 號線上共有兩種狀態,可分別用邏輯1和邏輯。來區分。在發送器空閒時,數據線應該保持在邏輯高電平狀態。
② 起 始 位:該位是一個邏輯0,總是加在每一幀的頭部,提示接受器數據傳輸即將開始,在接收數據位過程中又被分離出去。
③ 數 據 位:在起始位之後就是數據位,一般為8位一個字節的數據,低位在前,高位在後。如字母C在ASCII表中是十進制67,二進制01000011,那麼傳輸的將是110000100
④ 校 驗 位:該位一般用來判斷接收的數據位有無錯誤,常用的校驗方法是奇偶校驗法。
⑤ 停 止位 :停止位總在每一幀的末尾,為邏輯1,用於標志一個字符傳送的結束。
⑥ 幀 :從起始位到停止位為一幀。

在FPGA設計中,其分為波特率產生模塊、發送器模塊、接收器模塊三個部分。

原理設計:發送器和接收器按設定好的波特率分別進行發送和接收串行數據。具體設計如下:

1. 波特率發生器

    波特率發送器其實就是一個系統時鐘分頻器。首先,要根據串口波特率和系統時鐘的要求,確定分頻系數,然後根據這個分頻系數確定時鐘計數的位寬(這一點很重要,因為我在設計中,位寬取小了,導致無法產生正確的波特率時鐘)。下面是我設計的波特率發生器的代碼:主要利用50M的系統時鐘,產生8*9600 bits/s 的波特率。注:基於消除信號抖動的考慮,一般波特率發送器產生的頻率是所需波特率的8或者16倍,采用中間值采樣方法。

module REC_Tick(clk,
                BTick
                );
/***************port define************/              
input       clk;
output       BTick;
/****assign system and object baudRrate frequence******/
parameter sys_freq=50_000_000,
           obj_freq=76800;
 wire   [15:0] step=sys_freq/obj_freq -1;
 reg [15:0]  count;
always @ (posedge clk)
if (count!=step)count<=count+1;//注:這於平時所做的分頻有區別,因為這是非50%占空比
else count<=0;
wire BTick=(count==step);//這樣設計對後面的數據采集減少了一個計數器操作
endmodule

2 發送器的設計

發送器的主要功能是:在波特率時鐘周期裡,確定該時鐘周期內的應該發送數據的邏輯值。它是根據狀態,決定發送的數據的大小。

設計中考慮的問題:主要的設計在於狀態機的轉換過程,要確定轉換到下一狀態的觸發條件。

給出的實例,按照波特率時鐘轉換狀態,實際中從IDLE到START的轉換,應該是有中斷觸發的,即有發送數據的需求時,產生中斷,使狀態機有idle轉換到start之後按照波特率時鐘依次發送8bit,奇偶校驗,停止,idle,到此,數據發完成,等待下一次的中斷信號。本例中簡化了實際,沒有用中斷,實現的功能是:在波特率時鐘下,每個12個波特率時鐘發送8bits數據A0A0.

/***********************************8

串口發送模塊:

主要是利用波特率節拍,發送數據

***********************************/

module uart_send(clk,BTick,TxD);

/*port define*********************/

input clk,BTick;//本模塊使用的BTICK為波特率產生模塊時鐘再8分頻後得到

output TxD;

/****state definf***************/

parameter idle  = 4'b0000,

          start = 4'b0001,

          bit0  = 4'b1000,

          bit1  = 4'b1001,

          bit2  = 4'b1010,

          bit3  = 4'b1011,

          bit4  = 4'b1100,

          bit5  = 4'b1101,

          bit6  = 4'b1110,

          bit7  = 4'b1111,

          stop1 = 4'b0010,

          stop2 = 4'b0011;

reg  [7:0]  snd_data;

initial snd_data<=8'b10101010;

/*********timing sequence of state machine***/

reg [3:0]  state;

initial state<=idle;

always @(posedge clk)

case(state)

idle: if (BTick) state<=start;

start:if (BTick) state<=bit0;

bit0: if (BTick) state<=bit1;

bit1: if (BTick) state<=bit2;

bit2: if (BTick) state<=bit3;

bit3: if (BTick) state<=bit4;

bit4: if (BTick) state<=bit5;

bit5: if (BTick) state<=bit6;

bit6: if (BTick) state<=bit7;

bit7: if (BTick) state<=stop1;

stop1:if (BTick) state<=stop2;

stop2:if (BTick) state<=idle;

default :state<=idle;

endcase

/***define the logical of bit relating to current state*/

reg     mux_bit;

initial mux_bit <=1; /**attention!!!!It is absolutly significant**/

always @(state[3:0])

case(state[3:0])

4'b0001:mux_bit<=0;

4'b1000:mux_bit<=snd_data[0];

4'b1001:mux_bit<=snd_data[1];

4'b1010:mux_bit<=snd_data[2];

4'b1011:mux_bit<=snd_data[3];

4'b1100:mux_bit<=snd_data[4];

4'b1101:mux_bit<=snd_data[5];

4'b1110:mux_bit<=snd_data[6];

4'b1111:mux_bit<=snd_data[7];

default:mux_bit<=1;

endcase

wire TxD=mux_bit;

endmodule

 

3接收器的設計

接收器的功能:通過不斷采樣RxD線上的數據,將數據為正確的讀取出來。它是根據采樣的數據的大小,確定狀態。和發送器的過程剛好相反。

設計中考慮的幾個問題:

1)如何判斷開始位的到來,及如何根據當前的狀態和采樣的數據,判斷開始位的發生。

2)如何采樣數據位,怎樣做到正確的讀書數據位的邏輯值.

3)開始狀態和數據接收狀態,停止狀態的轉換觸發問題

一般的規則是在一個bit時間內對RxD進行8或16次的采樣,如果連續4次采樣的結果都是1,則認為該bit

為1,同理,如果連續4次采樣的結果都是0,則認為該bit為0.

/*************************************************

接收模塊控制器,主要有3個難點:

1)如何判斷開始位?

2)如何判斷下一位?

3)如何判斷當前為的值?

狀態機的設計原理:

開始是IDLE,當檢測到RxD線為0是,轉到START,之後,數據位,奇偶校驗位,停止位之間,依據下一位標志轉換。

那麼如何檢測RxD的開始為0呢?有技巧,即如果連續4測采樣RxD數據線,都是0,則說明當前的位為0,若連續4次為1,則當前位為1。

判斷下一位:連續8次波特率時鐘,認為是一個bit位的持續時間。

**********************************************************/

module uart_rec(clk,

                BaudTick,

                RxD,

                RxD_data

                );

/**port define***************/

input           clk,BaudTick,RxD;//BaudTick為波特率產生模塊時鐘

output [7:0]    RxD_data;

/****state define**********/

parameter idle  = 4'b0000,

          start = 4'b0001,

          bit0  = 4'b1000,

          bit1  = 4'b1001,

          bit2  = 4'b1010,

          bit3  = 4'b1011,

          bit4  = 4'b1100,

          bit5  = 4'b1101,

          bit6  = 4'b1110,

          bit7  = 4'b1111,

          stop  = 4'b0010;

/****sample process***********************/

reg            RxD_bit,current_bit;

reg   [7:0]    RxD_data;        

reg   [1:0]    count;

initial RxD_bit=1;//attention!!!!

initial current_bit=1;

initial count=2'b00;

always @(posedge clk)

if (BaudTick==1)

RxD_bit<=RxD;

always @ (posedge clk)

if  (BaudTick==1)begin

 if( RxD_bit&& count!=2'b11) count = count + 2'h1;

 else

 if(~RxD_bit && count!=2'b00) count = count - 2'h1;

 if(count==2'b00) current_bit = 1'b0;

 else

 if(count==2'b11) current_bit = 1'b1;

 end

/***judge a bit*****************************************/

reg [3:0]  Tick_num;

always @ (posedge clk)

if (state==idle)

Tick_num<=4'b0000;

if(BaudTick==1)

         Tick_num <= Tick_num[2:0]+4'b0001;

wire next_bit =Tick_num[3];

/********state reverse*********************************/

reg [3:0] state;

always @(posedge clk)

if (BaudTick)

case(state)

idle:if(~current_bit) state<=start;

start:if(next_bit)state<=bit0;

bit0:if(next_bit)state<=bit1;

bit1:if(next_bit)state<=bit2;

bit2:if(next_bit)state<=bit3;

bit3:if(next_bit)state<=bit4;

bit4:if(next_bit)state<=bit5;

bit5:if(next_bit)state<=bit6;

bit6:if(next_bit)state<=bit7;

bit7:if(next_bit)state<=stop;

stop:if(next_bit)state<=idle;

default:state<=idle;

endcase

/*****output data received from RxD line**************/

always @(posedge clk)

if (next_bit && state[3] && BaudTick)

RxD_data<={current_bit,RxD_data[7:1]};

//else if (state==start)

//RxD_data<=0;

endmodule

-----貌似上發送器時鐘有些問題,待修改

Copyright © Linux教程網 All Rights Reserved