我们进一步进行无线控制,依然是这几个模式,只不过这一次通过蓝牙方式进行。
先说说遇到的坑吧,首先是蓝牙调试,FRDM-MCXW71是一个双核工作的,虽然板子就一个天线接口:
也就是说我们目前调试M33核是一个主核,无线十一个专用的核,用于独立的内存,初始化状态下这个专有核是没有内容的,并不支持直接编辑,通过对无线板块的测试了解,可以看到专有核需要下载单独的固件,这一部分可以参考另一位网友的的下载过程,https://forum.eepw.com.cn/thread/391830/1。
固件问题解决后,在测试demo的时候,我是通过nRF Connect进行的搜索,居然搜不到,我直接通过手机蓝牙也没有搜到,无奈只能用NXP iot Toolbox这个官方软件了。
终于可以通信,接下来我们将通过wireless_uart例程了解蓝牙通信的过程,整体的流程是就与GATT协议的,在进行功能的启动后主要也是进行Callback处理,我们的主要处理也是在wireless_uart.c中进行。
我们先看一下wireless_uart例程,以下是串口打印的内容:
前一天晚上一直通过软件无法发现,官方软件都没有发现,原来是出在了这里,正常情况下例程初始状态是出于主机模式下的,通过SW2按键可以开启搜索,不过我们要让BLE出于从机,需要通过SW2+SW4组合键进行切换,这样就能让app发现了,通过NXP iot Toolbox的wireless_uart模块可以发现一个叫NXP_WU设备了,终于通了,接下来我们就在例程的继承下实现上面相同的LED控制,注意LED_B由于需要状态显示,我们不控制他,前期的时候也有RGB的控制,所以默认情况下连接上后是不启动的,只有收到1-3才会控制模式的开始,其他情况直接关闭。在测试例程的时候发现,手机app不能发送hex数据,1-3对应的是“1”-“3”。
咱们回到例程的程序中去,在main.c中实现的,添加定时器的初始化片段,我尝试通过初始化工具添加,会造成未知的错误,不好解决,这也是固件中的例程与初始化工具的不兼容,不知道为什么固件中的例程都是不适用初始化工具实现的,尤其是外设的使用,先添加定时器功能并启用:
#define DEMO_LPTMR_BASE LPTMR0 #define LPTMR_USEC_COUNT 1000000 #define DEMO_LPTMR_IRQn LPTMR0_IRQn #define LPTMR_LED_HANDLER LPTMR0_IRQHandler #define LPTMR_SOURCE_CLOCK (CLOCK_GetFreq(kCLOCK_ScgSircClk)) LPTMR_GetDefaultConfig(&lptmrConfig); LPTMR_Init(DEMO_LPTMR_BASE, &lptmrConfig); LPTMR_SetTimerPeriod(DEMO_LPTMR_BASE, USEC_TO_COUNT(LPTMR_USEC_COUNT, LPTMR_SOURCE_CLOCK)); LPTMR_EnableInterrupts(DEMO_LPTMR_BASE, kLPTMR_TimerInterruptEnable); EnableIRQ(DEMO_LPTMR_IRQn); LPTMR_StartTimer(DEMO_LPTMR_BASE);
然后LED的控制放到中断中,本例程的定时器中断放在fsl_adapter_timer.c中:
static void HAL_TimerInterruptHandle(uint8_t instance) { hal_timer_handle_struct_t *halTimerState = (hal_timer_handle_struct_t *)s_timerHandle[instance]; uint32_t lptmrIntFlag; if (NULL == halTimerState) { return; } lptmrIntFlag = LPTMR_GetStatusFlags(s_LptmrBase[instance]); LPTMR_ClearStatusFlags(s_LptmrBase[instance], (uint32_t)kLPTMR_TimerCompareFlag); LED_TimeCnt++; if(LED_TimeCnt >= 50) { LED_TimeCnt = 0; if(LED_Mode != LED_Modeing){ GPIO_PortSet(GPIOA, 1U << 19U); GPIO_PortSet(GPIOA, 1U << 20U); GPIO_PortSet(GPIOA, 1U << 21U); LED_Modeing = LED_Mode; } switch(LED_Modeing){ case 1: GPIO_PortToggle(GPIOA, 1U << 19U); break; case 2: GPIO_PortToggle(GPIOA, 1U << 20U); break; case 3: GPIO_PortToggle(GPIOA, 1U << 21U); break; default: break; } } if (0U != lptmrIntFlag) { if (halTimerState->callback != NULL) { halTimerState->callback(halTimerState->callbackParam); } } } void PWT_LPTMR0_IRQHandler(void); void PWT_LPTMR0_IRQHandler(void) { HAL_TimerInterruptHandle(0); SDK_ISR_EXIT_BARRIER; }
接下来就是重点的蓝牙接口的回调函数了,蓝牙的处理都在wireless_uart.c中,这里面有蓝牙信息处理的回调函数——static void BleApp_GattServerCallback(deviceId_t deviceId,gattServerEvent_t *pServerEven),我们主要在这里进行数据处理。我们这次用的是一个蓝牙+串口的一个透传函数,用的就是BleApp_ReceivedUartStream这个函数,我们对LED的模式处理就加载这里,通过获取蓝牙服务的数据和长度进行判断,以下是蓝牙服务的结构体gattServerEvent_t:
typedef struct { gattServerEventType_t eventType; /*!< Event type. */ union { gattServerMtuChangedEvent_t mtuChangedEvent; /*!< For event type gEvtMtuChanged_c: the new value of the ATT_MTU. */ gattServerAttributeWrittenEvent_t attributeWrittenEvent; /*!< For event types gEvtAttributeWritten_c, gEvtAttributeWrittenWithoutResponse_c: handle and value of the attempted write. */ gattServerCccdWrittenEvent_t charCccdWrittenEvent; /*!< For event type gEvtCharacteristicCccdWritten_c: handle and value of the CCCD. */ gattServerProcedureError_t procedureError; /*!< For event type gEvtError_c: error that terminated a Server-initiated procedure. */ gattServerLongCharacteristicWrittenEvent_t longCharWrittenEvent; /*!< For event type gEvtLongCharacteristicWritten_c: handle and value. */ gattServerAttributeReadEvent_t attributeReadEvent; /*!< For event types gEvtAttributeRead_c: handle of the attempted read. */ gattServerInvalidPdu_t attributeOpCode; /*!< For event type gEvtInvalidPduReceived_c: the ATT PDU that generated the error */ } eventData; /*!< Event data : selected according to event type. */ } gattServerEvent_t;
对应于`gattServerEvent_t`中的`gattServerAttributeWrittenEvent_t`事件,`aValue`和`cValueLength`字段的处理,本文采用了一种简化的方法。具体而言,该方法针对接收到的单一字符串执行单一状态的处理逻辑,例如,将字符串“1”映射为蓝灯闪烁状态。通过扩展字符串的长度,我们同样具备修改通信协议的能力。根据控制对象实现命令的控制:
void RGB_Command(void) { if (command_uart == '1' && command_lenght <= 2) { LED_Mode = command_uart-48; } else if (command_uart == '2' && command_lenght <= 2) { LED_Mode = command_uart-48; } else if (command_uart == '3' && command_lenght <= 2) { LED_Mode = command_uart-48; } else { LED_Mode = command_uart } }
接下来就是把他们放到各自的位置,首先是创建一个`aValue`和`cValueLength`字段对应的变量:
uint8_t command_uart; uint8_t command_lenght;
并与蓝牙服务字段关联:
然后将RGB_Command(void)放入处理程序位置,在BleApp_ReceivedUartStream中:
综合效果如下: