日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32F0使用LL库实现DMA方式AD采集

發布時間:2024/7/23 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F0使用LL库实现DMA方式AD采集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在本次項目中,限于空間要求我們選用了STM32F030F4作為控制芯片。這款MCU不但封裝緊湊,而且自帶的Flash空間也非常有限,所以我們選擇了LL庫實現。在本文中我們將介紹基于LL庫的ADC的DMA采集方式。

1、概述

這次我們使用DMA方式實現對AD的采集,在遺忘我們使用HAL庫和標準庫都做過,這次我們使用LL庫來實現。接下來我們簡單了解一下STM32F030F4中的ADC和DMA。

首先看一看ADC,STM32F030F4是12位的ADC。它有多達19個多路復用通道,允許它測量來自16個外部和2個內部源的信號。各種通道的A/D轉換可采用單通道、連續通道、掃描通道或不連續通道進行。ADC的結果存儲在左對齊或右對齊的16位數據寄存器中。ADC結構圖如下:

這次我們只使用第1路外部輸入。接下來說一說DMA,直接內存訪問(DMA)用于在外設和內存以及內存到內存之間提供高速數據傳輸。DMA可以在沒有任何CPU操作的情況下快速移動數據。這使CPU資源可以用于其他操作。STM32F030F4中的DMA控制器有5個通道,每個通道用于管理來自一個或多個外圍設備的內存訪問請求。它有一個仲裁器來處理DMA請求之間的優先級。DMA結構圖如下:

這次我們也使用DMA的第1通道。

2ADC配置

在使用之前我們需要對ADC和DMA的相關寄存器驚醒必要的配置,才能實現我們想要的功能。我們來看看ADC需要配置的寄存器。ADC需要注意的寄存器主要有兩個:ADC控制寄存器(ADC_CR)和ADC配置寄存器1(ADC_CFGR1)。首先我們來說說ADC控制寄存器(ADC_CR),器結構如下:

關于ADC控制寄存器(ADC_CR),有幾個設置需要說明一下。

ADCAL:ADC校準,設置該位可以軟件啟動校準,校準完成硬件會復位掉這一位。需要注意的是只有ADC處于失能狀態,軟件對ADCAL的操作才是有效的。也就是說軟件對ADCAL操作時,ADC控制寄存器(ADC_CR)必須是全復位狀態,即ADCAL=0,ADSTART=0,ADSTP=0, ADDIS=0和 ADEN=0。

ADSTART: ADC啟動轉換命令。需要注意只有在ADC已啟用,并且沒有禁用ADC的掛起請求。也就是說ADEN=1和ADDIS=0時,軟件對ADSTART的操作才有效。

ADEN: ADC使能命令。只有在ADC控制寄存器(ADC_CR)處于全復位狀態,即ADCAL=0,ADSTART=0,ADSTP=0,ADDIS=0 和 ADEN=0下,軟件對ADEN的操作才有效。這就有一個問題,如果你使用了ADCAL必須等校準完成,才能使能,否則無效。

接下來我們看一看ADC配置寄存器1(ADC_CFGR1),其結構如下:

關于ADC配置寄存器1(ADC_CFGR1),我們需要關注:CONT(轉換模式)、EXTEN[1:0](外部觸發使能)、DMACFG(DMA訪問配置)、DMAEN(DMA訪問使能)。需要說明的是,這幾個配置都必須在啟動轉換前完成配置,即配置時ADSTART=0。

3DMA配置

配置了ADC還需要配置DMA才能實現我們的想法。關于DMA的配置我們主要說一下4個寄存器:DMA通道配置寄存器(DMA_CCRx)、DMA通道數據數量寄存器(DMA_CNDTRx)、DMA通道外設地址寄存器(DMA_CPARx)、DMA通道內存地址寄存器(DMA_CMARx)。

首先,我們來看看DMA通道配置寄存器(DMA_CCRx),其結構如下:

對于DMA通道配置寄存器(DMA_CCRx),我們需要關注如下位:MSIZE[1:0](內存大小)、PSIZE[1:0] (外設大小)、MINC(內存的增加模式)、PINC(外設增加模式)、CIRC(循環模式)、DIR(數據傳輸方向)、EN(通道使能)。除通道使能外,其它均可通過初始化函數進行配置。

接下來,我們來看看DMA通道數據數量寄存器(DMA_CNDTRx),其結構如下:

其實DMA通道數據數量寄存器(DMA_CNDTRx)用于配置傳送數據的個數,如果是往內存中寫,就是內存緩沖區的大小,單位與配置寄存器中MSIZE和PSIZE有關。接下來,我們來看一看DMA通道外設地址寄存器(DMA_CPARx),其結構如下:

對于DMA通道外設地址寄存器(DMA_CPARx),就是存儲外設的地址,如果我們的外設是ADC,那就是ADC的地址。最后,我們來看一看DMA通道內存地址寄存器(DMA_CMARx),其結構如下:

對于DMA通道內存地址寄存器(DMA_CMARx),其存儲的就是對應的變量在內存中的地址,就是我們開辟的數據緩存區的首地址。

4、軟件實現

我們已經說明了ADC和DMA的配置,在這一小節,我們將根據我們前面的分析實現代碼。首先來實現ADC的配置代碼。

/* ADC 初始化配置 */ static void ADC_Init_Configuration(void) {LL_ADC_InitTypeDef ADC_InitStruct = {0};LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};LL_GPIO_InitTypeDef GPIO_InitStruct = {0};/* ADC相關外設時鐘使能 */LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_ADC1);LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);/**ADC GPIO 配置:PA0?? ------> ADC_IN0? */GPIO_InitStruct.Pin = LL_GPIO_PIN_0;GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;LL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* ADC DMA初始化 */LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_WORD);LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_WORD);LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_1,ADBufferSize);LL_DMA_SetPeriphAddress(DMA1,LL_DMA_CHANNEL_1,LL_ADC_DMA_GetRegAddr(ADC1,LL_ADC_DMA_REG_REGULAR_DATA));LL_DMA_SetMemoryAddress(DMA1,LL_DMA_CHANNEL_1,(uint32_t)ADC_ConvertedValue);LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_1);/* 配置ADC通道 */LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_0);/* 配置ADC的全局特性:時鐘、分辨率、數據對齊和轉換次數 */ADC_InitStruct.Clock = LL_ADC_CLOCK_ASYNC;ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;LL_ADC_Init(ADC1, &ADC_InitStruct);ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED;LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);LL_ADC_REG_SetSequencerScanDirection(ADC1, LL_ADC_REG_SEQ_SCAN_DIR_FORWARD);LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_239CYCLES_5);LL_ADC_DisableIT_EOC(ADC1);LL_ADC_DisableIT_EOS(ADC1);LL_ADC_StartCalibration(ADC1);while( LL_ADC_IsCalibrationOnGoing(ADC1));LL_ADC_Enable(ADC1);LL_ADC_REG_SetDMATransfer(ADC1,LL_ADC_REG_DMA_TRANSFER_UNLIMITED);LL_ADC_REG_StartConversion(ADC1); }

其實在ADC的初始化配置中也對DMA作了配置,但DMA還需要對始終和中斷進行配置。

/**??DMA 控制器初始化配置??*/ static void DMA_Init_Configuration(void) {/* DMA 控制器時鐘使能 */LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);/* DMA1_Channel1_IRQn中斷配置 */NVIC_SetPriority(DMA1_Channel1_IRQn, 0);NVIC_EnableIRQ(DMA1_Channel1_IRQn); }

配置后,ADC的寄存器如下:

配置后,DMA的寄存器如下:

其實,到這里ADC采集世紀上已經實現了,DMA已經將數據從ADC讀出來存到了指定的內存區域,后續的處理就很簡單了。

5、總結

我們已經實現了基于LL庫使用DMA方式獲取ADC的數據。下面我們就下載到目標設備并檢測一下結果。測試結果如下:

?????? 上圖中,上部是計算完成的物理量值,下部則是DMA寫到內存緩存區的ADC的原始碼值。

歡迎關注:

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的STM32F0使用LL库实现DMA方式AD采集的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。