單通道配置
單通道就比較簡單了,並且Duck不比用DMA,這裏正好講解一下,STM32內部自帶的一個溫度傳感器。
adc.c
#include "adc.h"
void Adc_Init(void){
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1/*|RCC_APB2Periph_GPIOB*/, ENABLE);
//如果用的是溫度傳感器則不需要初始化引腳,反之則必須
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//這個參數用來指定轉換是掃描(多通道模式)還是單個轉換(單通道模式)
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
//ADC轉換可以在一次轉換後停止,然後再次觸發後進行下一次轉換;也可以是持續不斷地轉換下去。
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
//使能溫度傳感器模塊,如果說不用的話,可以不用的
ADC_TempSensorVrefintCmd(ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
double Adc1_GetVal(u8 Channel_x){
//設置指定ADC的規則組通道,一個序列,採樣時間
//ADC1,ADC通道,採樣時間爲239.5週期,週期越大,測得越準確
ADC_RegularChannelConfig(ADC1, Channel_x, 1, ADC_SampleTime_239Cycles5 );
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
//返回最近一次ADC1規則組的轉換結果
return (double)ADC_GetConversionValue(ADC1)*3.3/4095;
}
//這個形參mode針對溫度傳感器的,如果說用的是普通ADC採樣,則mode參數給0
double Get_Adc_Average(u8 ch,u8 times,u8 mode)
{
double temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Adc1_GetVal(ch);
Delay_Ms(5);
}
temp_val=temp_val/times;
if(mode==1){
temp_val = (1430 - 1000*temp_val)/4.3 + 25;
}
return temp_val;
}
adc.h
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ADC_H
#define __ADC_H
/* Includes ------------------------------------------------------------------*/
#include "main.h"
void Adc_Init(void);
double Adc1_GetVal(u8 Channel_x);
double Get_Adc_Average(u8 ch,u8 times,u8 mode);
#endif
該注意的內容都在代碼註釋的很清楚了!
多通道配置
多通道就是讀取多個通道,此模式需要適用DMA。適用場景:連續採集多個通道的ADC。這裏我選用的是比如PA1,PA2,PB0。
adc.c
#include "adc.h"
//這個數組就是用來存放DMA讀到的數據,因此我們外部引用,就可以直接使用了
__IO uint16_t ADCConvertedValue[3];
void Adc_Init(void){
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
DMA_DeInit(DMA1_Channel1);
//ADC1_DR_Address這個是ADC的地址(固定值),我在adc.h直接定義了
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
//這裏設置的是數據存放的地址,因爲數組名本身就是地址,所以把取地址去掉了
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;
//下面的這句是設置 DMA 的傳輸方向,就如前面所說的,DMA 可以雙向傳輸,也可以單向傳輸
//這裏設置的是單向傳輸,如果需要雙向傳輸:把 DMA_DIR_PeripheralSRC 改成DMA_DIR_PeripheralDST 即可。
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//因爲我們設置數組的長度爲3
DMA_InitStructure.DMA_BufferSize = 3;
//下面這句是設置 DMA 的外設遞增模式,如果 DMA 選用的通道(CHx)有多個外設連接,需要使用外設遞增模式:DMA_PeripheralInc_Enable;
//我的例子裏 DMA 只與 ADC1 建立了聯繫,所以選用DMA_PeripheralInc_Disable。
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//下面的這句是設置DMA的內存遞增模式,DMA 訪問多個內存參數時,需要使用DMA_MemoryInc_Enable
//當DMA只訪問一個內存參數時可設置成 :DMA_MemoryInc_Disable。
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//下面的這句是設置 DMA 的傳輸模式:連續不斷的循環模式
//若只想訪問一次後就不要訪問了,可以設置成通用模式:DMA_Mode_Normal。
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//下面的這句是設置 DMA 的優先級別:可以分爲 4 級:VeryHigh,High,Medium,Low.
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1,&DMA_InitStructure);
DMA_Cmd(DMA1_Channel1,ENABLE);
/* ADC1 configuration ------------------------------------------------------*/
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;
//因爲我們用了三個通道,所以這裏用3
ADC_InitStructure.ADC_NbrOfChannel = 3;
ADC_Init(ADC1, &ADC_InitStructure);
//ADC_RegularChannelConfig中有四個參數
//第一個爲ADC1,第二個取決於你前面初始化IO口對應的是ADC的通道幾,第三個爲Rank的序號
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 3, ADC_SampleTime_239Cycles5);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
adc.h
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ADC_H
#define __ADC_H
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#define ADC1_DR_Address ((uint32_t)0x4001244C)
void Adc_Init(void);
extern __IO uint16_t ADCConvertedValue[3];
#endif
比較重要的我都在代碼裏註釋了,自己看下就可以了。