国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
STM32 UART DMA實現(xiàn)未知數(shù)據(jù)長度接收
串口通信是經(jīng)常使用到的功能,在STM32中UART具有DMA功能,并且收發(fā)都可以使用DMA,使用DMA發(fā)送基本上大家不會遇到什么問題,因為發(fā)送的時候會告知DMA發(fā)送的數(shù)據(jù)長度,DMA按照發(fā)送的長度直接發(fā)送就OK了,但是使用DMA接收時候就不同了,因為有時候數(shù)據(jù)接收并不是每一次都是定長的,但是DMA只在接收數(shù)據(jù)長度和設(shè)定數(shù)據(jù)長度相同的時候才可以觸發(fā)中斷,告訴MCU數(shù)據(jù)接收完畢,針對這個問題,解決方法如下,有一點復(fù)雜,但是很管用。
1、        首先了解串口通信的協(xié)議

(原文件名:1.jpg)

從上圖可知,UART在傳輸一個字節(jié)的時候,首先拉低,傳輸起始位,然后在是LSB –MSB,最后是停止位,停止位是高電平
2、        超時時間
搞過串口通信的都知道,如果串口有協(xié)議,一般都是有個超時時間的,超時時間是定義兩個幀之間的間隔的,如果串口接收到一個字節(jié)后,在規(guī)定的超時時間內(nèi)沒有接收到其他數(shù)據(jù),我們則認(rèn)為前面接收的數(shù)據(jù)位一幀。

(原文件名:2.jpg)
3、        定時器復(fù)位復(fù)位模式
STM32定時器功能比較強(qiáng)大,其中有一種模式為復(fù)位模式,

(原文件名:3.jpg)
上圖STM32 用戶手冊中的舉例,注意紅色箭頭指向的位置,TI1的輸入上升沿會復(fù)位定時器的計數(shù)器,具體請查閱STM32用戶手冊關(guān)于這部分的描述。
整體的思路是這樣的,一開始設(shè)置好DMA接收,可以把緩沖區(qū)長度設(shè)置為幀最大長度,我們可以把RX連接到定時器的管腳輸入端,并且一開始設(shè)置輸入并且使能引腳下降沿中斷,當(dāng)幀的第一個字節(jié)發(fā)送時,因為起始位為低電平,空閑時UART為高電平,滿足條件,進(jìn)入中斷,禁止中斷,并且在中斷中開啟定時器,該定時器工作在復(fù)位模式,上升沿復(fù)位,并且設(shè)置好定時器輸出比較值為超時時間,比如20ms,這樣,在傳輸后面字節(jié)時,肯定會有高低電平出現(xiàn),即便是傳輸?shù)氖?x00,0xFF,雖然UART數(shù)據(jù)區(qū)不變,但是都為1,或都為0,但是因為起始位為低電平,停止位是高電平,所以肯定會有上升沿,定時器會一直復(fù)位,輸出定時器的計數(shù)器一直到達(dá)不了輸出比較值,當(dāng)一幀傳輸結(jié)束后,定時在最后一個字節(jié)復(fù)位后,由于沒有數(shù)據(jù)繼續(xù)到達(dá),無法復(fù)位,則計數(shù)器就能計到輸出比較值,這時發(fā)出中斷,在定時器中斷中可以計算出接收數(shù)據(jù)的長度,并且通知外部數(shù)據(jù)已經(jīng)接收完畢。
4、        功能實現(xiàn)
實現(xiàn)的步驟:
1、硬件連接:UART的RX線在連接外部的同時,還需要連接到一個定時器的輸入端TIMx_CHx,定時器可以為任意定時器,但是CHx,只能為CH1或CH2,具體的需要看STM32的定時器邏輯圖,以STM32F101CB為例,我們暫定把UART1的RX在連接RS232的同時,還連接到TIM4_CH2。
2、軟件設(shè)置
a) IO、中斷設(shè)置:在把UART功能口設(shè)置好后,還需要設(shè)置TIM4_CH2為輸入上拉,并且使能該引腳外部中斷

/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval : None
  */
void GPIO_Configuration(void)
{
/* Configure USART1_Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
   
/* Configure USART1_Tx as alternate push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOB.7 Configuration: TIM4 Channel2 as input floatinng */
GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief  Configures the system EXIT.
  * @param  None
  * @retval None
  */
void EXTI_Configuration(void)
{
    EXTI_InitTypeDef   EXTI_InitStructure;
    /* Connect EXTI8 Line to PB.07 pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);
   
    /* Configure EXTI8 line */
    EXTI_InitStructure.EXTI_Line = EXTI_Line7;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
   
    /* Clears  EXTI line pending bits. */
    EXTI_ClearITPendingBit(EXTI_Line7);
}

/**
  * @brief  Configures NVIC and Vector Table base location.
  * @param  None
  * @retval : None
  */
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Configure the NVIC Preemption Priority Bits*/  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    /* Set the Vector Table base location at 0x08000000 */
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
  
   
    /* Enable the DMA1_Channel_Rx Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* Configure DMA1_Channel_Tx interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* Configure TIM1 update interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* Enable and set EXTI9_5 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
把DMA接收的數(shù)據(jù)緩沖區(qū)設(shè)置為你認(rèn)為最大的幀長度,(如果最長不能確定,也可以隨便指定一個長度,后面再講怎么實現(xiàn))。
b) 定時器設(shè)置
因為使用的是TIM4_CH2,所以需要配置TIM4,并且配置為復(fù)位模式,把超時時間定為20ms,為了方便TIM4時鐘定輸入為1KHZ
/*
* This function is called by timer_init() to perform the non-generic portion
* of the initialization of the timer module.
*/
void timer_init_non_generic(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    TIM_ICInitTypeDef  TIM_ICInitStructure;
   
    /* TIM4 configuration ----------------------------------------------------*/
    TIM_TimeBaseStructure.TIM_Period = 65535;
    TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/1000000 * 1000 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
   
    /* Output Compare  Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
    TIM_OCInitStructure.TIM_Pulse = 20;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC1Init(TIM4, &TIM_OCInitStructure);
   
    /* TIM4 Channel 2 Input Capture Configuration */
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0;
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
   
    /* TIM4 Input trigger configuration: External Trigger connected to TI2 */
    TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
   
    /* TIM4 configuration in slave reset mode  where the timer counter is
    re-initialied in response to rising edges on an input capture (TI2) */
    TIM_SelectSlaveMode(TIM4,  TIM_SlaveMode_Reset);
   
    /* TIM4 IT CC1 enable */
    TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
   
}
c)工作過程如下
在串口傳輸起始位的時候,首先產(chǎn)生外部中斷,在外部中斷中開啟定時器,禁止外部中斷,只要串口上一直有數(shù)據(jù),定時器肯定會不停的復(fù)位,到達(dá)不了定時時間,當(dāng)串口上沒有數(shù)據(jù)的時候,到超時時間后,定時器產(chǎn)生中斷,此時可以讀出接收的數(shù)據(jù)長度,然后開啟外部中斷,進(jìn)入下一個周期。

(原文件名:4.jpg)


總結(jié):本方法的缺點是程序開始的初始化麻煩些,但是優(yōu)點是非常明顯的,徹底解放了CPU,這樣在計算串口超時的時候,就不需要定時器不停的中斷,并且串口接收數(shù)據(jù)使用DMA方式,也不需要CPU參與,只是在接收結(jié)束的時候通知CPU取數(shù)據(jù),CPU的利用率會更高。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
零死角玩轉(zhuǎn)stm32
stm32使用體會
深入淺出STM32(2)
旋轉(zhuǎn)編碼器EC11_支持長按、短按、雙擊、順時針逆時針
無刷有感電機(jī)測速、速度閉環(huán)控制
stm32庫函數(shù)編程基礎(chǔ)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服