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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

STM32之ADC实例(基于DMA方式)

發布時間:2025/6/15 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32之ADC实例(基于DMA方式) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

出處:https://blog.csdn.net/zouleideboke/article/details/75112224?locationNum=9&fps=1

ADC簡介:

? ? ADC(Analog-to-Digital Converter,模/ 數轉換器)。也就是將模擬信號轉換為數字信號進行處理,在存儲或傳輸時,模數轉換器幾乎必不可少。

? ?STM32在片上集成的ADC外設非常強大,我使用的奮斗開發板是STM32F103VET6,屬于增強型的CPU,它有18個通道,可測量16個外部和2個內部信號源。各通道的A/D轉換可以單次,連續,掃描或間斷模式執行,ADC的結果可以左對齊或右對齊方式存儲在16位數據寄存器中。



ADC工作過程分析:

? ?我們以ADC規則通道轉換過程來分析,如上圖,所有的器件都是圍繞中間的模擬至數字轉換器部分展開的。它的左端VREF+,VREF- 等ADC參考電壓,ADCx_IN0 ~?ADCx_IN15為ADC的輸入信號通道,即某些GPIO引腳。輸入信號經過這些通道被送到ADC器件,ADC器件需要收到觸發信號才開始進行轉換,如EXTI外部觸發,定時器觸發,也可以使用軟件觸發。ADC部件接受到觸發信號后,在ADCCLK時鐘的驅動下對輸入通道的信號進行采樣,并進行模數轉換,其中ADCCLK是來自ADC預分頻器。

? ? ADC部件轉換后的數值被保存到一個16位的規則通道數據寄存器(或注入通道數據寄存器)中,我們可以通過CPU指令或DMA把它讀到內存(變量),模數轉換之后,可以出發DMA請求或者觸發ADC轉換結束事件,如果配置了模擬看門狗,并且采集的電壓大于閾值,會觸發看門狗中斷。

? ?其實對于ADC采樣,軟件編程主要就是ADC的配置,當然我是基于DMA方式的,所以DMA的配置也是關鍵!話不多說看代碼!

主函數:main.c

[cpp]?view plaincopy
  • #include?"printf.h"??
  • #include?"adc.h"??
  • #include?"stm32f10x.h"??
  • ??
  • extern?__IO?uint16_t?ADC_ConvertedValue;??
  • float?ADC_ConvertedValueLocal;??
  • void?Delay(__IO?uint32_t?nCount)??
  • {??
  • ???for(;nCount?!=0;nCount--);??
  • }??
  • int?main(void)??
  • {????
  • ??printf_init();??????
  • ??adc_init();??
  • ??printf("******This?is?a?ADC?test******\n");??
  • ??????????
  • ??while(1)??
  • ????{??
  • ????????ADC_ConvertedValueLocal?=(float)?ADC_ConvertedValue/4096*3.3;??
  • ????????printf("The?current?AD?value?=0x%04X\n",ADC_ConvertedValue);??
  • ????printf("The?current?AD?value?=%f?V\n",ADC_ConvertedValueLocal);??
  • ??????????
  • ????Delay(0xffffee);??
  • ????}??
  • ??return?0;???
  • }??
  • 注意ADC_ConvertedValueLocal保存了由轉換值計算出來的電壓值,計算公式是:實際電壓值=ADC轉換值 x LSB ,這里由于我的板子VREF+接的參考電壓為3.3V,所以LSB=3.3/4096,STM32的ADC的精度為12位。

    ADC與DMA配置:adc.c

    [cpp]?view plaincopy
  • #include?"adc.h"??
  • volatile?uint16_t?ADC_ConvertedValue;??
  • void?adc_init()??
  • {??
  • ????GPIO_InitTypeDef?GPIO_InitStructure;??
  • ????ADC_InitTypeDef?ADC_InitStructure;??
  • ????DMA_InitTypeDef?DMA_InitStructure;??
  • ??????
  • ????RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);??
  • ????RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1,ENABLE);??????
  • ??
  • ????GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;????????
  • ????GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;??
  • ????GPIO_Init(GPIOC,&GPIO_InitStructure);??
  • ????DMA_DeInit(DMA1_Channel1);??
  • ????DMA_InitStructure.DMA_PeripheralBaseAddr?=?ADC1_DR_Address;//ADC地址??
  • ????DMA_InitStructure.DMA_MemoryBaseAddr?=?(uint32_t)&ADC_ConvertedValue;?//內存地址??
  • ????DMA_InitStructure.DMA_DIR?=?DMA_DIR_PeripheralSRC;?//方向(從外設到內存)??
  • ????DMA_InitStructure.DMA_BufferSize?=?1;?//傳輸內容的大小??
  • ????DMA_InitStructure.DMA_PeripheralInc?=?DMA_PeripheralInc_Disable;?//外設地址固定??
  • ????DMA_InitStructure.DMA_MemoryInc?=?DMA_MemoryInc_Disable;?//內存地址固定??
  • ????DMA_InitStructure.DMA_PeripheralDataSize?=???
  • ????DMA_PeripheralDataSize_HalfWord?;?//外設數據單位??
  • ????DMA_InitStructure.DMA_MemoryDataSize?=???
  • ????DMA_MemoryDataSize_HalfWord?;????//內存數據單位??
  • ????DMA_InitStructure.DMA_Mode?=?DMA_Mode_Circular??;?//DMA模式:循環傳輸??
  • ????DMA_InitStructure.DMA_Priority?=?DMA_Priority_High?;?//優先級:高??
  • ????DMA_InitStructure.DMA_M2M?=?DMA_M2M_Disable;???//禁止內存到內存的傳輸??
  • ??????
  • ????DMA_Init(DMA1_Channel1,?&DMA_InitStructure);??//配置DMA1的4通道??
  • ????DMA_Cmd(DMA1_Channel1,ENABLE);??
  • ???
  • ????ADC_InitStructure.ADC_Mode?=?ADC_Mode_Independent;?//獨立ADC模式??
  • ????ADC_InitStructure.ADC_ScanConvMode?=?DISABLE;??//禁止掃描方式??
  • ????ADC_InitStructure.ADC_ContinuousConvMode?=?ENABLE;//開啟連續轉換模式???
  • ????ADC_InitStructure.ADC_ExternalTrigConv?=?ADC_ExternalTrigConv_None;?//不使用外部觸發轉換??
  • ????ADC_InitStructure.ADC_DataAlign?=?ADC_DataAlign_Right;?//采集數據右對齊??
  • ????ADC_InitStructure.ADC_NbrOfChannel?=?1;?//要轉換的通道數目??
  • ????ADC_Init(ADC1,?&ADC_InitStructure);??
  • ??????
  • ????RCC_ADCCLKConfig(RCC_PCLK2_Div8);//配置ADC時鐘,為PCLK2的8分頻,即9Hz??
  • ????ADC_RegularChannelConfig(ADC1,?ADC_Channel_11,?1,?ADC_SampleTime_55Cycles5);//配置ADC1通道11為55.5個采樣周期???
  • ??????
  • ????ADC_DMACmd(ADC1,ENABLE);??
  • ????ADC_Cmd(ADC1,ENABLE);??
  • ??
  • ????ADC_ResetCalibration(ADC1);//復位校準寄存器??
  • ????while(ADC_GetResetCalibrationStatus(ADC1));//等待校準寄存器復位完成??
  • ??
  • ????ADC_StartCalibration(ADC1);//ADC校準??
  • ????while(ADC_GetCalibrationStatus(ADC1));//等待校準完成??
  • ??
  • ????ADC_SoftwareStartConvCmd(ADC1,?ENABLE);//由于沒有采用外部觸發,所以使用軟件觸發ADC轉換??
  • }??
  • ADC配置還是比較簡單的,畢竟只配置了單通道,還是分析一下吧!這里我是把ADC1的通道11使用的GPIO引腳PC1配置成模擬輸入模式,在作為ADC的輸入時,必須使用模擬輸入。對于ADC通道,每個ADC通道對應一個GPIO引腳端口,GPIO的引腳在設為模擬輸入模式后可用于模擬電壓的輸入。STM32F103VET6有三個ADC,這三個ADC公用16個外部通道。
    DMA的整體配置為:使用DMA1的通道1,數據從ADC外設的數據寄存器(ADC1_DR_Address)轉移到內存(ADC_ConvertedValue變量),內存外設地址都固定,每次傳輸的大小為半字(16位),使用DMA循環傳輸模式。

    DMA傳輸的外設地址,也就是ADC1的地址為0x40012400+0x4c,這個地址可查STM32 datasheet獲得,如圖;



    要特別注意ADC轉換時間配置,由于ADC時鐘頻率越高,轉換速度越快,那是不是就把ADC的時鐘頻率設的越大越好呢?其實不然,根據ADC時鐘圖可知,ADC時鐘有上限值,即不能超過14MHz,如圖:


    這里ADC預分頻器的輸入為高速外設時鐘(PCLK2),使用RCC_ADCCLKConfig()庫函數來設置ADC預分頻的分頻值,PCLK2常用時鐘為72MHz,而ADCCLK必須小于14MHz,所以這里ADCCLK為PCLK2的6分頻,即12MHz,而我的程序中只是隨便設為8分頻,9MHz,若希望ADC以最高頻率14MHz運行,可以把PCLK2設置為56MHz,然后再4分頻得到ACCLK。

    ADC的轉換時間不僅與ADC的時鐘有關,還與采樣周期有關。每個ADC通道可以設置為不同的采樣周期。STM32的ADC采樣時間計算公式為:

    ? T=采樣周期+12.5個周期

    公式中的采樣周期就是函數中配置的?ADC_SampleTime,而后邊加上的12.5個周期為固定值,則ADC1通道11的轉換時間為T=(55.5+12.5) x 1/9=7.56us。

    補充:在adc.c文件中定義了ADC_ConvertedValue變量,要注意這個變量是由關鍵字volatile修飾的,volatile的作用是讓編譯器不要去優化這個變量,這樣每次用到這個變量時都要回到相應變量的內存中去取值,而如果不使用volatile進行修飾的話,ADC_ConvertedValue變量在被訪問的時候可能會直接從CPU的寄存器中取出(因為之前該變量被訪問過,也就是說之前就從內存中取出ADC_ConvertedValue的值保存到某個CPU寄存器中),之所以直接從寄存器中去取值而不去內存中取值,這是編譯器優化代碼的結果(訪問CPU寄存器比訪問內存快得多)。這里的CPU寄存器指R0,R1等CPU通用寄存器,用于CPU運算及暫存數據,不是指外設中的寄存器。

    ? ? ? ? ?因為ADC_ConvertedValue這個變量值隨時都會被DMA控制器改變的,所以用volatile來修飾它,確保每次讀取到的都是實時ADC轉換值。

    adc.h:

    [cpp]?view plaincopy
  • #ifndef?_adc_H??
  • #define?_adc_H??
  • #include?"stm32f10x.h"??
  • #include?"stm32f10x_dma.h"??
  • #include?"stm32f10x_adc.h"??
  • #define?ADC1_DR_Address??((uint32_t)0x4001244c);??
  • ??
  • void?adc_init(void);??
  • ??
  • #endif??
  • 效果圖:

    由于我的開發板沒有滑動變阻器,所以我就將電壓的輸入端接入通用IO口的3V引腳。如圖:



    總結

    以上是生活随笔為你收集整理的STM32之ADC实例(基于DMA方式)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 欧美乱视频 | 天堂网在线中文 | 色妻影院 | 国产精品一页 | 不卡的免费av | 亚洲天堂自拍 | 久久国产色av | 日韩一卡二卡三卡四卡 | 精品国产乱码久久久久久郑州公司 | 人禽高h交| 亚洲精品一区二 | 欧美a图 | 亚洲av成人无码一二三在线观看 | 欧美黑人性猛交xxxx | 精品99久久久久成人网站免费 | 欧美xxxx非洲 | 国产精华一区二区三区 | 久久久久不卡 | 二区国产 | 国产人澡人澡澡澡人碰视频 | 狠狠干狠狠操视频 | 国产区在线观看视频 | 狠狠干在线 | 国内精品久久久久久久影视简单 | 欧美日皮视频 | 苏晴忘穿内裤坐公交车被揉到视频 | 人妻在线一区二区三区 | 亚洲黄在线观看 | 国产黄视频在线观看 | 国产免费久久 | 免费黄色一级 | 国产欧美一区二区三区在线看蜜臀 | 欧美久久久一区二区三区 | 日韩欧美一区二区三区 | 国产男女猛烈无遮挡a片漫画 | 午夜天堂影院 | 国产精成人品 | 国产裸体网站 | 毛片动漫 | 91亚洲精品国偷拍自产在线观看 | 啪啪免费小视频 | 38激情| 国产色在线观看 | 老女人人体欣赏a√s | 91精品久久久久久久 | 亚洲第一成年人网站 | 性欧美17一18内谢 | 香蕉视频网页 | 中文字幕亚洲乱码熟女一区二区 | 日韩精品高清视频 | 日本色中色 | 日日夜夜狠狠爱 | 欧美日韩一区二区久久 | 视频网站在线观看18 | 日韩在线视频观看 | 天堂а√在线中文在线 | 看黄色的网址 | 亚洲天堂中文在线 | 欧洲一区在线观看 | 国产涩涩| 丁香花高清视频完整电影 | av在线免费不卡 | 久久久久在线 | 色秀视频网 | 国产视频精品自拍 | 情侣在线视频 | 汗汗视频 | 免费国产一区二区 | 依依综合网 | 亚洲一区二区成人 | 久久久wwww | 日本韩国欧美一区二区 | 蜜桃视频成人在线观看 | 一级黄色大全 | 中文字幕国产视频 | 黄色的网站免费观看 | 免费观看黄色的网站 | 性欧美色图| 欧美一级做a爰片久久高潮 久热国产精品视频 | 一级黄色片网址 | 日韩高清免费观看 | 成人三级在线视频 | 久久久久久亚洲中文字幕无码 | 久久在线中文字幕 | 欧美日韩国产精品综合 | 福利视频在线播放 | 伊人99热 | 这里只有精品999 | 欧美在线免费视频 | 桃谷绘里香在线播放 | 在线免费看mv的网站入口 | 香蕉久久夜色精品升级完成 | 日韩视频在线观看二区 | 女人的黄色片 | 亚洲成熟丰满熟妇高潮xxxxx | 国产精品久久久久久久久久免费看 | www.一区二区 | 大奶子在线| 欧美成人精品 |