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);
}이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
STM32CubeIDE를 사용해 보자 How To STM32CubeIDE 일본어판 (11) I2C를 사용해 보자 4 Si7020+ssd1306편STM32CubeIDE를 사용해 보자 How To STM32CubeIDE 일본어판 (10) I2C를 사용해 보자 3 ssd1306편의 계속입니다. Nucleo 보드와 Si7020, SSD1306을 연결합니다. 이번에...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.