目录
第一部分、关于ADC的基础知识
1、STM32ADC是多少位的?
STM32f103 系列有 3 个 ADC,精度都为 :12 位。
2、STM32ADCADC参考电压为多少?
STM32C8T6的 ADC 的输入电压范围为: 0~3.3V。
3、参考电压与ADC位数的转换关系
由上知STM32的 ADC是 12 位的,而最大电压为 3.3V,那么3.3V被分成了2^12这么多份。因此,如果ADC得到数值为 X , 那么该X对应的模拟电压为 Y = (3.3 / 2^12)* X 。
4、ADC通道对应的端口(来自野火的文档)
想要了解关于ADC的细节知识,可以去看《零死角玩转 STM32—基于野火 F103开发板》这本书,强烈推荐新手去看。
第二部分、直接上手的好用代码
1、adc.c文件
这里把通道二和通道三给屏蔽 ,因为串口2的管脚刚好对应与PA2和PA3。
#include "adc.h"
#include "delay.h"
void ADC_init(u8 ADC_CHx)
{
switch(ADC_CHx)
{
case ADC_CH0: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFFFFFF0; break; //PA0
case ADC_CH1: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFFFFF0F; break; //PA1
// case ADC_CH2: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFFFF0FF; break;//PA2
// case ADC_CH3: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFFF0FFF; break;//PA3
case ADC_CH4: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFF0FFFF; break; //PA4
case ADC_CH5: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFF0FFFFF; break; //PA5
case ADC_CH6: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XF0FFFFFF; break; //PA6
case ADC_CH7: RCC->APB2ENR|=1<<2; GPIOA->CRL&=0X0FFFFFFF; break; //PA7
case ADC_CH8: RCC->APB2ENR|=1<<3; GPIOB->CRL&=0XFFFFFFF0; break; //PB0
case ADC_CH9: RCC->APB2ENR|=1<<3; GPIOB->CRL&=0XFFFFFF0F; break; //PB1
case ADC_CH10:RCC->APB2ENR|=1<<4; GPIOC->CRL&=0XFFFFFFF0; break; //PC0
case ADC_CH11:RCC->APB2ENR|=1<<4; GPIOC->CRL&=0XFFFFFF0F; break; //PC1
case ADC_CH12:RCC->APB2ENR|=1<<4; GPIOC->CRL&=0XFFFFF0FF; break; //PC2
case ADC_CH13:RCC->APB2ENR|=1<<4; GPIOC->CRL&=0XFFFF0FFF; break; //PC3
case ADC_CH14:RCC->APB2ENR|=1<<4; GPIOC->CRL&=0XFFF0FFFF; break; //PC4
case ADC_CH15:RCC->APB2ENR|=1<<4; GPIOC->CRL&=0XFF0FFFFF; break; //PC5
}
//通道10/11设置
RCC->APB2ENR|=1<<9; //ADC1时钟使能
RCC->APB2RSTR|=1<<9; //ADC1复位
RCC->APB2RSTR&=~(1<<9); //复位结束
RCC->CFGR&=~(3<<14); //分频因子清零
//否则将导致ADC准确度下降!
RCC->CFGR|=2<<14;
ADC1->CR1&=0XF0FFFF; //工作模式清零
ADC1->CR1|= 0<<16;
ADC1->CR1|= ~(1<<8);
ADC1->CR2|= 1<<20;
ADC1->CR2&= ~(1<<1);
ADC1->CR2|= 7<<17;
ADC1->CR2&=~(1<<11);
ADC1->SMPR2&=~(7<<3);
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1|=0<<20;
ADC1->CR2|=1<<0;
ADC1->CR2|=1<<3;
while(ADC1->CR2&(1<<3));
ADC1->CR2|=1<<2;
while(ADC1->CR2&(1<<2));
}
/**
* @brief 得到ADC转换值函数
* @code
* // 得到ADC通道4值
* Get_Adc(ADC_CH4);
* @endcode
* @param[in] ADC_CHx ADC通道号: 值:ADC_CH0~ADC_CH15
*/
u16 Get_Adc(u8 ADC_CHx)
{
//设置转换序列
ADC1->SQR3&=0XFFFFFFE0; //规则序列1 通道ch
ADC1->SQR3|=ADC_CHx;
ADC1->CR2|=1<<22; //启动规则转换通道
while(!(ADC1->SR&1<<1)); //等待转换结束
return ADC1->DR; //返回adc值
}
/**
* @brief 得到ADC转换平均值函数
* @code
* // 得到ADC通道4值,次数为20
* Get_Adc_Average(ADC_CH4,20);
* @endcode
* @param[in] ADC_CHx ADC通道号: 值:ADC_CH0~ADC_CH15
* @param[in] times 平均次数
*/
u16 Get_Adc_Average(u8 ADC_CHx,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ADC_CHx);
delay_ms(5);
}
return temp_val/times;
}
2、adc.h文件
#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h"
#include "sys.h"
/* ADC规则通道 端口定义 */
#define ADC_CH0 0 // PA0
#define ADC_CH1 1 // PA1
//#define ADC_CH2 2 // PA2
//#define ADC_CH3 3 // PA3
#define ADC_CH4 4 // PA4
#define ADC_CH5 5 // PA5
#define ADC_CH6 6 // PA6
#define ADC_CH7 7 // PA7
#define ADC_CH8 8 // PB0
#define ADC_CH9 9 // PB1
#define ADC_CH10 10 // PC0
#define ADC_CH11 11 // PC1
#define ADC_CH12 12 // PC2
#define ADC_CH13 13 // PC3
#define ADC_CH14 14 // PC4
#define ADC_CH15 15 // PC5
//ADC1 API
void ADC_init(u8 ADC_CHx);
u16 Get_Adc(u8 ADC_CHx);
u16 Get_Adc_Average(u8 ADC_CHx,u8 times);
#endif
3、main.h文件
注意:这里不是完整的main.c函数,主要是明白这个函数如何调用。
int main()
{
/*ADC的采集值*/
u16 ADC_Value;
/*ADC初始化*/
ADC_init(ADC_CH4); //ADC1 通道四 PA4 初始化
while(1)
{
ADC_Value = Get_Adc_Average(ADC_CH4, 20);
}
}
第三部分、总结
代码是我的朋友发给我,其实很多时候你不必要去明白ADC的驱动代码它到底怎么配置的,为什么这么配置,你只要明白它是一个工具,学会怎么用这个工具就可以了。然后在照葫芦画瓢弄明白哪些代码是用来更改的,就可以了。
站在巨人的肩膀上,永远是最快的学习方法。