这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】+与同事对ESP-12开发调试经验分享

共11条 1/2 1 2 跳转至

【换取手持数字示波器】+与同事对ESP-12开发调试经验分享

工程师
2024-03-21 19:40:09   被打赏 50 分(兑奖)     打赏

进行这个之前首选要知道几个理解知识和工具。

下面是当时找的相关文档和资料连接:

ESP8266笔记 ---- 常用AT指令_esp8266 at-CSDN博客

esp8266WIFI模块教程:正点原子ATK-ESP8266进行网络通信,单片机与电脑,单片机与手机发送数据_正点原子esp8266-CSDN博客

【常用模块】ESP8266 WIFI串口通信模块使用详解(实例:附STM32详细代码)_正点原子wifiesp8266提供代码-CSDN博客

最有用的是乐鑫官方给的AT指令操作示例:

TCP-IP AT 示例 - ESP32 - — ESP-AT 用户指南 latest 文档 (espressif.com)

首先说说AT指令:

AT指令,也称为Attention指令,是应用于终端设备与PC应用之间的连接与通信的指令。这些指令是从终端设备(Terminal Equipment,TE)或数据终端设备(Data Terminal Equipment,DTE)向终端适配器(Terminal Adapter,TA)或数据电路终端设备(Data Circuit Terminal Equipment,DCE)发送的。AT指令主要用于控制移动台(Mobile Station,MS)的功能,与GSM网络业务进行交互。

工具:串口工具(调试助手),网络调试助手。

下面了解一下当时使用的WIFI模块:

https://docs.ai-thinker.com/_media/esp8266/docs/esp-12f_product_specification_zh_v1.0.pdf

型号:安信可ESP-12F。

模块的定义与尺寸图:

image.png

引脚定义:

image.png

模组启动模式:

1711020474473.jpg

推荐的电路连接方式(正常工作模式)

1711020497303.jpg


下载步骤:

下载模式需要把只需要把GPIO0接到地,rst先浮空,配置好flash下载软件之后,先点击擦除,之后会等待上电复位,将rst用杜邦线触碰一下地,即可开始烧录,此时等待烧录完毕,将GPIO接到高电平,重新上电即可正常使用AT指令集。

连接调试示意图:

1711020595809.jpg

使用串口助手操作时的相关信息显示:

1711020660351.jpg

当前程序具备收发功能,请注意,由于我的编程习惯可能不够规范,代码可能显得有些凌乱,建议仔细阅读和理解代码逻辑。

本程序在开发过程中参考了正点原子的代码,在使用串口助手进行调试时,务必确保所有发送的指令后都加上换行符。这是AT指令集的规定,如果不加换行符,指令将无法正确执行,并返回错误提示。

网络调试助手需设置为TCP服务器模式。在选择服务器的IP地址时,请确保它与wifi芯片所分配的IP地址处于同一网段。例如,如果通过查询得到的IP地址是192.168.137.89,掩码是255.255.255.0,那么服务器的IP地址前三个数字也应为192.168.137。设置好IP地址后,您可以在网络调试助手中选择相应的IP号,并使用默认的通道号进行通信。

TCP/IP是网络通信的基础协议,对于理解和使用网络通信至关重要。虽然在这里只需简要了解,但建议深入学习TCP/IP协议的相关知识,以便更好地进行网络编程和调试。

在完成上述注意点的检查和调整后,您可以重新生成程序,确保所有设置和配置都已正确无误,然后进行测试和验证。

1711020792311.jpg

1711020814976.jpg

当时测试时使用的开发板与wifi串口芯片:

1711020857441.jpg

连接参考图:

image.png


可以正常运行的代码:

void mywifi_uart_init(void)
{
    // GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能USART2,GPIOA时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    // USART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);          // 初始化GPIOA.2

    // USART1_RX	  GPIOA.10初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;             // PA3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                // 初始化GPIOA.3

    // Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        // 子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);                           // 根据指定的参数初始化VIC寄存器

    // USART 初始化设置
    USART_InitStructure.USART_BaudRate = 115200;                                    // 串口波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     // 字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                          // 一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;                             // 无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 // 收发模式

    USART_Init(USART2, &USART_InitStructure);      // 初始化串口2
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 开启串口接受中断
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 开启串口空闲中断
    USART_Cmd(USART2, ENABLE);                     // 使能串口1
}

/**
 * @description: 给wifi芯片传输指定长度数据
 * @param {char} *data 传输数据
 * @param {u8} len 传输数据长度
 * @return {*}
 */
void mywifi_send_nbytes(char *data, u8 len)
{
    for (int i = 0; i < len; i++)
    {
        USART_SendData(USART2, data[i]); // 发送测试
        while (!USART_GetFlagStatus(USART2, USART_FLAG_TC))
            ; // 等待发送完成
    }
}

/**
 * @description: wifi发送数据
 * @param {char} *cmd数据
 * @param {char} *ack期待的应答
 * @param {u32} timeout超时
 * @param {u8} len数据长度
 * @return {*}
 */
u8 mywifi_send_at_cmd(char *cmd, char *ack, u32 timeout, u8 len)
{
    char *ret = NULL; // 用于接收数据

    //    atk_mw8266d_uart_rx_restart();
    // 正点原子有一个硬件复位的过程,这里没设置了,
    mywifi_send_nbytes(cmd, len);

    if ((ack == NULL) || (timeout == 0))
    {
        return MYWIFI_OK;
    }
    else
    {
        while (timeout > 0)
        {

            if (mywifi_recv_data(ret))
            {
                if (strstr((const char *)mywifi_recv_buf, ack) != NULL) // ack 作为子串去查询
                {
                    // mywifi_send_nbytes(mywifi_recv_buf, sizeof(mywifi_recv_buf));
                    return MYWIFI_OK;
                }
                else
                {
                    // 不同则复位
                    // atk_mw8266d_uart_rx_restart();
                }
            }
            timeout--;
            delay_ms(1);
        }

        return MYWIFI_ERROR; // 这里代表超时
    }
}

/**
 * @description: 接收数据
 * @param {char} *data
 * @return {*} 返回当前是否完成了数据接收
 */
u8 mywifi_recv_data(char *data)
{
    char temp[MAX_LENGTH] = {0}; // 测试使用
    if (rev_finish_flag == 1)
    {
        // 当前接收完成
        data = mywifi_recv_buf; // 先预留的,目前我没有用到
        strncpy(temp, mywifi_recv_buf, receive_number);
        rev_finish_flag = 0;
        receive_number = 0;
        //        printf("the rec data : \r\n");
        //        printf("%s", temp);
        return 1;
    }
    else
        return 0;
}

/**
 * @description: wifi自检测
 * @return {*} 自检成功返回1
 */
u8 mywifi_self_test(void)
{
    char test[] = {"AT\r\n"};
    char ack[] = {"OK"};
    u8 flag = 0;
    for (u8 i = 0; i < 50; i++)
    {
        flag = mywifi_send_at_cmd(test, (char *)ack, 20, sizeof(test) / sizeof(test[0]));
        char temp[MAX_LENGTH] = {0};
        while (strstr((const char *)temp, "busy") != NULL) // 等待忙完成
        {
            // 等待不忙,才执行后面的,这里写的有点问题,没有达到预期的效果
            memset(temp, 0, MAX_LENGTH);
            strncpy(temp, mywifi_recv_buf, temp_rec_num);
            flag = mywifi_send_at_cmd(test, (char *)ack, 20, sizeof(test) / sizeof(test[0]));
            rev_finish_flag = 0;
            temp_rec_num = 0;
            // 开机都忙等待的话直接给它硬件复位
        }
        if (flag)
            return flag;
    }
    return flag; // 自检测5次,最后一次成功表示成功
}

/**
 * @description: wifi软件重启,这个操作在自检测成功之后
 * @return {*}
 */
char soft_rst[] = {"AT+RST\r\n"};
void mywifi_soft_rst(void)
{
    mywifi_send_at_cmd(soft_rst, NULL, 20, sizeof(soft_rst) / sizeof(soft_rst[0]));
}

/**
 * @description: WiFi回显开关
 * @param {u8} flag
 * @return {*}
 */
char polldispaly0[] = {"ATE0\r\n"};
char polldispaly1[] = {"ATE1\r\n"};
void mywifi_polldispaly(u8 flag)
{
    mywifi_send_at_cmd(flag ? polldispaly0 : polldispaly1, "OK", 20, sizeof(polldispaly0) / sizeof(polldispaly0[0]));
}

/**
 * @description: wifi设置工作模式,站点模式 Or AP模式
 * @param {u8} mode 1表示设置为站点模式
 * @return {*}
 */
char set_mode0[] = {"AT+CWMODE=0\r\n"};
char set_mode1[] = {"AT+CWMODE=1\r\n"};
void mywifi_set_mode(u8 mode)
{
    mywifi_send_at_cmd(mode ? set_mode1 : set_mode0, "OK", 20, sizeof(set_mode0) / sizeof(set_mode0[0]));
}

/**
 * @description: 芯片连接到热点,这里我默认是我电脑的热点
 * @return {*}
 */
char connecet_host[] = {"AT+CWJAP=\"mldesk\",\"12345671\"\r\n"};
bool mywifi_connect_host(void)
{
    mywifi_send_at_cmd(connecet_host, "OK", 4000, sizeof(connecet_host) / sizeof(connecet_host[0]));
    delay_ms(4000);
    return true;
}

/**
 * @description: 获取wifi连接获取的ip地址
 * @return {*}
 */
char get_ip[] = {"AT+CIPSTA?\r\n"};
void mywifi_get_ip(void)
{
    char temp[MAX_LENGTH] = {0};
    while (strstr((const char *)temp, "OK") == NULL)
    {
        // 等待不忙,才执行后面的
        memset(temp, 0, MAX_LENGTH);
        strncpy(temp, mywifi_recv_buf, temp_rec_num);
        rev_finish_flag = 0;
        temp_rec_num = 0;
    }
    mywifi_send_at_cmd(get_ip, NULL, 2000, sizeof(get_ip) / sizeof(get_ip[0]));
    delay_ms(1000);
    // 获取ip号先保存起来之后使用,这个打来之后是会调硬件错误的,可能是数组超了
    //    if (rev_finish_flag == 1)
    //    {
    //        // 当前接收完成
    //        u8 i = 0;
    //        rev_finish_flag = 0;

    //        for (; i < temp_rec_num; i++)
    //        {
    //            if ((mywifi_recv_buf[i] == 0x69) && (mywifi_recv_buf[i + 1] == 0x70))
    //                break;
    //        }
    //        // 找到了ip地址的位置
    //        memset(temp, 0, MAX_LENGTH);
    //        strncpy(temp, mywifi_recv_buf + i + 4, 15);
    //        temp_rec_num = 0;
    //        //printf("%s",temp);
    //    }
}

/**
 * @description: 判断热点是否连接
 * @return {*}
 */
bool mywifi_judge_host_connect(void)
{
    if ((strstr((const char *)mywifi_recv_buf, "CONNCETED") != NULL) ||
        (strstr((const char *)mywifi_recv_buf, "GOT") != NULL))
    {
        printf("\r\nconnecet_host ok\r\n");
        // 成功之后设置相应的标志位,比如可以用来连接tcp服务器
        wifi_connect_flag = 1; // wifi 连接成功

        return true;
    }
    else if ((strstr((const char *)mywifi_recv_buf, "DISCONNECT") != NULL))
    {
        printf("\r\nconnecet_host error\r\n");
        // 失败时候需要将相应标志位清除,显示连接丢失
        wifi_connect_flag = 0; // wifi 连接失败
        return false;
    }
    return false;
}

/**
 * @description: wifi芯片作为client 连接到服务器
 * @return {*}
 */
char connecet_sever[] = {"AT+CIPSTART=\"TCP\",\"192.168.137.1\",8080\r\n"};
void mywifi_connect_sever(void)
{
    if (wifi_connect_flag) // 需要保证wifi连接成功之后设置tcpip单路连接
    {
        char temp[MAX_LENGTH] = {0};
        while (strstr((const char *)temp, "OK") == NULL)
        {
            // 等待上一次指令完成,才执行后面的
            memset(temp, 0, MAX_LENGTH);
            strncpy(temp, mywifi_recv_buf, temp_rec_num);
            rev_finish_flag = 0;
            temp_rec_num = 0;
        }
        mywifi_send_at_cmd(connecet_sever, "OK", 2000, sizeof(connecet_sever) / sizeof(connecet_sever[0]));
        delay_ms(1000);
    }
}

/**
 * @description: 设置透传模式
 * @param {u8} flag 1 表示透传 0 表示关闭透传发送+++
 * @return {*}
 */
char open_transparent[] = {"AT+CIPMODE=1\r\n"};
char close_transparent[] = {"AT+CIPMODE=0\r\n"};
char send_data_cmd[] = {"AT+CIPSEND\r\n"};
char fade_transparent[] = {"+++"};
void mywifi_set_transparent(u8 flag)
{
    if (flag)
    {
        mywifi_send_at_cmd(open_transparent, "OK", 200, sizeof(open_transparent) / sizeof(open_transparent[0]));
        delay_ms(1000);
        mywifi_send_at_cmd(send_data_cmd, ">", 200, sizeof(send_data_cmd) / sizeof(send_data_cmd[0]));
    }
    else
    {
        delay_ms(2000);            // 需要等待一秒,结束透传
        mywifi_char_printf("+++"); // 发送结束标志
        delay_ms(4000);            // 需要等待一秒,结束透传
        mywifi_send_at_cmd("\r\n", NULL, 200, 0);
        mywifi_send_at_cmd(close_transparent, "OK", 200, sizeof(close_transparent) / sizeof(close_transparent[0]));
        mywifi_close_tcp_connection(); // 断开tcp连接
    }
}

/**
 * @description: 通过透传模式进行输出传输
 * @param {u8} *data
 * @param {u8} len
 * @return {*}
 */

void mywifi_data_send(u8 *data, u8 len)
{
    if (wifi_connect_flag) // 需要保证wifi连接成功,服务器连接成功,才能进行输出传输
    {
        mywifi_send_at_cmd(data, NULL, 0, len); // 数据发送,需要等待
    }
}

/**
 * @description: 断开tcp连接
 * @return {*}
 */
char close_tcp[] = {"AT+CIPCLOSE\r\n"};
void mywifi_close_tcp_connection(void)
{
    mywifi_send_at_cmd(close_tcp, "OK", 200, sizeof(close_tcp) / sizeof(close_tcp[0]));
}

/**
 * @description: 判断是否结束透传,需要通过服务器发送+++,判断
 * @return {*}
 */
void mywifi_judge_tranfer_end(void)
{
}

/**
 * @description: 用于打印+++,推出透传模式
 * @param {char} *fmt
 * @return {*}
 */
void mywifi_char_printf(char *fmt, ...)
{
    va_list ap;
    uint16_t len;
    char cmd[MAX_LENGTH] = {0};

    va_start(ap, fmt);
    vsprintf((char *)cmd, fmt, ap);
    va_end(ap);

    len = strlen((const char *)cmd);
    mywifi_send_nbytes(cmd, len);
}

/**
 * @description: 串口2中断回调函数
 * @return {*}
 */
void USART2_IRQHandler()
{
    static char res; // 静态变量防止堆栈溢出
    static u32 temp;
    char temp1[MAX_LENGTH] = {0}; // 静态变量防止堆栈溢出
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        res = USART_ReceiveData(USART2);  // 读取接收到的数据
        if (receive_number >= MAX_LENGTH) // 防止刷爆
            receive_number = MAX_LENGTH - 1;
        mywifi_recv_buf[receive_number] = res;
        receive_number++;
        USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    }
    if (USART_GetFlagStatus(USART2, USART_FLAG_IDLE) != RESET) // 命中空闲中断
    {
        /*---------------使用串口1打印从wifi芯片接收到的数据--------*/
        strncpy(temp1, mywifi_recv_buf, receive_number);
        temp_rec_num = receive_number;
        printf("%s", temp1);
        /*----------------end-------------------------------------*/
        rev_finish_flag = 1;
        // 判断wifi是否断开连接
        mywifi_judge_host_connect();
        // 判断服务器是否断开连接
        // ------还没实现,可以通过各个指令不同的返回值去判定

        // 下面这个操作是必要的,清除空闲中断标志位
        temp = USART2->SR;
        temp = USART2->DR;
        USART_ClearITPendingBit(USART2, USART_IT_IDLE); // 清除空闲中断标志位
        receive_number = 0;
    }
}




专家
2024-03-21 20:26:19     打赏
2楼

感谢分享


专家
2024-03-24 07:28:59     打赏
3楼

谢谢分享


高工
2024-03-25 06:28:28     打赏
4楼

感谢分享


助工
2024-03-25 09:26:53     打赏
5楼

感谢分享


高工
2024-03-25 09:31:16     打赏
6楼

太棒了   正好需要  感谢分享


工程师
2024-03-26 16:26:31     打赏
7楼

学习了,谢谢分享。


高工
2024-03-26 16:27:30     打赏
8楼

学习了,谢谢分享


高工
2024-03-26 16:33:26     打赏
9楼

感谢分享


高工
2024-03-26 16:37:41     打赏
10楼

感谢分享


共11条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]