STM32-ADC


图片均来自江科大STM32教学PPT

ADC

简介

  • ADC(Analog-Digital Converter)模拟-数字转换器
  • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
  • 12位逐次逼近型ADC,1us转换时间
  • 输入电压范围:0~3.3V,转换结果范围:0~4095
  • 18个输入通道,可测量16个外部和2个内部信号源
  • 规则组和注入组两个转换单元
  • 模拟看门狗自动监测输入电压范围

STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

ADC框图

规则组通道:一次性转换16个通道,但是数据寄存器只能保存一个,所以要及时把数据读走,就可以利用DMA。
注入组通道:一次性转换四个通道,数据寄存器也可以存四个数据。
在这里插入图片描述

ADC基本结构

在这里插入图片描述

ADC输入通道

在这里插入图片描述

转换模式

单次转换,非扫描模式
在非扫描模式下,只有序列一有效,就变成了选中单一一个的情况,转换完成后置EOC为1,下一次再转换就需要再次触发。
在这里插入图片描述

连续转换,非扫描模式
在一次转换后,可以接着下一次转换
在这里插入图片描述

单次转换,扫描模式
可以依次转换多个通道,转换结果放到数据寄存器里,防止数据被覆盖,就需要用到DMA。
在这里插入图片描述

连续转换,扫描模式
多个通道加连续转换。
在这里插入图片描述

转换时间

  • AD转换的步骤:采样,保持,量化,编码
  • STM32 ADC的总转换时间为:
    TCONV = 采样时间 + 12.5个ADC周期
  • 例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期
    TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs

校准

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

代码示例

#include "stm32f10x.h"                  // Device header


void AD_Init(void)
{
    //	1.开启RCC时钟。包括ADC和GPIO的时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);	//	ADCCLK=72MHz/6=12MHz

    //	2.配置GPIO,把需要用的GPIO配置成模拟输入的模式
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;	//	ADC专属模式
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);


    //	3.配置这里的多路开关。把左边的通道接入到右边的规则组列表里
    ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);

    //	4.配置ADC转换器
    ADC_InitTypeDef ADC_InitStruct;
    ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;		//	ADC工作模式
    ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
    ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;		//	触发源:软件触发
    ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;		//	单次转换
    ADC_InitStruct.ADC_ScanConvMode=DISABLE;			//	非扫描模式
    ADC_InitStruct.ADC_NbrOfChannel=1;
    ADC_Init(ADC1,&ADC_InitStruct);

    //	5.启动ADC
    ADC_Cmd(ADC1,ENABLE);

    //	6.对ADC进行校准
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1)==SET);
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1)==SET);
}

uint16_t AD_GetValue(void)
{
    //	软件触发转换
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);
    while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
    return ADC_GetConversionValue(ADC1);
}

DMA

简介

  • DMA(Direct Memory Access)直接存储器存取
  • DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
  • 12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
  • 每个通道都支持软件触发和特定的硬件触发

STM32F103C8T6 DMA资源:DMA1(7个通道)

STM32存储器映像

在这里插入图片描述

DMA框图

在这里插入图片描述

DMA基本结构

在这里插入图片描述

代码示例

#include "stm32f10x.h"                  // Device header

uint16_t MyDMA_Size;

void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
    MyDMA_Size=Size;
    //	1.RCC开启DMA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    //	2.初始化DMA参数
    DMA_InitTypeDef DMA_InitStruct;
    //	外设站点配置
    DMA_InitStruct.DMA_PeripheralBaseAddr=AddrA;		//外设站点基地址 32位
    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
    DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Enable;
    //	存储器站点配置
    DMA_InitStruct.DMA_MemoryBaseAddr=AddrB;
    DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
    //	传输方向配置
    DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
    //	传输次数配置
    DMA_InitStruct.DMA_BufferSize=Size;
    //	传输计数器配置
    DMA_InitStruct.DMA_Mode=DMA_Mode_Normal;

    DMA_InitStruct.DMA_M2M=DMA_M2M_Enable;
    DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;	//中等优先级
    DMA_Init(DMA1_Channel1,&DMA_InitStruct);
    //	3.开启DMA
    DMA_Cmd(DMA1_Channel1,DISABLE);
}

//	启动DMA转运
void MyDMA_Trandfer(void)
{
    //	先失能
    DMA_Cmd(DMA1_Channel1,DISABLE);
    DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size);
    DMA_Cmd(DMA1_Channel1,ENABLE);
    //	等待转运完成,标志位置1
    while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
    DMA_ClearFlag(DMA1_FLAG_TC1);
}

DMA循环转运+ADC连续扫描

#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4];

void AD_Init(void)
{
    //	1.开启RCC时钟。包括ADC和GPIO的时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);	//	ADCCLK=72MHz/6=12MHz

    //	2.配置GPIO,把需要用的GPIO配置成模拟输入的模式
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;	//	ADC专属模式
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //	3. 配置这里的多路开关。把左边的通道接入到右边的规则组列表里

    ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);


    //	4.配置ADC转换器
    ADC_InitTypeDef ADC_InitStruct;
    ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;						//	ADC工作模式
    ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
    ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;		//	触发源:软件触发
    ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;						//	单次转换
    ADC_InitStruct.ADC_ScanConvMode=ENABLE;								//	非扫描模式
    ADC_InitStruct.ADC_NbrOfChannel=4;
    ADC_Init(ADC1,&ADC_InitStruct);



    //	2.初始化DMA参数
    DMA_InitTypeDef DMA_InitStruct;
    //	外设站点配置
    DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;			//外设站点基地址 32位
    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
    //	存储器站点配置
    DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)AD_Value;
    DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;
    //	传输方向配置
    DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;
    //	传输次数配置
    DMA_InitStruct.DMA_BufferSize=4;
    //	传输计数器配置
    DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;							//	打开DMA循环模式

    DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;
    DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;					//中等优先级
    DMA_Init(DMA1_Channel1,&DMA_InitStruct);
    //	3.开启DMA
    DMA_Cmd(DMA1_Channel1,ENABLE);

    ADC_DMACmd(ADC1,ENABLE);
    //	5.启动ADC
    ADC_Cmd(ADC1,ENABLE);

    //	6.对ADC进行校准
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1)==SET);
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1)==SET);

    //	ADC软件触发
    ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值