文章目录[隐藏]
1.STM32F10xxx微控制器系列产品容量
- 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。
- 中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。
- 大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控制器。
- 互联型产品是指STM32F105xx和STM32F107xx微控制器。
2.ADC介绍
查阅ST官方STM32F10xxx参考手册,12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
3.ADC主要特征
- 12位分辨率
- 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
- 单次和连续转换模式
- 从通道0到通道n的自动扫描模式
- 自校准
- 带内嵌数据一致性的数据对齐
- 采样间隔可以按通道分别编程
- 规则转换和注入转换均有外部触发选项
- 间断模式
- 双重模式(带2个或以上ADC的器件)
- 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+
- 规则通道转换期间有DMA请求产生。
4.规则通道和注入通道的区别
STRT规则通道开始位 (Regular channel Start flag)
JSTRT:注入通道开始位 (Injected channel Start flag)
学习ADC的时候,我一直搞不懂为什么ADC通道要分为规则通道和注入通道?这个规则和注入不仅难记而且拗口,其要表达的意思更是让人不解。查阅英文参考手册知道,英文中的Regular channel被翻译为规则通道,而injected channel被翻译为注入通道。好吧,其实老外的思维和我们真的有点差别,想要表达的意思由于文化和语言的差异,而被生硬翻译为规则和注入两个词,好吧,取个名称只是为了更好的表达和描述一些东西,就像张三李四一样,其应用的意义远大于名字的意义,大可不必太过在意,若实在觉得生硬,就称为Regular 和 injected吧!
在明白了名称的前世今生后,我们再来探讨下其表达的意义,这里引用我认为讲的比较好的网友见解 。原文链接:http://bbs.ednchina.com/BLOG_ARTICLE_225912.HTM
-------------------------------------分割线-------------------------------------------------------
网友见解:
STM32的每个ADC模块通过内部的模拟多路开关,可以切换到不同的输入通道并进行转换。STM32特别地加入了多种成组转换的模式,可以由程序设置好之后,对多个模拟通道自动地进行逐个地采样转换。
有2种划分转换组的方式:规则通道组和注入通道组。通常规则通道组中可以安排最多16个通道,而注入通道组可以安排最多4个通道。
在执行规则通道组扫描转换时,如有其他处理则可启用注入通道组的转换。
一个不太恰当的比喻是:规则通道组的转换好比是程序的正常执行,而注入通道组的转换则好比是程序正常执行之外的一个中断处理程序。
再举一个不一定使用的例子:
假如你在家里的院子内放了5个温度探头,室内放了3个温度探头;你需要时刻监视室外温度即可,但偶尔你想看看室内的温度;因此你可以使用规则通道组循环扫描室外的5个探头并显示AD转换结果,当你想看室内温度时,通过一个按钮启动注入转换组(3个室内探头)并暂时显示室内温度,当你放开这个按钮后,系统又会回到规则通道组继续检测室外温度。
从系统设计上,测量并显示室内温度的过程中断了测量并显示室外温度的过程,但程序设计上可以在初始化阶段分别设置好不同的转换组,系统运行中不必再变更循环转换的配置,从而达到两个任务互不干扰和快速切换的结果。可以设想一下,如果没有规则组和注入组的划分,当你按下按钮后,需要重新配置AD循环扫描的通道,然后在释放按钮后需再次配置AD循环扫描的通道。
上面的例子因为速度较慢,不能完全体现这样区分(规则组和注入组)的好处,但在工业应用领域中有很多检测和监视探头需要较快地处理,这样对AD转换的分组将简化事件处理的程序并提高事件处理的速度。
-------------------------------------分割线-------------------------------------------------------
5.蓝桥杯考察ADC点
CT117E 嵌入式竞赛板(在没有用到扩展版情况下),由CT117Ev1.1电路原理图可知,ADC的采集电压引脚PB0,通过R37电位器来调节分压电路中的电压。
查阅stm32f103rbt6的Datasheet
(1)总体资源分布
(2)ADC资源分布
PC0~PC3
PA0~PA3
PA4~PA7 ; PC4~PC5 ;PB0~PB1(这次选用PB0引脚!)
6.配置ADC模式的理解
(1)我们先从STM32库函数入手,看一下
ADC_InitTypeDef ADC_InitStructure;
typedef struct
{
uint32_t ADC_Mode; /*!< Configures the ADC to operate in independent or
dual mode.
This parameter can be a value of @ref ADC_mode */
FunctionalState ADC_ScanConvMode; /*!< Specifies whether the conversion is performed in
Scan (multichannels) or Single (one channel) mode.
This parameter can be set to ENABLE or DISABLE */
FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in
Continuous or Single mode.
This parameter can be set to ENABLE or DISABLE. */
uint32_t ADC_ExternalTrigConv; /*!< Defines the external trigger used to start the analog
to digital conversion of regular channels. This parameter
can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */
uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment is left or right.
This parameter can be a value of @ref ADC_data_align */
uint8_t ADC_NbrOfChannel; /*!< Specifies the number of ADC channels that will be converted
using the sequencer for regular channel group.
This parameter must range from 1 to 16. */
}ADC_InitTypeDef;
7.配置ADC模板
配置ADC的步骤:
1.配置ADC相关GPIO引脚,如采集电压信号,GPIO引脚配置为模拟输入。
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
2.ADC配置
-
ADC的模式(独立模式,扫描模式,连续转换模式)
ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; /* 连续转换模式---不难理解---就是不停地采集---一次接一次 */
-
使不使用外部触发?(ADC_ExternalTrigConv);触发分为外部触发,比如中断和定时器。软件触发—>用专用函数。
-
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
-
ADC采集的数据对齐方式和转换的通道个数
-
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//采集的数据右对齐---方便计算 ADC_InitStructure.ADC_NbrOfChannel = 1; //总共需要转换的通道个数 ADC_Init(ADC1, &ADC_InitStructure);
-
到ADC_Init(ADC1, &ADC_InitStructure);这一步,我们把前面辛辛苦苦配置的结构体DC_InitStructure给初始化。
错误总结:我把ADC初始化的各种配置给封装成一个函数,这并没有什么问题,但是我给这个函数命名为ADC_Init()出现了错误,因为这个函数名已经用过了,为ADC_Init(ADC1, &ADC_InitStructure);故而改为adc_Init()
/* ADC1 regular channel_8 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
8.程序代码
实现功能:每隔100ms对PB0上的电压进行AD采样并计算电压数值(保留2位小数),显示在LCD的Line1行上
参考博客:https://blog.csdn.net/Zach_z/article/details/80548423
(1)ADC.c文件
/* PB0———ADC_IN8 / TIM3_CH3 */
#include "ADC.h"
void adc_Init()
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOB,ENABLE);
/*配置ADC相应的GPIO,这里配置PB0(ADC_IN8)作为模拟输入------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* ADC1 configuration -----------------------------------------*/
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_InitStructure.ADC_NbrOfChannel = 1; //总共需要转换的通道个数
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel_8 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
u16 get_adc()
{
u16 value;
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
value = ADC_GetConversionValue(ADC1);
return value;
}
(2)main.c文件
#include "stm32f10x.h"
#include "stdio.h"
#include "ADC.h"
void Delay_ms(unsigned int ms)
{
unsigned int i,j;
for(i=0; i<ms; i++)
{
for(j=0; j<8450; j++) ;
}
}
int main()
{
u16 adc_value;
u8 str[20];
STM3210B_LCD_Init();
Delay_ms(100);
LCD_SetTextColor(White);
LCD_SetBackColor(Black);
LCD_ClearLine(Line0);
adc_Init();
while(1)
{
adc_value=get_adc();
sprintf(str," PB0: %.2f V",(float)adc_value/4096*3.3);
LCD_DisplayStringLine(Line1, str);
Delay_ms(100);
}
}
版权声明:本文为CSDN博主「嵌入式历练者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Eterlove/article/details/122619260
1.STM32F10xxx微控制器系列产品容量
- 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。
- 中容量产品是指闪存存储器容量在64K至128K字节之间的STM32F101xx、STM32F102xx和STM32F103xx微控制器。
- 大容量产品是指闪存存储器容量在256K至512K字节之间的STM32F101xx和STM32F103xx微控制器。
- 互联型产品是指STM32F105xx和STM32F107xx微控制器。
2.ADC介绍
查阅ST官方STM32F10xxx参考手册,12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
3.ADC主要特征
- 12位分辨率
- 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
- 单次和连续转换模式
- 从通道0到通道n的自动扫描模式
- 自校准
- 带内嵌数据一致性的数据对齐
- 采样间隔可以按通道分别编程
- 规则转换和注入转换均有外部触发选项
- 间断模式
- 双重模式(带2个或以上ADC的器件)
- 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+
- 规则通道转换期间有DMA请求产生。
4.规则通道和注入通道的区别
STRT规则通道开始位 (Regular channel Start flag)
JSTRT:注入通道开始位 (Injected channel Start flag)
学习ADC的时候,我一直搞不懂为什么ADC通道要分为规则通道和注入通道?这个规则和注入不仅难记而且拗口,其要表达的意思更是让人不解。查阅英文参考手册知道,英文中的Regular channel被翻译为规则通道,而injected channel被翻译为注入通道。好吧,其实老外的思维和我们真的有点差别,想要表达的意思由于文化和语言的差异,而被生硬翻译为规则和注入两个词,好吧,取个名称只是为了更好的表达和描述一些东西,就像张三李四一样,其应用的意义远大于名字的意义,大可不必太过在意,若实在觉得生硬,就称为Regular 和 injected吧!
在明白了名称的前世今生后,我们再来探讨下其表达的意义,这里引用我认为讲的比较好的网友见解 。原文链接:http://bbs.ednchina.com/BLOG_ARTICLE_225912.HTM
-------------------------------------分割线-------------------------------------------------------
网友见解:
STM32的每个ADC模块通过内部的模拟多路开关,可以切换到不同的输入通道并进行转换。STM32特别地加入了多种成组转换的模式,可以由程序设置好之后,对多个模拟通道自动地进行逐个地采样转换。
有2种划分转换组的方式:规则通道组和注入通道组。通常规则通道组中可以安排最多16个通道,而注入通道组可以安排最多4个通道。
在执行规则通道组扫描转换时,如有其他处理则可启用注入通道组的转换。
一个不太恰当的比喻是:规则通道组的转换好比是程序的正常执行,而注入通道组的转换则好比是程序正常执行之外的一个中断处理程序。
再举一个不一定使用的例子:
假如你在家里的院子内放了5个温度探头,室内放了3个温度探头;你需要时刻监视室外温度即可,但偶尔你想看看室内的温度;因此你可以使用规则通道组循环扫描室外的5个探头并显示AD转换结果,当你想看室内温度时,通过一个按钮启动注入转换组(3个室内探头)并暂时显示室内温度,当你放开这个按钮后,系统又会回到规则通道组继续检测室外温度。
从系统设计上,测量并显示室内温度的过程中断了测量并显示室外温度的过程,但程序设计上可以在初始化阶段分别设置好不同的转换组,系统运行中不必再变更循环转换的配置,从而达到两个任务互不干扰和快速切换的结果。可以设想一下,如果没有规则组和注入组的划分,当你按下按钮后,需要重新配置AD循环扫描的通道,然后在释放按钮后需再次配置AD循环扫描的通道。
上面的例子因为速度较慢,不能完全体现这样区分(规则组和注入组)的好处,但在工业应用领域中有很多检测和监视探头需要较快地处理,这样对AD转换的分组将简化事件处理的程序并提高事件处理的速度。
-------------------------------------分割线-------------------------------------------------------
5.蓝桥杯考察ADC点
CT117E 嵌入式竞赛板(在没有用到扩展版情况下),由CT117Ev1.1电路原理图可知,ADC的采集电压引脚PB0,通过R37电位器来调节分压电路中的电压。
查阅stm32f103rbt6的Datasheet
(1)总体资源分布
(2)ADC资源分布
PC0~PC3
PA0~PA3
PA4~PA7 ; PC4~PC5 ;PB0~PB1(这次选用PB0引脚!)
6.配置ADC模式的理解
(1)我们先从STM32库函数入手,看一下
ADC_InitTypeDef ADC_InitStructure;
typedef struct
{
uint32_t ADC_Mode; /*!< Configures the ADC to operate in independent or
dual mode.
This parameter can be a value of @ref ADC_mode */
FunctionalState ADC_ScanConvMode; /*!< Specifies whether the conversion is performed in
Scan (multichannels) or Single (one channel) mode.
This parameter can be set to ENABLE or DISABLE */
FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in
Continuous or Single mode.
This parameter can be set to ENABLE or DISABLE. */
uint32_t ADC_ExternalTrigConv; /*!< Defines the external trigger used to start the analog
to digital conversion of regular channels. This parameter
can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */
uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment is left or right.
This parameter can be a value of @ref ADC_data_align */
uint8_t ADC_NbrOfChannel; /*!< Specifies the number of ADC channels that will be converted
using the sequencer for regular channel group.
This parameter must range from 1 to 16. */
}ADC_InitTypeDef;
7.配置ADC模板
配置ADC的步骤:
1.配置ADC相关GPIO引脚,如采集电压信号,GPIO引脚配置为模拟输入。
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
2.ADC配置
-
ADC的模式(独立模式,扫描模式,连续转换模式)
ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; /* 连续转换模式---不难理解---就是不停地采集---一次接一次 */
-
使不使用外部触发?(ADC_ExternalTrigConv);触发分为外部触发,比如中断和定时器。软件触发—>用专用函数。
-
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
-
ADC采集的数据对齐方式和转换的通道个数
-
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//采集的数据右对齐---方便计算 ADC_InitStructure.ADC_NbrOfChannel = 1; //总共需要转换的通道个数 ADC_Init(ADC1, &ADC_InitStructure);
-
到ADC_Init(ADC1, &ADC_InitStructure);这一步,我们把前面辛辛苦苦配置的结构体DC_InitStructure给初始化。
错误总结:我把ADC初始化的各种配置给封装成一个函数,这并没有什么问题,但是我给这个函数命名为ADC_Init()出现了错误,因为这个函数名已经用过了,为ADC_Init(ADC1, &ADC_InitStructure);故而改为adc_Init()
/* ADC1 regular channel_8 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
8.程序代码
实现功能:每隔100ms对PB0上的电压进行AD采样并计算电压数值(保留2位小数),显示在LCD的Line1行上
参考博客:https://blog.csdn.net/Zach_z/article/details/80548423
(1)ADC.c文件
/* PB0———ADC_IN8 / TIM3_CH3 */
#include "ADC.h"
void adc_Init()
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOB,ENABLE);
/*配置ADC相应的GPIO,这里配置PB0(ADC_IN8)作为模拟输入------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* ADC1 configuration -----------------------------------------*/
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_InitStructure.ADC_NbrOfChannel = 1; //总共需要转换的通道个数
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel_8 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
u16 get_adc()
{
u16 value;
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
value = ADC_GetConversionValue(ADC1);
return value;
}
(2)main.c文件
#include "stm32f10x.h"
#include "stdio.h"
#include "ADC.h"
void Delay_ms(unsigned int ms)
{
unsigned int i,j;
for(i=0; i<ms; i++)
{
for(j=0; j<8450; j++) ;
}
}
int main()
{
u16 adc_value;
u8 str[20];
STM3210B_LCD_Init();
Delay_ms(100);
LCD_SetTextColor(White);
LCD_SetBackColor(Black);
LCD_ClearLine(Line0);
adc_Init();
while(1)
{
adc_value=get_adc();
sprintf(str," PB0: %.2f V",(float)adc_value/4096*3.3);
LCD_DisplayStringLine(Line1, str);
Delay_ms(100);
}
}
版权声明:本文为CSDN博主「嵌入式历练者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Eterlove/article/details/122619260
暂无评论