本文想要设计一个设计一个有stm32控制的烟雾报警系统。通过MQ-2烟雾报警器将获取模拟的数值传递给stm32的ADC外设并在串口助手上显示对应的电压值。烟雾报警器浓度越高,他的电压就越高,但是不会超过3.3V。设置一个电压临界值,当传输回来的电压大于临界值时就意味着空气中可燃气体或烟雾的浓度过高,就会出发蜂鸣器报警。
名称 | 图片 | 作用 |
stm32f103c8t6单片机 | - | - |
MQ-2烟雾报警器 | 将空气中可燃气体或烟雾的浓度转化为具体的数值给到单片机的ADC外设 | |
蜂鸣器 | 空气中可燃气体或烟雾的浓度过高触发报警,由低电平触发 |
1.什么是ADC?
这里的ADC不是你游戏里的ADC打野,手册上说:12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
蒙逼不?淡定,从使用者的角度来说ADC就是一个把模拟电压转换成数字电压的工具,然后把数据放到内存中暂时储存。手册上说了那么多其实就是ADC使用时候的配置,下面我们慢慢讲。
2.ADC配置的描述
首先来说说这18个通道,图片中间靠左有GPIO端口,从IN0到IN15,一共有16个通道,还有两个通道是温度传感器还有VREFINT。但是在这个手册是针对stm32f10系列的,对于我们的stm32f103c8t6来说只有IN0到IN9,温度传感器还有VREFINT共计11个通道。ADC通道的作用是实现模拟信号的采样和量化,将连续变化的模拟信号转换为离散的数字信号,以便于数字系统的处理和分析。12位ADC转换的总时间T=采样周期(1.5个周期)+量化编码周期(12.5个周期),我们这里的ADC周期是12MHz,所以最短的转换时间为 1.17us。
2.简单常用转换的模式
2.1非扫描模式与扫描模式
非扫描模式适用于只占用一个通道,而扫描模式适用于多个通道。见下图
图1有一个通道,适用于非扫描模式;图二有多个通道,适用于扫描模式。如果在图二中使用非扫描模式,就只会发序列1里面的数据。
2.2单次转换与连续转换
单次转换就是说,每一次你使用的时候,都需要开启触发条件,通道的数据只要发送出去以后,通道就关闭了;连续转换就是说,你只需要在刚开始的时候开启一次触发条件,即使你这一轮通道里的数据发送完了,通道也不会关闭,下一轮数据还可以接着发。
看到了吗?连续模式下,触发转换的条件只需要一次就行。而且不管在什么模式下,每一轮的数据全部发出之后都会有EOC这个标志位置一。
当然了,还有别的模式,这里就不说了,有兴趣的可以自己看手册。
3.规则组与注射组
规则组(Regular Group)是ADC中最常用的组,它可以同时采集多个不同的模拟信号,并将这些信号转换为相应的数字值。规则组通常包含一个或多个ADC通道,每个通道都可以连接到一个外部模拟信号源上,并且可以设置不同的采样频率、分辨率等参数。规则组的输出数据可以通过DMA(直接存储器访问)或中断方式传输到内存或其他设备中。
结合最上面的图我们可以看出来规则组最多只有16个通道,但是经过模数转换器以后,每次只有一个通道的数据可以进入规则通道数据寄存器。打个比方,现在有16个人(人就是通道)来餐厅(餐厅就是模数转换器)吃饭,但是餐厅只能容下一个人(只有一个数据寄存器)。第一个人在里面吃饭,如果第二个人也想进去,就需要把第一个人撵走,占据第一个人的位置(这样的话,第一个数据就消失了,所以说要在第二个数据来之前把第一个数据取走),后面的人依次进行这样的操作。
注射组(Injected Group)是ADC中另一个可选的组,它可以在规则组正在进行转换时,对某些特定的模拟信号进行额外的采样和转换。注射组通常用于需要高速响应的应用场合,例如获取瞬态信号或快速变化的信号。注射组通常包含一个或多个ADC通道,每个通道都可以设置不同的触发条件、采样时间等参数。注射组的输出数据也可以通过DMA或中断方式传输到内存或其他设备中。
结合最上面的图,我们可以看到注射组最多只有4个通道,经过模数转换器以后,每次可以让四个通道的数据都进入规则通道数据寄存器。
需要注意的是,规则组和注射组之间并不是互斥的关系,它们可以同时使用,也可以单独使用。在使用ADC时,需要根据具体的应用场景和要求,选择适合的组合方式。
下面的内容都针对规则组。
4.左对齐与右对齐
左对齐的数据比右对齐的数据大了16倍,右对齐是我们基础的对齐方式。
SYS
RCC
ADC
GPIO
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
int fputc(int ch, FILE *f)
{
unsigned char temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,0xffff);
return ch;
}
int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t smoke_value=0;
/* 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_ADC1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1); //启动ADC单次转换
HAL_ADC_PollForConversion(&hadc1, 50); //等待ADC转换完成
smoke_value = HAL_ADC_GetValue(&hadc1); //读取ADC转换数据
dianya=smoke_value*3.3/4096;
if(dianya>1.0)//烟雾报警器电压返回值大于1.0,则蜂鸣器报警
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,GPIO_PIN_RESET);//蜂鸣器AO输出接在B7
HAL_Delay(1000);
}//蜂鸣器AO输出接在B7
else
{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7,GPIO_PIN_SET);
HAL_Delay(1000);
}
printf("dianya = %f\r\n",dianya);
//printf("smoke_value = %d \r\n", smoke_value);
HAL_Delay(100);
}
/* USER CODE END 3 */
}
用打火机来代替易燃气体,半按下打火机,对准烟雾报警器,里面的气体就会出来。