如何通过HTTP将消息发送到Azure IoT中心之间将BG96置于省电模式

我正在使用Nucleo L496ZG,X-NUcleo-IKS01A2和Quectel BG96模块通过HTTP将传感器数据(温度,湿度等)发送到Azure IoT Central。 我一直在使用Avnet here提供的示例实现,该示例运行良好,但未进行电源优化,并且使用6700mAh电池组,它只能持续30个小时左右,发送遥测数据的时间约为10秒。目标是持续约一周。我愿意增加发送消息之间的时间,但我也想节省发送之间的时间。

我已经阅读了Quectel BG96手册,并尝试了两件事:

1)通过驱动PWRKEY并在需要发送消息时将其重新打开来关闭设备电源 我已经做到这一点了,直到……直到出现硬故障异常,该异常似乎随机发生在运行约5分钟到2个小时内(消息在异常之前成功发送)。每次崩溃日志解析器的输出都是相同的:

        Crash location = strncmp [0x08038DF8] (based on PC value)
        Caller location = _findenv_r [0x0804119D] (based on LR value)
        Stack Pointer at the time of crash = [20008128]
        Target and Fault Info:
                Processor Arch: ARM-V7M or above
                Processor Variant: C24
                Forced exception,a fault with configurable priority has been escalated to HardFault
                A precise data access error has occurred. Faulting address: 03060B30

呼叫者位置可追溯到我的.map文件,但我不知道该怎么做。 我的代码:

// Copyright (c) microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

//#define USE_MQTT

#include <stdlib.h>
#include "mbed.h"
#include "iothubtransporthttp.h"
#include "iothub_client_core_common.h"
#include "iothub_client_ll.h"
#include "azure_c_shared_utility/platform.h"
#include "azure_c_shared_utility/agenttime.h"
#include "jsondecoder.h"
#include "bg96gps.hpp"
#include "azure_message_helper.h"

#define IOT_AGENT_OK CODEFIRST_OK

#include "azure_certs.h"


/* initialize the expansion board && sensors */

#include "XNucleoIKS01A2.h"
static HTS221Sensor   *hum_temp;
static LSM6DSLSensor  *acc_gyro;
static LPS22HBSensor  *pressure;


static const char* connectionString = "xxx";

// to report F uncomment this #define CTOF(x)         (((double)(x)*9/5)+32)
#define CTOF(x)         (x)

Thread azure_client_thread(osPriorityNormal,10*1024,NULL,"azure_client_thread");
static void azure_task(void);
Eventflags deleteOK;
size_t g_message_count_send_confirmations;

/* create the GPS elements for example program */
BG96Interface* bg96Interface;

//static int tilt_event;

// void mems_int1(void)
// {
//     tilt_event++;
// }

void mems_init(void)
{
    //acc_gyro->attach_int1_irq(&mems_int1);  // Attach callback to LSM6DSL INT1
    hum_temp->enable();                     // Enable HTS221 enviromental sensor
    pressure->enable();                     // Enable barametric pressure sensor
    acc_gyro->enable_x();                   // Enable LSM6DSL accelerometer
    //acc_gyro->enable_tilt_detection();      // Enable Tilt Detection

}

void powerup(void) {
        if (platform_init() != 0) {
            printf("Error initializing the platform\r\n");
            return;
        }
        bg96Interface = (BG96Interface*) easy_get_netif(true);
}

void BG96_Modem_PowerOFF(void)
{
    DigitalOut BG96_RESET(D7);
    DigitalOut BG96_PWRKEY(D10);
    DigitalOut BG97_WAKE(D11);

    BG96_RESET = 0;
    BG96_PWRKEY = 0;
    BG97_WAKE = 0;
    wait_ms(300);
}

void powerDown(){
        platform_deinit();
        BG96_Modem_PowerOFF();
}

//
// The main routine simply prints a banner,initializes the system
// starts the worker threads and waits for a termination (join)

int main(void)
{
    //printStartMessage();
    XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(I2C_SDA,I2C_SCL,D4,D5);
    hum_temp = mems_expansion_board->ht_sensor;
    acc_gyro = mems_expansion_board->acc_gyro;
    pressure = mems_expansion_board->pt_sensor;
    azure_client_thread.start(azure_task);
    azure_client_thread.join();
    platform_deinit();
    printf(" - - - - - - - ALL DONE - - - - - - - \n");
    return 0;
}

static void send_confirm_callback(IOTHUB_CLIENT_CONFIRMATION_RESULT result,void* userContextCallback)
{
    //userContextCallback;
    // When a message is sent this callback will get envoked
    g_message_count_send_confirmations++;
    deleteOK.set(0x1);
}

void sendMessage(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle,char* buffer,size_t size)
{
    IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)buffer,size);
    if (messageHandle == NULL) {
        printf("unable to create a new IoTHubMessage\r\n");
        return;
        }
    if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle,messageHandle,send_confirm_callback,NULL) != IOTHUB_CLIENT_OK)
        printf("FAILED to send! [RSSI=%d]\n",platform_RSSI());
    else
        printf("OK. [RSSI=%d]\n",platform_RSSI());

    IoTHubMessage_Destroy(messageHandle);
}

void azure_task(void)
{
    //bool tilt_detection_enabled=true;
    float gtemp,ghumid,gpress;

    int  k;
    int  msg_sent=1;


    while (true) {
        powerup();
        mems_init();
        /* Setup IoTHub client configuration */
        IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString,HTTP_Protocol);

        if (iotHubClientHandle == NULL) {
            printf("Failed on IoTHubClient_Create\r\n");
            return;
            }

        // add the certificate information
        if (IoTHubClient_LL_SetOption(iotHubClientHandle,"TrustedCerts",certificates) != IOTHUB_CLIENT_OK)
            printf("failure to set option \"TrustedCerts\"\r\n");

        #if MBED_CONF_APP_TELUSKIT == 1
            if (IoTHubClient_LL_SetOption(iotHubClientHandle,"product_info","TELUSIOTKIT") != IOTHUB_CLIENT_OK)
                printf("failure to set option \"product_info\"\r\n");
        #endif

        // polls will happen effectively at ~10 seconds.  The default value of minimumPollingTime is 25 minutes. 
        // For more information,see:
        //     https://azure.microsoft.com/documentation/articles/iot-hub-devguide/#messaging

        unsigned int minimumPollingTime = 9;
        if (IoTHubClient_LL_SetOption(iotHubClientHandle,"MinimumPollingTime",&minimumPollingTime) != IOTHUB_CLIENT_OK)
                printf("failure to set option \"MinimumPollingTime\"\r\n");

        IoTDevice* iotDev = (IoTDevice*)malloc(sizeof(IoTDevice));
        if (iotDev == NULL) {
            return;
        }
        setUpIotStruct(iotDev);

        char*  msg;
        size_t msgSize;

        hum_temp->get_temperature(&gtemp);           // get Temp
        hum_temp->get_humidity(&ghumid);             // get Humidity
        pressure->get_pressure(&gpress);             // get pressure


        iotDev->Temperature = CTOF(gtemp);
        iotDev->Humidity    = (int)ghumid;
        iotDev->Pressure    = (int)gpress;

        printf("(%04d)",msg_sent++);
        msg = makeMessage(iotDev);
        msgSize = strlen(msg);
        sendMessage(iotHubClientHandle,msg,msgSize);
        free(msg);
        iotDev->Tilt &= 0x2;

        /* schedule IoTHubClient to send events/receive commands */
        IOTHUB_CLIENT_STATUS status;
        while ((IoTHubClient_LL_GetSendStatus(iotHubClientHandle,&status) == IOTHUB_CLIENT_OK) && (status == IOTHUB_CLIENT_SEND_STATUS_BUSY))
        {
            IoTHubClient_LL_DoWork(iotHubClientHandle);
            ThisThread::sleep_for(100); 
        }
        deleteOK.wait_all(0x1);
        free(iotDev);
        IoTHubClient_LL_Destroy(iotHubClientHandle);
        powerDown();
        ThisThread::sleep_for(300000);
    }
    return;
}

我知道PSM可能是可行的方法,因为打开/关闭设备的电源会消耗很多功率,但是如果有人对这里发生的事情有所了解,这将很有用。

2)在发送消息之间将设备置于PSM

我使用的示例代码中的BG96库没有打开PSM的方法,因此我尝试实现自己的方法。当我尝试运行它时,它基本上会立即遇到异常,因此我知道这是错误的(我是嵌入式开发的新手,并且没有使用AT命令的经验)。

/** ---------------------------------------------------------- 
* this is a method provided by current library
* @brief  Tx a string to the BG96 and wait for an OK response
* @param  none
* @retval true if OK received,false otherwise
*/
bool BG96::tx2bg96(char* cmd) {
    bool ok=false;
    _bg96_mutex.lock();
    ok=_parser.send(cmd) && _parser.recv("OK");
    _bg96_mutex.unlock();
    return ok;
}

/**
* method I created in an attempt to use PSM
*/
bool BG96::psm(void) {
    return tx2bg96((char*)"AT+CPSMS=1,”00000100”,”00000001”");
}

有人可以告诉我我做错了什么,并提供有关如何实现我的设备使用电池供电更长的目标的任何指导吗?

谢谢!

dasfasdwqeee 回答:如何通过HTTP将消息发送到Azure IoT中心之间将BG96置于省电模式

我按照Quectel的文档使用Mbed的ATCmdParser和AT + QPSMS命令来使省电模式工作。调制解调器并不总是立即进入省电模式,因此应注意。我还发现以后必须重新启动调制解调器,否则会出现奇怪的行为。我的代码如下所示:

bool BG96::psm(char* T3412,char* T3324) {
_bg96_mutex.lock();

if(_parser.send("AT+QPSMS=1,\"%s\",\"%s\"",T3412,T3324) && _parser.recv("OK")) {
    _bg96_mutex.unlock();
}else {
    _bg96_mutex.unlock();
    return false;
}
return BG96Ready(); }//restarts modem

要将消息发送到Azure,将需要通过驱动PWRKEY来启动双向通信来手动唤醒调制解调器,并且每次创建新的客户端句柄并将其断开,因为Azure连接使用keepAlive和调制解调器在PSM中时将无法访问。

本文链接:https://www.f2er.com/3093260.html

大家都在问