ADC 模拟-数字转换器
ADC可以将引脚上连续变换的模拟电压转换成内存中存储的数字变量,建立模拟电路到数字电路的桥梁
12位逐次逼近型ADC,1us转换时间
输入电压:0~3.3V,转换结果范围:0~4095
18个输入通道,可测量16个外部(16个GPIO口)和2个内部信号源(内部温度传感器,内部参考电压)
规则组和注入组两个转换单元
模拟看门狗自动检测输入电压范围
外部16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路
规则通道:规则通道就是规矩意思,平时一般使用的通道
注入通道:插入,一种不安分的通道,是一种在规则通道转换的时候强行插入要转换的一种,这点和中断很像,只有在规则通道存在的时候才出现
配置时钟,6.3.2时钟配置RCC_CFGF中ADCPRE位
数据寄存器
1.16位有效,用于存放独立模式转换完成数据
2.ADC_CR2,ALIGN
3.高16位是双ADC模式
江科大回顾
ADC:模拟-数字转换器
12位逐次逼近 ADC,1us转换时间=1MHz
输入电压范围0~3.3V,转换结果范围:0~4095
18个输入通道
规则组和注入组两个转换单元
16个通道对应的GPIO口
typedef struct
{
uint32_t ADC_Mode; /*ADC工作模式*/
FunctionalState ADC_ScanConvMode; /*ADC扫描(多通道)或者单次(单通道)模式选择*/
FunctionalState ADC_ContinuousConvMode; /*ADC单次转换或连续转换选择*/
uint32_t ADC_ExternalTrigConv; /*外部触发转换*/
uint32_t ADC_DataAlign; /*数据寄存器对齐格式*/
uint8_t ADC_NbrOfChannel; /*ADC采集通道数 */
}ADC_InitTypeDef;
// ADC 模式配置
// 只使用一个ADC,属于独立模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;// 禁止扫描模式,多通道才要,单通道不需要
ADC_InitStructure.ADC_ScanConvMode = DISABLE ;// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// 转换通道1个
ADC_InitStructure.ADC_NbrOfChannel = 1;
几个常见的固件库函数
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
配置ADC时钟为PCLK2的8分频,即9MHz,设置采样时间
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
// 配置 ADC 通道转换顺序和采样时间
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
//软件触发
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
//外部触发
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
一.独立模式-单通道-中断读取
1. 初始化ADC用到的GPIO
2.初始化ADC初始化结构体
3.配置ADC时钟,配置通道的转换顺序和采样时间
4.使能ADC转换完成中断,配置中断优先级
5.使能ADC,准备开始转换
6.校准ADC
7.软件触发ADC,真正转换开始
8.编写中断服务函数,读取ADC转换数据
9.编写main函数,把转换数据打印出来
#include "bsp_adc.h"
__IO uint16_t ADC_ConvertedValue;
/**
* @brief ADC GPIO 初始化
* @param 无
* @retval 无
*/
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开 ADC IO端口时钟
ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );
// 配置 ADC IO 引脚模式
// 必须为模拟输入
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// 初始化 ADC IO
GPIO_Init(ADC_PORT, &GPIO_InitStructure);
}
/**
* @brief 配置ADC工作模式
* @param 无
* @retval 无
*/
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
// 打开ADC时钟
ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
// ADC 模式配置
// 只使用一个ADC,属于独立模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 禁止扫描模式,多通道才要,单通道不需要
ADC_InitStructure.ADC_ScanConvMode = DISABLE ;
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 转换通道1个
ADC_InitStructure.ADC_NbrOfChannel = 1;
// 初始化ADC
ADC_Init(ADCx, &ADC_InitStructure);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1,
ADC_SampleTime_55Cycles5);
// ADC 转换结束产生中断,在中断服务程序中读取转换值
ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
// 开启ADC ,并开始转换
ADC_Cmd(ADCx, ENABLE);
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADCx);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADCx));
// ADC开始校准
ADC_StartCalibration(ADCx);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADCx));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}
static void ADC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief ADC初始化
* @param 无
* @retval 无
*/
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
ADC_NVIC_Config();
}
/*********************************************END OF FILE**********************/
#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h"
// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADCx ADC2
#define ADC_CLK RCC_APB2Periph_ADC2
// ADC GPIO宏定义
// 注意:用作ADC采集的IO必须没有复用,否则采集电压会有影响
#define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
// ADC 通道宏定义
#define ADC_CHANNEL ADC_Channel_10
// ADC 中断相关宏定义
#define ADC_IRQ ADC1_2_IRQn
#define ADC_IRQHandler ADC1_2_IRQHandler
//#define ADC_IRQ ADC3_IRQn
//#define ADC_IRQHandler ADC3_IRQHandler
void ADCx_Init(void);
#endif /* __ADC_H */
void ADC_IRQHandler(void)
{
if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET)
{
// 读取ADC的转换值
ADC_ConvertedValue = ADC_GetConversionValue(ADCx);
}
ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
}
// ADC 单通道采集,不使用DMA,一般只有ADC2才这样使用,因为ADC2不能使用DMA
#include "stm32f10x.h"
#include "bsp_usart.h"
#include "bsp_adc.h"
extern __IO uint16_t ADC_ConvertedValue;
// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal;
// 软件延时
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
// 配置串口
USART_Config();
// ADC 初始化
ADCx_Init();
printf("\r\n ----这是一个ADC单通道中断读取实验----\r\n");
while (1)
{
ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3;
printf("\r\n The current AD value = 0x%04X \r\n",
ADC_ConvertedValue);
printf("\r\n The current AD value = %f V \r\n",
ADC_ConvertedValueLocal);
printf("\r\n\r\n");
Delay(0xffffee);
}
}
/*********************************************END OF FILE**********************/