Clion开发STM32之ESP8266系列(四)

前言

上一篇: Clion开发STM32之ESP8266系列(三)

本篇主要内容

  1. 实现esp8266需要实现的函数
  2. 串口3中断函数的自定义(这里没有使用HAL提供的)
  3. 封装esp8266服务端的代码和测试

正文

主要修改部分

核心配置头文件(添加一些宏定义)

  1. sys_core_conf.h文件中

Clion开发STM32之ESP8266系列(四)_第1张图片

Clion开发STM32之ESP8266系列(四)_第2张图片

实现esp8266需要实现的函数

Clion开发STM32之ESP8266系列(四)_第3张图片

源码

/*******************************************************************************
 * @author scl
 * @email [email protected]
 *      @brief 实现esp8266的驱动
 ******************************************************************************/
#include "module_esp8266.h"
#include "bsp.h"

extern data_frame_t esp_rx_frame;

static void sys_delay(uint32_t ms) {
    HAL_Delay(ms);
}

/**
 * @brief esp8266 驱动外设初始化
 */
void esp8266_driver_init() {
    /*设置系esp8266延时回调*/
    esp8266_set_delay_call(sys_delay);
    /*配置 CH_PD 引脚*/
    gpio_init(GPIOB, GPIO_PIN_8, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH);
    /* 配置 RST 引脚*/
    gpio_init(GPIOB, GPIO_PIN_9, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH);
    /*串口配置*/
    com3_init(115200);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8 | GPIO_PIN_9, GPIO_PIN_SET);
    /*开启串口中断*/
    UART_ENABLE_IT(USART3, UART_IT_RXNE);    /** 开启串口中断*/
    UART_ENABLE_IT(USART3, UART_IT_IDLE);   /** 开启串口空闲中断*/
}

/**
 * @brief esp8266 复位引脚
 * @param flag true: 置高; false: 置低
 */
void esp8266_rst_pin(bool flag) {
    if (flag) {
        pin_high(GPIOB, GPIO_PIN_9);
    } else {
        pin_low(GPIOB, GPIO_PIN_8);
    }
}

/**
 * @brief esp8266 使能引脚
 * @param flag true: 使能
 */
void esp8266_ch_enable(bool flag) {
    if (flag) {
        pin_high(GPIOB, GPIO_PIN_8);
    } else {
        pin_low(GPIOB, GPIO_PIN_8);
    }
}


/**
 * @brief esp8266 发送数据
 * @param data
 * @param len
 */
void esp8266_send(void *data, uint16_t len) {
    HAL_UART_Transmit(com_handle_get(com3), data, len, 1000);
}

/**
 * @brief 清空接收缓冲区
 */
void esp8266_clear_buf(void) {
    esp_rx_frame.InfAll = 0;
}

/**
 * @brief esp8266 接收数据
 * @return 接收数据
 */
char *esp8266_rec() {
    if (esp_rx_frame.InfBit.frame_finished_flag != 0) {
        /*添加结束符*/
        esp_rx_frame.p_rx_buf[esp_rx_frame.InfBit.frame_len] = '\0';
        esp_rx_frame.InfAll = 0;// 清除一次标志位
        return esp_rx_frame.p_rx_buf;
    }
    return NULL;
}

/**
 * @brief esp8266 构造指令的缓存区
 * @return
 */
char *esp8266_get_cmd_buf() {
    static char esp8266_buf[200] = {0};
    return esp8266_buf;
}

对应的串口3中断函数的编写

Clion开发STM32之ESP8266系列(四)_第4张图片

extern data_frame_t esp_rx_frame;

static inline void esp8266_tcp_server_IRQHandler() {
    uint8_t ucTemp;
    if (UART_GET_FLAG(USART3, UART_FLAG_RXNE)) {
        ucTemp = READ_REG(USART3->DR);// 读取数据
        if (esp_rx_frame.InfBit.frame_len < (esp_rx_frame.rx_buf_len - 1)) {
            esp_rx_frame.p_rx_buf[esp_rx_frame.InfBit.frame_len++] = ucTemp;
        }
    }
    //数据帧接收完毕
    if (UART_GET_FLAG(USART3, UART_FLAG_IDLE)) {
        esp_rx_frame.InfBit.frame_finished_flag = 1;
        // 添加结束符
        esp_rx_frame.p_rx_buf[esp_rx_frame.InfBit.frame_len] = '\0';
        //由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)
        _UART_CLEAR_PEFLAG(USART3);
    }
}

void USART3_IRQHandler(void) {
    /* HAL库中断处理函数*/
    // HAL_UART_IRQHandler(&com3_handle);
    /* 自定义中断处理函数*/
    esp8266_tcp_server_IRQHandler();
}

封装esp8266服务端的代码(针对驱动层再进行一个封装)

头文件

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/

#ifndef STM32F103VET6_ESP8266_ESP8266_SERVICE_H
#define STM32F103VET6_ESP8266_ESP8266_SERVICE_H

#include "service_include.h"
/*wifi 账号*/
#define WIFI_SSID "账号"
/*wifi 密码*/
#define WIFI_PWD "密码"
/*尝试执行次数*/
#define TRY_CNT 3
/*本地IP配置*/
#define LOCAL_SERVER_IP "192.168.199.12"
/*本地端口配置*/
#define LOCAL_SERVER_PORT 8000
/*宏定义调试日志*/
#define esp_ps(fmt, ...) os_ps(fmt,##__VA_ARGS__)
/*************************************ESP 服务端 STA模式**********************************************/
/**
 * @brief esp8266 在sta模式下初始化 sever
 * @return
 */
bool esp_sta_tcp_server_init(void);
/**
 * @brief esp8266 在sta模式下获取ip
 * @param dstIp 保存ip
 * @param len  dstIp的长度
 * @return
 */
bool esp_sta_tcp_server_get_ip(char *dstIp, uint8_t len);
/**
 * @brief esp8266 客户端请求处理
 * @param data 接收的数据
 * @param len  数据长度
 * @return
 */
bool esp_sta_tcp_server_request_handle(char *data, uint16_t len);

#endif //STM32F103VET6_ESP8266_ESP8266_SERVICE_H

源文件

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/

#include "esp8266_service.h"
#include "module_esp8266.h"
#include "bsp.h"

/**
 * @brief 禁止接收数据(静态内联函数)
 */
sys_force_static_inline void esp_disable_rec() {
    UART_DISABLE_IT(USART3, UART_IT_RXNE);
}

sys_force_static_inline void esp_enable_rec() {
    UART_ENABLE_IT(USART3, UART_IT_RXNE);
}

bool esp_sta_tcp_server_init(void) {
    esp_ps("--esp_sta_tcp_server_init start---\r\n");
    /*使能信号*/
    esp8266_ch_enable(true);
    /*测试AT指令*/
    try_cnt_run (esp8266_base_at_cmd_test(10, 500), 1);
    esp_ps("esp8266_base_at_cmd_test ok\r\n");
    /*动态分配IP地址*/
    try_cnt_run(esp8266_dhcp_cur_set(sta_mode, true, -1), TRY_CNT);
    /* 设置为STA模式 */
    try_cnt_run(esp8266_wifi_mode_cur_set(sta_mode, -1), TRY_CNT);
    esp_ps("esp8266_mode_cur_set ok\r\n");
    /* 设备本地设备ip*/
    try_cnt_run(esp8266_ip_sta_cur_set(LOCAL_SERVER_IP, NULL, NULL, -1), TRY_CNT);
    esp_ps("esp8266_ip_sta_cur_set ok\r\n");
    /*连接WiFi*/
    try_cnt_run (esp8266_wifi_join_cur_set(WIFI_SSID, WIFI_PWD, NULL, -1), TRY_CNT);
    esp_ps("esp8266_wifi_join_cur_set ok\r\n");
    /*允许多连接*/
    try_cnt_run (esp8266_mul_connect_set(true, -1), TRY_CNT);
    esp_ps("esp8266_mul_connect_set ok\r\n");
    /*开启服务器模式*/
    try_cnt_run (esp8266_server_tcp_start(true, LOCAL_SERVER_PORT, -1), TRY_CNT);
    esp_ps("esp8266_server_tcp_start ok\r\n");
    /*设置服务器链接超时时间*/
    try_cnt_run (esp8266_server_tcp_timeout_set(20, -1), TRY_CNT);
    esp_ps("esp8266_server_tcp_timeout_set ok\r\n");

    esp_ps("--esp_sta_tcp_server_init end---\r\n");

    return true;
}

bool esp_sta_tcp_server_get_ip(char *dstIp, uint8_t len) {
    esp_ps("--esp_sta_tcp_server_get_ip start---\r\n");
    try_cnt_run (esp8266_ip_sta_inquire(dstIp, len, -1), TRY_CNT);
    esp_ps("--esp_sta_tcp_server_get_ip end---\r\n");
    return true;
}
/**
 * @brief 解析接收的数据
 * @param rec_data 接收的数据
 * @param no_id socket id
 * @param data_len 发送的数据长度
 * @return 实际数据的位置
 */
sys_force_static_inline char *parse_rec_data(char *rec_data, uint8_t *no_id, uint16_t *data_len) {
    static char *pre_str = "+IPD,";
    char *p_data = strstr(rec_data, pre_str);
    // 数据解析错误 +IPD,0,2:12
    if (!p_data) return false;
    /*跳过前缀*/
    p_data += strlen(pre_str);
    /*解析socket id 号*/
    *no_id = strtol(p_data, &p_data, 10);
    if (!*p_data) return false;
    /*解析数据长度 */
    *data_len = strtol(p_data + 1, &p_data, 10);
    if (!*p_data) return false;
    /*获取数据*/
    p_data += 1;
    return p_data;
}

bool esp_sta_tcp_server_request_handle(char *data, uint16_t len) {
    /* 禁止esp多个客户端同时发送数据 */
    uint16_t data_len = 0;/*实际客户端发送的数据长度*/
    uint8_t socket_id;/*实际客户端连接的端口号*/
    bool result_flag = true;
    /*禁止接收,保证同一时间只只处理一个请求 */
    esp_disable_rec();
    /*实际客户端发送的数据位置*/
    char *p_data = parse_rec_data(data, &socket_id, &data_len);
    if (p_data) {
        // todo 这里就是做业务逻辑控制的地方,目前只是回显
        esp_ps("parse_rec_data:%d %d %s\r\n", socket_id, data_len, p_data);
        if (esp8266_server_tcp_send_to(socket_id, p_data, data_len, -1)) {
            esp_ps("response ok\r\n");
        } else {
            esp_ps("response error\r\n");
        }
    } else {
        result_flag = false;
    }
    /*清除这次的请求数据,保证下次数据为最新的*/
    esp8266_clear_buf();
    /*开启请求,保证同一时间只只处理一个请求 */
    esp_enable_rec();
    return result_flag;
}

esp8266驱动配置文件的编写

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/
#include "app_conf.h"
#include "module_esp8266.h"
#include "service.h"

/*创建数据接收帧*/
static char rx_buf[1024] = {0};
data_frame_t esp_rx_frame = {.p_rx_buf=rx_buf, .rx_buf_len=1024};

static void driver_init(void) {
    /*esp8266初始化*/
    esp8266_driver_init();
}




/*这句话就是将驱动导出到段中*/
DRIVER_EXPORT(esp8266_driver, driver_init);


/**
 * 测试阶段暂时使用此方法
 * */
void app_run() {
    if (esp_sta_tcp_server_init()) {
        os_ps("--esp_sta_tcp_server_init ok--\r\n");
        while (1) {
            if (esp_rx_frame.InfBit.frame_finished_flag) {
                esp_sta_tcp_server_request_handle(esp_rx_frame.p_rx_buf, esp_rx_frame.InfBit.frame_len);
            }
        }
    } else {
        os_ps("--esp_sta_tcp_server_init error--\r\n");
    }


}

代码测试

  1. 本次设置esp8266模块的IP为192.168.199.12,端口号为8000

主入口函数调整

Clion开发STM32之ESP8266系列(四)_第5张图片### 下载程序

观察日志记录

Clion开发STM32之ESP8266系列(四)_第6张图片

用客户端去连接192.168.199.12:8000

Clion开发STM32之ESP8266系列(四)_第7张图片

客户端

Clion开发STM32之ESP8266系列(四)_第8张图片

查看串口

  1. 接收数据正常

Clion开发STM32之ESP8266系列(四)_第9张图片
Clion开发STM32之ESP8266系列(四)_第10张图片

结尾

  1. ESP8266系列的章节也就更新完成,目前基础功能模板工程已经完。
  2. 目前可以根据此工程执行对应的指令控制的逻辑了。
  3. 后续在此基础之上设计一个指令集动态加载服务器接收处理和响应的框架。
  4. 完整的项目已上传到gitee,有需要自行查看开头结尾的git地址.

下个系列的目标

  1. 整合Freertos
  2. 整合Modbus协议和自定义协议框架

你可能感兴趣的:(STM32从0开始记录,stm32,单片机,嵌入式硬件)