Stm32 第四十四~四十五讲:ADC
STM32F10x ADC特点
- 12位逐次逼近型的模拟数字转换器;
- 最多带3个ADC控制器;
- 最多支持18个通道,可最多测量16个外部和2个内部信号源;
- 支持单次和连续转换模式;
- 转换结束、注入转换结束和发生模拟看门狗事件时产生中断;
- 通道0到通道n的自动扫描模式;
- 自动校准;
- 采样间隔可以按通道编程;
- 规则通道和注入通道均有外部触发选项;
- 转换结果支持左对齐或右对齐方式存储在16位数据寄存器;
- ADC转换时间:最大转换速率1us。(最大转换速度为1MHz,在ADCCLK=14M,采样周期为1.5个ADC时钟下得到)
- ADC供电要求:2.4V~3.6V;
- ADC输入范围:VREF-≤VIN≤VREF+。
ADC引脚
ADC框图
ADC通道组
①. 规则通道组:相当正常运行的程序。最多16个通道。
规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中。
②. 注入通道组:相当于中断,最多4个通道。
注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中。
单次转换&连续转换
扫描模式
ADC中断
ADC时钟配置
RCC_ADCCLKConfig();
不要让ADC时钟超过14MHz,否则可能不准。
ADC相关寄存器
ADC_CR1寄存器
ADC_CR2寄存器
ADC_SMPR1寄存器
ADC_SMPR2寄存器
ADC的采样时间
最小采样时间1us(ADC时钟=14MHz,采样周期为1.5周期下得到
ADC_SQR1/2/3规则序列寄存器
ADC_JSQR注入序列寄存器
ADC_DR规则通道数据寄存器
ADC_JDR规则通道数据寄存器
ADC_SR状态寄存器
ADC常用库函数
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_DeInit(ADC_TypeDef* ADCx)
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
ADC初始化函数
void ADC_Init(ADC_TypeDef ADCx, ADC_InitTypeDef ADC_InitStruct);
typedef struct
{
uint32_t ADC_Mode;//ADC模式:配置ADC_CR1寄存器的位[19:16]:DUALMODE[3:0]位
FunctionalState ADC_ScanConvMode; //是否使用扫描模式。ADC_CR1位8:SCAN位
FunctionalState ADC_ContinuousConvMode; //单次转换or连续转换:ADC_CR2的位1:CONT
uint32_t ADC_ExternalTrigConv; //触发方式:ADC_CR2的位[19:17] :EXTSEL[2:0]
uint32_t ADC_DataAlign; //对齐方式:左对齐还是右对齐:ADC_CR2的位11:ALIGN
uint8_t ADC_NbrOfChannel;//规则通道序列长度:ADC_SQR1的位[23:20]: L[3:0]
}ADC_InitTypeDef;
例如:
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE; //不开启扫描
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;//顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure);
ADC使能函数
void ADC_Cmd(ADC_TypeDef ADCx, FunctionalState NewState);
例如:
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC使能软件转换函数
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
例如:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能ADC1的软件转换启动
ADC规则通道配置函数
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
例如:
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1,ADC_SampleTime_239Cycles5);
ADC获取转换结果函数
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
例如:
ADC_GetConversionValue(ADC1);//获取ADC1转换结果
ADC模数转换实验
实验目的:ADC1的通道1(PA1)进行单次转化
转换过程
①. 开启PA口时钟和ADC1时钟,设置PA1为模拟输入;
GPIO_Init();
APB2PeriphClockCmd();
②. 复位ADC1,同时设置ADC1分频因子;
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_DeInit(ADC1);
③. 初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息;
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
④. 使能ADC并校准;
ADC_Cmd(ADC1, ENABLE);
⑤. 配置规则通道参数;
ADC_RegularChannelConfig();
⑥. 开启软件转换;
ADC_SoftwareStartConvCmd(ADC1);
⑦. 等待转换完成,读取ADC值。
ADC_GetConversionValue(ADC1);
程序代码
在这里只给出adc.h、adc.c和main.c的代码。
adc.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
#endif
adc.c
#include "adc.h"
#include "delay.h"
//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1,ENABLE ); //使能ADC1通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
//PA1 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
}
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
//设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
main.c
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "adc.h"
int main(void)
{
u16 adcx;
float temp;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
LCD_Init();
Adc_Init(); //ADC初始化
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,200,16,16,"WarShip STM32");
LCD_ShowString(60,70,200,16,16,"ADC TEST");
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2015/1/14");
//显示提示信息
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(60,130,200,16,16,"ADC_CH0_VAL:");
LCD_ShowString(60,150,200,16,16,"ADC_CH0_VOL:0.000V");
while(1)
{
adcx=Get_Adc_Average(ADC_Channel_1,10);
LCD_ShowxNum(156,130,adcx,4,16,0);//显示ADC的值
temp=(float)adcx*(3.3/4096);
adcx=temp;
LCD_ShowxNum(156,150,adcx,1,16,0);//显示电压值
temp-=adcx;
temp*=1000;
LCD_ShowxNum(172,150,temp,3,16,0X80);
LED0=!LED0;
delay_ms(250);
}
}