差别
这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
wifi_esp8266通信系统设计 [2018/10/22 10:03] anran 创建 |
wifi_esp8266通信系统设计 [2020/01/18 21:57] (当前版本) gongyu |
||
---|---|---|---|
行 1: | 行 1: | ||
- | =====WIFI_ESP8266通信系统设计===== | + | ### WIFI_ESP8266通信系统设计 |
- | ----- | + | |
- | ====实验任务==== | + | |
+ | --- | ||
- | ====实验目的==== | + | ####实验任务 |
+ | * 任务:基于 STEP-MAX10M08核心板 和 STEP BaseBoard V3.0底板 完成WIFI_ESP8266通信系统设计并观察调试结果 | ||
+ | * 要求:通过手机或电脑网络调试助手给ESP8266模块发送数据,FPGA驱动ESP8266模块获取数据,并显示在底板的数码管上。 | ||
+ | * 解析:要通过ESP8266实现WIFI通信有多种方式,本实验采用方式:FPGA驱动ESP8266模块,将ESP8266配置成SoftAP模式同时配置成TCP Server,手机或电脑连接ESP8266的WIFI热点,网络调试助手TCP Client连接到ESP8266的TCP Server,并发送数据,FPGA读取ESP8266数据并处理,最后显示在8位数码管上。 | ||
- | ====设计框图==== | + | #### 实验目的 |
+ | 在前面串口监视系统设计实验中我们学习了UART总线的驱动原理及设计实现,本实验主要了解WIFI通信TCP协议,熟悉AT指令集,掌握ESP8266模块的配置方法,最终通过FPGA编程实现对ESP8266模块的配置应用。 | ||
+ | * 熟悉基本网络通信原理,简要了解TCP协议 | ||
+ | * 熟悉AT指令集,掌握ESP8266模块的配置方法 | ||
+ | * FPGA通过UART配置ESP8266模块的设计实现 | ||
+ | * 完成WIFI_ESP8266通信系统设计实现 | ||
- | ====实验原理==== | + | #### 设计框图 |
- | ===ESP8266模块介绍=== | + | |
- | ===ESP8266模块连接=== | + | |
- | ===ESP8266模块配置流程=== | + | |
- | ===系统总体实现=== | + | |
+ | 根据前面的实验解析我们可以得知,该设计可以拆分成以下功能模块实现, | ||
+ | * WIFI_ESP8266:TOP模块,同时负责对ESP8266配置和处理接收的数据。 | ||
+ | * Baud:控制UART通信数据传输速率。 | ||
+ | * Uart_Rx:根据数据传输速率节拍控制UART数据接收。 | ||
+ | * Uart_Tx:根据数据传输速率节拍控制UART数据发送。 | ||
+ | * Segment_scan:通过驱动底板扫描式数码管将串口接收的数据显示出来。 | ||
- | ====实验步骤==== | + | {{:14-Top-Down层次设计.png?500|Top-Down层次设计}} {{:14-模块结构设计.png?500|模块结构设计}} |
+ | |||
+ | #### 实验原理 | ||
+ | |||
+ | ##### ESP8266模块介绍 | ||
+ | |||
+ | ESP8266是ai-thinker公司推出的一款无线WIFI模块,可以通过配置,和单片机上的串口进行通信,利用WIFI传输数据。模块内部使用乐鑫推出的低功耗高集成度的WIFI芯片,ESP8266EX内置超低功耗32位RISK处理器,CPU最高时钟频率可达160Mhz,支持实时操作系统RTOS,和WIFI协议栈,可将高达80%的处理能力留给编程与开发。 | ||
+ | |||
+ | ##### ESP8266模块连接 | ||
+ | |||
+ | STEP BaseBoard V3.0底板上的WIFI通信模块ESP8266-12F电路图如下: | ||
+ | |||
+ | {{:14-ESP8266-12F电路连接.png?800|ESP8266-12F电路连接}} | ||
+ | |||
+ | ##### ESP8266模块配置流程 | ||
+ | |||
+ | (1)取下小脚丫底板,将Baseboard的GPIO29与GPIO26用杜邦线连接起来,将GPIO27与GPIO28连接起来,这样就实现了CP2102与ESP8266的互联。 | ||
+ | |||
+ | {{:14-ESP配置1.png?600|CP2102与ESP8266手工互连}} | ||
+ | |||
+ | (2)打开串口调试助手,发送“AT”(AT指令集后要换行),发送,如果连接无误效果如下: | ||
+ | |||
+ | {{:14-ESP配置2.png?600|ESP8266串口回路测试}} | ||
+ | |||
+ | (3)保险起见,我们复位一下模块,发送AT+RST,如无误如下图所示(乱码为正常现象,有返回ready即可): | ||
+ | |||
+ | {{:14-ESP配置3.png?600|ESP8266软件复位}} | ||
+ | |||
+ | (4)如果你在一个存在WIFI的环境下,可以将ESP8266连入路由器,并获得IP,首先,配置ESP8266的工作模式为sta,输入AT+CWMODE=1,如无误如下图所示: | ||
+ | |||
+ | {{:14-ESP配置4.png?600|ESP8266配置STA模式}} | ||
+ | |||
+ | 然后,我们扫描附近WIFI: | ||
+ | |||
+ | {{:14-ESP配置5.png?600|显示无线列表}} | ||
+ | |||
+ | 找到我们要连入的WIFI,本例中,我们连入“FHQ”,密码为123456789 | ||
+ | |||
+ | {{:14-ESP配置6.png?600|配置无线连接}} | ||
+ | |||
+ | 我们可以从图片中看到已经成功连入并获取到IP,你可以使用AT+CWQAP来断开WIFI。 | ||
+ | |||
+ | (5)成功连入WIFI之后,我们就要开始配置透传了,首先,配置连接模式为单连接: | ||
+ | |||
+ | {{:14-ESP配置7.png?600|配置单连接模式}} | ||
+ | |||
+ | (6)打开网络调试助手,获取本机IP与端口: | ||
+ | |||
+ | {{:14-ESP配置8.png?600|网络调试助手}} | ||
+ | |||
+ | 我们将协议类型改为TCP Server,端口号改为1234。 | ||
+ | |||
+ | {{:14-ESP配置9.png?600|配置网络调试助手}} | ||
+ | |||
+ | (7)回到串口调试助手,发送AT+CIPSTART="TCP","192.168.20.125",1234,连入该端口。发送AT+CIPMODE=1打开透传。 | ||
+ | |||
+ | {{:14-ESP配置10.png?600|通过串口调试助手配置ESP8266连接电脑的服务器,打开透传功能}} | ||
+ | |||
+ | 发送AT+CIPSEND进入透传模式: | ||
+ | |||
+ | {{:14-ESP配置11.png?600|进入透传功能}} | ||
+ | |||
+ | 如果要退出透传,则发送不带回车的“+++”即可退出透传模式。 | ||
+ | |||
+ | (8)我们在成功进入透传模式后,在串口助手中发送”hello”,如连接无误,你可以在网络调试助手端接收到“hello”。 | ||
+ | |||
+ | {{:14-ESP配置12.png?800|透传通信}} | ||
+ | |||
+ | 你也可以在网络调试助手端发送数据,串口段也可接收到: | ||
+ | |||
+ | {{:14-ESP配置13.png?800|透传通信}} | ||
+ | |||
+ | 这样就完成了ESP8266的网络通讯。 | ||
+ | |||
+ | ##### 系统总体实现 | ||
+ | |||
+ | 本实验我们将ESP8266配置成SoftAP模式,同时配置成服务器,采用下表中的指令对ESP8266模块进行配置。 | ||
+ | |||
+ | ESP8266配置指令表: | ||
+ | |||
+ | |序号 |发送指令 |作用| | ||
+ | |1 |AT+CWMODE=2 |设置模块WIFI模式为SoftAP模式| | ||
+ | |2 |AT+CWSAP=”STEP_FPGA","12345678",5,4 |设置模块的AP参数:SSID为STEP_FPGA,密码为12345678,通道号为5,加密方式为WPA_WPA2_PSK| | ||
+ | |3 |AT+RST |重启生效| | ||
+ | |4 |AT+CIPMUX=1 |开启多连接| | ||
+ | |5 |AT+CIPSERVER=1,8686 |开启SERVER模式,端口设置为8686| | ||
+ | |||
+ | 这里我们发送的各种指令,实际发送的数据为字符对应的ASCII码,所以在FPGA程序实现的时候就是要取AT指令的ASCII码值,例如”AT+RST”复位指令,通过串口调试助手发送的数据为<0x41,0x54,0x2B,0x52,0x53,0x54,0x0D,0x0A>,每个字符的ASCII码都是8位位宽的数据,其中0x41为A的ASCII码,0x0D和0x0A为回车换行的ASCII码, Verilog语言中使用双引号获取字符的ASCII码。 | ||
+ | |||
+ | 变量char表示AT指令数据,变量num表示AT指令中包含的字符数量(包含回车和换行),程序实现如下: | ||
+ | |||
+ | <code verilog> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | 我们使用状态机的MAIN状态控制我们需要配置的所有指令数据,你可以比喻成帝王,把握整个设计的大局。 | ||
+ | |||
+ | 使用AT指令集控制ESP8266模块是UART接口,我们前面串口监视系统设计实验详细讲解了UART通信,本实验需要例化UART模块进行数据传输,如下: | ||
+ | |||
+ | <code verilog> | ||
+ | /////////////////////////uart_tx module////////////////////// | ||
+ | Baud # | ||
+ | ( | ||
+ | .BPS_PARA (BPS_PARA ) | ||
+ | ) | ||
+ | Baud_tx | ||
+ | ( | ||
+ | .clk (clk ), //系统时钟 12MHz | ||
+ | .rst_n (rst_n ), //系统复位,低有效 | ||
+ | .bps_en (bps_en_tx ), //接收时钟使能 | ||
+ | .bps_clk (bps_clk_tx ) //接收时钟输出 | ||
+ | ); | ||
+ | |||
+ | Uart_Tx Uart_Tx_uut | ||
+ | ( | ||
+ | .clk (clk ), //系统时钟 12MHz | ||
+ | .rst_n (rst_n ), //系统复位,低有效 | ||
+ | .bps_en (bps_en_tx ), //发送时钟使能 | ||
+ | .bps_clk (bps_clk_tx ), //发送时钟输入 | ||
+ | .tx_data_valid (tx_data_valid ), //发送数据有效脉冲 | ||
+ | .tx_data_in (tx_data_in ), //要发送的数据 | ||
+ | .uart_tx (wifi_tx ) //UART发送输出 | ||
+ | ); | ||
+ | </code> | ||
+ | |||
+ | Baud模块和Uart_Tx模块配合完成UART发送数据的功能,前级电路通过tx_data_valid和tx_data_in[7:0]端口将数据传递给Uart_Tx模块,然后Uart_Tx模块将数据按照UART总线时序发送出去,框图如下: | ||
+ | |||
+ | {{:6-UART发送功能设计实现.png?600|UART发送功能设计实现}} | ||
+ | |||
+ | 我们使用之前设计的UART发送模块将需要传递的数据通过UART总线发送出去,你可以比喻成士兵,是具体的执行人员。 | ||
+ | |||
+ | 帝王把握整体设计,有哪些数据需要传输;士兵只会干活,UART传输实现,每次传输8位数据;我们还需要一名将军,按照帝王的要求指挥士兵完成任务。所以每当MAIN(帝王)状态跳转到TXMD(将军)状态后,TXMD状态完成对Uart_Tx模块tx_data_valid和tx_data_in[7:0]端口的配置。 | ||
+ | |||
+ | <code verilog> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | 到这里对ESP8266的配置已经完成了,假设用手机或电脑连接该网络:STEP_FPGA,同时打开网络调试助手作为TCP Client连接TCP服务器:192.168.4.1,端口号:8686,那么就可以给ESP8266发数据了,ESP8266模块接收到WIFI数据,然后以UART总线时序发送给FPGA,FPGA需要UART总线的接收模块接收数据,所以设计中还需要对UART接收功能模块的例化,程序实现如下: | ||
+ | |||
+ | <code verilog> | ||
+ | ////////////////////////uart_rx module///////////////////// | ||
+ | Baud # | ||
+ | ( | ||
+ | .BPS_PARA (BPS_PARA ) | ||
+ | ) Baud_rx | ||
+ | ( | ||
+ | .clk (clk ), //系统时钟 12MHz | ||
+ | .rst_n (rst_n ), //系统复位,低有效 | ||
+ | .bps_en (bps_en_rx ), //接收时钟使能 | ||
+ | .bps_clk (bps_clk_rx ) //接收时钟输出 | ||
+ | ); | ||
+ | |||
+ | Uart_Rx Uart_Rx_uut | ||
+ | ( | ||
+ | .clk (clk ), //系统时钟 12MHz | ||
+ | .rst_n (rst_n ), //系统复位,低有效 | ||
+ | .bps_en (bps_en_rx ), //接收时钟使能 | ||
+ | .bps_clk (bps_clk_rx ), //接收时钟输入 | ||
+ | .uart_rx (wifi_rx ), //UART接收输入 | ||
+ | .rx_data_valid (rx_data_valid ), //接收数据有效脉冲 | ||
+ | .rx_data_out (rx_data_out ) //接收到的数据 | ||
+ | ); | ||
+ | </code> | ||
+ | |||
+ | Baud模块和Uart_Rx模块配合完成UART接收数据的功能,Uart_Rx模块按照UART总线时序接收数据,然后将接收到的数据通过rx_data_valid和rx_data_out[7:0]端口输出给后级电路,框图如下: | ||
+ | |||
+ | {{:6-UART接收功能设计实现.png?600|UART接收功能设计实现}} | ||
+ | |||
+ | {{:14-WIFI通信.png?800|WIFI通信}} | ||
+ | |||
+ | 当我们连接服务器,使用网络调试助手发送数据<123>,ESP8266模块接收WIFI信号,并通过UART返回数据<+IPD,0,3:123>,如上图所示,想要将123显示在数码管上,需要对UART接收的数据进行解析,包括两个方面, | ||
+ | 1)接收到的数据中<+IPD,0,3:>部分不能显示,需要排除,只显示数据<123> | ||
+ | 2)数据以ASCII码形式接收,需要解析成字符数据 | ||
+ | |||
+ | UART数据中被舍弃的数据<+IPD,0,3:>,我们可以简单的使用加号<+>和冒号<:>来控制显示的部分,例如显示冒号以后且加号以前的数据,程序实现如下 | ||
+ | |||
+ | <code verilog> | ||
+ | //解析UART通信,控制只显示有效数据部分 | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | ASCII码数据译码成对应的字符数据,程序实现如下: | ||
+ | |||
+ | <code verilog> | ||
+ | //对接收的ASCII码值解码,只对应0~9的数字 | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | 最后将显示部分的字符数据放到移位寄存器中缓存,程序实现如下: | ||
+ | |||
+ | <code verilog> | ||
+ | reg [35:0] seg_data; | ||
+ | //移位寄存器,UART接收数据的buffer | ||
+ | always @ (posedge clk or negedge rst_n) begin | ||
+ | if(!rst_n) begin | ||
+ | seg_data <= 36'haaaa_aaaa_a; // 本实验a对应数码管字库为不显示 | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | 例化扫描式数码管驱动模块,将移位寄存器缓存的数据显示在数码管上,程序实现如下: | ||
+ | |||
+ | <code verilog> | ||
+ | Segment_scan Segment_scan_uut | ||
+ | ( | ||
+ | .clk (clk ), //系统时钟 12MHz | ||
+ | .rst_n (rst_n ), //系统复位 低有效 | ||
+ | .dat_1 (seg_data[31:28] ), //SEG1 显示的数据输入 | ||
+ | .dat_2 (seg_data[27:24] ), //SEG2 显示的数据输入 | ||
+ | .dat_3 (seg_data[23:20] ), //SEG3 显示的数据输入 | ||
+ | .dat_4 (seg_data[19:16] ), //SEG4 显示的数据输入 | ||
+ | .dat_5 (seg_data[15:12] ), //SEG5 显示的数据输入 | ||
+ | .dat_6 (seg_data[11: 8] ), //SEG6 显示的数据输入 | ||
+ | .dat_7 (seg_data[ 7: 4] ), //SEG7 显示的数据输入 | ||
+ | .dat_8 (seg_data[ 3: 0] ), //SEG8 显示的数据输入 | ||
+ | .dat_en (8'b1111_1111 ), //数码管数据位显示使能 | ||
+ | .dot_en (8'b0000_0000 ), //数码管小数点位显示使能 | ||
+ | .seg_rck (seg_rck ), //74HC595的RCK管脚 | ||
+ | .seg_sck (seg_sck ), //74HC595的SCK管脚 | ||
+ | .seg_din (seg_din ) //74HC595的SER管脚 | ||
+ | ); | ||
+ | </code> | ||
+ | |||
+ | #### 实验步骤 | ||
- 双击打开Quartus Prime工具软件; | - 双击打开Quartus Prime工具软件; | ||
- 新建工程:File → New Project Wizard(工程命名,工程目录选择,设备型号选择,EDA工具选择); | - 新建工程:File → New Project Wizard(工程命名,工程目录选择,设备型号选择,EDA工具选择); | ||
行 28: | 行 316: | ||
- | ====实验现象==== | + | #### 实验现象 |
+ | |||
+ | 将设计加载到FPGA,手机或电脑WIFI连接到STEP_FPGA网络上,打开网络调试助手配置成TCP Client连接TCP服务器:192.168.4.1,端口号:8686,发送0~9的阿拉伯数字,底板数码管就能显示出来,当一次发送超过8位数据,只显示后面的8位数据。例如,网络调试助手发送数据<123>,数码管显示123。 | ||
+ | |||
+ | {{:14-实验现象.png?600|实验现象}} |