1. 程式人生 > >串列埠中怎樣接收一個完整資料包的解析

串列埠中怎樣接收一個完整資料包的解析

方法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