TIM定时器的应用——利用旋转编码器实现操控呼吸灯——点灯大王篇!

 

一,实验准备

1,实验目的 

本实验通过对TIM定时器PWM的学习,操控旋转编码器来对呼吸灯的亮度进行控制。

 

2,呼吸灯的原理

呼吸灯是让灯光呈现由亮到暗再到亮,类似人呼吸般节奏变化的灯光效果,其原理主要基于 PWM(脉冲宽度调制)技术 ,以常见的 LED 呼吸灯为典型。

 

3,旋转编码器的认识

旋转编码器是将旋转的机械量转换为电信号输出的传感器,常见类型有光电式、磁电式 ,按编码方式分为增量式和绝对式,以下是其原理介绍:

磁电式增量编码器

  • 结构组成:有一个带磁性材料的旋转码盘(磁极交替分布 ),以及磁敏元件(如霍尔元件 )。

  • 工作过程:码盘旋转时,磁极交替靠近磁敏元件,使磁敏元件周围磁场发生变化,根据霍尔效应等原理,磁敏元件会输出与磁场变化相关的电信号,经处理后得到类似光电式增量编码器的 A、B 相脉冲信号,用于判断旋转方向和计算旋转角度。 增量式编码器的特点是能反映旋转的相对变化,断电后位置信息丢失,再次工作需重新计数或找参考点。

 

 

二,工程创建

1,新建工程

依旧是轻车熟路的点击左上角的File,然后点击STM32 Project,选择收藏的STM32F103C8T6型号芯片。

之后将工程名称命名为“PWM_Encoder”,然后完成工程创建。

 

2,引脚参数配置 

首先我们需要梳理一下本次项目需要使用的外设模块:

  1. 一个定时器的三个通道设置为PWM模式来控制三盏LED灯
  2. 一个GPIO引脚用于连接按键控制切换LED灯
  3. 一个定时器设置为编码器模式来控制旋转编码器
  4. 一个I2C外设来设置OLED屏幕

因此我们需要对这些外设一步一步配置。

别忘了开启外部高速时钟和SWD调试端口,Crystal/Ceramic Resonator意为晶体 / 陶瓷谐振器 ,即外部晶振,开启之后来到时钟树将时钟频率改为72MHz。

 之后为三个LED小灯开启外部时钟,然后模式选择PWM1模式,预分频PSC改为72,自动重装载值ARR改为100,其余参数保持不变即可,这样我们就配置好了TIM3。

然后为旋转编码器开启TIM1,模式直接选择为编码器模式,分频数选择为2分频即可,然后需要将旋转编码器的其中一个引脚的输出脉冲反相一下,原因之后大家试过就知道了(桀桀桀)

再然后 给我们的OLED屏幕设置一下I2C,直接选择I2C模式即可,下方速度可以选择快速模式。

最后为按键选择一个GPIO引脚即可,模式设置为上拉输入模式,这里我选择的是GPIOB11引脚

这样所有的引脚参数都配置完毕了,整体的效果就是这样的 

最后别忘了到Project Manager处勾选为每一个外设单独创建一个.c文件和对应的.h文件,然后使用快捷键Ctrl键+S保存并生成初始化代码!

 

 

三,代码实现 

1,代码思想

在我们小学2年级的时候便学过了,调节呼吸灯的亮度是通过调节PWM的占空比来实现的,但是占空比是什么呢,简单来说就是一个脉冲信号的高电平与低电平的比值,占空比小,相当于电压降低,那么小灯自然而然也就变暗,当占空比增大时,相当于电压升高,小灯就亮了!

而捕获 / 比较寄存器CCR的值与我们设置的自动重装载值ARR的比值便是占空比,也就是说,我们只需要改变CCR的值便可以改变占空比从而实现改变小灯亮度的目的

根据我们的需求可以知道,要通过旋转编码器来操控LED的灯光亮度,那我们可以想到,获取旋转编码器的计数值作为LED灯对应通道的CCR值,这样,我们便将旋转编码器的计数值与小灯的亮度联系在了一起。

再之后就是通过按键达到选择小灯的目的,这就非常简单了,只需要简单将三个小灯的定时器通道序号添加在一个数组中,每次按下按键,将当前操控的定时器通道关闭,同时自加一位,开启下一个定时器通道即可。

 

2,代码实现

将需要使用的头文件声明

#include "oled.h"
#include <stdio.h>

 将需要用到的变量声明

  int counter=0; //用于存储旋转编码器计数值
  char message[20]="",R[20]="",B[20]="",Y[20]="";//用于为OLED屏幕拼接字符串来输出

  int Channel_i=0; //初始为操控Channel_0的LED灯
  uint32_t Channels[3]={TIM_CHANNEL_1,TIM_CHANNEL_2,TIM_CHANNEL_3};//将三个小灯的对应通道加在一个数组中,用于按键的选择

初始化OLED屏幕,并开启旋转编码器及LED对应模式 

  HAL_Delay(20);//延时20ms等待OLED屏幕开机
  OLED_Init();
  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //开启旋转编码器的a,b脚
  HAL_TIM_PWM_Start(&htim3, Channels[Channel_i]);//开启LED的PWM模式,通道初始选择为通道0

 将旋转编码器的计数值存储在counter变量中,并且将计数值限制在0~100中,使其能够与LED灯的占空比对应上

counter=__HAL_TIM_GET_COUNTER(&htim1); //读取旋转编码器的计数值
	  if(counter>60000){                     //保证旋转编码器的值在0~100之间,以便对应LED灯的亮度
		  counter=0;
		  __HAL_TIM_SET_COUNTER(&htim1,0);
	  }
	  else if(counter>100){
		  counter=100;
		  __HAL_TIM_SET_COUNTER(&htim1,100);
	  }

将变量counter的值当做LED灯的CCR值来使用

	  __HAL_TIM_SET_COMPARE(&htim3,Channels[Channel_i],counter); //将旋转编码器输出的数变为LED小灯的占空比,从而操控小灯的亮度

 之后来到按键选择模块

	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)==GPIO_PIN_RESET){      //按下按键来选择旋转编码器控制哪个LED灯
		  HAL_Delay(10);
		  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)==GPIO_PIN_RESET){
			  HAL_TIM_PWM_Stop(&htim3, Channels[Channel_i]);
			  Channel_i=(Channel_i+1)%3;                           //自加后对3取余保证在0~2中做出选择
			  HAL_TIM_PWM_Start(&htim3, Channels[Channel_i]);
		  }
		  while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)==GPIO_PIN_RESET);//等待按键抬起
	  }

最后就是OLED显示功能,这里大家可以直接去调用网上各种大佬的驱动库,然后使用取模软件为我们需要输出的汉字进行取模,需要使用的依旧是sprintf函数,这一部分并不影响功能使用,大家可以按照自己的想法去大胆的操作。

OLED_NewFrame();
sprintf(message,"亮度: %d%%",counter); 
OLED_PrintString(45, 0, message, &font16x16, OLED_COLOR_NORMAL);
OLED_DrawRectangle(13, 25, 101, 16, OLED_COLOR_NORMAL);         //画一个空心长方形
OLED_DrawFilledRectangle(13,26,counter, 15, OLED_COLOR_NORMAL); //画一个进度条
sprintf(R,"红灯");
sprintf(B,"蓝灯");
sprintf(Y,"黄灯");
 if(Channel_i==0){
	OLED_PrintString(15, 0, B, &font16x16, OLED_COLOR_NORMAL);
 }
 else if(Channel_i==1){
    OLED_PrintString(15, 0, Y, &font16x16, OLED_COLOR_NORMAL);
 }
 else{
	  OLED_PrintString(15, 0, R, &font16x16, OLED_COLOR_NORMAL);
	 }

OLED_ShowFrame();
 HAL_Delay(100);

 

3,检查编译下载程序

 点击上方的编译图标,检查代码完整性,之后点击Run将代码烧录,编译下载一气呵成!

 

 

四,硬件连接

硬件连接非常简单,唯一值得注意的就是旋转编码器的连接,上面的VCC和GND直接和面包板的正负极连接,下方的A,B脚与TIM1的1,2通道连接,C脚也是共地即可,按键的一脚接地,另一端与PB11相连,三个LED小灯按照颜色来对应,并且正极接在单片机GPIO口上。

 

 

五,实验现象 

 将程序烧入单片机中,可以观察到最开始从TIM_CHANNEL_0的蓝灯开始控制

 顺时针旋转编码器,蓝灯的亮度逐渐变亮,并且进度条也逐渐增加

按下按键,切换LED灯,并且占空比保持上一LED灯的值,屏幕上的灯的颜色也相应切换。

 实验现象符合预期,实验顺利完成!!!

 

 

六,实验小结

         本次实验与前几期跨度有些大,本来应该是从单独的呼吸灯或者TIM定时器的原理开始分析的,但是博主上周有事出门,加上也有些懈怠了,所以直接大跨步来到了旋转编码器控制呼吸灯,所以和前几篇看起来不是那么的连贯,不过这也是笔记嘛,最近学的确实是这个,就记下了。

        实验现象非常有意思,定时器也是非常实用重要的,可以结合各种外设实现各种各样意想不到的功能,通过本次实验可以发现,HAL库确实比标准库方便许多,居然还有专门的Encoder编码器模式,而且各种初始化的参数,例如预分频数及自动重装值的设置,直接可以设置,不需要调用各种繁琐的初始化函数,方便快捷了许多。本次的知识点不算太多,就是对旋转编码器的认识,对定时器几种参数的配置,还有模式的选择,当然本次并没有涉及到定时器的内部模式,感兴趣的小伙伴可以自行研究,也许博主之后勤快起来了会补上这一部分。

        理工科最重要的就是实践了,希望大家能够看完感兴趣的小项目后可以自己试着操作一下,说不定会有不同的体会哦,说到实践,当然少不了一套好用的STM32开发板套件了,这里我推荐大家上闲鱼,有博主亲手设计焊接的STM32开发板,说不定还能买到博主同款二手开发套件。

 

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐