国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

STM32 cubemx+串口空閑中斷+DMA雙緩沖

這篇具有很好參考價值的文章主要介紹了STM32 cubemx+串口空閑中斷+DMA雙緩沖。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

????????寫這篇文章是為了記錄下之前做過的項目中用到的一部分關鍵技術,之前做過的項目中涉及到采用最小開銷來實時接收遙控器數(shù)據(jù)、能夠準確驗證傳輸過來數(shù)據(jù)的準確性,減小誤差率,要求能穩(wěn)定適用于不同的環(huán)境。

目錄

1、為什么要用到串口空閑中斷?

2、為什么要用到DMA雙緩沖?

3、具體代碼流程。

????????(1)cubemx配置stm32串口DMA雙緩沖。

????????(2)添加串口中斷處理函數(shù)。

????????(3)根據(jù)手冊處理遙控器數(shù)據(jù)


1、為什么要用到串口空閑中斷?

????????在stm32 中,uart是最為常見的通信方式——它每次接收一個字節(jié),我們可以使用輪詢的方式,輪詢就是不斷去訪問一個信號的端口,看看有沒有信號進入,有則進行處理,但是對于某些數(shù)據(jù)不固定時間發(fā)送的數(shù)據(jù),輪詢的方式過多消耗系統(tǒng)資源了。

???????使用中斷的方式,中斷方式則是當輸入產生的時候,產生一個觸發(fā)信號告訴 STM32 有輸入信號進入,需要進行處理。如每一個字節(jié)都中斷一次,比較消耗系統(tǒng)資源。特別是HAL庫中,從中斷到回調函數(shù)運行了不少的程序,頻繁的中斷很可能造成數(shù)據(jù)溢出。

????????為了避免這個問題,我們使用指定接收一定長度的數(shù)據(jù),再調用回調函數(shù),這會讓我們可以接收大數(shù)據(jù),但是這種情況則造成了,要求每次的包是固定長度。

????????為了解決以上一些問題,網(wǎng)上最常用的辦法是使用空閑中斷,即在串口空閑的時候,觸發(fā)一次中斷,通知內核,本次運輸完成了。串口空閑中斷的判定是:當串口開始接收數(shù)據(jù)后,檢測到1字節(jié)數(shù)據(jù)的時間內沒有數(shù)據(jù)發(fā)送,則認為串口空閑了。由于我們的內核在串口接收數(shù)據(jù)到空閑這段時間,是不受理串口數(shù)據(jù)的,所以我們還需要使用DMA來協(xié)助我們把數(shù)據(jù)傳送到指定的地方,當數(shù)據(jù)傳輸完成后,通知內核去處理。

? ? ? ? 由于在項目中要用到遙控器發(fā)送數(shù)據(jù)給stm32,并且外界環(huán)境的干擾,可能會發(fā)生丟幀的情況。這時遙控器發(fā)送數(shù)據(jù)是不定時的,因此我在項目中采用的是不定時、不定長接收數(shù)據(jù)。

????????如果有一次數(shù)據(jù)被干擾,遙控器的18幀數(shù)據(jù)只有17個被串口接受,那么在下一次遙控器發(fā)送數(shù)據(jù)時,stm32會把下一次的第一個幀和上一次的17幀拼接在一次保存在緩存里,導致之后的數(shù)據(jù)全部接收錯誤。

2、為什么要用到DMA雙緩沖?

????????DMA全稱Direct Memory Access,即直接內存訪問。
普通DMA的使用是在DMA的數(shù)據(jù)流中進行的,設置好DMA的起點和終點以及傳輸?shù)臄?shù)據(jù)量即可開啟DMA傳輸。

????????DMA開啟后就開始從起點將數(shù)據(jù)搬運至終點,每搬一次,傳輸數(shù)據(jù)量大小就減1,當傳輸數(shù)據(jù)量為0時,DMA停止搬運。

普通模式:當傳輸數(shù)據(jù)量為0時,需要程序中手動將傳輸數(shù)據(jù)量重新設置滿才能開啟下一次的DMA數(shù)據(jù)傳輸。
循環(huán)模式:則當傳輸數(shù)據(jù)量為0時,會自動將傳輸數(shù)據(jù)量設置為滿的,這樣數(shù)據(jù)就能不斷的傳輸。

普通DMA模式下,普通DMA的目標數(shù)據(jù)儲存區(qū)域只有一個,也就是如果當數(shù)據(jù)存滿后,新的數(shù)據(jù)又傳輸過來了,那么舊的數(shù)據(jù)會被新的數(shù)據(jù)覆蓋。

雙緩沖模式下,我們DMA的目標數(shù)據(jù)儲存區(qū)域有兩個,也就是雙緩沖,
當一次完整的數(shù)據(jù)傳輸結束后(即Counter值從初始值變?yōu)?),會自動指向另一個內存區(qū)域。

????????但有時為了安全,當我們設置的DMA緩沖區(qū)大小大于一次完整的數(shù)據(jù)時,當接收完一次數(shù)據(jù)后,Counter值還沒有變?yōu)?,這時不會自動指向另一個緩沖區(qū),所以這時候我們就需要手動更改指向下一個緩沖區(qū)。(也就是當?shù)谝粠瑪?shù)據(jù)傳輸完成后,Counter值不會自動填滿,且內存區(qū)域還是指向Memory0,然后我們將剩余數(shù)據(jù)量保存下來,再將Counter值填滿,接著把DMA指向Memory1,最后通過判斷剩余數(shù)據(jù)量來決定是否對數(shù)據(jù)進行處理)

//設定緩沖區(qū)0
DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
//設定緩沖區(qū)1
hdma_usart1_rx.Instance->CR |= DMA_SxCR_CT;

3、具體代碼流程。

(1)cubemx配置stm32串口DMA雙緩沖。

????????網(wǎng)上教程很多,這里我就不具體說明了,這里可參考別人寫的這篇文章。

????????雖然我們使用的CubeMx來配置DMA,當然只是配置DMA模式為串口到內存(DMA初始化),但還需要在程序中進一步制定,DMA具體搬運到哪一個內存中,建立兩個數(shù)組用以存放DMA搬運的串口數(shù)據(jù),并將數(shù)組的地址傳給化函數(shù),具體代碼如下所示:文章來源地址http://www.zghlxwxcb.cn/news/detail-698919.html

//初始化代碼
#define SBUS_RX_BUF_NUM 16u  //定義的DMA緩沖區(qū)的大小,為了安全我定義了16(定義8以上就行了)
#define RC_FRAME_LENGTH 8u   //遙控器發(fā)送的數(shù)據(jù)長度

extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;

//接收原始數(shù)據(jù),為8個字節(jié),給了16個字節(jié)長度,防止DMA傳輸越界
static uint8_t sbus_rx_buf[2][SBUS_RX_BUF_NUM];

void RC_Init(uint8_t *rx1_buf, uint8_t *rx2_buf, uint16_t dma_buf_num)
{
    //使能DMA串口接收
    SET_BIT(huart1.Instance->CR3, USART_CR3_DMAR);
    //使能串口空閑中斷
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
    //失效DMA
    __HAL_DMA_DISABLE(&hdma_usart1_rx);
    while(hdma_usart1_rx.Instance->CR & DMA_SxCR_EN)
    {
        __HAL_DMA_DISABLE(&hdma_usart1_rx);
    }
    hdma_usart1_rx.Instance->PAR = (uint32_t) & (USART1->DR);
    //內存緩沖區(qū)1
    hdma_usart1_rx.Instance->M0AR = (uint32_t)(rx1_buf);
    //內存緩沖區(qū)2
    hdma_usart1_rx.Instance->M1AR = (uint32_t)(rx2_buf);
    //數(shù)據(jù)長度
    hdma_usart1_rx.Instance->NDTR = dma_buf_num;
    //使能雙緩沖區(qū)
    SET_BIT(hdma_usart1_rx.Instance->CR, DMA_SxCR_DBM);
    //使能DMA
    __HAL_DMA_ENABLE(&hdma_usart1_rx);	
}

void RC_unable(void)
{
    __HAL_UART_DISABLE(&huart1);
}
void RC_restart(uint16_t dma_buf_num)
{
    __HAL_UART_DISABLE(&huart1);
    __HAL_DMA_DISABLE(&hdma_usart1_rx);

    hdma_usart1_rx.Instance->NDTR = dma_buf_num;

    __HAL_DMA_ENABLE(&hdma_usart1_rx);
    __HAL_UART_ENABLE(&huart1);

}
//遙控器初始化
void remote_control_init(void)
{
    RC_Init(sbus_rx_buf[0], sbus_rx_buf[1], SBUS_RX_BUF_NUM);
}

(2)添加串口中斷處理函數(shù)。

void USART1_IRQHandler(void)
{
    //HAL_GPIO_TogglePin(GPIOA, led2_Pin);
    if(huart1.Instance->SR & UART_FLAG_RXNE)//接收到數(shù)據(jù)
    {
        __HAL_UART_CLEAR_PEFLAG(&huart1);//清除空閑中斷標志(否則會一直不斷進入中斷)
    }
    else if(USART1->SR & UART_FLAG_IDLE)//串口空閑時執(zhí)行
    {
        static uint16_t this_time_rx_len = 0;

        __HAL_UART_CLEAR_PEFLAG(&huart1);

        if ((hdma_usart1_rx.Instance->CR & DMA_SxCR_CT) == RESET)//現(xiàn)在是緩沖區(qū)1
        {
            /* Current memory buffer used is Memory 0 */

            //失效DMA或者停止DMA傳輸
            __HAL_DMA_DISABLE(&hdma_usart1_rx); //HAL_UART_DMAStop(&huart1);
            //獲取接收數(shù)據(jù)長度,長度 = 設定長度 - 剩余長度
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart1_rx.Instance->NDTR;
            //重新設定數(shù)據(jù)長度
            hdma_usart1_rx.Instance->NDTR = SBUS_RX_BUF_NUM;
            //設定緩沖區(qū)1
            hdma_usart1_rx.Instance->CR |= DMA_SxCR_CT;
            //使能DMA
            __HAL_DMA_ENABLE(&hdma_usart1_rx);
            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                sbus_to_rc(sbus_rx_buf[0], &rc_ctrl);
                //判斷遙控器數(shù)據(jù)是否出錯
				RC_data_is_error();
                //sbus_to_usart1(sbus_rx_buf[0]);//這里可以把接收的數(shù)據(jù)發(fā)送給出去
            }
        }
        else
        {
            /* Current memory buffer used is Memory 1 */
          
            //失效DMA
            __HAL_DMA_DISABLE(&hdma_usart1_rx);
            //獲取接收數(shù)據(jù)長度,長度 = 設定長度 - 剩余長度
            this_time_rx_len = SBUS_RX_BUF_NUM - hdma_usart1_rx.Instance->NDTR;
            //重新設定數(shù)據(jù)長度
            hdma_usart1_rx.Instance->NDTR = SBUS_RX_BUF_NUM;
            //設定緩沖區(qū)0
            DMA1_Stream1->CR &= ~(DMA_SxCR_CT);
            //使能DMA
            __HAL_DMA_ENABLE(&hdma_usart1_rx);
            if(this_time_rx_len == RC_FRAME_LENGTH)
            {
                //處理遙控器數(shù)據(jù)
                sbus_to_rc(sbus_rx_buf[1], &rc_ctrl);
                //判斷遙控器數(shù)據(jù)是否出錯
				RC_data_is_error();
				//sbus_to_usart1(sbus_rx_buf[1]);//這里可以把接收的數(shù)據(jù)發(fā)送給出去
            }
        }
		//RC_data_is_error();
    }
}

(3)根據(jù)手冊處理遙控器數(shù)據(jù)。

/**
  * @brief          遙控器協(xié)議解析
  * @param[in]      sbus_buf: 原生數(shù)據(jù)指針
  * @param[out]     rc_ctrl: 遙控器數(shù)據(jù)指
*/
static void sbus_to_rc(volatile const uint8_t *sbus_buf, RC_ctrl_t *rc_ctrl)
{
    if (sbus_buf == NULL || rc_ctrl == NULL)
    {
        return;
    }
    rc_ctrl->header = sbus_buf[0]; 
    rc_ctrl->alt    = sbus_buf[1]; 
    rc_ctrl->ele    = sbus_buf[2]; 
    rc_ctrl->thr	= sbus_buf[3];
    rc_ctrl->rudd   = sbus_buf[4]; 
    rc_ctrl->flag   = sbus_buf[5]; //標志位
    rc_ctrl->verify = sbus_buf[6]; //(BYTE[1]^BYTE[2]^BYTE[3]^BYTE[4]^BYTE[5])&0xff;
    rc_ctrl->tail   = sbus_buf[7]; //數(shù)據(jù)尾,固定為 0x99            
}

//判斷遙控器數(shù)據(jù)是否出錯,
uint8_t RC_data_is_error(void)
{
    //使用了go to語句 方便出錯統(tǒng)一處理遙控器變量數(shù)據(jù)歸零
    if (rc_ctrl.header != 0x66)
    {
        goto error;
    }
    //if (RC_abs(rc_ctrl.alt) > RC_CHANNAL_ERROR_VALUE)
    //{
    //    goto error;
    //}

	if (rc_ctrl.verify != ((rc_ctrl.alt ^ rc_ctrl.ele ^ rc_ctrl.thr ^ rc_ctrl.rudd ^ rc_ctrl.flag)&0xff))
    {
        goto error;
    }
    if (rc_ctrl.tail != 0x99)
    {	
        goto error;
    }
    return 0;

error:
    rc_ctrl.header = 0;
    rc_ctrl.alt = 128;
    rc_ctrl.ele = 128;
    rc_ctrl.thr = 0;
    rc_ctrl.rudd = 128;
    rc_ctrl.flag = 0;
    rc_ctrl.verify = 0;
	rc_ctrl.tail = 0;
    return 1;
}

//獲取遙控器數(shù)據(jù)指針
RC_ctrl_t *get_remote_control_point(void)
{
    return &rc_ctrl;
}

到了這里,關于STM32 cubemx+串口空閑中斷+DMA雙緩沖的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • STM32學習筆記(五)串口空閑中斷+DMA實現(xiàn)不定長收發(fā)(stm32c8t6)

    STM32學習筆記(五)串口空閑中斷+DMA實現(xiàn)不定長收發(fā)(stm32c8t6)

    記錄一下學習過程 DMA DMA,全稱為: Direct Memory Access,即直接存儲器訪問, DMA 傳輸將數(shù)據(jù)從一個 地址空間復制到另外一個地址空間。 這一過程無需cpu的參與,從而提高cpu使用的效率 DMA相關的參數(shù):1 數(shù)據(jù)的源地址、2 數(shù)據(jù)傳輸?shù)哪繕说刂?、3 傳輸寬度,4 傳輸多少字節(jié),5 傳

    2024年02月14日
    瀏覽(21)
  • 【STM32 CubeMX】串口編程DMA+IDLE中斷

    【STM32 CubeMX】串口編程DMA+IDLE中斷

    在嵌入式系統(tǒng)中,串口通信是一項關鍵的任務,而使用DMA(直接內存訪問)結合IDLE中斷進行串口編程,尤其是在STM32 CubeMX環(huán)境中,能夠提高系統(tǒng)的效率和性能。STM32 CubeMX為STM32微控制器提供了圖形化的配置工具,可以簡化初始化代碼的生成過程,使得串口編程變得更加容易。

    2024年02月20日
    瀏覽(19)
  • STM32使用串口空閑中斷(IDLE)和 DMA接收一串數(shù)據(jù)流

    STM32使用串口空閑中斷(IDLE)和 DMA接收一串數(shù)據(jù)流

    方法一、使用宏定義判斷IDLE標志位 空閑的定義是總線上在一個字節(jié)的時間內沒有再接收到數(shù)據(jù),USART_IT_IDLE空閑中斷是檢測到有數(shù)據(jù)被接收后,總線上在一個字節(jié)的時間內沒有再接收到數(shù)據(jù)的時候發(fā)生的。 串口空閑中斷(UART_IT_IDLE):STM32的IDLE的中斷在串口無數(shù)據(jù)接收的情況

    2024年01月23日
    瀏覽(27)
  • STM32-HAL庫串口DMA空閑中斷的正確使用方式+解析SBUS信號

    STM32-HAL庫串口DMA空閑中斷的正確使用方式+解析SBUS信號

    能夠點進這篇文章的小伙伴肯定是對STM32串口DMA空閑中斷接收數(shù)據(jù)感興趣的啦,今天用這一功能實現(xiàn)串口解析航模遙控器sbus信號時,查閱了很多網(wǎng)友發(fā)布的文章(勤勞的搬運工~),包括自己之前寫過一篇博客 STM32_HAL庫_CubeMx串口DMA通信(DMA發(fā)送+DMA空閑接收不定長數(shù)據(jù))。本文

    2024年02月09日
    瀏覽(24)
  • stm32串口空閑中斷+DMA傳輸接受不定長數(shù)據(jù)+letter?shell?實現(xiàn)命令行

    空閑中斷(IDLE),俗稱幀中斷,即第一幀數(shù)據(jù)接收完畢到第二幀數(shù)據(jù)開始接收期間存在一個空閑狀態(tài)(每接收一幀數(shù)據(jù)后空閑標志位置1),檢測到此空閑狀態(tài)后即執(zhí)行中斷程序。 空閑中斷的優(yōu)點在于省去了幀頭幀尾的檢測 ,進入中斷程序即意味著已經(jīng)接收到一組完整數(shù)據(jù),僅需

    2024年02月03日
    瀏覽(26)
  • Stm32407串口1空閑中斷+DMA收發(fā)(基于標準庫實現(xiàn))

    Stm32407串口1空閑中斷+DMA收發(fā)(基于標準庫實現(xiàn))

    stm32串口的配置很簡單,這里就不贅述了,使用 USART_SendData() 阻塞模式發(fā)送數(shù)據(jù),或是接收中斷配置 “接收緩沖區(qū)非空” USART_IT_RXNE ,這種做法效率很低,而且來一個數(shù)據(jù)中斷一次數(shù)據(jù)處理起來也麻煩。 這里基于STM32F407提供一種串口空閑中斷+DMA接收的方式,通過庫函數(shù)編程

    2024年02月16日
    瀏覽(19)
  • 【STM32】HAL庫 STM32CubeMX——DMA (串口DMA發(fā)送接收)

    【STM32】HAL庫 STM32CubeMX——DMA (串口DMA發(fā)送接收)

    軟件: STM32CubeMX KEIL5 mcuisp 串口通信助手 硬件: STM32F103C8Tx 杜邦線,面包板,USB轉TTL DMA,全稱Direct Memory Access,即直接存儲器訪問。 DMA傳輸將數(shù)據(jù)從一個地址空間復制到另一個地址空間,提供在外設和存儲器之間或者存儲器和存儲器之間的高速數(shù)據(jù)傳輸。 我們知道系統(tǒng)的運

    2024年02月12日
    瀏覽(24)
  • stm32串口+DMA環(huán)形緩沖收發(fā)保姆級

    stm32串口+DMA環(huán)形緩沖收發(fā)保姆級

    首先在此感謝開源項目,以及大佬們的無私奉獻,讓每一個逐夢人能夠免費學習,再次感謝! 發(fā)布只為記錄,記性不夠,筆記來湊。記得點贊哦 具體實現(xiàn)原理講起來確實挺復雜,不過用起來還是很NICE的!可以直接移植! 1.1、選擇單片機型號 2、配置時鐘和串口 或者直接在

    2024年02月10日
    瀏覽(28)
  • 【STM32】CUBEMX之串口:串口三種模式(輪詢模式、中斷模式、DMA模式)的配置與使用示例 + 串口重定向 + 使用HAL擴展函數(shù)實現(xiàn)不定長數(shù)據(jù)接收

    【STM32】CUBEMX之串口:串口三種模式(輪詢模式、中斷模式、DMA模式)的配置與使用示例 + 串口重定向 + 使用HAL擴展函數(shù)實現(xiàn)不定長數(shù)據(jù)接收

    目錄 ? 總覽 使用CUBEMX創(chuàng)建工程的基本配置 CUBEMX中的配置 Keil中的配置 實物連接 串口輪詢模式 輪詢模式HAL庫函數(shù) 特點 實驗一:發(fā)送數(shù)據(jù)給單片機并讓其返回相同值 串口重定向 串口中斷模式 在CUBEMX中打開串口中斷 中斷模式HAL庫函數(shù) 特點 實驗二:使用中斷回調完成實驗一

    2024年04月10日
    瀏覽(44)
  • 【STM32 CubeMX】串口編程DMA

    【STM32 CubeMX】串口編程DMA

    在嵌入式系統(tǒng)中,串口通信是一項至關重要的功能,它允許單片機與外部設備進行數(shù)據(jù)交換,如傳感器、顯示器或其他設備。然而,在高速數(shù)據(jù)傳輸?shù)膱鼍跋?,傳統(tǒng)的串口通信方式可能會使CPU過于繁忙,從而影響系統(tǒng)的性能。為了解決這一問題,STM32系列微控制器提供了DMA(

    2024年02月20日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包