stm32 블루투스 (uart) 등 장치 명령 처리

7298 단어 STM32
두 가지 방법이 있습니다.
방법 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);
			}				
		}
	}
}

방법2: 인터럽트 + 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
"); u8 cmd = BT_RcvBuf[1]; if(BT_GetCmd(cmd)) { //debug("got the cmd & excute handler .\r
"); bt_cmd.bt_handler(BT_RcvBuf[2], BT_RcvBuf[3]); } } else { debug("not standard cmd . please retry . \r
"); /* * 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
"); /* * 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
"); /* switch the mode to normal */ bt_mode = BT_MODE_NORMAL; } if((1 == cnt) && (BT_RcvBuf[0] == 'o')) { debug("OK .\r
"); } } 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
", 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
"); } DMA_SetCurrDataCounter(DMA1_Channel6,DMA_RX_SIZE); DMA_Cmd(DMA1_Channel6,ENABLE); }

좋은 웹페이지 즐겨찾기