日韩在线不卡免费视频一区,日韩欧美精品一区二区三区经典,日产精品码2码三码四码区,人妻无码一区二区三区免费,日本feerbbwdh少妇丰满

  • 回復(fù)
  • 收藏
  • 點(diǎn)贊
  • 分享
  • 發(fā)新帖

stm32之ADC應(yīng)用實(shí)例(單通道、多通道、基于DMA)簡單總結(jié)

對于單片機(jī)stm32f103VET6來說

片內(nèi)嵌3個(gè)12位的模擬/數(shù)字轉(zhuǎn)換器(ADC),每個(gè)ADC共用多達(dá)16個(gè)外部通道,2個(gè)內(nèi)部通道。

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

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

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

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

16個(gè)通道的引腳都在上面的圖中,拿其中的一個(gè)進(jìn)行說明:

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

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

2個(gè)內(nèi)部通道:一個(gè)是內(nèi)部溫度傳感器,一個(gè)是內(nèi)部參考電壓。

在某個(gè)項(xiàng)目中要用到芯片里面的AD轉(zhuǎn)換器,那么要怎么寫應(yīng)用代碼?(以下是代碼講解)

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

初始化(設(shè)置用f的哪個(gè)引腳、單通道、還是多通道同時(shí)轉(zhuǎn)換、是否使用DMA等配置)?怎么讓轉(zhuǎn)換器進(jìn)行一次數(shù)據(jù)獲???以下分別講述三種不同方式(單通道、多通道、基于DMA的多通道采集)的ADC應(yīng)用實(shí)例:

/*單通道的ADC采集*/
void  Adc_Config(void)
{ 	
    /*定義兩個(gè)初始化要用的結(jié)構(gòu)體,下面給每個(gè)結(jié)構(gòu)體成員賦值*/
	ADC_InitTypeDef ADC_InitStructure; 
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/*
	  使能GPIOA和ADC1通道時(shí)鐘
	  注意:除了RCC_APB2PeriphClockCmd還有RCC_APB1PeriphClockCmd,那么該如何選擇?
      APB2:高速時(shí)鐘,最高72MHz,主要負(fù)責(zé)AD輸入,I/O,串口1,高級定時(shí)器TIM
      APB1:低速時(shí)鐘,最高36MHz,主要負(fù)責(zé)DA輸出,串口2、3、4、5,普通定時(shí)器TIM,USB,IIC,CAN,SPI
  	*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );	  
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  //72M/6=12, ADC的采樣時(shí)鐘最快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); //復(fù)位,將ADC1相關(guān)的寄存器設(shè)為默認(rèn)值
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//工作模式:ADC1和ADC2獨(dú)立工作模式  (還有其他什么模式?請看下面的附錄圖2)
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//數(shù)模轉(zhuǎn)換工作:掃描(多通道)模式=ENABLE、單次(單通道)模式=DISABLE
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//數(shù)模轉(zhuǎn)換工作:連續(xù)=ENABLE、單次=DISABLE
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//ADC轉(zhuǎn)換由軟件觸發(fā)啟動 (還有其他什么模式?請看下面的附錄圖3)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC數(shù)據(jù)右對齊   除了右就是左:ADC_DataAlign_Left
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//順序進(jìn)行規(guī)則轉(zhuǎn)換的ADC通道的數(shù)目   范圍是1-16
	ADC_Init(ADC1, &ADC_InitStructure);	//根據(jù)ADC_InitStruct中指定的參數(shù)初始化外設(shè)ADC1的寄存器
 
    /*為啥要設(shè)置下面這一步?
     細(xì)心的你可以發(fā)現(xiàn)上面初始化了一個(gè)引腳通道,初始化了一個(gè)ADC轉(zhuǎn)換器,但ADC轉(zhuǎn)換器并不知道你用的是哪個(gè)引腳吧?
     這一步目的是:設(shè)置指定ADC的規(guī)則組通道(引腳),設(shè)置它們的轉(zhuǎn)化順序和采樣時(shí)間
     函數(shù)原型:void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, u8 ADC_Channel, u8 Rank, u8 ADC_SampleTime)
     參數(shù)1 ADCx:x可以是1或者2來選擇ADC外設(shè)ADC1或ADC2 
     參數(shù)2 ADC_Channel:被設(shè)置的ADC通道  范圍ADC_Channel_0~ADC_Channel_17
     參數(shù)3 Rank:規(guī)則組采樣順序。取值范圍1到16。
     ADC_SampleTime:指定ADC通道的采樣時(shí)間值  (取值范圍?請看下面的附錄圖4)
    */	
	 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );	  	
	  		    
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC  注意:函數(shù)ADC_Cmd只能在其他ADC設(shè)置函數(shù)之后被調(diào)用

    /*下面4步按流程走,走完就行*/
	ADC_ResetCalibration(ADC1);	//重置指定的ADC的校準(zhǔn)寄存器
	while(ADC_GetResetCalibrationStatus(ADC1)); //等待上一步操作完成
	ADC_StartCalibration(ADC1);	//開始指定ADC的校準(zhǔn)狀態(tài)	
	while(ADC_GetCalibrationStatus(ADC1));//等待上一步操作按成		
 }	

附錄圖1-GPIO_Mode值:

附錄圖2-ADC_Mode值:

附錄圖3-ADC_ExternalTrigConv值:

附錄圖4-ADC_SampleTime值:

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

為什么要使能時(shí)鐘?時(shí)鐘到底設(shè)置多少才合適?對于ADC_GetConversionValue(ADC1)這個(gè)函數(shù)參數(shù)并沒有指定那個(gè)通道,如果多個(gè)通道同時(shí)使用CAN1轉(zhuǎn)換器轉(zhuǎn)換時(shí)怎么獲取每個(gè)通道的值?第一個(gè)問題,所有的外設(shè)都要使能時(shí)鐘,時(shí)鐘源分為外部時(shí)鐘和內(nèi)部時(shí)鐘,外部時(shí)鐘比如接8MHz晶振,內(nèi)部時(shí)鐘就在芯片內(nèi)部集成,時(shí)鐘源為所有的時(shí)序電路提供基本的脈沖信號。時(shí)鐘源好比是一顆跳動的心臟,它按照一定的頻率在跳動,所有的器官(外設(shè))要跟心臟(時(shí)鐘源)橋接起來才能工作,但不同的外設(shè)需要的頻率不同,所以在時(shí)鐘源跟外設(shè)之中常常還會有一些分頻器或者倍頻器,以實(shí)現(xiàn)對頻率的衰減或增強(qiáng)。還想了解更多專業(yè)的解釋可以去研究stm32的時(shí)鐘樹圖。

**第二個(gè)問題,**回答這個(gè)問題那么就等于開始介紹多通道轉(zhuǎn)換怎么實(shí)現(xiàn)了,看下圖

由圖理解,一個(gè)ADC轉(zhuǎn)換器只能選擇轉(zhuǎn)換一個(gè)通道,那么對比單通道我們只需做一下改變(以雙通道為例):1.在void Adc_Config(void)函數(shù)里面添加:

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 
GPIO_Init(GPIOA, &GPIO_InitStructure);	

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

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

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );	

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

DMA跟其他外設(shè)一樣需要進(jìn)行配置通道,使能時(shí)鐘等參數(shù)。下面直接看代碼分析:

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

volatile uint16 ADCConvertedValue[10][3];//用來存放ADC轉(zhuǎn)換結(jié)果,也是DMA的目標(biāo)地址,3通道,每通道采集10次后面取平均數(shù)
         
void DMA_Init(void)
{

    DMA_InitTypeDef DMA_InitStructure;

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

    DMA_DeInit(DMA1_Channel1);    //將通道一寄存器設(shè)為默認(rèn)值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);//該參數(shù)用以定義DMA外設(shè)基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;//該參數(shù)用以定義DMA內(nèi)存基地址(轉(zhuǎn)換結(jié)果保存的地址)
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//該參數(shù)規(guī)定了外設(shè)是作為數(shù)據(jù)傳輸?shù)哪康牡剡€是來源,此處是作為來源
    DMA_InitStructure.DMA_BufferSize = 3*10;//定義指定DMA通道的DMA緩存的大小,單位為數(shù)據(jù)單位。這里也就是ADCConvertedValue的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//設(shè)定外設(shè)地址寄存器遞增與否,此處設(shè)為不變 Disable
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//用來設(shè)定內(nèi)存地址寄存器遞增與否,此處設(shè)為遞增,Enable
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//數(shù)據(jù)寬度為16位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//數(shù)據(jù)寬度為16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循環(huán)緩存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA通道擁有高優(yōu)先級 分別4個(gè)等級 低、中、高、非常高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//使能DMA通道的內(nèi)存到內(nèi)存?zhèn)鬏?    DMA_Init(DMA1_Channel1, &DMA_InitStructure);//根據(jù)DMA_InitStruct中指定的參數(shù)初始化DMA的通道

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

全部回復(fù)(3)
正序查看
倒序查看
#回復(fù)內(nèi)容已被刪除#
2
#回復(fù)內(nèi)容已被刪除#
3
ruohan
LV.9
4
2021-11-08 11:44

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

添加這句話后,就能多通道采集了嗎

0
回復(fù)
發(fā)