模拟信号转数字信号大致都不陌生,模拟信号是连续性变化的信号,ADC就是把连续型信号通过线性变换,转换成相应的数字信号保存在寄存器里,MCU直接读取即可。(传感器一般是线性的数据变换)
基础知识:1. 51中PCF8591是8位ADC芯片 (I2C对SCL,SDA控制,也算方便。后面把I2C,1-wire,SPI协议都讲了,就把各个协议对比一下,使用情况也分析一下)。而STM32内是12位ADC转换,18个通道(16个外部ADC, 2个内部信号源,下面代码就是测试使用内部信号源)
2. 4种模式:单次,连续 ,扫描和间断模式执行
3. ADC的输入时钟不能超过14MHZ, 像STM32F103ZE的RCC就是72MHZ,然而使用必须分频低于14MHZ来使用(ADC转换是要时间的,它要将模拟信号转换成数字信号填入数据寄存器,如果晶振太大,精度就会受影响,后面的数据没填进去)
4. 中断源:很多外设都有中断,ADC同样有
5. 可以使用DMA, 后面会将DMA_ADC混合使用复习一下
ADC引脚:
Vref, Vdda, Vref-, Vssa 这些了解一下即可,不重要。
ADCx_IN 模拟输入信号 (16个模拟输入信号,2个内部的不用ADCx_IN)
18个通道挂接在ADC1,ADC2,ADC3上, 16通道只负责ADC1的温度传感器
17通道只负责ADC1的内部参考电压(ADC采集可以随意挂接其他通道)
至于各个模式,结构体配置有介绍,代码里注解写上,也把个人认为有参考的心得,吐槽加上
#include "adc.h"
void adc_init()
{
GPIO_InitTypeDef GPIO_InitStructure; /* 配置GPIO结构体 */
ADC_InitTypeDef ADC_InitStructure; /* 配置ADC结构体*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); /ADC1挂接APB2总线上,APB2总线开启复用功能,ADC还不算复用?下次将STM32系统总线,AHB,APB1,APB2,DNA,FSMC挂接方式,总线仲裁写一下/
RCC_ADCCLKConfig(RCC_PCLK2_Div6); /72Mhz进行6分频,ADC晶振不能超过14Mhz/
/* 使用到GPIO采集数据,所以要配置GPIO */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /配置晶振/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //ADC123_IN1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; /讲过,ADC模拟量的采集就是这个模式/
GPIO_Init(GPIOA,&GPIO_InitStructure);
/* 配置ADC结构体 */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; /独立工作模式/
ADC_InitStructure.ADC_ScanConvMode =DISABLE; /多通道采集ENABLE,单通道DISABLE。我们就采集小手掌处电压值,故使用单通道
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; /单次采集DISABLE,多次采集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_1, 1, ADC_SampleTime_239Cycles5)/核心板上写的是ADC2,其实都是复用的,ADC123都是等价的,随意自己使用,但主意,ADC123_IN1代表ADC随意用,但通道是1,不然读不出来/;
ADC_Cmd(ADC1, ENABLE); /使能/
ADC_ResetCalibration(ADC1); /重设ADC1校准/
while(ADC_GetResetCalibrationStatus(ADC1)); /ADC外设速度都较慢,都要等待校准结束,后面还有外设如此/
ADC_StartCalibration(ADC1); /正式校准,吐槽:为毛不直接校准,还有重设这东西/
while(ADC_GetCalibrationStatus(ADC1)); /判断,再次吐槽,这博客注解不能加在//后,还乱码,TMD/
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
main.c文件
#include "public.h"
#include "Systick.h"
#include "printf.h"
#include "adc.h"
int main()
{
u8 i;
u32 ad=0;
printf_init();
adc_init();
while(1)
{
for(i=0;i<50;i++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
ad=ad+ADC_GetConversionValue(ADC1);
}
ad=ad/50;
printf("AD=%fV!\r\n",ad*3.3/4096);
delay_ms(1000);
}
}