【STM32自学笔记-ADC】

一、ADC简介

        ADC全称是模拟-数字转换器,主要作用是将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。其分辨率有12位,输入电压为0~3.3V,转换结果范围在0~4095.拥有18个输入通道,可测量16个外部和2个内部信号源。

二、ADC框图简介

2.1 第一部分:电压输入范围

ADC 输入范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+ 、 VDDA 、 VSSA、这四个外部引脚决定。我们在设计原理图的时候一般把 VSSA 和 VREF- 接地,把 VREF+ 和 VDDA 接 3V3,得到 ADC 的输入电压范围为: 0~3.3V。

2.2 第二部分:输入通道

STM32ADC的通道有18个,其中有16个外部通道,2个内部通道。外部的 16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有 16 路,注入通道最多有 4 路。

规则通道:规则通道就是这16个外部通道,一般使用规则通道比较多。

注入通道:它是一种在规则通道转换的时候强行插入要转换的一种通道。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。只有规则通道存在时才会有注入通道。

2.3 第三部分:转换顺序

        多个规则通道采集数据转换时需要进行转换顺序,SQR3,SQR2,SQR1这2个寄存器决定了这16个通道的转换顺序。

注入通道转换顺序由JSQR寄存器控制,他最多只支持4个通道,和规则转换的顺序是不一样的,如果有4个通道,第一个转换通道为JSQ1设置。

如果有3个通道,第一个转换通道为JSQ2设置。

如果有2个通道,第一个转换通道为JSQ3设置。

如果有1个通道,第一个转换通道为JSQ4设置。

2.4 第四部分:触发源

ADC的触发源可以是定时器中断触发、外部引脚中断触发,也可以由内部软件触发。

2.5 第五部分:转换时间

ADC的输入时钟ADC_CLK由ABP2(72M)经过分频提供,分频系数为2、4、6、8分频。其ADC_CLK最大时钟频率是14M,所以一般只能进行6分频(72/6=12)或8分频(72/8=9)。

ADC 使用若干个 ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过 ADC 采样时间来控制,其中最快采样时间为1.5周期。

2.6 第六部分:数据寄存器

规则通道的数据寄存器

        所有规则通道数据转换后的结果存放在ADC_DR数据寄存器中,ADC_DR数据寄存器是一个32位的寄存器,在单通道情况下,数据存储在ADC_DR数据寄存器的低16位,由于ADC的精度只有12位,所有可以现在左对齐存放和右对齐存放。右对齐存放数据高位补0,左对齐存放数据整数数据扩大了16倍。

采用ADC多通道采集数据,那么不断有数据放到ADC_DR寄存器中,没有及时把数据拿出来。采集到之前的数据就会被之后的数据覆盖。这时候就需要使用到DMA及时把数据搬运出来。(只有ADC1和ADC3具有DMA功能)

使用双ADC模式时,比如ADC1和ADC2,那么AD1采集到的数据就会被存放到ADC_DR寄存器的低16位。ADC2采集到的数据就会被存放到ADC_DR寄存器的高16位,他们是同时存放进ADC_DR数据寄存器中,不需要进行转换排序。

注入通道的数据寄存器

ADC 注入组最多有 4 个通道,刚好注入数据寄存器也有 4 个,每个通道对应着自己的寄存器,不
会跟规则寄存器那样产生数据覆盖的问题。数据也是存放到ADC_JDRx寄存器中。低16位存放数据,高16位保留。

2.7 第七部分:中断

转换结束中断

数据转换结束后,可以产生中断,中断分为三种:规则通道转换结束中断,注入转换通道转换结
束中断,模拟看门狗中断。其中转换结束中断很好理解,跟我们平时接触的中断一样,有相应的
中断标志位和中断使能位,我们还可以根据中断类型写相应配套的中断服务程序

模拟看门狗中断

当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模
拟看门狗中断,其中低阈值和高阈值由 ADC_LTR 和 ADC_HTR 设置。例如我们设置高阈值是
2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样

三、ADC校验

        ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差,建议在每次上电后执行一次校准启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

四、电压转换

模拟电压经过 ADC 转换后,是一个 12 位的数字值,如果通过串口以 16 进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。

我们一般在设计原理图的时候会把 ADC 的输入电压范围设定在: 0~3.3v,因为 ADC 是 12 位的,那么 12 位满量程对应的就是 3.3V, 12 位满量程对应的数字值是: 2^12。数值 0 对应的就是 0V。如果转换后的数值为 X , X 对应的模拟电压为 Y,那么会有这么一个等式成立: 2^12 / 3.3 = X/Y, => Y = (3.3 * X ) / 2^12。
 

五、ADC单通道采集-中断读取

ADC.H

#ifndef __ADC_H
#define __ADC_H


extern uint16_t Get_ADC_Value;

//GPIO_ADC
#define   RCC_GPIO_CLK      RCC_APB2Periph_GPIOA
#define   GPIO_X            GPIOA
#define   GPIO_ADC_PEAD     GPIO_Pin_1
//ADC
#define   RCC_ADC_CLK       RCC_APB2Periph_ADC1
#define   ADC_X             ADC1


void ADC_Init_Config(void);

#endif

ADC.C

#include "stm32f10x.h"     
#include "adc.h"  

uint16_t Get_ADC_Value;


static void ADCx_GPIO_Config(void)//ADC引脚初始化
{
    RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
   
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
    GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD;
    GPIO_Init(GPIO_X,&GPIO_InitStructure);
}

static void ADCx_Mode_Config(void)//ADC工作模式配置
{
   RCC_APB2PeriphClockCmd(RCC_ADC_CLK,ENABLE);
   
   
   ADC_InitTypeDef ADC_InitStructure;
   ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC模式为独立模式
   ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
   ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
   ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
   ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
   ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
   ADC_Init(ADC_X,&ADC_InitStructure);
   
   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
   
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间
   
   ADC_ITConfig(ADC_X,ADC_IT_EOC,ENABLE);//(开始ADC中断)指定ADC,指定中断源为规则通道,
   
   ADC_Cmd(ADC_X,ENABLE);//开启ADC
   
   ADC_ResetCalibration(ADC_X);//初始化ADC校验
   
   //****************ADC校准*********************
   while(ADC_GetResetCalibrationStatus(ADC_X));//等待校准初始化完成
   
   ADC_StartCalibration(ADC_X);//启动指定的ADC校准
   
   while(ADC_GetCalibrationStatus(ADC_X));//等待校准完成
   
   ADC_SoftwareStartConvCmd(ADC_X,ENABLE);//启用指定ADC软件启动转换
   //*******************************************
}


static void NVIC_Config(void)//中断分组
{
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
   
   NVIC_InitTypeDef NVIC_InitStructure;
   NVIC_InitStructure.NVIC_IRQChannel=ADC1_2_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
   NVIC_Init(&NVIC_InitStructure);
}

void ADC_Init_Config(void)//ADC初始化
{
   NVIC_Config();
   
   ADCx_GPIO_Config();
   
   ADCx_Mode_Config();
   
   
}


void ADC1_2_IRQHandler(void)//ADC中断函数
{
  if(ADC_GetITStatus(ADC_X,ADC_IT_EOC)==SET)//判断规则通道标志位是否触发中断
  {
   Get_ADC_Value=ADC_GetConversionValue(ADC_X);//获取ADC采样后的数据
  }
  ADC_ClearITPendingBit(ADC_X,ADC_IT_EOC);//清除规则通道标志位
}

Main.c

#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "serial.h"  
#include "adc.h"  
#include "delay.h"  

float ADC_Num;

int main(void)
{
   
   
   Serial_Init();
   ADC_Init_Config();
   printf("STM32战舰板ADC测试\r\n");
   
   while(1)
	{
      ADC_Num=(float)Get_ADC_Value/4096*3.3;
      printf("ADC数字量的值为0X%4X\r\n",Get_ADC_Value); 
      printf("ADC模拟量的值为%f V\r\n",ADC_Num); 
      
      Delay(0xFFFFEE);
	}
}

六、ADC单通道采集-DMA读取

ADC.H

#ifndef __ADC_H
#define __ADC_H


extern uint16_t Get_ADC_Value;

//GPIO_ADC
#define   RCC_GPIO_CLK    RCC_APB2Periph_GPIOA
#define   GPIO_X          GPIOA
#define   GPIO_ADC_PEAD   GPIO_Pin_1
//ADC
#define   RCC_ADC_CLK     RCC_APB2Periph_ADC1
#define   ADC_X           ADC1
//DMA
#define   RCC_DMA_CLK     RCC_AHBPeriph_DMA1
#define   DMA_X           DMA1_Channel1

void ADC_Init_Config(void);

#endif

ADC.C

#include "stm32f10x.h"     
#include "adc.h"  

uint16_t Get_ADC_Value;

static void ADCx_GPIO_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
   
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
    GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD;
    GPIO_Init(GPIO_X,&GPIO_InitStructure);
}

static void ADCx_Mode_Config(void)
{
   RCC_APB2PeriphClockCmd(RCC_ADC_CLK,ENABLE);//开启指定的ADC时钟
   RCC_AHBPeriphClockCmd(RCC_DMA_CLK,ENABLE);//开启指定的DMA时钟
   
   DMA_InitTypeDef DMA_InitStructure;
   
   DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设存储器地址
   DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设数据的大小
   DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不递增
   DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)&Get_ADC_Value;//内部存储器地址
   DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//内部数据大小
   DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;//内部地址不递增
   DMA_InitStructure.DMA_BufferSize=1;//数据缓冲区大小
   DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设为源地址
   DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//不开启内部存储器到内部存储器模式
   DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作模式为循环模式
   DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道优先级
   DMA_Init(DMA_X,&DMA_InitStructure);
 
   DMA_Cmd(DMA_X,ENABLE);//开启DMA
   
   ADC_InitTypeDef ADC_InitStructure;
   ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC模式为独立模式
   ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
   ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
   ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
   ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
   ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
   ADC_Init(ADC_X,&ADC_InitStructure);
   
   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
   
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间   
    
    ADC_DMACmd(ADC_X,ENABLE);//开启DMA请求
    
   ADC_Cmd(ADC_X,ENABLE);//开启ADC
   
   ADC_ResetCalibration(ADC_X);//初始化ADC校验
   
   while(ADC_GetResetCalibrationStatus(ADC_X));//等待校准初始化完成
   
   ADC_StartCalibration(ADC_X);//启动指定的ADC校准
   
   while(ADC_GetCalibrationStatus(ADC_X));//等待校准完成
   
   ADC_SoftwareStartConvCmd(ADC_X,ENABLE);//启用指定ADC软件启动转换
   
   
}


void ADC_Init_Config(void)//ADC初始化
{

   ADCx_GPIO_Config();
   
   ADCx_Mode_Config();
   
}

Main.c

#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "serial.h"  
#include "adc.h"  
#include "delay.h"  

float ADC_Num;

int main(void)
{
   
   Serial_Init();
   ADC_Init_Config();
   printf("STM32战舰板ADC测试\r\n");
   
   while(1)
	{
      ADC_Num=(float)Get_ADC_Value/4096*3.3;
      printf("ADC数字量的值为%d\r\n",Get_ADC_Value); 
      printf("ADC模拟量的值为%f V\r\n",ADC_Num); 
      
      Delay(0xFFFFEE);
	}
}

七、ADC多通道采集-DMA读取

ADC.H

#ifndef __ADC_H
#define __ADC_H


extern uint16_t Get_ADC_Value[];



//GPIO_ADC
#define   RCC_GPIO_CLK     RCC_APB2Periph_GPIOA
#define   GPIO_X           GPIOA
#define   GPIO_ADC_PEAD1   GPIO_Pin_0
#define   GPIO_ADC_PEAD2   GPIO_Pin_1
#define   GPIO_ADC_PEAD3   GPIO_Pin_2
#define   GPIO_ADC_PEAD4   GPIO_Pin_3
#define   GPIO_ADC_PEAD5   GPIO_Pin_4
#define   GPIO_ADC_PEAD6   GPIO_Pin_5
//ADC
#define   RCC_ADC_CLK     RCC_APB2Periph_ADC1
#define   ADC_X           ADC1
//DMA
#define   RCC_DMA_CLK     RCC_AHBPeriph_DMA1
#define   DMA_X           DMA1_Channel1


#define SIZE 6

void ADC_Init_Config(void);

#endif

ADC.C

#include "stm32f10x.h"     
#include "adc.h"  



uint16_t Get_ADC_Value[SIZE];

static void ADCx_GPIO_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
   
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
    GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD6 | GPIO_ADC_PEAD1 | GPIO_ADC_PEAD2 | GPIO_ADC_PEAD3 | GPIO_ADC_PEAD4 | GPIO_ADC_PEAD5;
    GPIO_Init(GPIO_X,&GPIO_InitStructure);
}

static void ADCx_Mode_Config(void)
{
   RCC_APB2PeriphClockCmd(RCC_ADC_CLK,ENABLE);
   RCC_AHBPeriphClockCmd(RCC_DMA_CLK,ENABLE);
   
   DMA_InitTypeDef DMA_InitStructure;
   
   DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设存储器地址
   DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设数据的大小
   DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不递增
   DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)Get_ADC_Value;//内部存储器地址
   DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//内部数据大小
   DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内部地址递增
   DMA_InitStructure.DMA_BufferSize=SIZE;//数据缓冲区大小
   DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设为源地址
   DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//不开启内部存储器到内部存储器模式
   DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作模式为循环模式
   DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道优先级
   DMA_Init(DMA_X,&DMA_InitStructure);
 
   DMA_Cmd(DMA_X,ENABLE);//开启DMA
   
   ADC_InitTypeDef ADC_InitStructure;
   ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC模式为独立模式
   ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
   ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
   ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
   ADC_InitStructure.ADC_NbrOfChannel=6;//配置采集ADC通道数为6
   ADC_InitStructure.ADC_ScanConvMode=ENABLE;//配置为单通道
   ADC_Init(ADC_X,&ADC_InitStructure);
   
   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
   
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间   
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); 
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_4,5,ADC_SampleTime_55Cycles5);
   ADC_RegularChannelConfig(ADC_X,ADC_Channel_6,6,ADC_SampleTime_55Cycles5);
   
   

    ADC_DMACmd(ADC_X,ENABLE);//开启DMA请求
    
   ADC_Cmd(ADC_X,ENABLE);//开启ADC
   
   ADC_ResetCalibration(ADC_X);//初始化ADC校验
   
   while(ADC_GetResetCalibrationStatus(ADC_X));//等待校准初始化完成
   
   ADC_StartCalibration(ADC_X);//启动指定的ADC校准
   
   while(ADC_GetCalibrationStatus(ADC_X));//等待校准完成
   
   ADC_SoftwareStartConvCmd(ADC_X,ENABLE);//启用指定ADC软件启动转换
   
   
}


void ADC_Init_Config(void)
{

   ADCx_GPIO_Config();
   
   ADCx_Mode_Config();
   
   
}

Main.c

#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "serial.h"  
#include "adc.h"  
#include "delay.h"  



float ADC_Num[6];

int main(void)
{
   
   Serial_Init();
   ADC_Init_Config();
   printf("STM32战舰板ADC测试\r\n");
   
   while(1)
	{
      ADC_Num[0]=(float)Get_ADC_Value[0]/4096*3.3;
	  ADC_Num[1]=(float)Get_ADC_Value[1]/4096*3.3;
      ADC_Num[2]=(float)Get_ADC_Value[2]/4096*3.3;
      ADC_Num[3]=(float)Get_ADC_Value[3]/4096*3.3;
      ADC_Num[4]=(float)Get_ADC_Value[4]/4096*3.3;
      ADC_Num[5]=(float)Get_ADC_Value[5]/4096*3.3;		
		

//      printf("ADC1数字量的值为%d\r\n",Get_ADC_Value[0]); 
      printf("ADC1模拟量的值为%f V\r\n",ADC_Num[0]); 
      
//      printf("ADC2数字量的值为%d\r\n",Get_ADC_Value[1]); 
      printf("ADC2模拟量的值为%f V\r\n",ADC_Num[1]); 
		
//      printf("ADC3数字量的值为%d\r\n",Get_ADC_Value[2]); 
      printf("ADC3模拟量的值为%f V\r\n",ADC_Num[2]); 
		
//	  printf("ADC4数字量的值为%d\r\n",Get_ADC_Value[3]); 
      printf("ADC4模拟量的值为%f V\r\n",ADC_Num[3]); 
		
//	  printf("ADC5数字量的值为%d\r\n",Get_ADC_Value[4]); 
      printf("ADC5模拟量的值为%f V\r\n",ADC_Num[4]); 
	  
//	  printf("ADC6数字量的值为%d\r\n",Get_ADC_Value[5]); 
      printf("ADC6模拟量的值为%f V\r\n",ADC_Num[5]); 
		
		
      Delay(0xFFFFEE);
	}
}

八、双ADC采集(规则同步模式)-DMA读取

ADC.H

#ifndef __ADC_H
#define __ADC_H

#define SIZE  2

extern uint32_t Get_ADC_Value[SIZE];




//GPIO_ADC
#define   RCC_GPIO_CLK    RCC_APB2Periph_GPIOA
#define   GPIO_X          GPIOA
#define   GPIO_ADC_PEAD1   GPIO_Pin_1
#define   GPIO_ADC_PEAD2   GPIO_Pin_4

//ADC
#define   RCC_ADC1_CLK     RCC_APB2Periph_ADC1
#define   ADCX_1           ADC1
#define   RCC_ADC2_CLK     RCC_APB2Periph_ADC2
#define   ADCX_2           ADC2
#define   ADC1_PassageX    ADC_Channel_1
#define   ADC2_PassageX    ADC_Channel_4

//DMA
#define   RCC_DMA_CLK     RCC_AHBPeriph_DMA1
#define   DMA_X           DMA1_Channel1




void ADC_Init_Config(void);

#endif

ADC.C

#include "stm32f10x.h"     
#include "adc.h"  

uint32_t Get_ADC_Value[SIZE];

static void ADCx_GPIO_Config(void)
{
    RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
   
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
    GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD1 | GPIO_ADC_PEAD2;
    GPIO_Init(GPIO_X,&GPIO_InitStructure);
}

static void ADCx_Mode_Config(void)
{
   RCC_APB2PeriphClockCmd(RCC_ADC1_CLK | RCC_ADC2_CLK,ENABLE);
   RCC_AHBPeriphClockCmd(RCC_DMA_CLK,ENABLE);
   
   DMA_InitTypeDef DMA_InitStructure;
   
   DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设存储器地址
   DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;//外设数据的大小
   DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不递增
   DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)Get_ADC_Value;//内部存储器地址
   DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;//内部数据大小
   DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;//内部地址不递增
   DMA_InitStructure.DMA_BufferSize=SIZE;//数据缓冲区大小
   DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设为源地址
   DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//不开启内部存储器到内部存储器模式
   DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作模式为循环模式
   DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道优先级
   DMA_Init(DMA_X,&DMA_InitStructure);
 
   DMA_Cmd(DMA_X,ENABLE);//开启DMA
   
   
   //**********ADC1的工作模式配置************
   
   ADC_InitTypeDef ADC_InitStructure;
   ADC_InitStructure.ADC_Mode=ADC_Mode_RegSimult;//配置ADC模式为双ADC规则同步模式
   ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
   ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
   ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
   ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
   ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
   ADC_Init(ADCX_1,&ADC_InitStructure);
   
   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
   //(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间   
   ADC_RegularChannelConfig(ADCX_1,ADC1_PassageX,1,ADC_SampleTime_55Cycles5);
    
   ADC_DMACmd(ADCX_1,ENABLE);//开启DMA请求
    
   ADC_Cmd(ADCX_1,ENABLE);//开启ADC
   
   //****************************************************
   
    //**********ADC2的工作模式配置************
   
   ADC_InitStructure.ADC_Mode=ADC_Mode_RegSimult;//配置ADC模式为双ADC规则同步模式
   ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
   ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
   ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
   ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
   ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
   ADC_Init(ADCX_2,&ADC_InitStructure);
   
//   RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
   
   ADC_RegularChannelConfig(ADCX_2,ADC2_PassageX,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间   
       
   ADC_Cmd(ADCX_2,ENABLE);//开启ADC
   
   //****************************************************
    ADC_ExternalTrigConvCmd(ADCX_2,ENABLE);//ADC2使用外部触发采样
   
  //************ADC1校验********************
  
   ADC_ResetCalibration(ADCX_1);//初始化ADC校验
   
   while(ADC_GetResetCalibrationStatus(ADCX_1));//等待校准初始化完成
   
   ADC_StartCalibration(ADCX_1);//启动指定的ADC校准
   
   while(ADC_GetCalibrationStatus(ADCX_1));//等待校准完成
   
   ADC_SoftwareStartConvCmd(ADCX_1,ENABLE);//ADC1启用软件启动转换
   
  //**************************************************
  
  
    //************ADC2校验********************
  
   ADC_ResetCalibration(ADCX_2);//初始化ADC校验
   
   while(ADC_GetResetCalibrationStatus(ADCX_2));//等待校准初始化完成
   
   ADC_StartCalibration(ADCX_2);//启动指定的ADC校准
   
   while(ADC_GetCalibrationStatus(ADCX_2));//等待校准完成
   
  
   
  //**************************************************
   
}


void ADC_Init_Config(void)
{

   ADCx_GPIO_Config();
   
   ADCx_Mode_Config();
    
}

Main.c

#include "stm32f10x.h"                  // Device header
#include "led.h"   
#include "serial.h"  
#include "adc.h"  
#include "delay.h"  

float ADC1_Num;
float ADC2_Num;

int main(void)
{
   
   Serial_Init();
   ADC_Init_Config();
   printf("STM32战舰板ADC测试\r\n");
   

   while(1)
	{
      
      ADC1_Num=(float) ((Get_ADC_Value[0] & 0xFFFF0000)>>16)/4096*3.3;
      printf("ADC数字量的值为%d\r\n",Get_ADC_Value[0]>>16); 
      printf("ADC模拟量的值为%f V\r\n",ADC1_Num); 
      ADC2_Num=(float) ((Get_ADC_Value[0] & 0x0000FFFF))/4096*3.3;
      printf("ADC数字量的值为%d\r\n",(Get_ADC_Value[0] & 0x0000FFFF)); 
      printf("ADC模拟量的值为%f V\r\n",ADC2_Num); 
      Delay(0xFFFFEE);
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 《STM32自学笔记第3版》是一本关于STM32微控制器的自学教程。该书深入介绍了STM32微控制器的原理、应用和编程方法。 本书第3版增加了最新的STM32系列微控制器的内容,包括了更多实际应用的案例和项目。读者通过该书可以学习到如何使用STM32微控制器进行各种应用开发,如控制系统、嵌入式系统、通讯系统等。 本书首先对STM32微控制器的硬件结构进行了详细的介绍,包括了芯片的内部结构、引脚的功能和特性。然后,通过具体的实验项目,教授了STM32的基本编程方法和技巧。读者可以通过这些实验,了解STM32的各种功能模块的使用方法,如ADC、USART、SPI等。同时,还介绍了如何使用STM32CubeMX和Keil MDK等常用的开发工具进行项目开发。 此外,本书还对STM32的外设扩展进行了介绍,如通过I2C总线连接外部设备,通过CAN总线实现通讯等。读者可以学习到如何通过外设扩展,实现更复杂的应用系统。 总的来说,《STM32自学笔记第3版》是一本系统、全面的STM32自学教程。通过学习该书,读者可以深入了解STM32微控制器,并掌握其在各种应用领域的开发方法。无论是初学者还是有一定STM32开发经验的人都可以从中获益。 ### 回答2: 《STM32自学笔记 第3版》是一本适合自学STM32开发板的参考书籍。本书以STM32微控制器为基础,详细介绍了STM32的硬件结构和软件开发环境。作者结合自身经验和实际案例,将复杂的知识点以简洁明了的方式呈现,使读者能够快速入门。 第3版的内容相比前两版有所扩充和更新。首先,在硬件方面,本书详细介绍了STM32引脚布局和外设接口,包括GPIO、USART、I2C、SPI等,使读者能够充分了解STM32的基本硬件结构和功能。 其次,在软件方面,本书提供了详细的开发环境配置和编程指南。包括了Keil MDK开发环境的安装和使用、编译、调试和下载等操作步骤,并且给出了一些常见问题的解决方法。同时,作者还介绍了如何使用STM32的标准外设库进行编程,包括GPIO控制、中断处理、定时器、串口通信等。 除此之外,本书还介绍了一些实际应用案例,以帮助读者更好地理解和应用所学知识。例如,如何使用STM32控制LED灯、驱动液晶显示屏、读取温度传感器数据等。 总体而言,本书是一本系统全面的STM32自学教程。通过学习本书,读者可以了解STM32的基本原理和应用,掌握STM32的硬件配置和软件开发,从而能够独立完成STM32的项目开发。无论是初学者还是有一定基础的开发者都可以从本书中获得很大的收益。 ### 回答3: 《STM32自学笔记第3版》是一本专门介绍如何自学STM32开发的书籍。本书主要针对初学者,通过详细的讲解和实践项目的演示,帮助读者快速上手STM32开发。 书中首先介绍了STM32系列微控制器的基本知识,包括硬件架构、外设功能和寄存器的使用等。对于没有接触过STM32的读者来说,这一部分对于理解后面的内容非常重要。 接着,书中从简单的LED控制开始,逐步引导读者学习各种外设的使用,如GPIO、定时器、UART等。同时,每个外设的使用都配有具体的实例代码和详细的注解,方便读者理解和实践。 书中还介绍了STM32开发中常用的开发工具和环境配置方法。从芯片选择、开发板选购到软件安装和项目配置,都有详细的指导。同时,书中还提供了一些调试技巧和常见问题的解答,帮助读者避开一些容易遇到的坑。 最后,书中还介绍了一些常用的外设应用案例,如按键控制、LCD显示、温湿度传感器等。通过这些案例,读者可以更好地理解STM32的应用场景和开发思路,提升自己的技能水平。 总的来说,《STM32自学笔记第3版》是一本适合学习STM32开发的入门书籍。通过系统完整的内容和实例演示,读者可以快速掌握STM32的基本知识和开发技巧。无论是初学者还是有一定经验的开发者,都可以从中获得实际的帮助和启示。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值