打印
[PSOC™]

【英飞凌PSOC 4000T DIY】3、液位监测之MQTT

[复制链接]
1401|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 sujingliang 于 2025-4-26 13:41 编辑

为了将检测到的液位数据发送出去,做了下面这个扩展板

主要的作用是分别连接套件中的开发板和扩展板,并通过搭载的WIFI模块用MQTT协议将数据发送的物联网平台

整体连接示意图:



实物图:



一、MQTT平台准备
采用巴法云,地址https://bemfa.com/

1、每一个用户平台都会分配个ClientID,后面会用到



2、新建MQTT设备云

按照巴法云规范标准,后3位为004,代表设备为传感器

平台准备完毕

二、软件准备

程序在液位检测例程上修改,液位检测的部分不再描述。


所用WIFI模块为WF24,和MCU UART(P2.2 P2.3)连接。

1、UART初始化
 /* Configure and enable the UART peripheral */
    Cy_SCB_UART_Init(scb_0_HW, &scb_0_config, &CYBSP_UART_context);
    Cy_SCB_UART_Enable(scb_0_HW);

    /* 配置 UART 中断 */
     Cy_SysInt_Init(&UART_IRQ_cfg, UART_InterruptHandler);
     NVIC_EnableIRQ(UART_IRQ_cfg.intrSrc);  // 使能 NVIC 中断

     // 当 RX FIFO 非空时启用 UART RX 中断
     Cy_SCB_SetRxInterruptMask(scb_0_HW , CY_SCB_RX_INTR_NOT_EMPTY);


     // 当 TX FIFO 未满时启用 UART TX 中断
     Cy_SCB_SetTxInterruptMask (scb_0_HW ,CY_SCB_TX_INTR_LEVEL);


    /* Enable global interrupts */
    __enable_irq();
初始化UART,并启用RX中断,RX中断处理函数UART_InterruptHandler。

2、RX中断处理函数UART_InterruptHandler
static void UART_InterruptHandler(void)
{
    /* 检查是否 RX FIFO 非空 */
    if (Cy_SCB_GetRxInterruptStatusMasked(scb_0_HW) & CY_SCB_UART_RX_NOT_EMPTY)
    {
        /* 读取接收到的数据 */
        uint8_t rxData = Cy_SCB_UART_Get(scb_0_HW);

        /* 存入缓冲区(可改为环形缓冲区) */
        if (rxCount < RX_BUFFER_SIZE)
        {
            rxBuffer[rxCount++] = rxData;
        }

        /* 可选:检查结束符(如 '\n') */
        if (rxData == '\n'&&rxCount>2)
        {
            // 可以设置标志位通知主循环

                atResponseReady=true;
        }

    }

    /* 清除中断标志 */
    Cy_SCB_ClearRxInterrupt(scb_0_HW, CY_SCB_UART_RX_NOT_EMPTY);
}
当接收数据最后一位为回车,设置接收完成标志为true,用于主循环处理。

3、主循环处理
if(atResponseReady)
{
              uartRxProcessHandler();
               rxCount=0;
               atResponseReady=false;
}
void uartRxProcessHandler(void)
{
if(strstr(rxBuffer,"on")!= NULL){
                Cy_GPIO_Write(CYBSP_LED3_PORT ,CYBSP_LED3_PIN,1);
                enCapSense=true;
        }
        else if(strstr(rxBuffer,"off")!= NULL)
        {
                Cy_GPIO_Write(CYBSP_LED3_PORT ,CYBSP_LED3_PIN,0);
        }
        memset(rxBuffer,0,sizeof(rxBuffer));
}
接收到含有on的字符串,点灯并使能液位监测
4、main函数中水位监测处理
if(enCapSense)
            {
            uint32_t level_w_FR, level_wo_FR;

        /* Scan the normal Liquid Level Widget */
            Cy_CapSense_ScanWidget(CY_CAPSENSE_LIQUIDLEVEL0_WDGT_ID, &cy_capsense_context);
        /* Wait until the scan is finished */
        while(Cy_CapSense_IsBusy(&cy_capsense_context)) {}

        /* Scan the Foam Rejection Widget */
        Cy_CapSense_ScanWidget(CY_CAPSENSE_LIQUIDLEVEL0_FR_WDGT_ID, &cy_capsense_context);
        /* Wait until the scan is finished */
        while(Cy_CapSense_IsBusy(&cy_capsense_context)) {}

        /* Process all th widgets */
        Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);

        /* Send capsense data to the Tuner */
        //Cy_CapSense_RunTuner(&cy_capsense_context);

        /* store the liquid level before and after foam rejection */
        level_wo_FR = CY_CAPSENSE_LIQUIDLEVEL0_PTRPOSITION_VALUE->x;
        level_w_FR = CY_CAPSENSE_LIQUIDLEVEL0_FR_PTRPOSITION_VALUE->x;

        sprintf(cmd,"AT+MQTTPUBRAW=WATER004,%d,0,0",getDigits(level_wo_FR)+2);
        Send_AT_Command(cmd, response, AT_TIMEOUT_MS);
        sprintf(cmd,"%ld",level_wo_FR);
        Send_AT_Command(cmd, response, AT_TIMEOUT_MS);

        /* keep the compiler happy */
        (void)level_wo_FR;
        (void)level_w_FR;
                enCapSense=false;
            }
液位监测标志使能状态,获取level_wo_FR 。通过以下AT指令发送出去

        sprintf(cmd,"AT+MQTTPUBRAW=WATER004,%d,0,0",getDigits(level_wo_FR)+2);
        Send_AT_Command(cmd, response, AT_TIMEOUT_MS);
        sprintf(cmd,"%ld",level_wo_FR);
        Send_AT_Command(cmd, response, AT_TIMEOUT_MS);


5、发送AT指令
bool Send_AT_Command(const char* atCommand, char* response, uint16_t timeout_ms) {
    /* 清空缓冲区 */
    memset(rxBuffer, 0, RX_BUFFER_SIZE);
    rxCount = 0;
    atResponseReady = false;

    /* 发送 AT 指令(带换行符) */
    Cy_SCB_UART_PutString(scb_0_HW, atCommand);
    Cy_SCB_UART_PutString(scb_0_HW, "\r\n"); // 添加结束符

    /* 等待响应 */
    Cy_SysLib_Delay(timeout_ms);

    /* 返回响应内容 */
    strcpy(response, rxBuffer);
    return true;
}
6、MQTT初始化
 //WIFI模块RESET
  Send_AT_Command("AT+RST", response, AT_TIMEOUT_MS);

  //WIFI连接
    if (Send_AT_Command("AT+CWSTATE?", response, AT_TIMEOUT_MS)) {
                if (strstr(rxBuffer, "+CWSTATE:2") == NULL)
                {
                    Send_AT_Command("AT+CWJAP=ssid,password", response, AT_TIMEOUT_MS);
                }
    }

   //发送clientid,其中的clientid要替换成自己的
    Send_AT_Command("AT+MQTTLONGCLIENTID=1892ce3cc45c4xxxxxxxxxxxxxxxx7", response, AT_TIMEOUT_MS);

   //连接巴法云
    Send_AT_Command("AT+MQTTCONN=bemfa.com,9501,0", response, AT_TIMEOUT_MS);

  //发布WATER004主题登录指令
    Send_AT_Command("AT+MQTTPUBRAW=WATER004/up,7,0,0", response, AT_TIMEOUT_MS);
    Send_AT_Command("**n", response, AT_TIMEOUT_MS);

  //订阅WATER004
    Send_AT_Command("AT+MQTTSUB=WATER004,0", response, AT_TIMEOUT_MS);

  //发布一条数据用于测试
    Send_AT_Command("AT+MQTTPUBRAW=WATER004,4,0,0", response, AT_TIMEOUT_MS);
    Send_AT_Command("25", response, AT_TIMEOUT_MS);
三、运行

wifi模块初始化成功,并且mqtt连接成功,绿灯亮


通过巴法云APP,可以搜到WATER004,连接后可以设置为"液位监测"方便使用,可以看到测试数据25cm已经显示出来
点击进去,显示如下:

可以按这个按钮控制LED亮,使能液位监测标志,MCU会采集一次数据,并通过MQTT发送数据,这时手机APP显示的数据随之改变。

MCU发给WIFI模块日志:


WIFI模块发给MCU日志:



MQTT+CapSense的潜在使用场景:
1、远程鱼缸水位监测

2、远程降雨量测量


3、农田灌溉优化


4、洪灾灾害易发区监控

...




使用特权

评论回复
沙发
和下土| | 2025-4-30 22:20 | 只看该作者
在 Arduino IDE 中,可以使用 PubSubClient 库来实现 MQTT 功能。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

62

主题

120

帖子

2

粉丝