一、ADC是什么?
ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。那么就有人要问了,什么是模拟信号,什么是数字信号。
模拟信号:指的是连续变化的物理量,如温度,压力,湿度。而数字信号可以简单的理解为0和1两种状态。
12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中
二、ADC的基本使用
1.ADC的主要特征
●12位分辨率 //0-4095
● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断 //转换完成注入结束发生中断
● 单次和连续转换模式 //常用连续转换模式
● 从通道0到通道n的自动扫描模式 //多通道扫描模式
● 自校准 //自动校准函数
● 带内嵌数据一致性的数据对齐 //左对齐或右对齐,常用右对齐
● 采样间隔可以按通道分别编程 //多通道
● 规则转换和注入转换均有外部触发选项 //外部触发模式
● 间断模式
● 双重模式(带2个或以上ADC的器件) //ADC1,ADC2,ADC3
● ADC转换时间: ─ STM32F103xx增强型产品:时钟为56MHz时为1μs(时钟为72MHz为1.17μs) ─ STM32F101xx基本型产品:时钟为28MHz时为1μs(时钟为36MHz为1.55μs) ─ STM32F102xxUSB型产品:时钟为48MHz时为1.2μs ─ STM32F105xx和STM32F107xx 产 品:时钟为56MHz时为1μs(时钟为72MHz为1.17μs)
● ADC供电要求:2.4V到3.6V
● ADC输入范围:VREF- ≤ VIN ≤ VREF+ // 0~3.3V
● 规则通道转换期间有DMA请求产生 //DMA搬用,不占用CPU资源
2.功能框图
1.ADC供电
2.18通道,包含16个外部通道和两个内部通道(温度传感器,和电压)
3.模拟至数字转换器,规则通道和注入通道,常用规则通道,注入通道理解为插入通道。
4.规则通道数据寄存器,单ADC模式下,低16位有效,双ADC模式下高低16位有效
注入双通道数据寄存器,低16位有效。
5.中断控制器,转换结束,根据EOC标志位,使能中断,注入转换结束标志位JEOC,模拟看门狗事件
3.寄存器
ADC_SR->EOC EOC:转换结束位 (End of conversion) 0转换未完成,1转换完成
ADC_CR1->DOALMOD 双模式选择 (Dual mode selection)
0000:独立模式
0001:混合的同步规则+注入同步模式
0010:混合的同步规则+交替触发模式
0011:混合同步注入+快速交叉模式
0100:混合同步注入+慢速交叉模式
0101:注入同步模式
0110:规则同步模式
0111:快速交叉模式
1000:慢速交叉模式
1001:交替触发模式
ADC_CR1->SCAN 扫描模式 (Scan mode),0关闭扫描模式,1开启扫描模式
ADC_CR1->EOCIE 允许产生EOC中断 (Interrupt enable for EOC)
ADC_CR2->SWSTART 开始转换规则通道 (Start conversion of regular channels)
ADC_CR2->ALIGN 数据对齐 (Data alignment)
ADC_CR2->DMA 直接存储器访问模式 (Direct memory access mode)
ADC_CR2->CONT 连续转换 (Continuous conversion)
ADC_CR2->ADON 开/关A/D转换器 (A/D converter ON / OFF)
ADC_DR->DATA[15:0] 规则转换的数据 (Regular data)/ADC2DATA[15:0]:ADC2转换的数据 (ADC2 data
4.常用模式
1.独立模式,单ADC工作。
2.同步规则模式,双ADC同时工作,并且在ADC1产生DMA请求,将ADC_DR寄存器中的32位数据同时进行DMA传输。
3.快速交叉模式,双ADC工作通常为1个通道,ADC2立即启动并且 ●ADC1在延迟7个ADC时钟周期后启动。
5.代码
独立模式+dma
#include "adc.h"
#include "uart.h"
__IO uint16_t ADC_ConvertedValue;
void ADC_dma_init(void)
{
//2.init dma struct
DMA_InitTypeDef DMA_Initstructrue;
//1.使能DMA外设时钟,open rcc.h
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
DMA_Initstructrue.DMA_PeripheralBaseAddr = (uint32_t) ADC1_DR;//外设基地址ADC1_DR寄存器
DMA_Initstructrue.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; //存储器地址
DMA_Initstructrue.DMA_DIR =DMA_DIR_PeripheralSRC; //外设作为源
DMA_Initstructrue.DMA_BufferSize=1; // 数据长度
DMA_Initstructrue.DMA_PeripheralInc =DMA_PeripheralInc_Disable; //数据移位不使能
DMA_Initstructrue.DMA_MemoryInc =DMA_MemoryInc_Disable; //存储器移位不使能
DMA_Initstructrue.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord; //半字16位传输
DMA_Initstructrue.DMA_Priority =DMA_Priority_High ; //优先级高
DMA_Initstructrue.DMA_MemoryDataSize =DMA_MemoryDataSize_HalfWord;
DMA_Initstructrue.DMA_Mode =DMA_Mode_Circular; //循环传输
DMA_Initstructrue.DMA_M2M =DMA_M2M_Disable; //存储器到存储器不使能
DMA_Init(DMA1_Channel1, &DMA_Initstructrue);
DMA_Cmd(DMA1_Channel1, ENABLE); // DMA使能
}
// void ADC_NVIC_config(void)
//{
// NVIC_InitTypeDef nvic_initsturct;
//
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //
// nvic_initsturct.NVIC_IRQChannel=ADC1_2_IRQn;
// nvic_initsturct.NVIC_IRQChannelPreemptionPriority=1;
// nvic_initsturct.NVIC_IRQChannelSubPriority=1;
// nvic_initsturct.NVIC_IRQChannelCmd=ENABLE;
// NVIC_Init(&nvic_initsturct);
//}
void adc_config(void)
{
//1.init gpio a init
ADC_InitTypeDef adc_initsturct;
GPIO_InitTypeDef GPIO_initsturct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO_initsturct.GPIO_Mode=GPIO_Mode_AIN;
GPIO_initsturct.GPIO_Pin=GPIO_Pin_1;
GPIO_Init(GPIOA,&GPIO_initsturct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
adc_initsturct.ADC_ContinuousConvMode=ENABLE; //连续转换模式
adc_initsturct.ADC_DataAlign=ADC_DataAlign_Right; //数据右对齐
adc_initsturct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //外部触发关
adc_initsturct.ADC_Mode=ADC_Mode_Independent ; //独立模式
adc_initsturct.ADC_NbrOfChannel=1; //通道数
adc_initsturct.ADC_ScanConvMode=DISABLE; //扫描模式
ADC_Init(ADC1, &adc_initsturct);
//ADC_RCC
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //ADCCLK 8分频
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); //规则通道配置
// ADC_ITConfig(ADC1,ADC_IT_EOC, ENABLE);
ADC_DMACmd(ADC1, ENABLE); //dma请求
// ADC_NVIC_config();
ADC_Cmd(ADC1, ENABLE); //adc1使能
ADC_StartCalibration(ADC1);
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADC1);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC1));
// ADC开始校准
ADC_StartCalibration(ADC1);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC1));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_dma_init();
}
总结
遇到了个坑就是将DMA_PeripheralDataSize_HalfWord和DMA_MemoryDataSize_HalfWord混用后MD5不会报错,导致在数据转换完成后,3.3V电压显示0.2,原因为两者对应的寄存器值表示是不相同的,会导致只能传输1个字节。