STM32传感器ADC采样以及蜂鸣器的使用


1- ADC(Analog-to-Digital Converter)

什么是ADC:

单片机中的ADC是Analog(模拟量)-to-Digital(数字量) Converter(转换器)的缩写,指模/数转换器或者模数转换器。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式,模/数转换器可以实现这个功能。
ADC就是数模转换,将模拟量转换为数字量

2- 原理图分析

我们可以看见开发板上的声音传感器和光强传感器,他们工作的原理都是ADC采样。
在这里插入图片描述

原理图我们可以看见,声音传感器连接在了CPU的PA6管脚上,环境光强传感器连接在了CPU的PA4管脚上。
在这里插入图片描述

从原理图和CPU的管脚我们看到,环境光强传感器使用的是ADC_IN9(第一个ADC采样的第9个通道上),声音传感器使用的是ADC_IN11。后面我们配置的时候也是需要注意的。

在这里插入图片描述


3- 配置使能ADC

配置ADC1,使能通道IN9 和IN11,选择Single-ended (Differential为差分信号)。这时候PA4 和PA6两个管脚就设置为ADC输入模式了,另外我们也可以鼠标右键点在这两个管脚上,对这两个管脚重命名,分别为AdcLux和AdcMix。
在这里插入图片描述

在这里插入图片描述

我们将ADC的时钟设置为12MHZ。
在这里插入图片描述

按住Ctrl+s生成代码。


4- 添加代码

修改adc.c文件,添加环境光强传感器和的声音传感器实现。

/* USER CODE BEGIN 1 */
enum
{
	ADCCHN_NOISY,
	ADCCHN_LUX,
	ADCCHN_MAX,
};

int adc_sample_lux_noisy(uint32_t *lux, uint32_t *noisy)
{
	uint8_t i;
	uint32_t  timeout = 0xffffff;
	for(i=0; i<ADCCHN_MAX; i++)
	{
		HAL_ADC_Start(&hadc1);
		HAL_ADC_PollForConversion(&hadc1, timeout);
		if(ADCCHN_NOISY == i)
		{
			*noisy = HAL_ADC_GetValue(&hadc1);
		}
		else if(ADCCHN_LUX == i)
		{
			*lux = HAL_ADC_GetValue(&hadc1);
		}
		HAL_Delay(10);
	}
	HAL_ADC_Stop(&hadc1);
	return 0;
}
/* USER CODE END 1 */

adc.h中添加ADC采样的函数声明。


/* USER CODE BEGIN Includes */
extern int adc_sample_lux_noisy(uint32_t *lux, uint32_t *noisy);
/* USER CODE END Includes */

在main.c添加源代码:

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  adc_sample_lux_noisy(&lux, &noisy);
	  printf("Lux:[%lu] Noisy[%lu]\r\n", lux, noisy);
	  HAL_Delay(500);
  }
  /* USER CODE END 3 */

5- 烧录连接测试

烧录之后连接sscom进行测试,我们对着开发板声音改变或者光强改变的时候数字是不一样的,说明测试成功。
在这里插入图片描述


6- 蜂鸣器原理图

下图是BearKE1开发板原理图上蜂鸣器的电路图,由下图可知它受PA1管脚的控制。
在该开发板上我们采用的是无源蜂鸣器,因为人耳能听到的频率范围在20Hz–20kHz之间,此时我们只需要使用PA1管脚的定时器PWM输出功能,输出一个2.4KHz左右的PWM方波蜂鸣器就会发声了,通过调整PWM的频率就可以调整蜂鸣器的音色了。

在这里插入图片描述
PWM(Pulse Width Modulation,脉冲宽度调制)是通过对一系列脉冲的宽度进行调制,输出所需要的波形(包含形状以及幅值)。在PWM里有两个重要的专业术语:

  • 频率是指1秒内高低电平周期性出现的次数。
  • 占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如下图所示的PWM波形占空比为25%,而方波则是指占空比为50%的PWM波形。
    在这里插入图片描述

PWM在很多场合都会使用,我们经常见到的就是交流调光电路,也可以说是无级调速,高电平占多一点,也就是占空比大一点亮度就亮一点,占空比小一点亮度就没有那么亮,前提是PWM的频率要大于我们人眼识别频率,要不然会出现闪炼现象。除了在调光电路应用,还有在直流斩波电路、蜂鸣器驱动、电机驱动、逆变电路、加湿机雾化量等都会有应用。

在STM32的通用定时器中有两个重要的寄存器:

  • ARR(Auto-reload register,自动重装载寄存器)是个16位的寄存器,这里面装着计数器能计数的最大数值。如果使能了中断,当计数到达这个值时定时器就产生溢出中断;
  • CCR(Capture/Compare Registers,捕获/比较寄存器), CCR与定时器的值进行比较:如果CCR大则输出低电平,反之则输出高电平。通过改变CCR值可以改变PWM的占空比;

7- 配置蜂鸣器

首先配置使能TIM2,让Channel2输出PWM。这时PA1管脚的状态就被设置成TIM2_CH2功能模式了。
在这里插入图片描述

因为PWM会输出高低电平,接着设置GPIO下拉防止蜂鸣器误发声音。
在这里插入图片描述

配置预分频:
TIM2的输入时钟为APB1时钟80MHz,这个速率对定时器来说实在太快,这时需要对它做个预分频: CK_CNT = TIMxCLK/(PSC+1)=80MHz/(80-1+1)=1MHz

配置PWM时钟:
通过TIM2定时器的ARR(自动重装载寄存)的值可以调整PWM的输出频率,这里想让蜂鸣器工作在2.7KHz,则: ARR=1MHz/2700 约等于 370

配置占空比:
这里我们设置占空比为50%,则Pulse=370/2=185
在这里插入图片描述

Ctrl+s生成代码。


8- 添加代码

修改tim.c文件,添加蜂鸣器操作函数beep_start()实现,其中times为蜂鸣器响几次,而interval 为响、停的时间间隔。

/* USER CODE BEGIN 1 */
void beep_start(uint8_t times, uint16_t interval)
{
	while(times--)
	{
		if(HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2) != HAL_OK)
		{
			Error_Handler();
		}
		HAL_Delay(interval);
		if(HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2) != HAL_OK)
		{
			Error_Handler();
		}
		HAL_Delay(interval);
	}
}
/* USER CODE END 1 */

修改tim.h,添加蜂鸣器操作函数的声明。

/* USER CODE BEGIN Includes */
void beep_start(uint8_t times, uint16_t interval);
/* USER CODE END Includes */

main.c函数中调用 beep_start(2, 300);

  /* USER CODE BEGIN WHILE */
  /*响两次,间隔300毫秒*/
  beep_start(2, 300);
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    /*这一部分为ADC采样的例子*/
	  adc_sample_lux_noisy(&lux, &noisy);
	  printf("Lux:[%lu] Noisy[%lu]\r\n", lux, noisy);
	  HAL_Delay(500);

  }
  /* USER CODE END 3 */

运行测试之后会听见开发板滴滴叫两声。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个示例代码,用于在STM32使用气体传感器检测气体浓度,并通过蜂鸣器触发报警: ```c #include "stm32f4xx.h" // 定义传感器的引脚 #define GAS_SENSOR_PIN GPIO_Pin_0 #define GAS_SENSOR_PORT GPIOA // 定义蜂鸣器的引脚 #define BUZZER_PIN GPIO_Pin_1 #define BUZZER_PORT GPIOA // 定义阈值 #define ALARM_THRESHOLD 500 // ADC配置 void ADC_Configuration(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能GPIOA和ADC1的时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 配置PA0引脚为模拟输入 GPIO_InitStructure.GPIO_Pin = GAS_SENSOR_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GAS_SENSOR_PORT, &GPIO_InitStructure); // ADC配置 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); // 配置ADC通道0为采样通道 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_15Cycles); // 使能ADC1 ADC_Cmd(ADC1, ENABLE); // 启动ADC1校准 ADC_StartOfConversion(ADC1); } // 控制蜂鸣器状态 void ControlBuzzer(uint8_t state) { if (state) GPIO_SetBits(BUZZER_PORT, BUZZER_PIN); // 设置蜂鸣器引脚为高电平 else GPIO_ResetBits(BUZZER_PORT, BUZZER_PIN); // 设置蜂鸣器引脚为低电平 } int main(void) { // 初始化ADC ADC_Configuration(); // 初始化蜂鸣器引脚 GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = BUZZER_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(BUZZER_PORT, &GPIO_InitStructure); while (1) { // 读取传感器ADC_SoftwareStartConv(ADC1); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {} uint16_t sensorValue = ADC_GetConversionValue(ADC1); // 根据传感器值进行相应的处理,例如触发报警 if (sensorValue > ALARM_THRESHOLD) { ControlBuzzer(1); // 开启蜂鸣器 } else { ControlBuzzer(0); // 关闭蜂鸣器 } } } ``` 请注意,以上代码仅提供了一个基本的框架,你需要根据你实际使用蜂鸣器传感器模块进行适当的修改和扩展。另外,确保在使用ADC和GPIO之前正确配置引脚和时钟,并根据需要调整阈值和报警逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值