方法有两种:
方法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);
}
上一篇:STM32F103 代码远程升级(一)初识IAP编程
下一篇:STM32实现蓝牙HC-06通信
推荐阅读最新更新时间:2024-11-10 16:37