HT32芯片用ESP8266连接ONENET出现了发送数据的时候无法收到下达命令

HT32芯片,使用ESP8266连接ONENET出现了发送数据的时候无法收到下达命令。

        while(1)
    {
        delay_s(1);
        if(timeset==5)
        {
      OLED_ShowString(20,3,(unsigned char *)"C_T:",3); // Current_Temperature 当前温度
      OLED_ShowCHinese_Three(80,3,11); //C        
      OLED_ShowString(20,5,(unsigned char *)"C_H:",3); // Current_Humidity 当前湿度
      OLED_ShowCHinese_Three(80,5,13); //.
      dou_dht11_get_data();//获取温度数据
      OLED_ShowNum(50,3,T_H/10,3,3);
      OLED_ShowNum(60,3,T_H%10,3,3); 
      OLED_ShowNum(50,5,H_H/10,3,3);
      OLED_ShowNum(60,5,H_H%10,3,3);
        delay_s(1);
        dou_dht11_get_data();
        delay_s(1);
        //printf("hum temp=%d .%d %d .%d\r\n",H_H,H_L,T_H,T_L);
      //printf( "OneNet_SendData\r\n");//通过串口1发送提示信息(要开始发送数据了)
        OneNet_SendData();//发送数据给onenet
        printf("send_data_end\n");
        ESP8266_Clear();
      timeset=0;
        }
        dataPtr = ESP8266_GetIPD(0);//获取平台返回的数据
        if(dataPtr != NULL)//如果返回数据不为空
        {
        OneNet_RevPro(dataPtr);//平台返回数据检测        
        }
    else
        {
            printf("NO REV");
        }            
  delay_s(1);
  timeset++;        
        
    }

该代码在注释掉

        OneNet_SendData();//发送数据给onenet
        printf("send_data_end\n");
        ESP8266_Clear();

可以正常工作,单片机可以接收来自ONENET的指令。
保持原代码的情况,单片机可以正常向ONENET发送指令,但是无法接收指令。
同时保存两行代码的时候,单片机似乎接受不到指令,而且出现部分回应Tips: MQTT Publish Send OK
HT系列芯片似乎没有配置NVIC的初始化函数以及关于控制中断优先级的函数。个人怀疑是中断优先级引起的问题。
部分配置

unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{

    char *ptrIPD = NULL;
    
    do
    {
        if(ESP8266_WaitRecive() == REV_OK)                                //如果接收完成
        {
            ptrIPD = strstr((char *)esp8266_buf, "IPD,");                //搜索“IPD”头
            if(ptrIPD == NULL)                                            //如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
            {
                UsartPrintf(USART_DEBUG, "\"IPD\" not found\r\n");
            }
            else
            {
                ptrIPD = strchr(ptrIPD, ':');                            //找到':'
                if(ptrIPD != NULL)
                {
                    ptrIPD++;
                    return (unsigned char *)(ptrIPD);
                }
                else
                    return NULL;
                
            }
        }
        
        delay_ms(5);                                                    //延时等待
    } while(timeOut--);
    
    return NULL;                                                        //超时还未找到,返回空指针

}

初始化


void ESP8266_Init(void)
{
    
    CKCU_PeripClockConfig_TypeDef CKCUClock= {{0}};
    CKCUClock.Bit.PC=1;
    CKCU_PeripClockConfig(CKCUClock, ENABLE);
    
    GPIO_DirectionConfig(HT_GPIOC, ESP8266_RST, GPIO_DIR_OUT); //设置PC5为输出
    WIFI_Clr();

    delay_ms(250);
    WIFI_Set();
    delay_ms(500);
    
    ESP8266_Clear();

    UsartPrintf(USART_DEBUG, "1. AT\r\n");
    while(ESP8266_SendCmd("AT\r\n", "OK"))
        delay_ms(500);
    
    UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
    while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
        delay_ms(500);
    
    UsartPrintf(USART_DEBUG,"3. AT+CWDHCP\r\n");
    while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
        delay_ms(500);
    
    UsartPrintf(USART_DEBUG, "3. CWJAP\r\n");
    while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
        delay_ms(500);
    
    UsartPrintf(USART_DEBUG, "4. CIPSTART\r\n");
    while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
        delay_ms(500);
    
    
    UsartPrintf(USART_DEBUG, "5. ESP8266 Init OK\r\n");

}

发送相关


unsigned char OneNet_FillBuf(char *buf)
{
    //定义需要发送的数据
    
    char text[32];
    int BUZZER_FLAG;
    BUZZER_FLAG=GPIO_ReadOutBit(HT_GPIOC, GPIO_PIN_1);
    //在这里添加需要发送的封包
    memset(text, 0, sizeof(text));
    strcpy(buf, ",;");
    //添加处
    memset(text, 0, sizeof(text));//控制1
  sprintf(text,"B,%d;",BUZZER_FLAG);
  strcat(buf, text);
    
    memset(text, 0, sizeof(text));
    //sprintf(text, "Tempreture,%d.%d;",T_H,T_L);
    sprintf(text,"Hu,%d.%d;",H_H,H_L);//湿度
    strcat(buf, text);
    
    memset(text, 0, sizeof(text));
    //sprintf(text, "Humidity,%d.%d;",H_H,H_L);
    sprintf(text,"Te,%d.%d;",T_H,T_L);//温度
    strcat(buf, text);
    
    printf("buf_mqtt=%s\r\n",buf);
    return strlen(buf);

}

//==========================================================
//    函数名称:    OneNet_SendData
//
//    函数功能:    上传数据到平台
//
//    入口参数:    type:发送数据的格式
//
//    返回参数:    无
//
//    说明:        
//==========================================================
void OneNet_SendData(void)
{
    
    MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};                                                //协议包
    
    char buf[128];//128
    
    short body_len = 0, i = 0;
    
    printf( "Tips:    OneNet_SendData-MQTT\r\n");
    
    memset(buf, 0, sizeof(buf));//清空数组内容
    
    body_len = OneNet_FillBuf(buf);                                                                    //获取当前需要发送的数据流的总长度
    
    if(body_len)
    {
        if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0)                            //封包
        {
            for(; i < body_len; i++)
                mqttPacket._data[mqttPacket._len++] = buf[i];
            
            ESP8266_SendData(mqttPacket._data, mqttPacket._len);                                    //上传数据到平台
            printf( "Send %d Bytes\r\n", mqttPacket._len);
            
            MQTT_DeleteBuffer(&mqttPacket);                                                            //删包
        }
        else
            printf(  "WARN:    EDP_NewBuffer Failed\r\n");
    }
    
}

非常疑惑,尝试了很多方法没有解决,希望高人指点。

该回答引用于ChatGPT:
这个问题可能是由于发送数据和接收数据的代码之间存在竞争条件导致的。具体来说,当发送数据的函数OneNet_SendData()在执行时,单片机的CPU需要花费一定时间来等待数据被从ESP8266模块发送出去并得到ONENET平台的响应。在这段时间内,如果有新的指令到达,单片机将无法立即进行处理,因为它正在等待当前的数据传输完成。

要解决这个问题,可以尝试使用中断或多线程编程技术来实现异步处理。例如,您可以使用一个单独的线程或中断服务程序来接收来自ONENET平台的指令,并将其放入一个缓冲区中。然后,在主循环中,您可以检查该缓冲区是否有新的指令,并根据需要执行相应的操作。这种方式可以避免发送数据和接收指令之间的竞争条件,从而提高系统的响应能力。

另外,要确保发送数据的函数OneNet_SendData()能够快速地返回,而不会占用CPU太长的时间。您可以考虑使用DMA(Direct Memory Access)或硬件加速技术来提高数据传输的效率,以减少对CPU的占用。

最后,请确保您的中断优先级正确设置,并且不会阻塞或延迟其他重要的中断处理。在HT32芯片中,您可以使用NVIC模块来设置和管理中断优先级。请注意,不同的外设有不同的中断优先级分配规则,因此请仔细查阅相关文档,并根据需要进行调整。

由于您的代码涉及到许多具体的细节,我无法直接为您提供一份完整的解决方案。不过,以下是一些可能有用的建议:

  1. 调试串口输出

在需要调试的地方添加一些调试串口输出语句(例如“Entering function XYZ”或“Variable ABC is now equal to 123”等),以便更好地了解程序正在做什么。这样可以帮助您快速定位问题所在,并且可以检查程序是否按照您预期的方式运行。

  1. 使用延时函数

如果您使用了延时函数来等待数据传输完成,请确保您使用的延时时间足够长,以免数据还没有完全发送就开始等待响应。最好使用一个比较精确的延时函数,例如基于系统时钟的定时器或者循环延时函数。

  1. 检查缓冲区溢出

请确保缓冲区的大小足够大,能够容纳所有可能的接收数据。如果缓冲区太小,可能会导致数据溢出并覆盖其他内存区域,从而引起崩溃或其他错误。另外,建议使用循环缓冲区,以确保接收数据时不会阻塞主循环。

  1. 检查中断优先级

确保您的中断优先级设置正确,并且不会阻塞或延迟其他重要的中断处理。在HT32芯片中,您可以使用NVIC模块来设置和管理中断优先级。请注意,不同的外设有不同的中断优先级分配规则,因此请仔细查阅相关文档,并根据需要进行调整。

  1. 考虑使用RTOS

如果您的程序较为复杂,并且涉及到多个任务或线程的管理,可以考虑使用实时操作系统(RTOS)来简化编程过程。RTOS可以提供更好的任务管理和资源管理机制,从而使程序更容易调试和维护。

希望这些建议能够对您有所帮助。如果您仍然遇到问题,请提供更具体的代码和错误信息,以便我们更好地理解问题所在并提供建议。

非常抱歉,我的前一条回答中提到使用NVIC模块来管理中断优先级可能不适用于HT32芯片。在HT32芯片中,中断处理方式可能会有所不同,可以通过设置相应的寄存器来管理中断优先级。以下是一些可能有用的建议:

  1. 查阅HT32芯片手册

查阅HT32芯片手册以获取关于中断处理和优先级设置的详细信息。手册应包含有关如何设置中断向量表、如何配置中断控制器和如何分配中断优先级等方面的说明。

  1. 使用HT32标准库

如果您使用了HT32标准库,则可以使用该库中已经定义的函数来管理中断优先级。例如,在HT32标准库中,可以使用HT_INT_SetPriority()函数设置中断优先级。请参阅HT32标准库文档以获取更多信息。

  1. 在代码中直接设置寄存器

如果您没有使用HT32标准库,则可以在代码中直接设置相关寄存器来管理中断优先级。HT32芯片具有一些特殊的寄存器,可以用于配置中断优先级。例如,可以使用IPR(中断优先级寄存器)来设置每个中断的优先级。请查阅HT32芯片手册以获取更多信息。

希望这些建议能够对您有所帮助。如果您仍然遇到问题,请提供更具体的代码和错误信息,以便我们更好地理解问题所在并提供建议。

该回答引用ChatGPT
根据您提供的代码和描述,我认为可能是中断优先级造成的问题。虽然HT系列芯片没有配置NVIC的初始化函数以及关于控制中断优先级的函数,但是单片机在执行的过程中,如果外部中断接收到信号,那么他就会立即中断当前运行的代码并转到对应的中断服务程序去执行,执行完该中断服务程序后才会继续执行之前的代码。

在您的代码中,使用了延时函数来等待数据接收,这个等待时间设置得不够长,如果外部中断在这个等待时间内发生了,那么代码就会被中断掉,导致接收不到下达命令。

解决方法可以是在接收数据的时候使用中断服务程序来接收数据,而不是使用延时函数等待接收。另外,如果您确信是中断优先级问题,您也可以在中断服务程序中使用“软件优先级”来解决。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据你提供的代码,你的问题可能出现在中断优先级上。你可以使用NVIC_Init函数初始化控制中断优先级。举个例子,以下是设置USB唤醒中断的优先级:

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn; // USBWakeUp中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占式优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

请注意,在设置中断优先级时,抢占式优先级必须低于临界区域内所调用函数的优先级,否则可能会出现问题。希望这能帮到你解决问题。
如果我的回答解决了您的问题,请采纳!

引用chatGPT作答,根据提供的代码,初步判断问题出现在数据的发送和接收处理过程中。

在代码中,发送数据时,通过OneNet_SendData()函数发送数据给OneNet平台,然后清空ESP8266缓存,并等待数据返回,获取数据并进行处理。

而在问题代码中,注释掉了发送数据的代码,此时单片机可以接收来自OneNet平台的指令。

因此,可以初步判断问题可能是由于发送数据和接收数据的处理方式不当,导致单片机在发送数据时无法接收来自OneNet平台的指令。

针对这个问题,可以考虑优化发送数据和接收数据的处理方式,尽可能地减少处理时间,避免发送数据时单片机无法接收指令的情况发生。

具体来说,可以考虑在发送数据前,先清空ESP8266缓存,并等待数据返回,获取数据并进行处理。同时,在接收数据时,可以使用超时等待的方式,避免因为数据处理时间过长而导致的单片机无法接收指令的情况发生。

代码优化建议如下:

1.发送数据前,先清空ESP8266缓存,并等待数据返回,获取数据并进行处理:

ESP8266_Clear();  //清空ESP8266缓存
OneNet_SendData(); //发送数据给OneNet平台

2.在接收数据时,使用超时等待的方式,避免数据处理时间过长而导致的单片机无法接收指令的情况发生:

dataPtr = ESP8266_GetIPD(1000); //等待最长1秒,获取平台返回的数据
if (dataPtr != NULL)            //如果返回数据不为空
{
    OneNet_RevPro(dataPtr);     //平台返回数据检测 
}
else
{
    printf("NO REV\n");
}

这样可以有效减少数据处理时间,提高单片机的处理效率,避免出现无法接收指令的情况。

更新,目前发现,只要发送过一次数据,单片机就无法再次接收命令,在发送数据之前都可以接受指令。
目前修改后:

        while(1)
    {
        delay_s(1);
    
        if(timeset==5)
        {
        //ESP8266_Clear();
      dou_dht11_get_data();//获取温度数据
      OLED_ShowNum(50,3,T_H/10,3,3);
      OLED_ShowNum(60,3,T_H%10,3,3); 
      OLED_ShowNum(50,5,H_H/10,3,3);
      OLED_ShowNum(60,5,H_H%10,3,3);
        delay_s(1);
        dou_dht11_get_data();
        delay_s(1);
        UsartPrintf(HT_USART0,"");//很神奇的一行垃圾代码,别动,动了没法运行。
        //printf("hum temp=%d .%d %d .%d\r\n",H_H,H_L,T_H,T_L);
      printf( "OneNet_SendData\r\n");//通过串口1发送提示信息(要开始发送数据了)
        OneNet_SendData();//发送数据给onenet
        printf("send_data_end\n");
        delay_s(1);
      timeset=0;
        ESP8266_Clear();
    }

        dataPtr = ESP8266_GetIPD(50);//获取平台返回的数据
        if(dataPtr != NULL)//如果返回数据不为空
        {
        OneNet_RevPro(dataPtr);//平台返回数据检测        
        }
        else
        {
            printf("NO REV");
        }
  delay_s(1);
  timeset++;        
}


还发现一个问题

void USART0_IRQHandler(void)
{

    if(USART_GetFlagStatus(COM0_PORT, USART_FLAG_RXDR) != RESET) //接收中断
    {
        if(esp8266_cnt >= sizeof(esp8266_buf))    esp8266_cnt = 0; //防止串口被刷爆
        esp8266_buf[esp8266_cnt++] = COM0_PORT->DR;
        
        USART_ClearFlag(COM0_PORT, USART_FLAG_RSADD);
    }

}

修稿为COM0(ESP使用的频道后)引起单片机初始化卡死。

以下内容部分参考ChatGPT模型:
首先,根据描述,单片机可以正常向ONENET发送指令,但是无法接收指令,这提示可能是数据接收的问题。其次,出现部分回应Tips: MQTT Publish Send OK,可能是发送数据时出现了问题。

解决思路:

  1. 检查串口通信是否正常

在单片机发送数据给ONENET的过程中,需要使用串口通信来与ESP8266通信,因此需要检查串口通信是否正常。可以使用串口调试工具来检查是否有数据发送出去,以及单片机是否接收到了期望的数据。

  1. 检查代码逻辑

代码逻辑可能存在问题,需要逐行检查代码,特别是发送数据和接收数据的代码,确保代码没有逻辑错误,并且没有出现死循环等问题。

  1. 检查中断优先级

中断优先级可能会影响程序的运行,因此需要检查中断优先级的设置。可以通过NVIC_Init函数来初始化中断优先级,确保程序正常运行。

  1. 确认ONENET的数据格式是否正确

在向ONENET发送数据时,需要按照规定的格式发送数据,否则ONENET将无法正确解析数据。因此需要确认发送的数据格式是否正确,并且数据内容是否符合要求。

  1. 确认网络连接是否正常

在向ONENET发送数据时,需要确保网络连接正常,否则将无法发送数据。可以通过ping命令或者其他方式检查网络连接是否正常。

  1. 确认ESP8266模块是否正常工作

ESP8266模块可能存在硬件问题,需要检查ESP8266模块是否正常工作。可以通过AT命令来检查ESP8266模块的状态,并且确保ESP8266模块正常工作。

综上所述,可以通过检查串口通信、代码逻辑、中断优先级、数据格式、网络连接和ESP8266模块来解决该问题。同时,可以参考其他类似问题的解决方案来解决该问题。
如果我的建议对您有帮助、请点击采纳、祝您生活愉快

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

可以请问一下,我改用onenet的mqtt代码移植到合泰单片机上,代码可以上发数据,但是下发数据的时候打印req_payload会出现乱码,这是什么情况呢,有大佬解答一下吗

img


[图片]