Nuoeriris · 2020年07月08日

MM32W无线MCU系列产品应用笔记 —— 阻塞式例程

在上一章节,我们了解了MM32W0系列蓝牙模块的中断式例程,也使用AT指令对模块进行了简单的操作。下面我们将对软件架构进行简单的讲解。

阻塞式例程介绍

对于大部分的低功耗设备来说,CPU都是处在休眠模式中,只在接收到特定数据的时候被唤醒处理少量数据,这种应用场景比较适合阻塞方式运行,这种方式配置简单,CPU大部分时间都被蓝牙服务占用,在收到来自射频模块的IRQ信号时需要及时处理,因此,用户的代码不允许出现阻塞
 
我们先看一下例程中的main函数:

int main(void)
{
unsigned long temp=0x800000;
SystemClk_HSEInit();               //系统时钟配置为48MHz

#ifdef USE_UART                    //目前只支持UART接收与发送AT指令
#ifdef USE_AT_CMD    //开启AT指令功能
SleepStop = 0x01;       //空闲时低功耗,0x00不休眠,0x01睡眠,0x02停机模式
#endif
#endif

#ifdef USE_UART                    //开启UART功能,修改全局宏定义改变UART和对应引脚
uart_initwBaudRate();               //波特率默认9600,可以修改uart.c中的BaudRate变量
#endif

#ifdef USE_I2C                        //开启I2C功能
IIC_Init(I2C1);               // I2C1,标准模式,SCL PB6 ,SDA PB7 ,SendDataFlag PA10
#endif
 
#ifdef USE_USB                      //开启USB功能
usb_test();                    //使用PA11、PA12,枚举为USB HID设备
#endif
 
//SysTick_Count每1ms加一,系统时钟改变时应调用SysTick_Config()函数
SysTick_Configuration();

//启用SPI2,在芯片内部与射频模块通信,速度应不低于6Mhz
SPIM_Init(SPI2,/*0x06*/0x06); 

IRQ_RF();         //配置PB8的IRQ 功能处理射频模块信号,用于低功耗唤醒

while(temp--);                //延时,方便烧录程序
radio_initBle(0x48, &ble_mac_addr);   //初始化射频模块(3dBm),并获取MAC地址
printf("\r\nMAC:%02x-%02x-%02x-%02x-%02x-%02x\r\n", ble_mac_addr[5],ble_mac_addr[4],ble_mac_addr[3],ble_mac_addr[2],ble_mac_addr[1],ble_mac_addr[0]);

ble_run(160*2); //广播间隔320*0.625=200 ms,
}

对于蓝牙,必要的系统资源有:用于计时的Systick和与射频模块通信的SPI2,Systick使用SysTick\_Count变量计时,也可以使用这个变量主动避开与IRQ处理任务的冲突。

目前程序支持RUN MODE,SLEEP MODE,STOP MODE模式,其中,在stop模式下MCU可以通过任意一个外部中断线唤醒,比如MM32W073NTB封装,在芯片设计上将IRQ与PB8共用一个GPIO口,在MM32W073PFB封装上,IRQ是独立的GPIO,需要用户在设计时将IRQ连接到任意一个GPIO口修改外部中断唤醒源即可实现stop唤醒模式。

例程中通过修改全局宏定义,可以启用UART、IIC和USB,目前都支持AT指令方式。

蓝牙的广播间隔由ble\_run()中的参数决定,单位为0.625ms。

与中断式例程不同的地方:

  1. 蓝牙服务会定时调用接口函数McuGotoSleepAndWakeup();
  2. ble\_run()是一个阻塞函数,后续程序将不会执行,中断模式中ble\_run参数为0,且不是阻塞函数;
  3. 中断式例程中蓝牙广播间隔由ble\_run\_interrupt\_start()函数的参数决定,阻塞式例程中蓝牙广播间隔由ble\_run()的参数决定。

1.jpg
图2 阻塞式程序流程

阻塞式程序流程如上图。实际使用中,蓝牙服务将定时调用UsrProcCallback()函数,在连接后允许时调用gatt\_user\_send\_notify\_data\_callback()。两个函数的处理时间应尽可能短,不能影响IRQ信号的处理,否则可能出现蓝牙连接断开、无蓝牙广播等问题。
 
我们可以将用户程序放在callback.c的UsrProcCallback()函数中定时执行,如例程中的AT指令的处理CheckAtCmdInfo()函数,注意不要阻塞。可以将发送自身状态的程序放在gatt\_user\_send\_notify\_data\_callback()函数中,同样不得阻塞。

推荐阅读
关注数
6143
内容数
276
灵动MM32 MCU相关技术知识,欢迎关注~
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息