原理
基础知识
1、GPIO
根据滑动变阻器的引脚,我们可以知道应该用 PB0 来作为ADC的获取引脚。 再通过芯片手册(注意,不是数据手册哈),我们可以知道ADC是通道8. 板子有三个ADC,那么用哪个ADC呢? 咱们就默认ADC1就行。反正比赛就先讲效率吧(摆烂)。
2、通道
ADC有规则通道和注入通道。 规则通道就是很正常的通道。 注入通道就是类似中断一样的,且前提是有规则通道的存在。 但是我们比赛只用得到规则通道。 所以,初始化时,我们要默认配置成规则通道。
3、触发方式
肯定用软件啊!!! Pass.
4、转换时间
转换时间:Tconv = 采样时间 + 12.5 个周期
先看周期—— ADC_CLK:ADC模拟电路时钟,最大值为14M,由 PCLK2提供,还可分频,2/4/6/8,RCC_CFGR 的 ADCPRE[1:0]设置。PCLK2=72M 所以我们最大分频为72 / 6 = 12M。 这里是后面初始化分频时要注意的地方,分频系数注意要大于等于6。
采样时间在库里会有枚举好的变量,这里只要知道采样时间越长,精度越高就行。 我们比赛当然还是精度高点好。
5、数据
数据的寄存器是十六位有效,但是ADC数据的分辨率是12位的, 所以初始化中会有一个数据左对齐或者右对齐。 我们使用右对齐会方便很多。
另外,由于精度是12位,且最大电压为3.3V,所以最小精度为(3.3 / pow(2,12)) //(这里是2的十二次方哈,最近二级把我搞麻了) 所以直接写成 3.3 / 4096. 即计算公式为 Y = (3.3 / 4096)*X
初始化结构体
第一个,我们选择独立模式,因为我们只用到了ADC1. 第二个也是一样的道理,所以DISABLE。 第三个,这个看自己吧,开连续转换和不开的区别我还不清楚,很多人都说关,但是我开了(狗头)。等我会了再来改。 第四个,是否选择外部触发,选否,ADC_ExternalTrigConv_None 这个。 第五个,右对齐啦,上面讲过了。 第六个,我们只用了一个通道(那个通道8的),所以这里选1.
常用库函数
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
配置ADC时钟分频。这里我们就选 六分频就行——RCC_PCLK2_Div6 。 **注意这个函数在RCC头文件里哈。 **
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
这个就不用多说了吧。
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
使能 ADC。
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
使能ADC的中断,注意这里的标志位是 ADC_IT_EOC ,EOC是规则转换完的标志位。
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
使能 ADC 复位校准。
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
获取复位校准标志位。
void ADC_StartCalibration(ADC_TypeDef* ADCx);
开启 ADC 校准。
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
获取校准标志位。
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
软件转换使能;
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
规则通道配置。 第二个参数是通道,我们填通道8——ADC_Channel_8 ; 第三个是转换顺序,我们只有一个,所以就填 1 ; 第四个是采样时间,找到参数列表,自己选择,根据前面讲的越大越好(当然只是在蓝桥杯比赛中,实际应用肯定要注意效率),我选 ADC_SampleTime_239Cycles5 ,239.5。
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
获取转换后的数值。
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
获取中断标志位。
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);
清零中断标志位。
代码
//bsp_adc.c
#include "bsp_adc.h"
static void ADC1_GPIO_Comfig(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
static void ADC1_Comfig(void){
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
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_Cmd(ADC1, ENABLE);
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
static void ADC1_NVIC_Comfig(void){
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void ADC1_Init(void){
ADC1_GPIO_Comfig();
ADC1_Comfig();
ADC1_NVIC_Comfig();
}
//bsp_adc.h
#ifndef __BSP_ADC_H
#define __BSP_ADC_H
#include "stm32f10x.h"
void ADC1_Init(void);
#endif
//stm32f10x_it.c
uint16_t ADC_ConversionValue;
void ADC1_2_IRQHandler(void){
if(ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET){
ADC_ConversionValue = ADC_GetConversionValue(ADC1);
}
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
//main.c
extern uint16_t ADC_ConversionValue;
float ADC_ConversionValueLocal = 0;
ADC1_Init();
while(1){
ADC_ConversionValueLocal = (float)ADC_ConversionValue * 3.3 / 4096 ;
printf("ADC : %f V \r\n",ADC_ConversionValueLocal);
}
要点
1-初始化ADC用到的GPIO ; 2-初始化ADC初始化结构体 ; 3-配置ADC时钟,配置通道的转换顺序和采样时间 ; 4-使能ADC转换完成中断,配置中断优先级; 5-使能ADC,准备开始转换 ; 6-校准ADC ; 7-软件触发ADC,真正开始转换 ; 8-编写中断服务函数,读取ADC转换数据 ; 9-编写main函数,把转换的数据打印出来 ;
注意
记得开 ADC 时钟!!!
代码快速配置
打开文件:赛点资源数据包_嵌入式\6-STM32固件库代码V3.5版\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\ADC\ADC1_DMA 打开main.c文件——
复制修改为——
void Adc1_Init(void){
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
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(GPIOC, &GPIO_InitStructure);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
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_RegularChannelConfig(ADC1, ADC_Channel_8, 1, 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);
}
获取函数
u16 Adc_get(void){
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0);
return ADC_GetConversionValue(ADC1);
}
|