datasheet

stm32 接收蓝牙(uart)等设备命令的处理

2019-07-11来源: eefocus关键字:stm32  接收蓝牙  uart  设备命令

方法有两种:


方法1:查询法


static void BT_RX_Handler(void)

{

u8 data = USART_ReceiveData(USART2);

if((BT_Buf_Status & 0x80) == 0)  /* not complete */ 

{

if(BT_Buf_Status & 0x40)

{

BT_RcvBuf[BT_RecCur] = data;

BT_RecCur++;

 

if((data == 0xEC) && (8 == BT_RecCur))

//if((data == 0xEC))

{

BT_Buf_Status |= (1 << 7);       /* complete */

BT_Handler();

BT_Buf_Status &= ~(1 << 7);       /* clear */

BT_RecCur = 0;

}

}

else

{

/* filt the head */ 

if(data == 0xBC)

{

/* standard cmd */

BT_RcvBuf[BT_RecCur] = data;           /* save the head */

BT_RecCur++;

BT_Buf_Status |= (1 << 6) ;

}

else

{

BT_Buf_Status = 0;

 

/* not standard cmd, just save */

 

buff[cnt] = data;

cnt++;

cnt &= (16 - 1);

}

}

}

}

方法二:中断 + FIFO方法


定义结构:


#define MAX_BT_DATA 32

 

 

typedef struct _bt_data

{

u8 pBtData[MAX_BT_DATA];

u8 cursor;

}BT_DATA;

 

static BT_DATA btData;

void BT_Routine(void)

{

u8 cnt = 0;

BT_DATA *pData = &btData;

u8 i = pData->cursor;

u8 count;

 

if(bt_mode == BT_MODE_NORMAL)

{

count = BT_Rx(pData->pBtData + i, 1);

if(1 == count)

{

//debug("%x ", pData->pBtData[i]);

if(pData->pBtData[i] == 0xBC)

{

cnt = BT_Rx(BT_RcvBuf, 7);

if((cnt == 7) && (BT_RcvBuf[6] == 0xEC) && (BT_RcvBuf[0] == 0x08))

{

//BT_Handler();

//debug("excute the BT-handler .rn");

u8 cmd = BT_RcvBuf[1];

if(BT_GetCmd(cmd))

{

//debug("got the cmd & excute handler .rn");

bt_cmd.bt_handler(BT_RcvBuf[2], BT_RcvBuf[3]);

}

}

else

{

debug("not standard cmd . please retry . rn");

 

/*

* TODO : here will check package-lost or package-error

*/

u8 i;

for(i = 0; i < cnt ; i++)

{

debug("%x ", BT_RcvBuf[i]);

}

}

}

else if(pData->pBtData[i] == 0x2B)                    /* disconnect */

{

/*

* read the other byte and discard

* @2B 44 69 73 63 6F 6E 6E 65 63 74 0D 0A

*/

cnt = BT_Rx(BT_RcvBuf, 12);

if((12 == cnt ) && (BT_RcvBuf[0] == 'D'))

{

debug("disconnect .rn");

 

/*

* disconnect ,and switch the mode for connection

*/ 

bt_mode = BT_MODE_ADMIN;

}

}

else

{

/* read and discard */ 

BT_Rx(BT_RcvBuf, 1);

}

}

}

else if(bt_mode == BT_MODE_ADMIN)

{

/*

* get admin package,such as connect and AT cmd

*/ 

count = BT_Rx(pData->pBtData + i, 1);

if(1 == count)

{

if(pData->pBtData[i] == 0x2B) 

{

cnt = BT_Rx(BT_RcvBuf, 1);

if((1 == cnt) && (BT_RcvBuf[0] == 'c'))

{

/*

* read the other byte and discard

* @2B 63 6F 6E 6E 65 63 74 0D 0A 

*/

cnt = BT_Rx(BT_RcvBuf, 8);

debug("connect .rn");

 

/* switch the mode to normal */ 

bt_mode = BT_MODE_NORMAL;

}

if((1 == cnt) && (BT_RcvBuf[0] == 'o'))

{

debug("OK .rn");

}

}

else

{

/* read and discard */ 

BT_Rx(BT_RcvBuf, 1);

printf("%x ", BT_RcvBuf[0]);

}

}

}

else if(bt_mode == BT_MODE_LOAD)

{

//TODO: load music package

}

}

对于支持“透传+ AT指令”模式的传输设备,且默认是透传模式, 可以定义如下模式:


 

typedef enum

{

    BT_MODE_NORMAL = 0,          /* normal command mode */ 

    BT_MODE_ADMIN,               /* control mode ,such as AT  */

}BT_MODE;   

当检测到设备disconnect后,切换模式到AT指令模式,这样在透传模式下可以控制输出“AT指令”查询设备信息


 


更新:


BUG: 以上FIFO接收蓝牙信息时会出现数据丢失的情况;原因是使用RX中断导致中断频率很高。而使用RTOS过程中,许多临界数据需要关中断来保护,所以会出现丢包;


解决:不适用USART的RXNE中断, 而使用idle中断和DMA中断, 这样会大大降低中断频率。


重点代码如下:


初始化USART2 的RX DMA功能:


void HAL_DMA_Init(void)

{

DMA_InitTypeDef DMA_InitStructure;

NVIC_InitTypeDef NVIC_InitStruct;

 

DMA_RecvBuf = (u8 *)_MemMalloc(DMA_RX_SIZE);         /* never free */

 

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

DMA_DeInit(DMA_CH);

 

DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART2->DR;  

DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_RecvBuf;       /* dest addr */

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;             /* periph to buffer */

DMA_InitStructure.DMA_BufferSize = DMA_RX_SIZE;                /* DMA buff size */

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;             /* DMA buff auto update */

DMA_InitStructure.DMA_Priority = DMA_Priority_High;       /* priority of medium */

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                /* not buffer to buffer */

DMA_Init(DMA_CH, &DMA_InitStructure);

 

/*  transfer complete interrupt */

    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel6_IRQn;

    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;

    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStruct);

 

DMA_ITConfig(DMA_CH,DMA_IT_TC,ENABLE);

 

DMA_Cmd(DMA_CH, ENABLE);

}

改变DMA BUFF的API:


void DMA_Enable(void)

DMA_Cmd(DMA_CH, DISABLE ); 

  DMA_SetCurrDataCounter(DMA_CH , DMA_RX_SIZE);   /* DMA buffer */

  DMA_Cmd(DMA_CH, ENABLE);  

}

相关全局变量和宏:


/*

* USART2 RX DMA1 ch6 

*

*/

 

#define DMA_DEV DMA1

#define DMA_CH DMA1_Channel6

 

 

#define DMA_RX_SIZE 4096

 

static u8 *DMA_RecvBuf;

//static u32 validLength;

最后使能:


USART_DMACmd(USART2 , USART_DMAReq_Rx , ENABLE);      /* enable RX-DMA */

此外, 注释掉原来USART的RXNE中断,加上IDLE相关的中断使能:


// config the interrupt

//USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);    /* RX not empty */ 

USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);      /* IDLE */

最后看中断处理函数里面,其实移植RX中断里面代码即可:


static void BT_IDLE_Handler(void)

{

u32 temp = 0; 

    u16 cnt = 0; 

    u16 i = 0;  

 

u32 tail = BTRxTail;

u32 space = CIRC_SPACE(BTRxHead,tail,MAX_BT_RX_LEN);

 

temp = USART2->SR;  

    temp = USART2->DR; //清USART_IT_IDLE标志 

 

DMA_Cmd(DMA1_Channel6,DISABLE);  

temp = DMA_RX_SIZE - DMA_GetCurrDataCounter(DMA1_Channel6);  

 

printf("DMA receive : %d rn", temp);

 

if((space > 0) && (temp > 0))

{

        if(temp >= space)

            cnt = space ;

        else

            cnt = temp;

 

for(i = 0; i < temp; i++)

{

BTRxBuf[tail++] = DMA_RecvBuf[i];  

BTRxTail = tail & (MAX_BT_RX_LEN - 1);

}

}

else

{

// should not happen

debug("BT_RX_Handler RxBuf over flow .rn");

}

 

DMA_SetCurrDataCounter(DMA1_Channel6,DMA_RX_SIZE);  

DMA_Cmd(DMA1_Channel6,ENABLE);

}


关键字:stm32  接收蓝牙  uart  设备命令

编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic467489.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32F103 代码远程升级(一)初识IAP编程
下一篇:STM32实现蓝牙HC-06通信

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32解决:st-link连接下载程序的问题

STM32解决:Error: Flash Download failed - "Cortex-M3"本人由于使用普中科技的stm32 的开发板的 USB的下载的地方坏了,所以不得不使用arm仿真器 st-link 进行下载。鼓捣了半天下面总结一下几个问题:1、st-link的驱动下载首先你插上st-link的时候,电脑的设备管理器这个地方是有感叹号的,说明还没有装好驱动,所以我就在网上找啊找。终于根据:win8【笔者没这个系统,无法测试,请大家测试后报告】:http://pan.baidu.com/s/1sjJQxZn(转载来自:https://blog.csdn.net/imxiangzi/article
发表于 2019-07-19
STM32解决:st-link连接下载程序的问题

解决stm32f103通过stlink不能烧录程序问题

问题:   stm32(stm32f103c8T6)开发板只能通过串口烧录程序,而st—link居然不行描述:解决:st-link固件升级用stm32cubemx快速开发时没有配置好调试模式重新生成代码就可以了如果还是不行的话,就得升级一下stlink固件了,具体升级方法可百度
发表于 2019-07-19
解决stm32f103通过stlink不能烧录程序问题

STM32下载不成功问题汇总

在某宝上买了五个最小系统核心板是STM32F103C8T6的芯片,刚拿到手准备下载程序调试,上电后板子自带LED闪烁,这是商家自己下载的示例程序,说明芯片工作着,用KEIL4进行下载自己程序,把自己编译好的程序下载。用的JLINK的四线下载调试下载口,SW的调试接口,点击下载后发现擦除成功,下载失败,提示:Load "..\Output\STM32-DEMO.axf" Set JLink Project File to "F:文件RFID程序电机USERJLinkSettings.ini"* JLink Info: Device "STM32
发表于 2019-07-19
STM32下载不成功问题汇总

STM32高级开发(11)-使用GDB调试你的工程

/scripts/target/stm32f4x_stlink.cfg在执行完此条指令后该终端就会一直执行OpenOCD的程序了,不要关闭它,我们再打开一个终端界面,进入我们的工程目录,比如我这里进入的就是我的libopencm3样例工程下的blink子工程目录。$ cd '/home/yangliu/workspace/libopencm3-my-example/blink'然后我们使用指令输入调试文件并打开GDB程序。$ arm-none-eabi-gdb blink.elf 然后我们在GDB的指令界面中,输入连接指令,连接本地的3333端口。(gdb)target remote localhost:3333此时
发表于 2019-07-19
STM32高级开发(11)-使用GDB调试你的工程

STM32F4标准外设库模板工程建立与使用

SW4STM32安装其实固件库安装过程很简单,在第一次新建工程时会提示选择使用Stdperiph 驱动还是Cube HAL,由于Stm32官方大力推行Cube HAL固件库,所以Cube HAL的固件库直接可以从网上直接一键下载安装。然而对于老的StdPeriph固件库不能一键式下载安装,会提示出错。所以,我们需要自己下载一个.zip固件包,放在C:UsersLYAppDataRoamingAc6SW4STM32firmwares文件夹下,其中的LY就是计算机的用户名。然后新建工程时在选择Stdperiph固件时会自动解压缩,这样就能使用该库进行编译了。界面如下所示:工程配置器件与时钟或者,修改晶振与时钟,根据注释可以算得
发表于 2019-07-19
STM32F4标准外设库模板工程建立与使用

基于STM32的外设的GPIO外设设置总结

1、背景外设驱动的寄存器设置对于外设功能正常运行异常重要。现在对GPIO的配置进行总结。2、GPIO的配置总结复用GPIO配置GPIO设置为输出或者是复用模式时,需要设置输出速度;而无论设置为什么模式,都要对GPIO的内部上下拉进行设置。注意:在输入模式(普通输入/模拟输入)下,OTYPE和OSPEED参数无效!!
发表于 2019-07-19
基于STM32的外设的GPIO外设设置总结

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved