蓝桥杯嵌入式_STM32学习_ADC配置

原理

基础知识

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配置
	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、中断、软件触发,配置规则通道
	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校准
	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 /* __BSP_ADC_H */

//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 / 4095 ;
	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);//PB0

  /* Configure PC.04 (ADC Channel14) as analog input -------------------------*/
  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);
	 /* ADC1 regular channel14 configuration */ 
  ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);

  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
  
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
     
  /* Start ADC1 Software Conversion */ 
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

获取函数

u16 Adc_get(void){
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0);
	return ADC_GetConversionValue(ADC1);
}
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moqim Flourite.

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值