国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

深度解析三種不同方式ADC應用實例

電子設計 ? 來源:csdn ? 作者:脆弱的代碼 ? 2021-04-28 11:26 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

所用的芯片內嵌3個12位的模擬/數字轉換器(ADC),每個ADC共用多達16個外部通道,2個內部通道。

3個:代表ADC1、ADC2、ADC3(下圖是芯片固件庫的截圖)

12位:也叫ADC分辨率、采樣精度。先來看看二進制的12位可表示0-4095個數,也就是說轉換器通過采集轉換所得到的最大值是4095,如:“111111111111”=4095,那么我們怎么通過轉換器轉換出來的值得到實際的電壓值呢?如果我們要轉換的電壓范圍是0v-3.3v的話,轉換器就會把0v-3.3v平均分成4096份。設轉換器所得到的值為x,所求電壓值為y。

那么就有:

16個外部通道:簡單的說就是芯片上有16個引腳是可以接到模擬電壓上進行電壓值檢測的。16個通道不是獨立的分配給3個轉換器(ADC1、ADC2、ADC3)使用,有些通道是被多個轉換器共用的。首先看看16個通道在固件庫的宏定義(寫代碼要看的):

到這里大家可能會有疑問,每個通道到底對應哪個引腳呢?下面先給出部分引腳圖:

16個通道的引腳都在上面的圖中,拿其中的一個進行說明:

ADC123_IN10:字母“ADC”不用多說,“123”代表它被3個(ADC1、ADC2、ADC3)轉換器共用的引腳,“10”對應剛才那張宏定義圖里面的ADC_Channel_10,這樣就能找到每個通道對應的引腳了。

2個內部通道:一個是內部溫度傳感器,一個是內部參考電壓。

在某個項目中要用到芯片里面的AD轉換器,那么要怎么寫應用代碼?(以下是代碼講解)

芯片固件的庫函數為我們提供了很多封裝好的函數,只要運用它提供的函數接口就可以了,宏觀上來講就搞懂兩個事情就行了:

初始化(設置用的哪個引腳、單通道、還是多通道同時轉換、是否使用DMA等配置)?

怎么讓轉換器進行一次數據獲取?

以下分別講述三種不同方式(單通道、多通道、基于DMA的多通道采集)的ADC應用實例:

/*單通道的ADC采集*/

void Adc_Config(void)

{

/*定義兩個初始化要用的結構體,下面給每個結構體成員賦值*/

ADC_InitTypeDef ADC_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

/*

使能GPIOA和ADC1通道時鐘

注意:除了RCC_APB2PeriphClockCmd還有RCC_APB1PeriphClockCmd,那么該如何選擇?

APB2:高速時鐘,最高72MHz,主要負責AD輸入,I/O,串口1,高級定時器TIM

APB1:低速時鐘,最高36MHz,主要負責DA輸出,串口2、3、4、5,普通定時器TIM,USB,IIC,CAN,SPI

*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );

RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12, ADC的采樣時鐘最快14MHz

/*配置輸入電壓所用的PA0引腳*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //GPIO_Mode_AIN:模擬輸入(還有其他什么模式?請看下面的附錄圖1)

GPIO_Init(GPIOA, &GPIO_InitStructure);

ADC_DeInit(ADC1); //復位,將ADC1相關的寄存器設為默認值

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //工作模式:ADC1和ADC2獨立工作模式 (還有其他什么模式?請看下面的附錄圖2)

ADC_InitStructure.ADC_ScanConvMode = DISABLE; //數模轉換工作:掃描(多通道)模式=ENABLE、單次(單通道)模式=DISABLE

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//數模轉換工作:連續=ENABLE、單次=DISABLE

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ADC轉換由軟件觸發啟動 (還有其他什么模式?請看下面的附錄圖3)

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC數據右對齊 除了右就是左:ADC_DataAlign_Left

ADC_InitStructure.ADC_NbrOfChannel = 1; //順序進行規則轉換的ADC通道的數目 范圍是1-16

ADC_Init(ADC1, &ADC_InitStructure); //根據ADC_InitStruct中指定的參數初始化外設ADC1的寄存器

/*為啥要設置下面這一步?

細心的你可以發現上面初始化了一個引腳通道,初始化了一個ADC轉換器,但ADC轉換器并不知道你用的是哪個引腳吧?

這一步目的是:設置指定ADC的規則組通道(引腳),設置它們的轉化順序和采樣時間

函數原型:void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, u8 ADC_Channel, u8 Rank, u8 ADC_SampleTime)

參數1 ADCx:x可以是1或者2來選擇ADC外設ADC1或ADC2

參數2 ADC_Channel:被設置的ADC通道 范圍ADC_Channel_0~ADC_Channel_17

參數3 Rank:規則組采樣順序。取值范圍1到16。

ADC_SampleTime:指定ADC通道的采樣時間值 (取值范圍?請看下面的附錄圖4)

*/

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );

ADC_Cmd(ADC1, ENABLE); //使能指定的ADC 注意:函數ADC_Cmd只能在其他ADC設置函數之后被調用

/*下面4步按流程走,走完就行*/

ADC_ResetCalibration(ADC1); //重置指定的ADC的校準寄存器

while(ADC_GetResetCalibrationStatus(ADC1)); //等待上一步操作完成

ADC_StartCalibration(ADC1); //開始指定ADC的校準狀態

while(ADC_GetCalibrationStatus(ADC1));//等待上一步操作按成

}

初始化完成之后,在主函數中:

void main(void)

{

float ADC_ConvertedValue;

float ADC_ConvertedValueLocal;

Adc_Config();

while(1)

{

ADC_SoftwareStartConvCmd(ADC1, ENABLE); //啟動轉換

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )); //等待轉換完成

ADC_ConvertedValue=ADC_GetConversionValue(ADC1); //獲取轉換結果*ADC_ConvertedValue*

ADC_ConvertedValueLocal=(float)ADC_ConvertedValue*(3.3/4096); //計算出實際電壓值*ADC_ConvertedValueLocal*

//這里適當加上一些延遲

//最好連續轉換幾次 取平均值 這里就省略寫了 點到為止}}

附錄圖1-GPIO_Mode值:

附錄圖4-ADC_SampleTime值:

對于一些剛接觸stm32的人來說,看了上面的代碼可能還會有很多疑問。

為什么要使能時鐘?時鐘到底設置多少才合適?

對于ADC_GetConversionValue(ADC1)這個函數參數并沒有指定那個通道,如果多個通道同時使用CAN1轉換器轉換時怎么獲取每個通道的值?

第一個問題,所有的外設都要使能時鐘,時鐘源分為外部時鐘和內部時鐘,外部時鐘比如接8MHz晶振,內部時鐘就在芯片內部集成,時鐘源為所有的時序電路提供基本的脈沖信號。時鐘源好比是一顆跳動的心臟,它按照一定的頻率在跳動,所有的器官(外設)要跟心臟(時鐘源)橋接起來才能工作,但不同的外設需要的頻率不同,所以在時鐘源跟外設之中常常還會有一些分頻器或者倍頻器,以實現對頻率的衰減或增強。還想了解更多專業的解釋可以去研究stm32的時鐘樹圖。

**第二個問題,**回答這個問題那么就等于開始介紹多通道轉換怎么實現了,看下圖

由圖理解,一個ADC轉換器只能選擇轉換一個通道,那么對比單通道我們只需做一下改變(以雙通道為例):

1.在void Adc_Config(void)函數里面添加:

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

配置多一個IO(PA1)口, 也就是通道1。

2.在void Adc_Config(void)函數里面添加:

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );

先不指定ADC轉換通道。

3.在主函數循環里改為:

while(1)

{

/*先采集通道1數據*/

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));

ADC_ConvertedValue=ADC_GetConversionValue(ADC1);

ADC_ConvertedValueLocal=(float)ADC_ConvertedValue*(3.3/4096);

/*再采集通道2數據*/

ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));

ADC_ConvertedValue=ADC_GetConversionValue(ADC1);

ADC_ConvertedValueLocal=(float)ADC_ConvertedValue*(3.3/4096);

//加入適當延時

}

完成以上三步就能把單通道擴展到雙通道(或者更多個通道)。不過還有一種基于DMA的多通道轉換更加合適。

首先簡單介紹DMA,DMA(Direct Memory Access,直接內存存取) ,用來提供在外設和存儲器之間或者存儲器和存儲器之間的高速數據傳輸。無需CPU干預,節省CPU資源;ADC轉換出來的值直接賦值給定義好的變量中。配置好的DMA可以不停地將ADC轉換值寫到該變量中,在主函數直接判斷該變量就知道此時的AD值,也就是說在主函數中不需要調用ADC_GetConversionValue()函數來獲取轉換值。

DMA跟其他外設一樣需要進行配置通道,使能時鐘等參數。

下面直接看代碼分析:

/*基于DMA的ADC多通道采集*/

volatile uint16 ADCConvertedValue[10][3];//用來存放ADC轉換結果,也是DMA的目標地址,3通道,每通道采集10次后面取平均數

void DMA_Init(void)

{

DMA_InitTypeDef DMA_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能時鐘

DMA_DeInit(DMA1_Channel1); //將通道一寄存器設為默認值

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);//該參數用以定義DMA外設基地址

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;//該參數用以定義DMA內存基地址(轉換結果保存的地址)

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//該參數規定了外設是作為數據傳輸的目的地還是來源,此處是作為來源

DMA_InitStructure.DMA_BufferSize = 3*10;//定義指定DMA通道的DMA緩存的大小,單位為數據單位。這里也就是ADCConvertedValue的大小

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//設定外設地址寄存器遞增與否,此處設為不變 Disable

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//用來設定內存地址寄存器遞增與否,此處設為遞增,Enable

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//數據寬度為16位

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//數據寬度為16位

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循環緩存模式

DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA通道擁有高優先級 分別4個等級 低、中、高、非常高

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//使能DMA通道的內存到內存傳輸

DMA_Init(DMA1_Channel1, &DMA_InitStructure);//根據DMA_InitStruct中指定的參數初始化DMA的通道

DMA_Cmd(DMA1_Channel1, ENABLE);//啟動DMA通道一

}

下面是ADC的初始化,可以將它與上面的對比一下有啥不同,重復的就不解析了

void Adc_Init(void)

{

ADC_InitTypeDef ADC_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

/*3個IO口的配置(PA0、PA1、PA2)*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/*IO和ADC使能時鐘*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA,ENABLE);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

ADC_InitStructure.ADC_ScanConvMode = ENABLE;

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //連續轉換

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructure.ADC_NbrOfChannel = 3;

ADC_Init(ADC1, &ADC_InitStructure);

ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_239Cycles5);//通道一轉換結果保存到ADCConvertedValue[0~10][0]

ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_239Cycles5););//通道二轉換結果保存到ADCConvertedValue[0~10][1]

ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_239Cycles5); );//通道三轉換結果保存到ADCConvertedValue[0~10][2]

ADC_DMACmd(ADC1, ENABLE);//開啟ADC的DMA支持

ADC_Cmd(ADC1, ENABLE);

ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1));

ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1));

}

做完這兩步,ADCConvertedValue數組的值就會隨輸入的模擬電壓改變而改變,在主函數中最好取多幾次的平均值,再通過公式換算成電壓單位。下面是主函數:

int main(void)

{

int sum;

u8 i,j;

float ADC_Value[3];//用來保存經過轉換得到的電壓值

ADC_Init();

DMA_Init();

ADC_SoftwareStartConvCmd(ADC1, ENABLE);//開始采集

while(1)

{

for(i=0;i<3;i<++)

{

sum=0;

for(j=0;j<10;j++)

{

sum+=ADCConvertedValue[j][i];

}

ADC_Value[i]=(float)sum/(10*4096)*3.3;//求平均值并轉換成電壓值

//打印(略)

}

//延時(略)

}}

ADCConvertedValue的定義用了volatile修飾詞,因為這樣可以保證每次的讀取都是從絕對地址讀出來的值,不會因為被會編譯器進行優化導致讀取到的值不是實時的AD值。

最后提醒一下,接線測試的時候記得接上基準電壓,就是VREF+和VREF-這兩個引腳。如果不想外接線測試就將內部通道的電壓讀出來,這樣就不用配置IO口了。

水平有限,僅供參考,錯誤之處以及不足之處還望多多指教。

編輯:hfy

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 轉換器
    +關注

    關注

    27

    文章

    9418

    瀏覽量

    156345
  • 數字轉換器
    +關注

    關注

    0

    文章

    347

    瀏覽量

    28763
  • AD轉換器
    +關注

    關注

    4

    文章

    252

    瀏覽量

    43033
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    TLV320ADC5140:高性能音頻ADC深度解析與應用指南

    TLV320ADC5140:高性能音頻ADC深度解析與應用指南 在音頻處理領域,高性能的模擬 - 數字轉換器(ADC)是實現高質量音頻采集
    的頭像 發表于 01-29 11:15 ?310次閱讀

    探索TLV320ADC3120:高性能音頻ADC深度解析

    探索TLV320ADC3120:高性能音頻ADC深度解析 在音頻信號處理領域,高性能的模數轉換器(ADC)是實現優秀音頻質量的關鍵。TI推
    的頭像 發表于 01-29 10:15 ?219次閱讀

    深度解析ADC3668/3669:高性能ADC的卓越之選

    深度解析ADC3668/3669:高性能ADC的卓越之選 在電子設計領域,模擬到數字轉換器(ADC)的性能往往直接影響著整個系統的表現。今天
    的頭像 發表于 01-26 10:15 ?339次閱讀

    深度解析AMC130M03:高精度通道ADC的卓越之選

    深度解析AMC130M03:高精度通道ADC的卓越之選 在電子設計領域,高精度、高性能的模擬 - 數字轉換器(ADC)一直是工程師們追求的
    的頭像 發表于 01-20 15:50 ?232次閱讀

    C語言中實現函數宏的三種方式

    在宏的第一個分號后便結束。即 a = b 和 b = tmp 均不受控制語句所作用。 因此,在工程中,一般使用三種方式來對函數宏進行封裝,分別為 {}、do{...}while(0
    發表于 12-29 07:34

    請問CW32芯片的三種工作模式是什么?

    CW32芯片的三種工作模式是什么?
    發表于 12-26 06:48

    深入解析ADC081C021/ADC081C027:高性能8位ADC的技術洞察

    與速度 ADC081C021和ADC081C027采用I2C兼容的2線接口,支持標準(100kHz)、快速(400kHz)和高速(3.4MHz)三種模式。這種靈活的
    的頭像 發表于 11-26 14:26 ?706次閱讀

    伺服電機的三種制動方式有什么區別?

    伺服電機作為自動化控制系統中執行元件的核心部件,其制動性能直接影響設備的定位精度和安全可靠性。目前主流的伺服電機制動方式包括動態制動、再生制動和電磁機械制動三種,它們在制動原理、應用場景及技術特點上
    的頭像 發表于 09-19 18:26 ?1758次閱讀
    伺服電機的<b class='flag-5'>三種</b>制動<b class='flag-5'>方式</b>有什么區別?

    MEMS中的三種測溫方式

    在集成MEMS芯片的環境溫度測量領域,熱阻、熱電堆和PN結原理是三種主流技術。熱阻是利用熱敏電阻,如金屬鉑或注入硅的溫度電阻系數恒定,即電阻隨溫度線性變化的特性測溫,電阻變化直接對應絕對溫度,需恒流源供電。
    的頭像 發表于 07-16 13:58 ?1666次閱讀
    MEMS中的<b class='flag-5'>三種</b>測溫<b class='flag-5'>方式</b>

    1553B總線常見三種組網方式

    1553B總線作為航空電子系統中的關鍵通信協議,其組網方式直接影響系統的可靠性和實時性。本文將深入解析1553B總線的三種典型組網結構:單總線結構、雙冗余總線和多總線分層架構,并結合實際應用場景分析
    的頭像 發表于 06-21 17:39 ?1928次閱讀
    1553B總線常見<b class='flag-5'>三種</b>組網<b class='flag-5'>方式</b>

    開關電源三種控制模式:PWM/PFM/PSM

    摘要 本文詳細介紹了開關電源的三種主要調制方式:PWM(脈沖寬度調制)、PFM(脈沖頻率調制)和PSM(脈沖跨周期調制)。PWM通過調整脈沖寬度保持恒定頻率,適用于重負載,但輕負載效率低。PFM則在
    發表于 06-09 16:11

    介紹三種常見的MySQL高可用方案

    在生產環境中,為了確保數據庫系統的連續可用性、降低故障恢復時間以及實現業務的無縫切換,高可用(High Availability, HA)方案至關重要。本文將詳細介紹三種常見的 MySQL 高可用
    的頭像 發表于 05-28 17:16 ?1239次閱讀

    信號隔離器三種供電方式的區別

    信號隔離器是一重要的信號隔離裝置,其供電方式主要有獨立供電、回路供電和輸出回路供電三種。以下是這三種供電方式的詳細區別: 一、獨立供電 1
    的頭像 發表于 04-17 16:23 ?1539次閱讀
    信號隔離器<b class='flag-5'>三種</b>供電<b class='flag-5'>方式</b>的區別

    redis三種集群方案詳解

    在Redis中提供的集群方案總共有三種(一般一個redis節點不超過10G內存)。
    的頭像 發表于 03-31 10:46 ?1531次閱讀
    redis<b class='flag-5'>三種</b>集群方案詳解

    FOC中的三種電流采樣方式,你真的會選擇嗎?(可下載)

    的基礎,用一句話來形容就是“基礎不對,努力白費”,由此可見電流采樣在整 個 FOC 算法中的作用電流采樣的方式一般分為電阻、雙電阻、單電阻,這三種采樣方式都有其
    發表于 03-12 15:04 ?4次下載