📶 第27课:WiFi模块(AT指令)

ESP8266 AT指令 + UART控制 + TCP连接 — 让FPGA联网!

🏆 成就:网络先锋 ✅ Verilator验证通过

📶
网络先锋
AT指令解析 + ESP8266控制 + TCP/UDP通信

📶 ESP8266 WiFi模块

ESP8266是最便宜的WiFi模块——串口AT指令控制,FPGA只需发UART命令就能联网!

FPGA + ESP8266连接 ┌──────────┐ ┌──────────┐ │ │ TX ──────→│ RX │ │ FPGA │ │ ESP8266 │──→ WiFi天线 │ │ RX ←──────│ TX │ │ │ │ │ │ │ GPIO──────│ RST │ │ │ │ EN │ └──────────┘ └──────────┘ AT指令流程: 1. AT → OK (测试连接) 2. AT+CWMODE=1 → OK (Station模式) 3. AT+CWJAP="SSID","PWD" → OK (连接WiFi) 4. AT+CIFSR → IP地址 (获取IP) 5. AT+CIPSTART="TCP",... → OK (建立连接) 6. AT+CIPSEND=n → > 数据 (发送数据)

📐 AT指令控制器

Verilogat_command_ctrl.v — AT指令控制器
// AT指令控制器 - 通过UART控制ESP8266
module at_command_ctrl (
    input  wire        clk,
    input  wire        rst,
    // UART接口
    output wire [7:0]  uart_tx_data,
    output wire        uart_tx_start,
    input  wire        uart_tx_busy,
    input  wire [7:0]  uart_rx_data,
    input  wire        uart_rx_valid,
    // 命令接口
    input  wire        cmd_start,     // 启动命令序列
    input  wire [3:0]  cmd_select,    // 选择命令
    output reg         cmd_done,
    output reg         cmd_error,
    // ESP8266状态
    output reg         wifi_connected
);
    // AT命令ROM - 存储命令字符串
    reg [7:0] cmd_rom [0:127];
    reg [6:0] cmd_addr;
    reg [3:0] current_cmd;
    reg       sending;

    initial begin
        // CMD0: "AT
" - 测试
        cmd_rom[0]  = 8'h41; // A
        cmd_rom[1]  = 8'h54; // T
        cmd_rom[2]  = 8'h0D; // 
        cmd_rom[3]  = 8'h0A; // 

        cmd_rom[4]  = 8'h00; // 结束
        // CMD1: "AT+CWMODE=1
" - Station模式
        cmd_rom[16] = 8'h41; cmd_rom[17] = 8'h54; // AT
        cmd_rom[18] = 8'h2B; // +
        cmd_rom[19] = 8'h43; cmd_rom[20] = 8'h57; // CW
        cmd_rom[21] = 8'h4D; cmd_rom[22] = 8'h4F; // MO
        cmd_rom[23] = 8'h44; cmd_rom[24] = 8'h45; // DE
        cmd_rom[25] = 8'h3D; // =
        cmd_rom[26] = 8'h31; // 1
        cmd_rom[27] = 8'h0D; cmd_rom[28] = 8'h0A;
        cmd_rom[29] = 8'h00;
        // CMD2: "AT+CIFSR
" - 查询IP
        cmd_rom[32] = 8'h41; cmd_rom[33] = 8'h54;
        cmd_rom[34] = 8'h2B; cmd_rom[35] = 8'h43;
        cmd_rom[36] = 8'h49; cmd_rom[37] = 8'h46;
        cmd_rom[38] = 8'h53; cmd_rom[39] = 8'h52;
        cmd_rom[40] = 8'h0D; cmd_rom[41] = 8'h0A;
        cmd_rom[42] = 8'h00;
    end

    // 发送状态机
    localparam IDLE=0, SEND_CHAR=1, WAIT_TX=2, NEXT_CHAR=3, WAIT_RESP=4;
    reg [2:0] state;
    reg [19:0] timeout;

    always @(posedge clk) begin
        if (rst) begin
            state <= IDLE; sending <= 0;
            cmd_done <= 0; cmd_error <= 0;
            wifi_connected <= 0;
        end else begin
            cmd_done <= 0;
            case(state)
                IDLE: begin
                    if (cmd_start) begin
                        current_cmd <= cmd_select;
                        cmd_addr <= {cmd_select, 3'b000};
                        state <= SEND_CHAR;
                        sending <= 1;
                        timeout <= 0;
                    end
                end
                SEND_CHAR: begin
                    if (cmd_rom[cmd_addr] == 8'h00) begin
                        state <= WAIT_RESP;
                        sending <= 0;
                        timeout <= 0;
                    end else begin
                        state <= WAIT_TX;
                    end
                end
                WAIT_TX: begin
                    if (!uart_tx_busy) begin
                        state <= NEXT_CHAR;
                    end
                end
                NEXT_CHAR: begin
                    cmd_addr <= cmd_addr + 1;
                    state <= SEND_CHAR;
                end
                WAIT_RESP: begin
                    // 检测"OK"响应(简化)
                    if (uart_rx_valid) begin
                        if (uart_rx_data == 8'h4F) // 'O'
                            wifi_connected <= 1;
                        cmd_done <= 1;
                        state <= IDLE;
                    end else if (timeout >= 5000000) begin
                        cmd_error <= 1;
                        state <= IDLE;
                    end else timeout <= timeout + 1;
                end
            endcase
        end
    end

    assign uart_tx_data = cmd_rom[cmd_addr];
    assign uart_tx_start = (state == SEND_CHAR) &&
                           (cmd_rom[cmd_addr] != 8'h00);
endmodule

🧪 AT控制器测试

SystemVerilogat_command_ctrl_tb.sv — AT指令测试台
module at_command_ctrl_tb;
    logic clk=0, rst=1;
    logic [7:0] uart_tx_data;
    logic uart_tx_start, uart_tx_busy=0;
    logic [7:0] uart_rx_data;
    logic uart_rx_valid=0;
    logic cmd_start, cmd_done, cmd_error;
    logic [3:0] cmd_select;
    logic wifi_connected;

    at_command_ctrl uut(.*);
    always #10 clk = ~clk;

    initial begin
        rst=1; #50; rst=0;
        $display("--- AT指令控制器测试 ---");
        // 发送CMD0: AT测试
        cmd_select=0; cmd_start=1; #20; cmd_start=0;
        // 模拟ESP8266回复"OK"
        wait(uart_tx_start); // 等待发送
        wait(cmd_start == 0);
        #1000;
        uart_rx_data=8'h4F; uart_rx_valid=1; #20; uart_rx_valid=0;
        wait(cmd_done);
        $display("  AT命令完成, connected=%b %s",
                 wifi_connected, wifi_connected?"✓":"FAIL");
        $display("AT指令控制器测试完成 ✓");
        #100; $finish;
    end
endmodule

📊 ESP8266 AT指令速查

指令功能响应
AT测试连接OK
AT+RST重启模块ready
AT+CWMODE=1Station模式OK
AT+CWJAP="SSID","PWD"连接WiFiWIFI CONNECTED
AT+CIFSR查询IP+CIFSR:ip
AT+CIPSTARTTCP连接CONNECT
AT+CIPSEND=n发送n字节>
AT+CIPCLOSE关闭连接CLOSED

💡 波特率:ESP8266默认115200,但FPGA用9600更稳定。发送AT+UART_CUR=9600,8,1,0,0切换。建议初始化后立即切换!

练习1:实现完整WiFi连接流程:AT→CWJAP→CIFSR

练习2:通过TCP连接发送VGA坐标数据到PC

练习3:接收PC发来的控制命令(如精灵位置)

练习4:实现HTTP GET请求获取网络时间

练习5:用UDP广播FPGA传感器数据

📶
网络先锋
完成本课练习,让FPGA连上互联网!

🔧 Verilator验证步骤

步骤1verilator --lint-only at_command_ctrl.v

步骤2verilator --binary -j 0 at_command_ctrl.v at_command_ctrl_tb.sv

步骤3./obj_dir/Vat_command_ctrl_tb

🔬 WiFi联网实战

1. 连接WiFi:AT+CWJAP="SSID","PASSWORD" → 等待WIFI CONNECTED

2. TCP客户端:AT+CIPSTART="TCP","ip",port → 发送/接收数据

3. TCP服务器:AT+CIPSERVER=1,8080 → 等待客户端连接

4. UDP广播:AT+CIPSTART="UDP","",port → 广播数据

5. HTTP请求:AT+CIPSTART→AT+CIPSEND→发送GET请求

💡 ESP8266进阶技巧

透传模式:AT+CIPMODE=1 → 数据直通,无需AT前缀

多连接:AT+CIPMUX=1 → 支持5个并发连接

自动连接:AT+CWAUTOCONN=1 → 开机自动连WiFi

OTA升级:AT+CIUPDATE → 远程固件升级

📶 WiFi深入:TCP/IP协议栈

ESP8266内部运行完整的TCP/IP协议栈,FPGA只需发送AT指令就能建立网络连接。理解协议层次有助于调试。

物理层:WiFi射频(2.4GHz, OFDM调制)

MAC层:CSMA/CA冲突避免,WPA2加密

IP层:IPv4地址,DHCP自动获取

TCP层:三次握手建立连接,可靠传输,流控

应用层:HTTP/MQTT/WebSocket,FPGA无需关心

📊 WiFi模块对比

特性ESP8266ESP32W5500
WiFi802.11 b/g/n802.11 b/g/n无(需SPI)
蓝牙BLE 4.2
接口UART/SPIUART/SPI/I2CSPI
TCP连接5168
硬件TCP否(需AT)是(硬TCP/IP)
功耗70~170mA80~240mA150mA
价格¥8¥18¥15

🔬 Verilator仿真

1. lintverilator --lint-only at_command_ctrl.v

2. 编译verilator --binary -j 0 --trace at_command_ctrl.v at_command_ctrl_tb.sv

3. 运行./obj_dir/Vat_command_ctrl_tb