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

发布者:devilcore最新更新时间: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  设备命令 引用地址:stm32 接收蓝牙(uart)等设备命令的处理

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

推荐阅读最新更新时间:2024-11-10 16:37

stm32通用定时器的使用
一、定时器的种类和时钟 stm一共有8个定时器,其中tim1和tim8为高级定时器。tim2~tim7为通用定时器。 高级定时器的时钟源挂载在apb2上(apb2=AHB),通用定时器挂载在apb1上(apb1=1/2AHB)。 下面给出一张时钟树的图: 从图中可以看出,如果apb1 prescaler=1,则tim2~tim7的时钟为定时器时钟等于apb1的时钟,而在stm32时钟的默认配置中,apb1=1/2 AHB,所以,这里定时器时钟频率是apb1的两倍,即72M。而tim1和TIM7的频率也是72M。 二、stm32通用定时器配置步骤: 1、初始化时钟 RCC_APB1PeriphClockCmd (RCC_APB
[单片机]
<font color='red'>stm32</font>通用定时器的使用
STM32红外发射的实现
一、环境: 公司所采用的是STM32F103RBT6芯片,本人开发是基于官方提供的V3.5.0的函数库。 二、所要实现的功能是: 1. 开发板能够学习由遥控器发送来的红外码,并在串口上打印出来。 2. 上位机通过串口程序,发送学习来的码,可控制红外设备。 3. 发送时共有四路,上位机发送码子时,可选择通道。 三、实现: 0. 在写功能之前先要对我们所用的模块和时钟进行初始化。 (此部分 自己看手册) 1. 开发板能够学习由遥控器发送来的红外码,并在串口上打印出来。 红外的学习功能我是利用中断+定时,来记录红外码高低电平的时间长度,程序如下:
[单片机]
STM32 HAL库串口发送多字节数据
串口发送16字节数据 int16_t MotorEncoder; uint8_t low,high; high=(uint8_t)(MotorEncoder 8); low=(uint8_t)(MotorEncoder&0xFF); HAL_UART_Transmit(&huart1 , &low, 1, 0xff); HAL_UART_Transmit(&huart1 , &high, 1, 0xff); 串口发送32字节数据 int32_t MotorEncoder; uint8_t code ; code =(uint8_t)(MotorEncoder 24); code =(uint8_t)(MotorEnco
[单片机]
STM32 基础系列教程 8 - 互补PWM
前言 PWM及互补PWM是电机控制的基础,前面我们已经学习了PWM的产生,今天来学习一下互补PWM的产生,互补PWM就是两个互补的PWM的组合,用stm32 的高级定时器可以直接产生两路互补的PWM(即互补PWM)。 示例详解 基于硬件平台: STM32F10C8T6最小系统板, MCU 的型号是 STM32F103c8t6, 使用stm32cubemx 工具自动产生的配置工程,使用KEIL5编译代码。 本示例所用的最小系统板原理图: 从本节开始,关于CUBEMX工具及KEIL工具的操作将不再细讲,如果还有不熟悉的可以查看之前的教程文档。下面直接介绍工程配置: 系统时钟树 高级定时器TIM1配置
[单片机]
<font color='red'>STM32</font> 基础系列教程 8 - 互补PWM
STM32 FSMC的用法--LCD
1. LCD/LCM的基本概念 液晶显示器(Liquid Crystal Display: LCD)的构造是在两片平行的玻璃当中放置液态的晶体,两片玻璃中间有许多垂直和水平的细小电线,透过通电与否来控制杆状水晶分子改变方向,将光线折射出来产生画面。 LCM(LCD Module)即LCD显示模组、液晶模块,是指将液晶显示器件,连接件,控制与驱动等外围电路,PCB电路板,背光源,结构件等装配在一起的组件。 在平时的学习开发中,我们一般使用的是LCM,带有驱动IC和LCD屏幕等多个模块。 2. FSMC的基本概念 在STM32上开发LCD显示,可以有两种方式来对LCD进行操作,一种是通过普通的IO口,连接LCM的相应引脚来进行操作,
[单片机]
MSP430程序库UART异步串口
硬件介绍: MSP单片机的USART模块可以配置成SPI(同步通信)模式或UART(异步通信)模式,这里只讨论UART方式。UART数据传输格式如下: 起始位,数据位由高到低7/8位,地址位 0/1位,奇偶校验位 奇偶或无,停止位1/2位。数据位位数、地址位、奇偶校验位、停止位均可由单片机内部寄存器控制;这两款单片机都有两个USART模块,有两套独立的寄存器组;以下寄存器命中出现x代表0或是1,0代表对应0模块的寄存器,1代表对应1模块的寄存器;其中,与串口模式设置相关的控制位都位于UxCTL寄存器,与接收相关的控制位都位于UxRCTL寄存器,与发送相关的控制位都位于UxTCTL寄存器;波特率设置用UxBR0、UxBR1、U
[单片机]
MSP430程序库<font color='red'>UART</font>异步串口
stm32 Fdts
[单片机]
<font color='red'>stm32</font> Fdts
STM32红牛开发板非固件库控制LED
摘要 STM32红牛开发板上的5个LED,接在GPIOF6~10脚,输出低电平时,LED亮。这样我们设置GPIOF的相关寄存器,让其输出低电平就可以让LED亮。因为没有用到ST提供的固件库,所以是直接对寄存器的内存地址读写,即对一个指向该地址的指针变量进行读写。并且该变量必须为易变型的,即用volatile定义,这样是为了告诉编译器不要去优化这个变量,导致其它一些寄存器的数据变化。GPIOx是挂载在APB2高速外设总线上的,最大频率是72MHZ,所以我们除了了打开HSE(外部高速时钟)并关闭内部高速时钟(开机默认选择了HSI)外,还要打开APB2总线的时钟。 一、寄存器地址映射 外设的基址PERI
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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