一、硬體
STM32F407開發板,杜邦線。
透過通道獲取板載電壓的模擬輸入訊號轉變為數字訊號,並透過轉換變成電壓。
STM32F407有3個ADC,每個ADC有16個通道,下表為ADC通道對應的引腳,使用哪個通道就用杜邦線將對應的引腳與模擬輸入連線起來。
二、整體流程
① 開啟PA時鐘和ADC1時鐘,設定PA1為模擬輸入。
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
GPIO_Init();
對於IO初始化要注意的是這裡採用的模式為模擬輸入模式:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
② 復位ADC1:
ADC_DeInit();
③ 初始化ADC_CCR暫存器。
ADC_CommonInit();
該函式傳入引數為例項化的結構體,有四個引數分別是ADC模式,預分頻係數,延遲週期,DMA訪問模式。其中為了保證ADC時鐘的準確性,最小取樣時間0.42us(ADC時鐘=36MHz,取樣週期為3週期下得到),要挑選合適的預分頻係數保證時鐘小於36MHz,延遲週期越大采樣延遲越高。
④初始化ADC1引數,設定ADC1的工作模式以及規則序列的相關資訊。
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
其中的 ADC_Resolution選擇了12位,因為暫存器為16位,放不滿,所以還要設定它的對齊方式。只用到了一個通道,因此轉換規則序列為1。
⑤ 使能ADC。
ADC_Cmd(ADC1, ENABLE);
⑥配置規則通道引數:
ADC_RegularChannelConfig();
⑦開啟軟體轉換:ADC_SoftwareStartConvCmd(ADC1);
⑧ 等待轉換完成,讀取ADC值。
用while判斷轉換是否完成,調取ADC_GetFlagStatus可以知道當前轉換的狀態。
最後返回ADC_GetConversionValue(ADC1)的值。
在主函式只需對讀取到的數值進行相應的轉換輸出即可。
三、原始碼
ADC部分
#include "adc.h"
#include "sys.h"
#include "delay.h"
void Adc_Init(void) //ADC通道初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_InitTypeDef ADC_InitStruct;
RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模擬輸入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit();//ADC復位
ADC_CommonInitStruct.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_Mode=ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler=ADC_Prescaler_Div4;
ADC_CommonInitStruct.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_NbrOfConversion=1;
ADC_InitStruct.ADC_Resolution=ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode=DISABLE;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_Cmd(ADC1, ENABLE);
}
u16 Get_Adc(u8 ch) //獲得某個通道值
{
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles );
ADC_SoftwareStartConv(ADC1);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
return ADC_GetConversionValue(ADC1);
}
u16 Get_Adc_Average(u8 ch,u8 times)//得到某個通道給定次數取樣的平均值
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{</times;t++)
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
main函式
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "adc.h"
int main(void)
{
u16 adcx;
float temp;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設定系統中斷優先順序分組2
delay_init(168); //初始化延時函式
uart_init(115200); //初始化串列埠波特率為115200
LED_Init(); //初始化LED
LCD_Init(); //初始化LCD介面
Adc_Init(); //初始化ADC
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
LCD_ShowString(30,70,200,16,16,"ADC TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2014/5/6");
POINT_COLOR=BLUE;//設定字型為藍色
LCD_ShowString(30,130,200,16,16,"ADC1_CH5_VAL:");
LCD_ShowString(30,150,200,16,16,"ADC1_CH5_VOL:0.000V"); //先在固定位置顯示小數點
while(1)
{
adcx=Get_Adc_Average(ADC_Channel_5,20);//獲取通道5的轉換值,20次取平均
LCD_ShowxNum(134,130,adcx,4,16,0); //顯示ADCC取樣後的原始值
temp=(float)adcx*(3.3/4096); //獲取計算後的帶小數的實際電壓值,比如3.1111
adcx=temp; //賦值整數部分給adcx變數,因為adcx為u16整形
LCD_ShowxNum(134,150,adcx,1,16,0); //顯示電壓值的整數部分,3.1111的話,這裡就是顯示3
temp-=adcx; //把已經顯示的整數部分去掉,留下小數部分,比如3.1111-3=0.1111
temp*=1000; //小數部分乘以1000,例如:0.1111就轉換為111.1,相當於保留三位小數。
LCD_ShowxNum(150,150,temp,3,16,0X80); //顯示小數部分(前面轉換為了整形顯示),這裡顯示的就是111.
LED0=!LED0;
delay_ms(250);
}
}