【蓝桥杯——物联网设计与开发】拓展模块4 - 脉冲模块

一、脉冲模块

(1)资源介绍

🔅原理图

蓝桥杯物联网竞赛实训平台提供了一个拓展接口 CN2 ,所有拓展模块均可直接安装在 Lora终端上使用;
图1 拓展接口

脉冲模块电路原理图如下所示:
图2 脉冲模块电路原理图

通过两张电路图连接可知,引脚资源配置情况为:

PULSE MCU
PR1 PB1
PULS PB0
LED1 PB7
LED2 PB6
[表1 引脚资源配置情况]

🔅采集原理

脉冲信号由脉冲芯片产生,通过PR3滑动变阻器控制,不同阻值下的脉冲频率不同。

通过公式可得,脉冲频率 = 脉冲周期的倒数,那么我们可以将问题转换为求取脉冲周期。

PULS 连接在PB0 引脚,该引脚为定时器3的通道3,我们可以使用定时器的输入捕获模式(Input Capture direct mode)。捕获脉冲的上升沿,通过计算相邻两个上升沿之间的差值,即可得到该脉冲的周期。示意图如下所示:
图3 脉冲示意图

⚠️注意: ++由于定时器周期不为1Hz,所以这里需要用定时器时钟频率除以脉冲周期++;

定时器的计数寄存器为16位,范围是0~65535,溢出后清零重新计数。在计算脉冲周期时会遇到三种情况,如图4所示:
图4 计数不同情况

对于情况3,如果两次获取的值相等,需要考虑是否为定时器计数异常等情况,所以一般判为error

🟠️伪代码如下:

cpp 复制代码
if(第一个上升沿)
{
	cnt1 = 获取定时器cnt值;
}
else if(第二个上升沿)
{
	cnt2 = 获取定时器cnt值;
    /* 判断情况 */
	if(cnt2 > cnt1)
		脉冲周期 = cnt2 - cnt1;
	else if(cnt2 < cnt1)
		脉冲周期 = 0xFFFF - cnt1 + 1 + cnt2;
	else
		error报错;
	uwFreq = 定时器时钟频率 / 脉冲周期;
}

PR1为AD采集,参考之前的文章即可:

【蓝桥杯------物联网设计与开发】拓展模块2 - 电位器模块_lowpowerautowait-CSDN博客https://blog.csdn.net/m0_63116406/article/details/139212183?spm=1001.2014.3001.5501

(2)STM32CubeMX 软件配置

🔅"工程建立、时钟树配置、Debug 串行线配置、代码生成配置" 在下文中有讲解,这里不再赘述❗️

【蓝桥杯------物联网设计与开发】基础模块1- GPIO输出https://blog.csdn.net/m0_63116406/article/details/135604705?spm=1001.2014.3001.5502

1️⃣点击引脚 PB0 → 选择 TIM3_CH3 ;(此时引脚呈黄色,因为TIM 还未配置)

2️⃣点击 "Timers " → 点击"TIM3 " → 将 "Channel3 " 栏修改为 "Input Capture direct mode ",即将 PB0 引脚配置为TIM3 通道3的输入捕获模式;(此时引脚呈绿色,可以正常工作)

⚠️**注意:**下方参数表中:

  1. 计数周期为65535
  2. 通道3输入捕获极性为++上升沿++或++下降沿++;

图5 引脚配置

3️⃣配置PB1 引脚为AD 采集引脚;(具体参考AD采集一文)

4️⃣初始化 OLED ;(具体参考OLED一文)

5️⃣生成代码即可;

(3)代码编写

🟢️main 函数

cpp 复制代码
/* USER CODE BEGIN PV */
uint8_t puc_oled[17];    // oled显示缓存区
uint16_t pui_adc;        // adc采集值

uint8_t uc_ic_state;     // 输入捕获状态,区分第一次和第二次上升沿
uint32_t uwValue1;       // 第一次上升沿的计数值
uint32_t uwValue2;       // 第二次上升沿的计数值
uint32_t uwDiff;         // 脉冲周期
uint32_t uwFreq;         // 脉冲频率
/* USER CODE END PV */

/* USER CODE BEGIN 0 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)                    // 判断是否为通道3中断
	{
		if(uc_ic_state == 0)    // 第一次上升沿
		{
			uwValue1 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3);    // 获取计数值
			uc_ic_state = 1;    // 修改状态变量
		}
		else if(uc_ic_state == 1)    // 第二次上升沿
		{
			uwValue2 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3);    // 获取计数值
			/* 判断情况 */
            if(uwValue2 > uwValue1)    
				uwDiff = uwValue2 - uwValue1;
			else if(uwValue2 < uwValue1)
				uwDiff = 0xFFFF - uwValue1 + 1 + uwValue2;
			else
				Error_Handler();
			uwFreq = HAL_RCC_GetPCLK1Freq() / uwDiff;    // 计算脉冲频率
			uc_ic_state = 0;    // 修改状态变量
		}
	}
}
/* USER CODE END 0 */
/**
  * @brief  The application entry point.
  * @retval int
  */
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_ADC_Init();
  MX_TIM3_Init();
  MX_I2C3_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();
	HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_3);    // 开启定时器捕获中断
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
        /* ADC采集 */
		HAL_ADC_Start(&hadc);
		if(HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)
			pui_adc = HAL_ADC_GetValue(&hadc);
        /* OLED显示 */
		sprintf((char*)puc_oled, "TIM:%u     ", uwFreq);
		OLED_ShowString(0, puc_oled);
		sprintf((char*)puc_oled, "ADC:%.2f   ", pui_adc * 3.3 / 4095);
		OLED_ShowString(2, puc_oled);
		HAL_Delay(200);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(4)实验现象

  • 旋转PR1按钮,能够实时采集AD值;
  • 旋转PR3按钮,能够实时采集频率值;

二、脉冲模块接口函数封装

🟡️定时器输入捕获中断函数

cpp 复制代码
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)                    // 判断是否为通道3中断
	{
		if(uc_ic_state == 0)    // 第一次上升沿
		{
			uwValue1 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3);    // 获取计数值
			uc_ic_state = 1;    // 修改状态变量
		}
		else if(uc_ic_state == 1)    // 第二次上升沿
		{
			uwValue2 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3);    // 获取计数值
			/* 判断情况 */
            if(uwValue2 > uwValue1)    
				uwDiff = uwValue2 - uwValue1;
			else if(uwValue2 < uwValue1)
				uwDiff = 0xFFFF - uwValue1 + 1 + uwValue2;
			else
				Error_Handler();
			uwFreq = HAL_RCC_GetPCLK1Freq() / uwDiff;    // 计算脉冲频率
			uc_ic_state = 0;    // 修改状态变量
		}
	}
}

三、踩坑日记

(1)中断使能

🔅中断使能应该使用函数HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_3);否则中断无法进入;

(2)引脚配置

🔅引脚模式配置为**++带上拉电阻++**(目前没发现不配置有什么问题);

🔅速度配置为Very High

(3)ADC校准

🔅ADC模块注意:初始化函数里面需要进行++ADC校准++,否则无法测量准确的值‼️

相关推荐
weixin_4526006929 分钟前
串行时钟保持芯片D1380/D1381,低功耗工作方式自带秒、分、时、日、日期、月、年的串行时钟保持芯片,每个月多少天以及闰年能自动调节
科技·单片机·嵌入式硬件·时钟·白色家电电源·微机串行时钟
Amarantine、沐风倩✨1 小时前
设计一个监控摄像头物联网IOT(webRTC、音视频、文件存储)
java·物联网·音视频·webrtc·html5·视频编解码·七牛云存储
森旺电子4 小时前
51单片机仿真摇号抽奖机源程序 12864液晶显示
单片机·嵌入式硬件·51单片机
不过四级不改名6776 小时前
蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)
stm32·嵌入式硬件·蓝桥杯
TT哇6 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
小A1596 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
Rorsion6 小时前
各种电机原理介绍
单片机·嵌入式硬件
善 .9 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件
超级码农ProMax9 小时前
STM32——“SPI Flash”
stm32·单片机·嵌入式硬件
Asa31910 小时前
stm32点灯Hal库
stm32·单片机·嵌入式硬件