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 .\r\n");
					u8 cmd = BT_RcvBuf[1];					
					
					if(BT_GetCmd(cmd))
					{
						//debug("got the cmd & excute handler .\r\n");
						bt_cmd.bt_handler(BT_RcvBuf[2], BT_RcvBuf[3]);
					}
				}
				else
				{
					debug("not standard cmd . please retry . \r\n");

					/*
					* 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 .\r\n");

						/*
						* 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 .\r\n");

					/* switch the mode to normal */ 
					bt_mode = BT_MODE_NORMAL;
				}
				if((1 == cnt) && (BT_RcvBuf[0] == 'o'))
				{
					debug("OK .\r\n");
				}
			}
			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 \r\n", 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 .\r\n");
	}

	
	
	DMA_SetCurrDataCounter(DMA1_Channel6,DMA_RX_SIZE);  
	DMA_Cmd(DMA1_Channel6,ENABLE);
}

 

你可能感兴趣的:(STM32)