STM32CubeMX之ADC采集烟雾值
1.ADC简介
STM32中硬件本身自带ADC外设,ADC精度为12位。ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。 ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
2.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请求产生。
3.ADC转换模式
有16个多路通道。可以把转换组织成两组:规则组和注入组。在任意多个通道上以任意顺序进行的一系列转换构成成组转换。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道2、通道0、通道2、通道2、通道15。
● 规则组由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规则组中转换的总数应写入ADC_SQR1 寄存器的L[3:0]位中。
● 注入组由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。
如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉冲将发送到ADC以转换新选择的组。
ADC转换支持单次转换模式和连续转换模式。转换过程中支持扫描模式和间断模式。
3.1 单次转换模式
单次转换模式下, ADC只执行一次转换。该模式既可通过设置ADC_CR2寄存器的ADON位(只适用于规则通道)启动,也可通过外部触发启动(适用于规则通道或注入通道),这时CONT位为0。
3.2 连续转换模式
在连续转换模式中,当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。
如下图所示, ADC在开始精确转换前需要一个稳定时间tSTAB。在开始ADC转换和14个时钟周期后, EOC标志被设置, 16位ADC数据寄存器包含转换的结果。
3.3 扫描模式
此模式用来扫描一组模拟通道。
扫描模式可通过设置ADC_CR1 寄存器的SCAN位来选择。一旦这个位被设置, ADC扫描所有被ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。
如果设置了 DMA位,在每次EOC后, DMA控制器把规则组通道的转换数据传输到SRAM中。而注入通道转换的数据总是存储在ADC_JDRx寄存器中。
3.4 间断模式
STM32在配置过程有规则组转换和注入组转换两种方式。配置过程使用的寄存器则不一样,在间断模式下配置执行过程如下:
- 规则组
此模式通过设置ADC_CR1 寄存器上的DISCEN位激活。它可以用来执行一个短序列的n次转换(n<=8),此转换是ADC_SQRx寄存器所选择的转换序列的一部分。数值n由ADC_CR1 寄存器的DISCNUM[2:0]位给出。
一个外部触发信号可以启动ADC_SQRx寄存器中描述的下一轮n次转换,直到此序列所有的转换完成为止。总的序列长度由ADC_SQR1 寄存器的L[3:0]定义。
举例:
n=3,被转换的通道 = 0、 1 、 2、 3、 6、 7、 9、 10
第一次触发:转换的序列为 0、 1 、 2
第二次触发:转换的序列为 3、 6、 7
第三次触发:转换的序列为 9、 10,并产生EOC事件
第四次触发:转换的序列 0、 1 、 2
注意:当以间断模式转换一个规则组时,转换序列结束后不自动从头开始。当所有子组被转换完成,下一次触发启动第一个子组的转换。在上面的例子中,第四次触发重转换第一子组的通道 0、1和2。
- 注入组
此模式通过设置ADC_CR1 寄存器的JDISCEN位激活。在一个外部触发事件后,该模式按通道顺序逐个转换ADC_JSQR寄存器中选择的序列。
一个外部触发信号可以启动ADC_JSQR寄存器选择的下一个通道序列的转换,直到序列中所有的转换完成为止。总的序列长度由ADC_JSQR寄存器的JL[1:0]位定义。
例子:
n=1 ,被转换的通道 = 1 、 2、 3
第一次触发:通道1 被转换
第二次触发:通道2被转换
第三次触发:通道3被转换,并且产生EOC和JEOC事件
第四次触发:通道1 被转换
注意:
1.当完成所有注入通道转换,下个触发启动第1个注入通道的转换。在上述例子中,第四个触发重新转换第1个注入通道1。
2.不能同时使用自动注入和间断模式。
3.必须避免同时为规则和注入组设置间断模式。间断模式只能作用于一组转换。
4.烟雾传感器MQ-2
MQ-2 气体传感器所使用的气敏材料是在清洁空气中电导率较低的二氧化锡(SnO2) 。当传感器所处环境中存在可燃气体时,传感器的电导率随空气中可燃气体浓度的增加而增大。 使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。将模拟量转换为数字量的技术我们称之为ADC。
本次实验采用开发板硬件ADC功能进行烟雾数据采集,STM32F103 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用,也可以使用双重模式(提高采样率)。 STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
4.1 硬件设计
采用PA0(ADC1_CH0)接口完成烟雾浓度采集。
4.2 软件设计
- ADC工作频率配置
根据STM32中文参考手册ADC章节(第155页),ADC的工作时钟不能超过14MHZ。
- ADC模式
STM32F103开发板有两种转换方式:规则转换和注入转换。规则转换有可同时转换16路通道,但只有一个数据寄存器,所以想完成16路通道同时转换就需要DMA配合使用;注入通道有4个数据寄存器,可同时转换4路通道。
- ADC模式配置
4.3 代码生成
- ADC初始化配置代码
/* ADC1 init function */
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;//ADC1
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;//非扫描模式
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;//单次转换
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;//软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;//右对齐
hadc1.Init.NbrOfConversion = 1;//一个转换
if (HAL_ADC_Init(&hadc1) != HAL_OK)//ADC1初始化
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;//通道0
sConfig.Rank = ADC_REGULAR_RANK_1;//一个序列
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;//采样周期239.5
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)//adc通道配置
{
Error_Handler();
}
}
- PA0引脚配置和ADC校准。
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();//开启ADC时钟
__HAL_RCC_GPIOA_CLK_ENABLE();//开PA时钟
/**ADC1 GPIO Configuration
PA0-WKUP ------> ADC1_IN0
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;//PA0
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;//模拟输入
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//GPIO口配置
/* USER CODE BEGIN ADC1_MspInit 1 */
HAL_ADCEx_Calibration_Start(adcHandle);//启动并校准ADC
/* USER CODE END ADC1_MspInit 1 */
}
}
- 完成一次规则通道转换
u16 Get_Regular_Channelx(u16 ch)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel=ch;//通道号
sConfig.SamplingTime=ADC_SAMPLETIME_239CYCLES_5;//采样周期
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)//ADC通道初始化
{
Error_Handler();
}
HAL_ADC_Start(&hadc1);//开启ADC
HAL_ADC_PollForConversion(&hadc1,20);//等待规则通道转换完成
return HAL_ADC_GetValue(&hadc1);
}
- 主函数
初始化硬件,通过MQ2烟雾传感器采用烟雾值,设置烟雾报警阈值,超过范围通过蜂鸣器报警。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
u16 data;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)//轮询
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
data=ADC1_Get_Regular_Chx(ADC_CHANNEL_0);
printf("data=%d\r\n",data);
if(data>=1000)//烟雾浓度超过1000,则报警
{
HAL_GPIO_WritePin(BEEP_GPIO_Port,BEEP_Pin,GPIO_PIN_SET);
}
else
HAL_GPIO_WritePin(BEEP_GPIO_Port,BEEP_Pin,GPIO_PIN_RESET);
Delay_Ms(500);
}
/* USER CODE END 3 */
}
5.ADC常用函数介绍
/**********************在stm32f1xx_hal_adc.c中*********************************************/
HAL_ADC_Start(ADC_HandleTypeDef* hadc); //开启ADC
HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc); //中断方式开启ADC
HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length); //DMA方式开启
//等待转换完成
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);//获取数据
//ADC通道配置
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc,ADC_ChannelConfTypeDef* sConfig);
uint32_t HAL_ADC_GetState(ADC_HandleTypeDef* hadc);//获取状态
/***************************************在stm32f1xx_hal_adc_ex.h中*****************************/
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc);//ADC校准
HAL_StatusTypeDef HAL_ADCEx_InjectedStart(ADC_HandleTypeDef* hadc);//使能ADC,开始注入转换