[PSOC™] 【英飞凌 CY8CKIT-062S2-AI评测】05MQTT实现LED、按键的监控

[复制链接]
37|0
EPTmachine 发表于 2025-11-18 18:27 | 显示全部楼层 |阅读模式

开发板上搭载一个LBEE5KL1YN-814 SiP模块,使用英飞凌的CYW43439双模无线通讯芯片,支持802.11b/g/n Wi-Fi and Bluetooth® 5.2。MCU和模块的接口连接如下。

Wireless_Module_Interface.png

MQTT(Message Queuing Telemetry Transport)是物联网无线应用中常见的协议,是一种轻量级、支持发布/订阅模式、提供消息队列/消息队列服务的网络协议。用于连接网络带宽受限的设备,比如IoT设备。

英飞凌的驱动库中提供MQTT的功能支持,可以使用提供的接口快速开发MQTT应用。

1、添加MQTT驱动库和相应配置

创建空的应用工程,在library-manager中添加retarget-io(1.8.1 release)库用于支持printf串口重定向、添加wifi-core-freertos-lwip-mbedtls(2.2.1 release)库用于支持wifi模块驱动、FreeRTOS、lwip协议等模块、添加mqtt(4.7.0 release)库用于支持mqtt协议。在添加库时,由于软件库是由git管理的,需要指定库的版本,避免兼容性的问题。

library-manager-list.png

1.1 添加Makefile变量

添加的组件中FreeRTOS、MQTT、Wifi连接都需要提供相应的配置信息用于相应资源的分配。工程使用Makefile文件进行相应的管理,在工程目录中添加configs文件夹用于存放工程配置文件,比如FreeRTOSConfig.hmqtt_client_config.hwifi_config.h。Makefile中的INCLUDES变量中添加文件的相对路径包含到编译过程中。

INCLUDES=./configs

其中FreeRTOSConfig.h与处理的内核架构相关,管理该文件时,可以创建COMPONENT_CM4文件夹用于存储Cortex-M4内核对应的FreeRTOSConfig.h。对应的INCLUDES变量中添加相应的路径

INCLUDES+=./configs/COMPONENT_$(CORE)

其中的$(CORE)为ModusToolbox的构建系统中的系统变量,用于管理工程。

build_system_vars.png

在Makefile中添加组件信息以及预定宏

COMPONENTS=FREERTOS LWIP MBEDTLS SECURE_SOCKETS

# Add additional defines to the build process (without a leading -D).
DEFINES=$(MBEDTLSFLAGS) CYBSP_WIFI_CAPABLE CY_RETARGET_IO_CONVERT_LF_TO_CRLF CY_RTOS_AWARE
# Number of milliseconds to wait for a ping response to a ping
DEFINES+= MQTT_PINGRESP_TIMEOUT_MS=5000
# The number of retries for receiving CONNACK
DEFINES+= MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT=2

bug1.png

bug1:05Wifi MQTT连接工程,按照示例工程添加项,编译时出现编译报错,提示编译报错无法找到core_http_config.h

在工程的.cyignore文件中添加以下内容,将coreHTTP组件排除在编译过程。对于组件中不需要的内容,可以通过.cyignore文件中添加文件的路径将其排除在编译过程外。

$(SEARCH_aws-iot-device-sdk-embedded-C)/libraries/standard/coreHTTP

1.2 Wifi设置、MQTT设置

wifi_config.h中设置Wifi连接的SSID和对应的密码

/* SSID of the Wi-Fi Access Point to which the MQTT client connects. */
#define WIFI_SSID                         "MY_WIFI_SSID"

/* Passkey of the above mentioned Wi-Fi SSID. */
#define WIFI_PASSWORD                     "MY_WIFI_PASSWORD"

mqtt_client_config.h

/***************** MQTT CLIENT CONNECTION CONFIGURATION MACROS *****************/
/* MQTT Broker/Server address and port used for the MQTT connection. */
#define MQTT_BROKER_ADDRESS               "test.mosquitto.org"
#define MQTT_PORT                         1883

/* Set this macro to 1 if a secure (TLS) connection to the MQTT Broker is
 * required to be established, else 0.
 */
#define MQTT_SECURE_CONNECTION            ( 0 )

/* Configure the user credentials to be sent as part of MQTT CONNECT packet */
#define MQTT_USERNAME                     ""
#define MQTT_PASSWORD                     ""


/********************* MQTT MESSAGE CONFIGURATION MACROS **********************/
/* The MQTT topics to be used by the publisher and subscriber. */
#define MQTT_PUB_TOPIC                    "ledstatus"
#define MQTT_SUB_TOPIC                    "ledstatus"

/* Set the QoS that is associated with the MQTT publish, and subscribe messages.
 * Valid choices are 0, 1, and 2. Other values should not be used in this macro.
 */
#define MQTT_MESSAGES_QOS                 ( 1 )

/* MQTT messages which are published on the MQTT_PUB_TOPIC that controls the
 * device (user LED in this example) state in this code example.
 */
#define MQTT_DEVICE_ON_MESSAGE            "TURN ON"
#define MQTT_DEVICE_OFF_MESSAGE           "TURN OFF"


/******************* OTHER MQTT CLIENT CONFIGURATION MACROS *******************/
/* A unique client identifier to be used for every MQTT connection. */
#define MQTT_CLIENT_IDENTIFIER            "psoc6-mqtt-client"

2、MQTT控制开发板LED状态

通过MQTT协议提供的publish/subscribe机制,可以显示开发板外设的状态监控。以开发板上的用户按键和两个LED的控制为例。

2.1 建立网络连接并初始化MQTT协议

网络连接使用到英飞凌的wifi-connection-manager组件库,使用其中的API接口实现Wifi初始化和连接。相关的接口函数以及代码调用如下

cy_rslt_t cy_wcm_init(cy_wcm_config_t *config);
uint8_t cy_wcm_is_connected_to_ap(void);
cy_rslt_t cy_wcm_connect_ap(cy_wcm_connect_params_t *connect_params, cy_wcm_ip_address_t *ip_addr);

/* Configure the Wi-Fi interface as a Wi-Fi STA (i.e. Client). */
cy_wcm_config_t config = {.interface = CY_WCM_INTERFACE_TYPE_STA};

if (CY_RSLT_SUCCESS != cy_wcm_init(&config))
{
    printf("\nWi-Fi Connection Manager initialization failed!\n");
    goto exit_cleanup;
}

cy_rslt_t result = CY_RSLT_SUCCESS;
cy_wcm_connect_params_t connect_param;
cy_wcm_ip_address_t ip_address;

/* Configure the connection parameters for the Wi-Fi interface. */
memset(&connect_param, 0, sizeof(cy_wcm_connect_params_t));
memcpy(connect_param.ap_credentials.SSID, WIFI_SSID, sizeof(WIFI_SSID));
memcpy(connect_param.ap_credentials.password, WIFI_PASSWORD, sizeof(WIFI_PASSWORD));
connect_param.ap_credentials.security = WIFI_SECURITY;

/* Check if Wi-Fi connection is already established. */
if (cy_wcm_is_connected_to_ap() == 0)
{

    /* Connect to the Wi-Fi AP. */
    for (uint32_t retry_count = 0; retry_count < MAX_WIFI_CONN_RETRIES; retry_count++)
    {
        result = cy_wcm_connect_ap(&connect_param, &ip_address);
    }
}

指定Wifi连接的类型为Station,并在wifi_config.h指定Wifi连接的SSID和password,调用连接函数即可建立wifi连接。

mqtt协议组件用于实现mqtt协议的初始化、发布和订阅mqtt主题消息。使用到的API和关键的函数调用如下

cy_mqtt_t mqtt_connection;
cy_rslt_t cy_mqtt_init( void );
cy_rslt_t cy_mqtt_create( uint8_t *buffer, uint32_t buff_len,
                          cy_awsport_ssl_credentials_t *security,
                          cy_mqtt_broker_info_t *broker_info,
                          char *descriptor,
                          cy_mqtt_t *mqtt_handle );
cy_rslt_t cy_mqtt_register_event_callback( cy_mqtt_t mqtt_handle,
                                           cy_mqtt_callback_t event_callback,
                                           void *user_data );

cy_rslt_t cy_mqtt_connect( cy_mqtt_t mqtt_handle, cy_mqtt_connect_info_t *connect_info );


/* Initialize the MQTT library. */
result = cy_mqtt_init();

/* MQTT client identifier string. */
char mqtt_client_identifier[(MQTT_CLIENT_IDENTIFIER_MAX_LEN + 1)] = MQTT_CLIENT_IDENTIFIER;

/* Configure the user credentials as a part of MQTT Connect packet */
if (strlen(MQTT_USERNAME) > 0)
{
    connection_info.username = MQTT_USERNAME;
    connection_info.password = MQTT_PASSWORD;
    connection_info.username_len = sizeof(MQTT_USERNAME) - 1;
    connection_info.password_len = sizeof(MQTT_PASSWORD) - 1;
}

/* Generate a unique client identifier with 'MQTT_CLIENT_IDENTIFIER' string 
    * as a prefix if the `GENERATE_UNIQUE_CLIENT_ID` macro is enabled.
    */
#if GENERATE_UNIQUE_CLIENT_ID
result = mqtt_get_unique_client_identifier(mqtt_client_identifier);
CHECK_RESULT(result, 0, "Failed to generate unique client identifier for the MQTT client!\n");
#endif /* GENERATE_UNIQUE_CLIENT_ID */

/* Set the client identifier buffer and length. */
connection_info.client_id = mqtt_client_identifier;
connection_info.client_id_len = strlen(mqtt_client_identifier);


/* Create the MQTT client instance. */
result = cy_mqtt_create(mqtt_network_buffer, MQTT_NETWORK_BUFFER_SIZE,
                        security_info, &broker_info,MQTT_HANDLE_DESCRIPTOR,
                        &mqtt_connection);

if(CY_RSLT_SUCCESS == result)
{
    /* Register a MQTT event callback */
    result = cy_mqtt_register_event_callback( mqtt_connection, (cy_mqtt_callback_t)mqtt_event_callback, NULL );
} 

/* Establish the MQTT connection. */
result = cy_mqtt_connect(mqtt_connection, &connection_info);

在工程的mqtt_client_config.h中指定mqtt连接的用户名,topic信息等通讯参数。调用mqtt初始化、回调注册以及建立连接函数,建立mqtt通讯。

2.2 MQTT发布任务

MQTT协议中的发布功能,可以向MQTT网络中发布消息,传递外设的基本状态。发布消息涉及到的数据结构体以及函数为:

typedef struct cy_mqtt_publish_info
{
    cy_mqtt_qos_t  qos;          /**< Quality of Service for message. */
    bool           retain;       /**< Whether this is a retained message. */
    bool           dup;          /**< Whether this is a duplicate publish message. */
    const char     *topic;       /**< Topic name on which the message is published. */
    uint16_t       topic_len;    /**< Length of topic name. */
    const char     *payload;     /**< Message payload. */
    size_t         payload_len;  /**< Message payload length. */
} cy_mqtt_publish_info_t;

cy_rslt_t cy_mqtt_publish( cy_mqtt_t mqtt_handle, cy_mqtt_publish_info_t *pub_msg );

通过MQTT的发布功能可以将按键点击事件发布到MQTT网络中。初始化按键以及按键的中断回调。

static void publisher_init(void)
{
    /* Initialize the user button GPIO and register interrupt on falling edge. */
    cyhal_gpio_init(CYBSP_USER_BTN, CYHAL_GPIO_DIR_INPUT,
                    CYHAL_GPIO_DRIVE_PULLUP, CYBSP_BTN_OFF);
    cyhal_gpio_register_callback(CYBSP_USER_BTN, &cb_data);
    cyhal_gpio_enable_event(CYBSP_USER_BTN, CYHAL_GPIO_IRQ_FALL,
                            USER_BTN_INTR_PRIORITY, true);
    
    printf("\nPress the user button (SW2) to publish \"%s\"/\"%s\" on the topic '%s'...\n", 
           MQTT_DEVICE_ON_MESSAGE, MQTT_DEVICE_OFF_MESSAGE, publish_info.topic);
}

static void isr_button_press(void *callback_arg, cyhal_gpio_event_t event)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    publisher_data_t publisher_q_data;

    /* To avoid compiler warnings */
    (void) callback_arg;
    (void) event;

    /* Assign the publish command to be sent to the publisher task. */
    publisher_q_data.cmd = PUBLISH_MQTT_MSG;

    /* Assign the publish message payload so that the device state toggles. */
    if (current_device_state == DEVICE_ON_STATE)
    {
        publisher_q_data.data = (char *)MQTT_DEVICE_OFF_MESSAGE;
    }
    else
    {
        publisher_q_data.data = (char *)MQTT_DEVICE_ON_MESSAGE;
    }

    /* Send the command and data to publisher task over the queue */
    xQueueSendFromISR(publisher_task_q, &publisher_q_data, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

在发布函数中,通过调用消息发布函数,将按键消息发送到MQTT网络中

case PUBLISH_MQTT_MSG:
{
    /* Publish the data received over the message queue. */
    publish_info.payload = publisher_q_data.data;
    publish_info.payload_len = strlen(publish_info.payload);

    printf("\nPublisher: Publishing '%s' on the topic '%s'\n",
            (char *) publish_info.payload, publish_info.topic);

    result = cy_mqtt_publish(mqtt_connection, &publish_info);

    if (result != CY_RSLT_SUCCESS)
    {
        printf("  Publisher: MQTT Publish failed with error 0x%0X.\n\n", (int)result);

        /* Communicate the publish failure with the the MQTT 
            * client task.
            */
        mqtt_task_cmd = HANDLE_MQTT_PUBLISH_FAILURE;
        xQueueSend(mqtt_task_q, &mqtt_task_cmd, portMAX_DELAY);
    }
}

2.3 MQTT订阅

MQTT协议中的订阅功能,可以通过MQTT网络订阅相关的主题,用于接收外部的数据,从而改变开发板中与此订阅相关的设备状态。订阅消息涉及到的数据结构体以及函数为:

typedef struct cy_mqtt_subscribe_info
{
    cy_mqtt_qos_t  qos;           /**< Requested quality of Service for the subscription. */
    const char     *topic;        /**< Topic filter to subscribe to. */
    uint16_t       topic_len;     /**< Length of subscription topic filter. */
    cy_mqtt_qos_t  allocated_qos; /**< QoS allocated by the broker for the subscription. \ref CY_MQTT_QOS_INVALID indicates subscription failure. */
} cy_mqtt_subscribe_info_t;
cy_rslt_t cy_mqtt_subscribe( cy_mqtt_t mqtt_handle, cy_mqtt_subscribe_info_t *sub_info, uint8_t sub_count );

调用相关的接口,可以订阅MQTT网络中发布的主题,接收其中的数据用于修改开发板上的LED状态,涉及到的关键调用如下

/* Configure the subscription information structure. */
static cy_mqtt_subscribe_info_t subscribe_info =
{
    .qos = (cy_mqtt_qos_t) MQTT_MESSAGES_QOS,
    .topic = MQTT_SUB_TOPIC,
    .topic_len = (sizeof(MQTT_SUB_TOPIC) - 1)
};


result = cy_mqtt_subscribe(mqtt_connection, &subscribe_info, SUBSCRIPTION_COUNT);



case CY_MQTT_EVENT_TYPE_SUBSCRIPTION_MESSAGE_RECEIVE:
{
    status_flag |= MQTT_MSG_RECEIVED;

    /* Incoming MQTT message has been received. Send this message to 
        * the subscriber callback function to handle it. 
        */

    received_msg = &(event.data.pub_msg.received_message);

    mqtt_subscription_callback(received_msg);
    break;
}

/* Send the command and data to subscriber task queue */
xQueueSend(subscriber_task_q, &subscriber_q_data, portMAX_DELAY);

case UPDATE_DEVICE_STATE:
{
    /* Update the LED state as per received notification. */
    cyhal_gpio_write(CYBSP_USER_LED, subscriber_q_data.data);

    /* Update the current device state extern variable. */
    current_device_state = subscriber_q_data.data;

    print_heap_usage("subscriber_task: After updating LED state");
    break;
}

3、搭建本地MQTT Broker

在PC端安装mosquitto可以方便地建立MQTT服务器,用于MQTT服务测试。

download_mosquitto.png

修改安装路径下的mosquitto.conf文件,设置MQTT Borker服务器的监听地址、登录授权配置。

listener 1883 #服务器监听端口
allow_anonymous false #禁止匿名登录 
password_file pwfile.example #指定验证信息位置

在命令行中运行下列指令,添加登录ID,根据提示输入密码,完成登录账户的配置

“./mosquitto_passwd -c pwfile.example eeworld

运行.\mosquitto -c .\mosquitto.conf -v运行配置好的服务器。

上述使用的配置信息同步更新到工程的mqtt_client_config.h中以及wifi_config.h的连接设置中。编译通过后,烧录到开发板。

可以看到本地的MQTT服务器与开发板建立连接,接收开发板发送的按键消息。

mqtt_connect.png

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
您需要登录后才可以回帖 登录 | 注册

本版积分规则

40

主题

698

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部