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에 따라 라이센스가 부여됩니다.