1.UART
UART是異步串行通信口的總稱。它所包含的RS232RS449RS423等等是對(duì)應(yīng)各種異步串行通信口的接口標(biāo)準(zhǔn)和總線標(biāo)準(zhǔn)。他們規(guī)定了通信口的電氣特性、傳輸速率、連接特性和機(jī)械特性等一系列內(nèi)容,實(shí)際上屬于通信網(wǎng)絡(luò)的底層概念,與通信協(xié)議沒有直接關(guān)系。
幾個(gè)相關(guān)名詞的解釋:
·波特率:每秒鐘傳送的bit的個(gè)數(shù)。
·起始位:先發(fā)出一個(gè)邏輯0的信號(hào),表示傳輸數(shù)據(jù)的開始。
·數(shù)據(jù)位:衡量通信中實(shí)際數(shù)據(jù)位的參數(shù),標(biāo)準(zhǔn)數(shù)據(jù)位可以是5、7、8位,從最低位開始傳輸。
·奇偶校驗(yàn)位:UART發(fā)送時(shí),檢查發(fā)送數(shù)據(jù)中“1”的個(gè)數(shù),自動(dòng)在奇偶校驗(yàn)位添加1/0,用于發(fā)送數(shù)據(jù)的校驗(yàn)。
·停止位:一個(gè)數(shù)據(jù)的結(jié)束標(biāo)志,可以為1位、1.5位、2位的高電平。
·空閑位:處于邏輯1狀態(tài),表示當(dāng)前線路上無數(shù)據(jù)傳輸。
·時(shí)序圖:
·發(fā)送數(shù)據(jù)過程:空閑狀態(tài),線路處于高電平,當(dāng)收到發(fā)送數(shù)據(jù)指令后,拉低電平一個(gè)數(shù)據(jù)位的時(shí)間,接著數(shù)據(jù)按從低位到高位依次發(fā)送,數(shù)據(jù)發(fā)送完畢,接著發(fā)送奇偶校驗(yàn)位和停止位(停止位為高電平),一幀數(shù)據(jù)發(fā)送結(jié)束。
·接收數(shù)據(jù)過程:空閑狀態(tài),線路處于高電平,當(dāng)檢測(cè)到線路的下降沿,說明線路有數(shù)據(jù)傳輸,按照約定的波特率從低位到高位接收數(shù)據(jù),數(shù)據(jù)接收完畢,接著接收并比較奇偶校驗(yàn)位是否正確,如果正確則通知接收端設(shè)備準(zhǔn)備接收數(shù)據(jù)或存入緩存。
由于UART是異步傳輸,沒有同步傳輸時(shí)鐘。為保證數(shù)據(jù)傳輸?shù)恼_性,每個(gè)數(shù)據(jù)有16個(gè)時(shí)鐘采樣,取中間的采樣值,以保證不會(huì)誤碼或滑碼。
·設(shè)計(jì)實(shí)例:
下面是一個(gè)UART的回環(huán)實(shí)例代碼設(shè)計(jì):
接收模塊uart_rx:
module uart_rx( input rxd, input clk, output receive_ack, output reg [7:0] data_i ); parameter IDLE = 0; parameter RECEIVE = 1; parameter RECEIVE_END = 2; reg [3:0] CS,NS; reg [4:0] count; reg [7:0] data_o_tmp; always@(posedge clk) CS <= NS; always@(*) begin NS <= CS; case(CS) IDLE: if(!rxd) NS = RECEIVE; RECEIVE: if(count == 7) NS = RECEIVE_END;else NS = NS; RECEIVE_END:NS = IDLE; default: NS = IDLE; endcase end always@(posedge clk) if(CS == RECEIVE) count <= count + 1; else if(CS == IDLE | CS == RECEIVE_END) count <= 0; always @(posedge clk) if(CS == RECEIVE)begin data_i[6:0] <= data_i[7:1]; data_i[7] <= rxd; end assign receive_ack = (CS == RECEIVE_END) ? 1 : 0; endmodule發(fā)送模塊uart_tx:
module uart_tx( input [7:0] data_o, input clk, input receive_ack, output reg txd ); parameter IDLE = 0; parameter SEND_START = 1; parameter SEND_DATA = 2; parameter SEND_END = 3; reg [3:0] CS,NS; reg [4:0] count; reg [7:0] data_o_tmp; always @ (posedge clk) CS <= NS; always @ (*) begin NS <= CS; case(CS) IDLE: begin if(receive_ack) NS = SEND_START; end SEND_START: begin NS = SEND_DATA; end SEND_DATA: begin if(count == 7) NS = SEND_END; end SEND_END: begin if(receive_ack) NS = SEND_START; end default: NS = IDLE; endcase end always @(posedge clk) if(CS == SEND_START) count <= count + 1; else if(CS == IDLE | CS == SEND_END) count <= 0; else count <= count; always @(posedge clk) if(CS == SEND_START) data_o_tmp <= data_o; else if(CS == SEND_DATA) data_o_tmp[6:0] <= data_o_tmp[7:1]; always @(posedge clk) if(CS == SEND_START) txd <= 0; else if(CS == SEND_DATA) txd <= data_o_tmp; else if(CS == SEND_END) txd <= 1; endmodulemodule uart_tx( input [7:0] data_o, input clk, input receive_ack, output reg txd ); parameter IDLE = 0; parameter SEND_START = 1; parameter SEND_DATA = 2; parameter SEND_END = 3; reg [3:0] CS,NS; reg [4:0] count; reg [7:0] data_o_tmp; always @ (posedge clk) CS <= NS; always @ (*) begin NS <= CS; case(CS) IDLE: begin if(receive_ack) NS = SEND_START; end SEND_START: begin NS = SEND_DATA; end SEND_DATA: begin if(count == 7) NS = SEND_END; end SEND_END: begin if(receive_ack) NS = SEND_START; end default: NS = IDLE; endcase end always @(posedge clk) if(CS == SEND_START) count <= count + 1; else if(CS == IDLE | CS == SEND_END) count <= 0; else count <= count; always @(posedge clk) if(CS == SEND_START) data_o_tmp <= data_o; else if(CS == SEND_DATA) data_o_tmp[6:0] <= data_o_tmp[7:1]; always @(posedge clk) if(CS == SEND_START) txd <= 0; else if(CS == SEND_DATA) txd <= data_o_tmp; else if(CS == SEND_END) txd <= 1; endmodule特定波特率產(chǎn)生模塊clk_div:
module clk_div( input clk, output reg clk_out ); parameter baud_rata = 9600;parameterdiv_num='d125_000_000/baud_rata;//分頻數(shù)等于時(shí)鐘頻率除以想要得到的波特率 reg [15:0] num; always @(posedge clk) begin if(num == div_num) begin num <= 0; clk_out <= 1; end else begin num <= num + 1; clk_out <= 0; end end endmodule
頂層文件uart_top:
module uart_top( input clk,inputrxd,outputtxd ); wire clk_9600; wire receive_ack; wire [7:0] data; uart_tx uart_tx ( .clk (clk_9600), .txd (txd), .data_o (data), .receive_ack(receive_ack) ); uart_rx uart_rx ( .clk (clk_9600), .rxd (rxd), .data_i (data), .receive_ack(receive_ack) ); clk_div clk_div ( .clk (clk), .clk_out (clk_9600) ); endmodule
2.PS/2 PS/2是一種雙向同步串行通信協(xié)議。接口是一種6針的連接口,但只有四個(gè)引腳是有意義的,分別是Clock(時(shí)鐘)、Data(數(shù)據(jù))、VCC和GND。其中時(shí)鐘和數(shù)據(jù)引腳是雙向的。PS/2常用于連接某些輸入設(shè)備,例如鼠標(biāo)、鍵盤等。通信的兩端通過時(shí)鐘來同步,通過數(shù)據(jù)引腳來交換數(shù)據(jù)。任何一方想要抑制另外一方的通信,只需要將時(shí)鐘引腳拉低即可。 如果是PC和PS/2鍵盤之間通信,PC必須做主機(jī),即PC可以抑制鍵盤發(fā)送數(shù)據(jù),而鍵盤不能抑制PC發(fā)送數(shù)據(jù)。 PS/2的每一位數(shù)據(jù)幀包含11-12位,具體含義如下:
數(shù)據(jù)位名稱 | 說明 |
1個(gè)起始位 | 總是邏輯0 |
8個(gè)數(shù)據(jù)位 | 低位在前 |
1個(gè)奇偶校驗(yàn)位 | 奇校驗(yàn) |
1個(gè)停止位 | 總是邏輯1 |
1個(gè)應(yīng)答位 | 僅用在主機(jī)對(duì)設(shè)備的通信中 |
·PS/2的時(shí)序圖:
由設(shè)備產(chǎn)生時(shí)鐘和數(shù)據(jù),主機(jī)根據(jù)時(shí)鐘來讀取數(shù)據(jù)。以FPGA和PS/2鍵盤為例,鍵盤產(chǎn)生時(shí)鐘和數(shù)據(jù),F(xiàn)PGA只需要讀數(shù)據(jù)。當(dāng)時(shí)鐘下降沿時(shí),F(xiàn)PGA記錄數(shù)據(jù)信號(hào)。 ·設(shè)計(jì)實(shí)例: 主機(jī)為FPGA,根據(jù)PS/2的時(shí)序,得到鍵盤的按鍵值。雖然在時(shí)序圖中,主機(jī)是在時(shí)鐘下降沿讀取數(shù)據(jù),但實(shí)際上要為了排除噪聲干擾,需要在FPGA端對(duì)信號(hào)進(jìn)行濾波。下面給出設(shè)計(jì)代碼。
module ps2_keyboard( input clk, input clr, input PS2C, //ps2 clk in input PS2D, //ps2 data in output [15:0] xkey);reg PS2CF;reg PS2DF;reg [7:0] ps2c_filter;reg [7:0] ps2d_filter;reg [10:0] shift1;reg [10:0] shift2; assign xkey = { shift2[8:1], shift1[8:1] };always @(posedge clk or posedge clr) begin if (clr) begin ps2c_filter <= 11'b0; ps2d_filter <= 11'b0; PS2CF <= 1; PS2DF <= 1; end else begin ps2c_filter[7] <= PS2C; ps2c_filter[6:0] <= ps2c_filter[7:1]; ps2d_filter[7] <= PS2D; ps2d_filter[6:0] <= ps2d_filter[7:1]; if(ps2c_filter == 8'b1111_1111) PS2CF <= 1; //去時(shí)鐘毛刺 else if(ps2c_filter == 8'b0000_0000) PS2CF <= 0; if(ps2d_filter == 8'b1111_1111) PS2DF <= 1; //去數(shù)據(jù)毛刺 else if(ps2d_filter == 8'b0000_0000) PS2DF <= 0; endend always @(negedge PS2CF or posedge clr) begin if (clr) begin shift1 <= 11'b0; shift2 <= 11'b0; end else begin shift1 <= {PS2DF, shift1[10:1]}; shift2 <= {shift1[0], shift2[10:1]}; endend endmodule
原文標(biāo)題:常用通信協(xié)議總結(jié)及FPGA實(shí)現(xiàn)(上)
文章出處:【微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
uart
+關(guān)注
關(guān)注
22文章
1219瀏覽量
101121 -
代碼
+關(guān)注
關(guān)注
30文章
4723瀏覽量
68236 -
異步串行通信
+關(guān)注
關(guān)注
0文章
16瀏覽量
8406
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論