WIFI_ESP8266通信系統(tǒng)設(shè)計(jì)
實(shí)驗(yàn)任務(wù)
實(shí)驗(yàn)?zāi)康?/h4>在前面串口監(jiān)視系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)中我們學(xué)習(xí)了UART總線的驅(qū)動(dòng)原理及設(shè)計(jì)實(shí)現(xiàn),本實(shí)驗(yàn)主要了解WIFI通信TCP協(xié)議,熟悉AT指令集,掌握ESP8266模塊的配置方法,最終通過FPGA編程實(shí)現(xiàn)對(duì)ESP8266模塊的配置應(yīng)用。
本文引用地址:http://cafeforensic.com/article/202312/453984.htm設(shè)計(jì)框圖
根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成以下功能模塊實(shí)現(xiàn),
實(shí)驗(yàn)原理
ESP8266模塊介紹
ESP8266是ai-thinker公司推出的一款無線WIFI模塊,可以通過配置,和單片機(jī)上的串口進(jìn)行通信,利用WIFI傳輸數(shù)據(jù)。模塊內(nèi)部使用樂鑫推出的低功耗高集成度的WIFI芯片,ESP8266EX內(nèi)置超低功耗32位RISK處理器,CPU最高時(shí)鐘頻率可達(dá)160Mhz,支持實(shí)時(shí)操作系統(tǒng)RTOS,和WIFI協(xié)議棧,可將高達(dá)80%的處理能力留給編程與開發(fā)。
ESP8266模塊連接
STEP BaseBoard V3.0底板上的WIFI通信模塊ESP8266-12F電路圖如下:
ESP8266模塊配置流程
(1)取下小腳丫底板,將Baseboard的GPIO29與GPIO26用杜邦線連接起來,將GPIO27與GPIO28連接起來,這樣就實(shí)現(xiàn)了CP2102與ESP8266的互聯(lián)。
(2)打開串口調(diào)試助手,發(fā)送“AT”(AT指令集后要換行),發(fā)送,如果連接無誤效果如下:
(3)保險(xiǎn)起見,我們復(fù)位一下模塊,發(fā)送AT+RST,如無誤如下圖所示(亂碼為正?,F(xiàn)象,有返回ready即可):
(4)如果你在一個(gè)存在WIFI的環(huán)境下,可以將ESP8266連入路由器,并獲得IP,首先,配置ESP8266的工作模式為sta,輸入AT+CWMODE=1,如無誤如下圖所示:
然后,我們掃描附近WIFI:
找到我們要連入的WIFI,本例中,我們連入“FHQ”,密碼為123456789
我們可以從圖片中看到已經(jīng)成功連入并獲取到IP,你可以使用AT+CWQAP來斷開WIFI。
(5)成功連入WIFI之后,我們就要開始配置透?jìng)髁耍紫?,配置連接模式為單連接:
(6)打開網(wǎng)絡(luò)調(diào)試助手,獲取本機(jī)IP與端口:
我們將協(xié)議類型改為TCP Server,端口號(hào)改為1234。
(7)回到串口調(diào)試助手,發(fā)送AT+CIPSTART=“TCP”,“192.168.20.125”,1234,連入該端口。發(fā)送AT+CIPMODE=1打開透?jìng)鳌?/p>
發(fā)送AT+CIPSEND進(jìn)入透?jìng)髂J剑?/p>
如果要退出透?jìng)鳎瑒t發(fā)送不帶回車的“+++”即可退出透?jìng)髂J健?/p>
(8)我們?cè)诔晒M(jìn)入透?jìng)髂J胶?,在串口助手中發(fā)送”hello”,如連接無誤,你可以在網(wǎng)絡(luò)調(diào)試助手端接收到“hello”。
你也可以在網(wǎng)絡(luò)調(diào)試助手端發(fā)送數(shù)據(jù),串口段也可接收到:
這樣就完成了ESP8266的網(wǎng)絡(luò)通訊。
系統(tǒng)總體實(shí)現(xiàn)
本實(shí)驗(yàn)我們將ESP8266配置成SoftAP模式,同時(shí)配置成服務(wù)器,采用下表中的指令對(duì)ESP8266模塊進(jìn)行配置。
ESP8266配置指令表:
序號(hào) 發(fā)送指令 作用 1 AT+CWMODE=2 設(shè)置模塊WIFI模式為SoftAP模式 2 AT+CWSAP=”STEPFPGA“,”12345678“,5,4 |設(shè)置模塊的AP參數(shù):SSID為STEPFPGA,密碼為12345678,通道號(hào)為5,加密方式為WPAWPA2PSK
3 AT+RST 重啟生效 4 AT+CIPMUX=1 開啟多連接 5 AT+CIPSERVER=1,8686 開啟SERVER模式,端口設(shè)置為8686
這里我們發(fā)送的各種指令,實(shí)際發(fā)送的數(shù)據(jù)為字符對(duì)應(yīng)的ASCII碼,所以在FPGA程序?qū)崿F(xiàn)的時(shí)候就是要取AT指令的ASCII碼值,例如”AT+RST”復(fù)位指令,通過串口調(diào)試助手發(fā)送的數(shù)據(jù)為<0x41,0x54,0x2B,0x52,0x53,0x54,0x0D,0x0A>,每個(gè)字符的ASCII碼都是8位位寬的數(shù)據(jù),其中0x41為A的ASCII碼,0x0D和0x0A為回車換行的ASCII碼, Verilog語言中使用雙引號(hào)獲取字符的ASCII碼。
變量char表示AT指令數(shù)據(jù),變量num表示AT指令中包含的字符數(shù)量(包含回車和換行),程序?qū)崿F(xiàn)如下:
MAIN:begin
if(cnt_main >= 4'd5) cnt_main <= 4'd5; //write mode
else cnt_main <= cnt_main + 1'b1;
case(cnt_main)
4'd0: begin num<=8'd13; char<={"AT+CWMODE=2",16'h0d0a};state<=TXMD; end
4'd1: begin num<=8'd37; char<={"AT+CWSAP=",8'h22,"STEP_FPGA",8'h22,",",8'h22,"12345678",8'h22,",5,4",16'h0d0a};state <= TXMD; end
4'd2: begin num<=8'd08; char <= {"AT+RST",16'h0d0a};state <= TXMD; end
4'd3: begin num<=8'd13; char<={"AT+CIPMUX=1",16'h0d0a};state<=TXMD; end
4'd4: begin num <= 8'd21; char <= {"AT+CIPSERVER=1,8686",16'h0d0a};state <= TXMD; end
4'd5: begin state <= REMD; end
default: state <= IDLE;
endcase
end
我們使用狀態(tài)機(jī)的MAIN狀態(tài)控制我們需要配置的所有指令數(shù)據(jù),你可以比喻成帝王,把握整個(gè)設(shè)計(jì)的大局。
使用AT指令集控制ESP8266模塊是UART接口,我們前面串口監(jiān)視系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)詳細(xì)講解了UART通信,本實(shí)驗(yàn)需要例化UART模塊進(jìn)行數(shù)據(jù)傳輸,如下:
/////////////////////////uart_tx module//////////////////////
Baud #
(.BPS_PARA (BPS_PARA )
)
Baud_tx(.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz
.rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效
.bps_en (bps_en_tx ), //接收時(shí)鐘使能
.bps_clk (bps_clk_tx ) //接收時(shí)鐘輸出
);
Uart_Tx Uart_Tx_uut(.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz
.rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效
.bps_en (bps_en_tx ), //發(fā)送時(shí)鐘使能
.bps_clk (bps_clk_tx ), //發(fā)送時(shí)鐘輸入
.tx_data_valid (tx_data_valid ), //發(fā)送數(shù)據(jù)有效脈沖
.tx_data_in (tx_data_in ), //要發(fā)送的數(shù)據(jù)
.uart_tx (wifi_tx ) //UART發(fā)送輸出
);
Baud模塊和UartTx模塊配合完成UART發(fā)送數(shù)據(jù)的功能,前級(jí)電路通過txdatavalid和txdatain[7:0]端口將數(shù)據(jù)傳遞給UartTx模塊,然后Uart_Tx模塊將數(shù)據(jù)按照UART總線時(shí)序發(fā)送出去,框圖如下:
我們使用之前設(shè)計(jì)的UART發(fā)送模塊將需要傳遞的數(shù)據(jù)通過UART總線發(fā)送出去,你可以比喻成士兵,是具體的執(zhí)行人員。
帝王把握整體設(shè)計(jì),有哪些數(shù)據(jù)需要傳輸;士兵只會(huì)干活,UART傳輸實(shí)現(xiàn),每次傳輸8位數(shù)據(jù);我們還需要一名將軍,按照帝王的要求指揮士兵完成任務(wù)。所以每當(dāng)MAIN(帝王)狀態(tài)跳轉(zhuǎn)到TXMD(將軍)狀態(tài)后,TXMD狀態(tài)完成對(duì)UartTx模塊txdatavalid和txdata_in[7:0]端口的配置。
TXMD:begin
case(cnt_txmd)
3'd0: if(bps_en_tx) cnt_txmd <= cnt_txmd;
else cnt_txmd <= cnt_txmd + 1'b1;
3'd1: begin num <= num - 1'b1; cnt_txmd <= cnt_txmd + 1'b1; end
3'd2: begin tx_data_valid <= 1'b1; tx_data_in <= char[(num*8)+:8]; cnt_txmd <= cnt_txmd + 1'b1; end
3'd3: begin
tx_data_valid <= 1'b0;
if(num>=1'b1) cnt_txmd <= 3'd0;
else cnt_txmd <= cnt_txmd + 1'b1;
end
3'd4: begin state <= DELAY; cnt_txmd <= 1'b0; end
default: state <= IDLE;
endcase
end
到這里對(duì)ESP8266的配置已經(jīng)完成了,假設(shè)用手機(jī)或電腦連接該網(wǎng)絡(luò):STEP_FPGA,同時(shí)打開網(wǎng)絡(luò)調(diào)試助手作為TCP Client連接TCP服務(wù)器:192.168.4.1,端口號(hào):8686,那么就可以給ESP8266發(fā)數(shù)據(jù)了,ESP8266模塊接收到WIFI數(shù)據(jù),然后以UART總線時(shí)序發(fā)送給FPGA,F(xiàn)PGA需要UART總線的接收模塊接收數(shù)據(jù),所以設(shè)計(jì)中還需要對(duì)UART接收功能模塊的例化,程序?qū)崿F(xiàn)如下:
////////////////////////uart_rx module/////////////////////
Baud #
(
.BPS_PARA (BPS_PARA )) Baud_rx(
.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz
.rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效
.bps_en (bps_en_rx ), //接收時(shí)鐘使能
.bps_clk (bps_clk_rx ) //接收時(shí)鐘輸出
);
Uart_Rx Uart_Rx_uut(.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz
.rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效
.bps_en (bps_en_rx ), //接收時(shí)鐘使能
.bps_clk (bps_clk_rx ), //接收時(shí)鐘輸入
.uart_rx (wifi_rx ), //UART接收輸入
.rx_data_valid (rx_data_valid ), //接收數(shù)據(jù)有效脈沖
.rx_data_out (rx_data_out ) //接收到的數(shù)據(jù)
);
Baud模塊和UartRx模塊配合完成UART接收數(shù)據(jù)的功能,UartRx模塊按照UART總線時(shí)序接收數(shù)據(jù),然后將接收到的數(shù)據(jù)通過rxdatavalid和rxdataout[7:0]端口輸出給后級(jí)電路,框圖如下:
當(dāng)我們連接服務(wù)器,使用網(wǎng)絡(luò)調(diào)試助手發(fā)送數(shù)據(jù)<123>,ESP8266模塊接收WIFI信號(hào),并通過UART返回?cái)?shù)據(jù)<+IPD,0,3:123>,如上圖所示,想要將123顯示在數(shù)碼管上,需要對(duì)UART接收的數(shù)據(jù)進(jìn)行解析,包括兩個(gè)方面, 1)接收到的數(shù)據(jù)中<+IPD,0,3:>部分不能顯示,需要排除,只顯示數(shù)據(jù)<123> 2)數(shù)據(jù)以ASCII碼形式接收,需要解析成字符數(shù)據(jù)
UART數(shù)據(jù)中被舍棄的數(shù)據(jù)<+IPD,0,3:>,我們可以簡(jiǎn)單的使用加號(hào)<+>和冒號(hào)<:>來控制顯示的部分,例如顯示冒號(hào)以后且加號(hào)以前的數(shù)據(jù),程序?qū)崿F(xiàn)如下
//解析UART通信,控制只顯示有效數(shù)據(jù)部分
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) display_en <= 1'b0;
else if((state == REMD)&&(rx_data_valid))
case(rx_data_out)
":": display_en <= 1'b1;
"+": display_en <= 1'b0;
default: display_en <= display_en;
endcase
else display_en <= display_en;
end
ASCII碼數(shù)據(jù)譯碼成對(duì)應(yīng)的字符數(shù)據(jù),程序?qū)崿F(xiàn)如下:
//對(duì)接收的ASCII碼值解碼,只對(duì)應(yīng)0~9的數(shù)字
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) seg_data_r <= 4'ha;
else if((state == REMD)&&(rx_data_valid))
case(rx_data_out)
"0": seg_data_r <= 4'd0;
"1": seg_data_r <= 4'd1;
"2": seg_data_r <= 4'd2;
"3": seg_data_r <= 4'd3;
"4": seg_data_r <= 4'd4;
"5": seg_data_r <= 4'd5;
"6": seg_data_r <= 4'd6;
"7": seg_data_r <= 4'd7;
"8": seg_data_r <= 4'd8;
"9": seg_data_r <= 4'd9;
default: seg_data_r <= seg_data_r;
endcase
else seg_data_r <= seg_data_r;
end
最后將顯示部分的字符數(shù)據(jù)放到移位寄存器中緩存,程序?qū)崿F(xiàn)如下:
reg [35:0] seg_data;//移位寄存器,UART接收數(shù)據(jù)的buffer
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
seg_data <= 36'haaaa_aaaa_a; // 本實(shí)驗(yàn)a對(duì)應(yīng)數(shù)碼管字庫為不顯示
end else if(!display_en_r2) begin //
seg_data <= 36'haaaa_aaaa_a;
end else if(rx_data_valid_r1) begin
seg_data <= {seg_data[31:0],seg_data_r};
end else seg_data <= seg_data;
end
例化掃描式數(shù)碼管驅(qū)動(dòng)模塊,將移位寄存器緩存的數(shù)據(jù)顯示在數(shù)碼管上,程序?qū)崿F(xiàn)如下:
Segment_scan Segment_scan_uut
(
.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz
.rst_n (rst_n ), //系統(tǒng)復(fù)位 低有效
.dat_1 (seg_data[31:28] ), //SEG1 顯示的數(shù)據(jù)輸入
.dat_2 (seg_data[27:24] ), //SEG2 顯示的數(shù)據(jù)輸入
.dat_3 (seg_data[23:20] ), //SEG3 顯示的數(shù)據(jù)輸入
.dat_4 (seg_data[19:16] ), //SEG4 顯示的數(shù)據(jù)輸入
.dat_5 (seg_data[15:12] ), //SEG5 顯示的數(shù)據(jù)輸入
.dat_6 (seg_data[11: 8] ), //SEG6 顯示的數(shù)據(jù)輸入
.dat_7 (seg_data[ 7: 4] ), //SEG7 顯示的數(shù)據(jù)輸入
.dat_8 (seg_data[ 3: 0] ), //SEG8 顯示的數(shù)據(jù)輸入
.dat_en (8'b1111_1111 ), //數(shù)碼管數(shù)據(jù)位顯示使能
.dot_en (8'b0000_0000 ), //數(shù)碼管小數(shù)點(diǎn)位顯示使能
.seg_rck (seg_rck ), //74HC595的RCK管腳
.seg_sck (seg_sck ), //74HC595的SCK管腳
.seg_din (seg_din ) //74HC595的SER管腳
);
實(shí)驗(yàn)步驟
實(shí)驗(yàn)現(xiàn)象
將設(shè)計(jì)加載到FPGA,手機(jī)或電腦WIFI連接到STEP_FPGA網(wǎng)絡(luò)上,打開網(wǎng)絡(luò)調(diào)試助手配置成TCP Client連接TCP服務(wù)器:192.168.4.1,端口號(hào):8686,發(fā)送0~9的阿拉伯?dāng)?shù)字,底板數(shù)碼管就能顯示出來,當(dāng)一次發(fā)送超過8位數(shù)據(jù),只顯示后面的8位數(shù)據(jù)。例如,網(wǎng)絡(luò)調(diào)試助手發(fā)送數(shù)據(jù)<123>,數(shù)碼管顯示123。
在前面串口監(jiān)視系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)中我們學(xué)習(xí)了UART總線的驅(qū)動(dòng)原理及設(shè)計(jì)實(shí)現(xiàn),本實(shí)驗(yàn)主要了解WIFI通信TCP協(xié)議,熟悉AT指令集,掌握ESP8266模塊的配置方法,最終通過FPGA編程實(shí)現(xiàn)對(duì)ESP8266模塊的配置應(yīng)用。
本文引用地址:http://cafeforensic.com/article/202312/453984.htm根據(jù)前面的實(shí)驗(yàn)解析我們可以得知,該設(shè)計(jì)可以拆分成以下功能模塊實(shí)現(xiàn),
ESP8266是ai-thinker公司推出的一款無線WIFI模塊,可以通過配置,和單片機(jī)上的串口進(jìn)行通信,利用WIFI傳輸數(shù)據(jù)。模塊內(nèi)部使用樂鑫推出的低功耗高集成度的WIFI芯片,ESP8266EX內(nèi)置超低功耗32位RISK處理器,CPU最高時(shí)鐘頻率可達(dá)160Mhz,支持實(shí)時(shí)操作系統(tǒng)RTOS,和WIFI協(xié)議棧,可將高達(dá)80%的處理能力留給編程與開發(fā)。
STEP BaseBoard V3.0底板上的WIFI通信模塊ESP8266-12F電路圖如下:
(1)取下小腳丫底板,將Baseboard的GPIO29與GPIO26用杜邦線連接起來,將GPIO27與GPIO28連接起來,這樣就實(shí)現(xiàn)了CP2102與ESP8266的互聯(lián)。
(2)打開串口調(diào)試助手,發(fā)送“AT”(AT指令集后要換行),發(fā)送,如果連接無誤效果如下:
(3)保險(xiǎn)起見,我們復(fù)位一下模塊,發(fā)送AT+RST,如無誤如下圖所示(亂碼為正?,F(xiàn)象,有返回ready即可):
(4)如果你在一個(gè)存在WIFI的環(huán)境下,可以將ESP8266連入路由器,并獲得IP,首先,配置ESP8266的工作模式為sta,輸入AT+CWMODE=1,如無誤如下圖所示:
然后,我們掃描附近WIFI:
找到我們要連入的WIFI,本例中,我們連入“FHQ”,密碼為123456789
我們可以從圖片中看到已經(jīng)成功連入并獲取到IP,你可以使用AT+CWQAP來斷開WIFI。
(5)成功連入WIFI之后,我們就要開始配置透?jìng)髁耍紫?,配置連接模式為單連接:
(6)打開網(wǎng)絡(luò)調(diào)試助手,獲取本機(jī)IP與端口:
我們將協(xié)議類型改為TCP Server,端口號(hào)改為1234。
(7)回到串口調(diào)試助手,發(fā)送AT+CIPSTART=“TCP”,“192.168.20.125”,1234,連入該端口。發(fā)送AT+CIPMODE=1打開透?jìng)鳌?/p>
發(fā)送AT+CIPSEND進(jìn)入透?jìng)髂J剑?/p>
如果要退出透?jìng)鳎瑒t發(fā)送不帶回車的“+++”即可退出透?jìng)髂J健?/p>
(8)我們?cè)诔晒M(jìn)入透?jìng)髂J胶?,在串口助手中發(fā)送”hello”,如連接無誤,你可以在網(wǎng)絡(luò)調(diào)試助手端接收到“hello”。
你也可以在網(wǎng)絡(luò)調(diào)試助手端發(fā)送數(shù)據(jù),串口段也可接收到:
這樣就完成了ESP8266的網(wǎng)絡(luò)通訊。
本實(shí)驗(yàn)我們將ESP8266配置成SoftAP模式,同時(shí)配置成服務(wù)器,采用下表中的指令對(duì)ESP8266模塊進(jìn)行配置。
ESP8266配置指令表:
序號(hào) | 發(fā)送指令 | 作用 |
1 | AT+CWMODE=2 | 設(shè)置模塊WIFI模式為SoftAP模式 |
2 | AT+CWSAP=”STEPFPGA“,”12345678“,5,4 |設(shè)置模塊的AP參數(shù):SSID為STEPFPGA,密碼為12345678,通道號(hào)為5,加密方式為WPAWPA2PSK | |
3 | AT+RST | 重啟生效 |
4 | AT+CIPMUX=1 | 開啟多連接 |
5 | AT+CIPSERVER=1,8686 | 開啟SERVER模式,端口設(shè)置為8686 |
這里我們發(fā)送的各種指令,實(shí)際發(fā)送的數(shù)據(jù)為字符對(duì)應(yīng)的ASCII碼,所以在FPGA程序?qū)崿F(xiàn)的時(shí)候就是要取AT指令的ASCII碼值,例如”AT+RST”復(fù)位指令,通過串口調(diào)試助手發(fā)送的數(shù)據(jù)為<0x41,0x54,0x2B,0x52,0x53,0x54,0x0D,0x0A>,每個(gè)字符的ASCII碼都是8位位寬的數(shù)據(jù),其中0x41為A的ASCII碼,0x0D和0x0A為回車換行的ASCII碼, Verilog語言中使用雙引號(hào)獲取字符的ASCII碼。
變量char表示AT指令數(shù)據(jù),變量num表示AT指令中包含的字符數(shù)量(包含回車和換行),程序?qū)崿F(xiàn)如下:
MAIN:begin if(cnt_main >= 4'd5) cnt_main <= 4'd5; //write mode else cnt_main <= cnt_main + 1'b1; case(cnt_main) 4'd0: begin num<=8'd13; char<={"AT+CWMODE=2",16'h0d0a};state<=TXMD; end 4'd1: begin num<=8'd37; char<={"AT+CWSAP=",8'h22,"STEP_FPGA",8'h22,",",8'h22,"12345678",8'h22,",5,4",16'h0d0a};state <= TXMD; end 4'd2: begin num<=8'd08; char <= {"AT+RST",16'h0d0a};state <= TXMD; end 4'd3: begin num<=8'd13; char<={"AT+CIPMUX=1",16'h0d0a};state<=TXMD; end 4'd4: begin num <= 8'd21; char <= {"AT+CIPSERVER=1,8686",16'h0d0a};state <= TXMD; end 4'd5: begin state <= REMD; end default: state <= IDLE; endcase end
我們使用狀態(tài)機(jī)的MAIN狀態(tài)控制我們需要配置的所有指令數(shù)據(jù),你可以比喻成帝王,把握整個(gè)設(shè)計(jì)的大局。
使用AT指令集控制ESP8266模塊是UART接口,我們前面串口監(jiān)視系統(tǒng)設(shè)計(jì)實(shí)驗(yàn)詳細(xì)講解了UART通信,本實(shí)驗(yàn)需要例化UART模塊進(jìn)行數(shù)據(jù)傳輸,如下:
/////////////////////////uart_tx module////////////////////// Baud # (.BPS_PARA (BPS_PARA ) ) Baud_tx(.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz .rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_tx ), //接收時(shí)鐘使能 .bps_clk (bps_clk_tx ) //接收時(shí)鐘輸出 ); Uart_Tx Uart_Tx_uut(.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz .rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_tx ), //發(fā)送時(shí)鐘使能 .bps_clk (bps_clk_tx ), //發(fā)送時(shí)鐘輸入 .tx_data_valid (tx_data_valid ), //發(fā)送數(shù)據(jù)有效脈沖 .tx_data_in (tx_data_in ), //要發(fā)送的數(shù)據(jù) .uart_tx (wifi_tx ) //UART發(fā)送輸出 );
Baud模塊和UartTx模塊配合完成UART發(fā)送數(shù)據(jù)的功能,前級(jí)電路通過txdatavalid和txdatain[7:0]端口將數(shù)據(jù)傳遞給UartTx模塊,然后Uart_Tx模塊將數(shù)據(jù)按照UART總線時(shí)序發(fā)送出去,框圖如下:
我們使用之前設(shè)計(jì)的UART發(fā)送模塊將需要傳遞的數(shù)據(jù)通過UART總線發(fā)送出去,你可以比喻成士兵,是具體的執(zhí)行人員。
帝王把握整體設(shè)計(jì),有哪些數(shù)據(jù)需要傳輸;士兵只會(huì)干活,UART傳輸實(shí)現(xiàn),每次傳輸8位數(shù)據(jù);我們還需要一名將軍,按照帝王的要求指揮士兵完成任務(wù)。所以每當(dāng)MAIN(帝王)狀態(tài)跳轉(zhuǎn)到TXMD(將軍)狀態(tài)后,TXMD狀態(tài)完成對(duì)UartTx模塊txdatavalid和txdata_in[7:0]端口的配置。
TXMD:begin case(cnt_txmd) 3'd0: if(bps_en_tx) cnt_txmd <= cnt_txmd; else cnt_txmd <= cnt_txmd + 1'b1; 3'd1: begin num <= num - 1'b1; cnt_txmd <= cnt_txmd + 1'b1; end 3'd2: begin tx_data_valid <= 1'b1; tx_data_in <= char[(num*8)+:8]; cnt_txmd <= cnt_txmd + 1'b1; end 3'd3: begin tx_data_valid <= 1'b0; if(num>=1'b1) cnt_txmd <= 3'd0; else cnt_txmd <= cnt_txmd + 1'b1; end 3'd4: begin state <= DELAY; cnt_txmd <= 1'b0; end default: state <= IDLE; endcase end
到這里對(duì)ESP8266的配置已經(jīng)完成了,假設(shè)用手機(jī)或電腦連接該網(wǎng)絡(luò):STEP_FPGA,同時(shí)打開網(wǎng)絡(luò)調(diào)試助手作為TCP Client連接TCP服務(wù)器:192.168.4.1,端口號(hào):8686,那么就可以給ESP8266發(fā)數(shù)據(jù)了,ESP8266模塊接收到WIFI數(shù)據(jù),然后以UART總線時(shí)序發(fā)送給FPGA,F(xiàn)PGA需要UART總線的接收模塊接收數(shù)據(jù),所以設(shè)計(jì)中還需要對(duì)UART接收功能模塊的例化,程序?qū)崿F(xiàn)如下:
////////////////////////uart_rx module///////////////////// Baud # ( .BPS_PARA (BPS_PARA )) Baud_rx( .clk (clk ), //系統(tǒng)時(shí)鐘 12MHz .rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_rx ), //接收時(shí)鐘使能 .bps_clk (bps_clk_rx ) //接收時(shí)鐘輸出 ); Uart_Rx Uart_Rx_uut(.clk (clk ), //系統(tǒng)時(shí)鐘 12MHz .rst_n (rst_n ), //系統(tǒng)復(fù)位,低有效 .bps_en (bps_en_rx ), //接收時(shí)鐘使能 .bps_clk (bps_clk_rx ), //接收時(shí)鐘輸入 .uart_rx (wifi_rx ), //UART接收輸入 .rx_data_valid (rx_data_valid ), //接收數(shù)據(jù)有效脈沖 .rx_data_out (rx_data_out ) //接收到的數(shù)據(jù) );
Baud模塊和UartRx模塊配合完成UART接收數(shù)據(jù)的功能,UartRx模塊按照UART總線時(shí)序接收數(shù)據(jù),然后將接收到的數(shù)據(jù)通過rxdatavalid和rxdataout[7:0]端口輸出給后級(jí)電路,框圖如下:
當(dāng)我們連接服務(wù)器,使用網(wǎng)絡(luò)調(diào)試助手發(fā)送數(shù)據(jù)<123>,ESP8266模塊接收WIFI信號(hào),并通過UART返回?cái)?shù)據(jù)<+IPD,0,3:123>,如上圖所示,想要將123顯示在數(shù)碼管上,需要對(duì)UART接收的數(shù)據(jù)進(jìn)行解析,包括兩個(gè)方面, 1)接收到的數(shù)據(jù)中<+IPD,0,3:>部分不能顯示,需要排除,只顯示數(shù)據(jù)<123> 2)數(shù)據(jù)以ASCII碼形式接收,需要解析成字符數(shù)據(jù)
UART數(shù)據(jù)中被舍棄的數(shù)據(jù)<+IPD,0,3:>,我們可以簡(jiǎn)單的使用加號(hào)<+>和冒號(hào)<:>來控制顯示的部分,例如顯示冒號(hào)以后且加號(hào)以前的數(shù)據(jù),程序?qū)崿F(xiàn)如下
//解析UART通信,控制只顯示有效數(shù)據(jù)部分 always @ (posedge clk or negedge rst_n) begin if(!rst_n) display_en <= 1'b0; else if((state == REMD)&&(rx_data_valid)) case(rx_data_out) ":": display_en <= 1'b1; "+": display_en <= 1'b0; default: display_en <= display_en; endcase else display_en <= display_en; end
ASCII碼數(shù)據(jù)譯碼成對(duì)應(yīng)的字符數(shù)據(jù),程序?qū)崿F(xiàn)如下:
//對(duì)接收的ASCII碼值解碼,只對(duì)應(yīng)0~9的數(shù)字 always @ (posedge clk or negedge rst_n) begin if(!rst_n) seg_data_r <= 4'ha; else if((state == REMD)&&(rx_data_valid)) case(rx_data_out) "0": seg_data_r <= 4'd0; "1": seg_data_r <= 4'd1; "2": seg_data_r <= 4'd2; "3": seg_data_r <= 4'd3; "4": seg_data_r <= 4'd4; "5": seg_data_r <= 4'd5; "6": seg_data_r <= 4'd6; "7": seg_data_r <= 4'd7; "8": seg_data_r <= 4'd8; "9": seg_data_r <= 4'd9; default: seg_data_r <= seg_data_r; endcase else seg_data_r <= seg_data_r; end
最后將顯示部分的字符數(shù)據(jù)放到移位寄存器中緩存,程序?qū)崿F(xiàn)如下:
reg [35:0] seg_data;//移位寄存器,UART接收數(shù)據(jù)的buffer always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin seg_data <= 36'haaaa_aaaa_a; // 本實(shí)驗(yàn)a對(duì)應(yīng)數(shù)碼管字庫為不顯示 end else if(!display_en_r2) begin // seg_data <= 36'haaaa_aaaa_a; end else if(rx_data_valid_r1) begin seg_data <= {seg_data[31:0],seg_data_r}; end else seg_data <= seg_data; end
例化掃描式數(shù)碼管驅(qū)動(dòng)模塊,將移位寄存器緩存的數(shù)據(jù)顯示在數(shù)碼管上,程序?qū)崿F(xiàn)如下:
Segment_scan Segment_scan_uut ( .clk (clk ), //系統(tǒng)時(shí)鐘 12MHz .rst_n (rst_n ), //系統(tǒng)復(fù)位 低有效 .dat_1 (seg_data[31:28] ), //SEG1 顯示的數(shù)據(jù)輸入 .dat_2 (seg_data[27:24] ), //SEG2 顯示的數(shù)據(jù)輸入 .dat_3 (seg_data[23:20] ), //SEG3 顯示的數(shù)據(jù)輸入 .dat_4 (seg_data[19:16] ), //SEG4 顯示的數(shù)據(jù)輸入 .dat_5 (seg_data[15:12] ), //SEG5 顯示的數(shù)據(jù)輸入 .dat_6 (seg_data[11: 8] ), //SEG6 顯示的數(shù)據(jù)輸入 .dat_7 (seg_data[ 7: 4] ), //SEG7 顯示的數(shù)據(jù)輸入 .dat_8 (seg_data[ 3: 0] ), //SEG8 顯示的數(shù)據(jù)輸入 .dat_en (8'b1111_1111 ), //數(shù)碼管數(shù)據(jù)位顯示使能 .dot_en (8'b0000_0000 ), //數(shù)碼管小數(shù)點(diǎn)位顯示使能 .seg_rck (seg_rck ), //74HC595的RCK管腳 .seg_sck (seg_sck ), //74HC595的SCK管腳 .seg_din (seg_din ) //74HC595的SER管腳 );
將設(shè)計(jì)加載到FPGA,手機(jī)或電腦WIFI連接到STEP_FPGA網(wǎng)絡(luò)上,打開網(wǎng)絡(luò)調(diào)試助手配置成TCP Client連接TCP服務(wù)器:192.168.4.1,端口號(hào):8686,發(fā)送0~9的阿拉伯?dāng)?shù)字,底板數(shù)碼管就能顯示出來,當(dāng)一次發(fā)送超過8位數(shù)據(jù),只顯示后面的8位數(shù)據(jù)。例如,網(wǎng)絡(luò)調(diào)試助手發(fā)送數(shù)據(jù)<123>,數(shù)碼管顯示123。
評(píng)論