串列埠中怎樣接收一個完整資料包的解析
阿新 • • 發佈:2019-01-05
方法1:串列埠接受資料,定時器來判斷超時是否接受資料完成。
方法2:DMA接受+IDLE中斷
實現思路:採用STM32F103的串列埠1,並配置成空閒中斷IDLE模式且使能DMA接收,並同時設定接收緩衝區和初始化DMA。那麼初始化完成之後,當外部給單片機發送資料的時候,假設這幀資料長度是200個位元組,那麼在微控制器接收到一個位元組的時候並不會產生串列埠中斷,而是DMA在後臺把資料默默地搬運到你指定的緩衝區裡面。當整幀資料傳送完畢之後串口才會產生一次中斷,此時可以利用DMA_GetCurrDataCounter();函式計算出本次的資料接受長度,從而進行資料處理。
應用物件:適用於各種串列埠相關的通訊協議,如:MODBUS,PPI ;還有類似於GPS資料接收解析,串列埠WIFI的資料接收等,都是很好的應用物件。
關鍵程式碼分析:
- 1
- 2
- 3
- 4
- 5
- 6
void uart_init(u32 bound);
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);
#endif
usart.C
//初始化IO 串列埠1
//bound:波特率
void uart_init(u32 bound)
{
//GPIO埠設定
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE); //使能USART1,GPIOA時鐘
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA傳輸
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2時鐘
USART_DeInit(USART1); //復位串列埠1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推輓輸出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶佔優先順序3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先順序3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的引數初始化VIC暫存器
//USART 初始化設定
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位資料格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;//無硬體資料流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式
USART_Init(USART1, &USART_InitStructure); //初始化串列埠
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//開啟空閒中斷
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串列埠1 DMA接收
USART_Cmd(USART1, ENABLE); //使能串列埠
//相應的DMA配置
DMA_DeInit(DMA1_Channel5); //將DMA的通道5暫存器重設為預設值 串列埠1對應的是DMA通道5
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外設usart基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf; //DMA記憶體基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //資料傳輸方向,從外設讀取傳送到記憶體
DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len; //DMA通道的DMA快取的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址暫存器不變
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //記憶體地址暫存器遞增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //資料寬度為8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //資料寬度為8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常快取模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x擁有中優先順序
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x沒有設定為記憶體到記憶體傳輸
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //根據DMA_InitStruct中指定的引數初始化DMA的通道
DMA_Cmd(DMA1_Channel5, ENABLE); //正式驅動DMA傳輸
}
//重新恢復DMA指標
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
DMA_Cmd(DMA_CHx, DISABLE ); //關閉USART1 TX DMA1所指示的通道
DMA_SetCurrDataCounter(DMA_CHx,DMA_Rec_Len);//DMA通道的DMA快取的大小
DMA_Cmd(DMA_CHx, ENABLE); //開啟USART1 TX DMA1所指示的通道
}
//傳送len個位元組
//buf:傳送區首地址
//len:傳送的位元組數
void Usart1_Send(u8 *buf,u8 len)
{
u8 t;
for(t=0;t<len;t++) //迴圈傳送資料
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1,buf[t]);
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
//串列埠中斷函式
void USART1_IRQHandler(void) //串列埠1中斷服務程式
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收中斷(接收到的資料必須是0x0d 0x0a結尾)
{
USART_ReceiveData(USART1);//讀取資料注意:這句必須要,否則不能夠清除中斷標誌位。
Usart1_Rec_Cnt =DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本幀資料長度
//***********幀資料處理函式************//
printf ("Thelenght:%d\r\n",Usart1_Rec_Cnt);
printf ("The data:\r\n");
Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);
printf ("\r\nOver! \r\n");
//*************************************//
USART_ClearITPendingBit(USART1,USART_IT_IDLE); //清除中斷標誌
MYDMA_Enable(DMA1_Channel5); //恢復DMA指標,等待下一次的接收
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112