模拟信号转数字信号大致都不陌生,模拟信号是连续性变化的信号,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); } }