天天看點

【STM32标準庫】【基礎知識】ADC轉換,非DMA的單通道和多通道ADC概述ADC初始化模拟多通道采集(非DMA)總例程

文章目錄

  • ADC概述
  • ADC初始化
    • GPIO初始化
    • 時鐘
    • 全局ADC設定
      • 定義結構體
      • 是否使用DMA
      • 工作模式
      • 分頻
      • 采樣延遲
      • 例程
    • 單獨ADC設定
      • 定義結構體
      • 連續轉換
      • 資料對齊
      • 外部觸發
      • 通道數量
      • 分辨率
      • 掃描模式
      • 例程
    • 設定規則
    • 打開軟體調用ADC
  • 模拟多通道采集(非DMA)
    • 思路
    • 函數
  • 總例程

文章基于适用于STM32F4系列,作者使用STM32F401CCU6開發闆。

本文章基于此系列和開發闆展開讨論。

ADC概述

A是指模拟信号,D是指數字信号,C是指變換

故名思意,ADC即将模拟信号轉換為數字信号的一種變換。

STM32F4的ADC為逐次逼近型ADC

原理是利用DAC産生不同大小的電壓,與輸入的電壓比較,得到輸入電壓的大體範圍,這個範圍的誤差即為分辨率

如為8位分辨率的ADC,則分度值為

3.3/2^8

,即與真實值的誤差不會超過12.89mV

具體原理請看微機原理

ADC初始化

流程

  1. GPIO初始化
  2. 打開時鐘
  3. 全局ADC設定
  4. 單獨ADC設定

GPIO初始化

之前文章中介紹過,傳送門,需要設定為模拟模式

例程

GPIO_InitTypeDef GPIO_InitStruct;						//GPIO初始化結構體
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);	//打開時鐘
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;				//模拟模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;				//随意設定
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;		//端口
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;			//随意設定
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;			//高速
GPIO_Init(GPIOA, &GPIO_InitStruct);	
           

時鐘

本系列單片機隻有1個ADC,ADC1,端口對應請看這篇文章,傳送門

使用這句指令打開ADC的時鐘

全局ADC設定

這部分的設定是對全部的ADC有效的(本單片機即ADC1)

定義結構體

是否使用DMA

ADC_CommonInitStruct.ADC_DMAAccessMode
           

可以的選擇使用或不使用,本文為不使用的情況。

工作模式

可以選擇外部觸發源或者不使用觸發

本文為不使用外部觸發(獨立工作模式)

分頻

ADC需要頻率在12MHz以下,以AHB1的頻率(與系統頻率相等)為基準進行分頻

本文選擇8分頻

采樣延遲

這個隻有在多ADC時才有效,作為兩個ADC采樣之間的時間間隔

例程

ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;	   //不使用DMA
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;					   //獨立工作模式
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;				   //分頻,建議分頻後小于12MHZ
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //采樣延遲,多ADC使用才有效
ADC_CommonInit(&ADC_CommonInitStruct);
           

單獨ADC設定

下面的設定是針對單獨的ADC的

定義結構體

連續轉換

将所有開啟的通道采集轉換完一輪後自動開啟下一輪的采集轉換,這是連續模式

資料對齊

選擇右對齊即可,其他基本上用不到

外部觸發

可以選擇邊沿觸發或者定時器中斷觸發,或者不使用外部觸發

這裡選擇的不使用外部觸發

ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		 //選擇外部觸發事件,這裡随意即可,因為使用了不允許外部觸發
	ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //軟體觸發
           

通道數量

即選擇打開了幾個通道

分辨率

即最大誤差範圍,這個資料的選擇與後期計算電壓值相關

可以是

分辨率 分割數量
6bit 64
8bit 256
10bit 1024
12bit 4096

掃描模式

用于多通道掃描,完成全部打開的通道的掃描後中斷标志置位

但是後接受的資料會被覆寫,需要使用DMA

這裡是單通道(非DMA多通道是軟體模拟的),是以此處設定與不設定均可

例程

ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;							 //連續模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;						 //右對齊
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		 //選擇外部觸發事件,這裡随意即可,因為使用了不允許外部觸發
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //軟體觸發
ADC_InitStruct.ADC_NbrOfConversion = 1;									 //通道數量
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;						 //分辨率
ADC_InitStruct.ADC_ScanConvMode = ENABLE;								 //掃描模式
ADC_Init(ADC1, &ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);
           

設定規則

使用此函數設定對應規則

分别輸入ADC号(本單片機隻有ADC1),ADC通道号,标記号,采樣時間

标記号隻能小于等于通道數,從1開始,采樣時間是會将這段時間内的資料平均後輸出

打開軟體調用ADC

如果使用軟體讀取ADC,需要事先調用此函數

需要在設定後才可以使用軟體調用ADC

是以可以使用這段代碼確定已經設定成功

while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
		;
           

模拟多通道采集(非DMA)

思路

每次調用此讀取ADC時,改變ADC對應的通道,設定成功後讀取ADC并傳回資料

函數

u16 ADC1_Read(u8 ch)
{
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_144Cycles); //設定通道規則
	ADC_SoftwareStartConv(ADC1);									 //開啟軟體觸發
	while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
		;
	return ADC_GetConversionValue(ADC1); //軟體觸發
}
           

總例程

void ADC_init()
{
	GPIO_InitTypeDef GPIO_InitStruct;
	ADC_InitTypeDef ADC_InitStruct;
	ADC_CommonInitTypeDef ADC_CommonInitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;	   //不使用DMA
	ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;					   //獨立工作模式
	ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div8;				   //分頻,建議分頻後小于12MHZ
	ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //采樣延遲,多ADC使用才有效
	ADC_CommonInit(&ADC_CommonInitStruct);

	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;							 //連續模式
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;						 //右對齊
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		 //選擇外部觸發事件,這裡随意即可,因為使用了不允許外部觸發
	ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //軟體觸發
	ADC_InitStruct.ADC_NbrOfConversion = 1;									 //通道數量
	ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;						 //分辨率
	ADC_InitStruct.ADC_ScanConvMode = ENABLE;								 //掃描模式
	ADC_Init(ADC1, &ADC_InitStruct);
	ADC_Cmd(ADC1, ENABLE);
}

           
u16 ADC1_Read(u8 ch)
{
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_144Cycles); //設定通道規則
	ADC_SoftwareStartConv(ADC1);									 //開啟軟體觸發
	while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
		;
	return ADC_GetConversionValue(ADC1); //軟體觸發
}
           
需要讀取時隻需要調用此函數即可,更改通道号即可讀取多通道資料,例如這樣
int main()
{
	int i = 0;
	ADC_init();
	Usart_init();
	while (1)
	{
		i = 0;
		i = ADC1_Read(ADC_Channel_1);
		i = (i * 3300 / 0xfff);
		printf("ch1=%d mV \r\n", i);
		Delay_ms(300);
		i = 0;
		i = ADC1_Read(ADC_Channel_0);
		i = (i * 3300 / 0xfff);
		printf("ch0=%d mV \r\n", i);
		Delay_ms(300);
	}
}