STM32F407-ADC(模數轉換)

电子_精灵發表於2024-08-21

一、硬體

STM32F407開發板,杜邦線。

透過通道獲取板載電壓的模擬輸入訊號轉變為數字訊號,並透過轉換變成電壓。

STM32F407有3個ADC,每個ADC有16個通道,下表為ADC通道對應的引腳,使用哪個通道就用杜邦線將對應的引腳與模擬輸入連線起來。

STM32F407-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);

}

}

相關文章