STM32中ADC模拟信号转数字信号

xiaoxiao2021-02-28  171

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

转载请注明原文地址: https://www.6miu.com/read-28201.html

最新回复(0)