功能简介
本项目是基于nRF7002DK开发板开发设计的LED控制和按键监控系统。nRF7002DK开发板主控芯片是nRF5340单片机,此单片机是基于ARM Cortex-M33内核的双核单片机,拥有项目主要用到的单片机外设有ADC、I2C、SPI、PWM、UART和GPIO,包含的硬件有LCD屏、nst112温度传感器、LED灯和按键。
实现思路
通过Wi-Fi连接路由器实现网络通讯功能,然后通过MQTT协议实现设备端和应用端的通讯,最后通过LED和按键完成整个功能的展示。
硬件连接
硬件上主要涉及到nRF5340与按键、LED、nRF7002之间的连接,原理图如下:
按键:
按键1连接到了P1.08,按键2连接到了P1.09,触发电平是低电平,空闲电平是高电平。
LED:
LED1连接到了P1.06,LED2连接到了P1.07,触发电平是高电平。
nRF7002:通过QSPI与主控进行数据通讯。
代码分析
软件整体的逻辑图:
首先是主函数:
void main(void)
{
int rc;
struct net_if *iface = net_if_get_default();
struct wifi_connect_req_params cnx_params = { 0 };
/* Sleep 1 seconds to allow initialization of wifi driver. */
k_sleep(K_SECONDS(1));
/* Configurate net controller. */
LOG_INF("Configuration found. Try to apply.\n");
cnx_params.ssid = "PDD";
cnx_params.ssid_length = strlen(cnx_params.ssid);
cnx_params.security = WIFI_SECURITY_TYPE_PSK;
cnx_params.psk = NULL;
cnx_params.psk_length = 0;
cnx_params.sae_password = NULL;
cnx_params.sae_password_length = 0;
cnx_params.psk = "12345678";
cnx_params.psk_length = strlen(cnx_params.psk);
cnx_params.channel = WIFI_CHANNEL_ANY;
cnx_params.band = WIFI_FREQ_BAND_2_4_GHZ;
cnx_params.mfp = WIFI_MFP_OPTIONAL;
rc = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface,
&cnx_params, sizeof(struct wifi_connect_req_params));
if (rc < 0) {
LOG_ERR("Cannot apply saved Wi-Fi configuration, err = %d.\n", rc);
} else {
LOG_INF("Configuration applied.\n");
}
net_mgmt_init_event_callback(&wifi_prov_cb,
wifi_connect_handler,
NET_EVENT_WIFI_CONNECT_RESULT);
net_mgmt_add_event_callback(&wifi_prov_cb);
k_sem_take(&wifi_connected_sem, K_FOREVER);
/* Wait for the interface to be up */
k_sleep(K_SECONDS(6));
LOG_INF("Connecting to MQTT Broker...");
/* Connect to MQTT Broker */
init_hw_and_connect_mqtt();
}
主函数主要功能是配置网络控制器来配置Wi-Fi连接,等Wi-Fi连接完成之后进行硬件相关及MQTT的初始化。
网络配置通过wifi_connect_req_params数据对象进行初始化的,里面包含的ssid、密码、加密方式,频段等信息。
下面是硬件及MQTT的初始化过程
static void init_hw_and_connect_mqtt(void)
{
int err;
uint32_t connect_attempt = 0;
if (dk_leds_init() != 0) {
LOG_ERR("Failed to initialize the LED library");
}
if (dk_buttons_init(button_handler) != 0) {
LOG_ERR("Failed to initialize the buttons library");
}
err = client_init(&client);
if (err) {
LOG_ERR("Failed to initialize MQTT client: %d", err);
return;
}
do_connect:
if (connect_attempt++ > 0) {
LOG_INF("Reconnecting in %d seconds...",
CONFIG_MQTT_RECONNECT_DELAY_S);
k_sleep(K_SECONDS(CONFIG_MQTT_RECONNECT_DELAY_S));
}
err = mqtt_connect(&client);
if (err) {
LOG_ERR("Error in mqtt_connect: %d", err);
goto do_connect;
}
err = fds_init(&client,&fds);
if (err) {
LOG_ERR("Error in fds_init: %d", err);
return;
}
while (1) {
err = poll(&fds, 1, mqtt_keepalive_time_left(&client));
if (err < 0) {
LOG_ERR("Error in poll(): %d", errno);
break;
}
err = mqtt_live(&client);
if ((err != 0) && (err != -EAGAIN)) {
LOG_ERR("Error in mqtt_live: %d", err);
break;
}
if ((fds.revents & POLLIN) == POLLIN) {
err = mqtt_input(&client);
if (err != 0) {
LOG_ERR("Error in mqtt_input: %d", err);
break;
}
}
if ((fds.revents & POLLERR) == POLLERR) {
LOG_ERR("POLLERR");
break;
}
if ((fds.revents & POLLNVAL) == POLLNVAL) {
LOG_ERR("POLLNVAL");
break;
}
}
LOG_INF("Disconnecting MQTT client");
err = mqtt_disconnect(&client);
if (err) {
LOG_ERR("Could not disconnect MQTT client: %d", err);
}
goto do_connect;
}
mqtt初始化函数里面最关键的两个任务就是mqtt_live和mqtt_input,mqtt_live用来维持mqtt的心跳,需要周期性的调用,mqtt_input用来处理接收到的mqtt数据包。
通过client_init来初始化mqtt客户端结构体对象,通过mqtt_connect来连接mqtt服务器。
通过poll机制来监听mqtt的数据包。
功能展示
连接网络和MQTT是自动的,通过日志来展示连接过程,日志里展示了Wi-Fi连接的结果,动态获取到的IP地址,MQTT服务器连接的结果及订阅的话题:
应用连接相应的话题:
LED控制:
通过发送LED相关的命令来触发LED的亮灭。
按键监控,当按下按键的时候,会上报对应的消息,按键1对应的BTN_1_PRES,按键2对应BTN_2_PRES:
心得体会
通过本次活动,了解了nRF5340单片机和nRF7002网络协处理器的相关功能、性能参数,了解了开发环境的搭建,了解ncs相关API的使用,主要涉及网络、sdk、mqtt相关的API。期待下一期的活动。