在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<s id="cmphk"><label id="cmphk"></label></s>
    <span id="cmphk"><var id="cmphk"></var></span>
    <dfn id="cmphk"><var id="cmphk"></var></dfn>
    <menu id="cmphk"><thead id="cmphk"></thead></menu>

    <address id="cmphk"></address>

      <dfn id="cmphk"></dfn>
      
      
      <span id="cmphk"></span>

      <object id="cmphk"><tt id="cmphk"></tt></object>
      1. 新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > STM32串口DMA方式接收數(shù)據(jù)

        STM32串口DMA方式接收數(shù)據(jù)

        作者: 時間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
        一直以來都為串口接收數(shù)據(jù)所困擾:
        1:如果用接收中斷的話,每接收1byte就得中斷一次。這樣太消耗CPU資源!
        2:如果用DMA方式接收數(shù)據(jù),那么如何確定接收數(shù)據(jù)的長度又不好確定了。(比如GPRS模塊AT命令的接收!)
        3:DMA方式接收+定時器的超時中斷。這樣處理也比較復(fù)雜,需要開定時器,關(guān)定時器。。。。個人不喜歡!(ATMEL的ARM系列的串口倒是有硬件超時中斷可以直接使用。我現(xiàn)在用AT91SAM7系列處理GPRS的AT命令就采用這種方式,挺好用。但是STM32就沒有了,需要自己加定時器,還要硬件處理:RXD連接定時器的一個觸發(fā)引腳?。?br />
        所以之前用STM32接收串口數(shù)據(jù)都是采用接收中斷,然后寫入一個FIFO隊列。然后在主函數(shù)里面去查詢隊列緩沖中是否有數(shù)據(jù)需要處理。但是這樣的話,串口中斷服務(wù)函數(shù)始終是很大的硬件開銷。比如我現(xiàn)在用串口下載STM32的升級固件的時候,數(shù)據(jù)量較大。

        廢話完畢,今天突然腦子發(fā)熱想要把DMA和環(huán)形的FIFO隊列結(jié)合一下使用。把想法跟同事交流一下,覺得有可行性!馬上動手實驗。經(jīng)過半天調(diào)試,結(jié)果令人滿意。
        說說我的思路(本人表達(dá)能力有限,描述不清楚的希望大家跟帖):關(guān)在在于讓DMA來實現(xiàn)“環(huán)形隊列中往緩沖區(qū)寫入1byte”的功能!剩下的讀取隊列就跟普通環(huán)形隊列沒多大區(qū)別了。這樣我們的程序中擁有了一個不占用CPU資源的“環(huán)形隊列”后,我們就不用擔(dān)心CPU頻繁中斷,我們只需要在適當(dāng)?shù)臅r間讀取隊列中的數(shù)據(jù)然后慢慢分析處理數(shù)據(jù)!
        A:串口初始化配置串口為DMA方式接收數(shù)據(jù)。具體配置請看:

        DMA1_Channel5->CCR = DMA_CCR5_PL //通道優(yōu)先級最高
        | DMA_CCR5_MINC //MEM地址增量使能
        | DMA_CCR5_CIRC //接收緩沖區(qū)循環(huán)模式
        | DMA_CCR5_TCIE //傳輸完成中斷
        ;
        DMA1->IFCR |= 0x000F0000;
        DMA1_Channel5->CPAR = USART1_BASE + 4;
        // Enable the DMA1_CH5 Interrupt
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQChannel;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        關(guān)鍵,開啟DMA循環(huán)模式,這樣接收完之后會自動回到FIFO緩沖區(qū)開頭地方,這樣能省不少事情。
        當(dāng)然,考慮到可能把緩沖區(qū)撐爆的情況,所以開啟通道傳輸完成標(biāo)志位,在傳輸完成中斷中查詢一下隊列中有多少數(shù)據(jù)沒有讀取出來,如果太多數(shù)據(jù)沒有讀取,那么在中斷里面處理讀取FIFO數(shù)據(jù)并做相應(yīng)處理!

        B:關(guān)于FIFO的一些聲明:
        #define FIFO_OK 0
        #define FIFO_ERROR_PARAM -1
        #define FIFO_ERROR_MEM -2
        #define FIFO_ERROR_FULL -3
        #define FIFO_ERROR_EMPTY -4
        #define FIFO_ERROR_BUSY -5

        typedef struct _FIFO_TYPE_
        {
        INT32U size; //FIFO緩沖區(qū)大小
        INT32U front; //FIFO下一讀取位置
        INT32U staraddr; //FIFO緩沖區(qū)起始地址
        INT32U endaddr; //FIFO緩沖區(qū)結(jié)束地址
        INT8U buffer[1]; //實際長度由初始化分配內(nèi)存!(memloc的時候確定)
        }FIFOTYPE;


        C:關(guān)于FIFO隊列的初始化,具體配置
        //
        //函數(shù):FIFO_Init
        //參數(shù):FIFO類型的指針地址,隊列大小
        //返回:>=0初始化成功
        //描述:初始化FIFO隊列
        //
        Int32S FIFO_Init(FIFOTYPE * *fifo,INT32U fifosize)
        {
        volatile INT32U da;
        if(fifo==NULL || fifosize == 0)
        {
        return FIFO_ERROR_PARAM;
        }
        (*fifo) = malloc(16+fifosize);
        if((*fifo) == NULL)
        {
        //已經(jīng)在堆里面申請了地址
        return FIFO_ERROR_MEM;
        }
        (*fifo)->size = fifosize;
        (*fifo)->staraddr = (INT32U)(&(*fifo)->buffer[0]); //記錄FIFO緩沖區(qū)起始地址
        (*fifo)->endaddr = (INT32U)(&(*fifo)->buffer[fifosize-1]); //記錄FIFO緩沖區(qū)結(jié)束地址
        (*fifo)->front = (*fifo)->staraddr; //FIFO下一讀取數(shù)據(jù)地址
        memset((*fifo)->buffer,0,(*fifo)->size); //清除緩沖區(qū)里面的數(shù)據(jù),可省略

        DMA1_Channel5->CCR &= ~DMA_CCR5_EN;
        DMA1_Channel5->CMAR = (INT32U)(*fifo)->staraddr; //配置DMA傳輸?shù)刂?br /> DMA1_Channel5->CNDTR = (*fifo)->size; //配置DMA傳輸數(shù)據(jù)量
        da = USART1->DR;
        da = da;
        DMA1->IFCR |= 0x000F0000;
        DMA1_Channel5->CCR |= DMA_CCR5_EN;

        return FIFO_OK;
        }

        D:清空隊列緩沖區(qū)函數(shù)
        //
        //函數(shù):FIFO_Clear
        //參數(shù):無
        //返回:無
        //描述:清空FIFO隊列
        //
        Int32S FIFO_Clear(FIFOTYPE *fifo)
        {
        volatile INT32U da;
        if(fifo == NULL)
        return FIFO_ERROR_PARAM;
        fifo->front = fifo->staraddr; //將下一讀取地址設(shè)置為FIFO緩沖開始
        DMA1_Channel5->CCR &= ~DMA_CCR5_EN;
        DMA1_Channel5->CMAR = fifo->staraddr; //重新配置DMA地址
        DMA1_Channel5->CNDTR = fifo->size; //重新配置DMA傳輸數(shù)據(jù)量
        memset(fifo->buffer,0,fifo->size);
        da = USART1->DR;
        da = da;
        DMA1->IFCR |= 0x000F0000;
        DMA1_Channel5->CCR |= DMA_CCR5_EN;

        return FIFO_OK;
        }

        E:讀取FIFO緩沖區(qū),這個跟標(biāo)準(zhǔn)的環(huán)形隊列基本沒區(qū)別
        //
        //函數(shù):FIFO_Read
        //參數(shù):隊列指針,1byte數(shù)據(jù)指針
        //返回:>=0讀取成功
        //描述:從FIFO隊列中讀出1byte數(shù)據(jù)
        //
        Int32S FIFO_Read(FIFOTYPE *fifo,INT8U *data)
        {
        if(fifo == NULL )
        return FIFO_ERROR_PARAM;
        if(FIFO_Status(fifo)==0)
        {
        return FIFO_ERROR_EMPTY;
        }
        *data = (INT8U)(*((INT8U *)(fifo->front)));
        if(fifo->front == fifo->endaddr)
        {
        fifo->front = fifo->staraddr;
        }
        else
        {
        fifo->front++;
        }
        return FIFO_OK;
        }

        F:獲取緩沖區(qū)的數(shù)據(jù)量
        //
        //函數(shù):FIFO_Status
        //參數(shù):隊列指針
        //返回:>0隊列中有未讀出數(shù)據(jù)
        //描述:獲取FIFO隊列狀態(tài)
        //
        INT32S FIFO_Status(FIFOTYPE *fifo)
        {
        INT32S res;
        INT32S nextsave = (INT32S)fifo->endaddr + 1 - (INT32S)DMA1_Channel5->CNDTR;
        res = nextsave- (INT32S)(fifo->front);
        if(res < 0)
        {
        res = ( (INT32S)(fifo->endaddr)+1 - (INT32S)(fifo->front) ) + (nextsave - (INT32S)fifo->staraddr);
        }
        return res;
        }
        說明:
        1:STM32的DMA_CMAR傳輸?shù)刂芳拇嫫鞑粫S傳輸數(shù)據(jù)量的變化而真正的指向下一個存儲位置(AT91SAM就是總是指向下一個存儲地址的)。所以我需要根據(jù)傳輸數(shù)量寄存器DMA_CNDTR來推算下一傳輸位置寄存器!
        2:需要考慮環(huán)形隊列寫入指針已經(jīng)重新回到緩沖區(qū)開頭了,而讀取指針還在緩沖區(qū)尾部的情況!


        評論


        技術(shù)專區(qū)

        關(guān)閉
        ×

        “芯”朋友见面大会
        珠海|11.14|泰克“芯”朋友见面大会珠海站|泰克带您从测试角度看半导体的整条产业链,快来报名抢位吧>>