在开始教学之前我们需要准备旋转编码器一个,LED灯一个、OLED屏幕一个和一个stm32f103c8t6最小系统板一个,我们的大致流程是先进行连线然后配置旋转编码器和PWM信号,最后在主函数里面写相关的逻辑代码,目前看来这个流程还是比较简单的。

首先是连线,我们需要把旋转编码器的GND和VCC接到相应的部分上,GND 接地, VCC 接电源,接着把PB0接到旋转编码器的A相上,把B相接到PB1上,然后LED 灯接到PA6上,OLED 接到相应的部分,这样最基本的接线也就完成了。

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向类型:机械触点式/霍尔传感器式/光栅式

具体的电路图如上图所示,我们这主要用旋转编码器的A相和B相。

配置旋转编码器

大致的配置思路是,因为旋转编码器产生的旋转信号是一个外部中断,因此这里我们要用到两个外部中断分别控制旋转编码器的正转和反转,然后就是GPIO的初始化,大致流程就是这样。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

uint8_t   b=0,i=0;
int16_t EN_num;
void EN_INIT()
{

  
		//开启GPIOB的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
		
		//开启复用功能,因为我们需要使用到外部中断因此在使用外部中断的时候都需要打开复用功能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

    GPIO_InitTypeDef  GPIO_INIT; //GPIO的初始化
    EXTI_InitTypeDef  EXTI_INIT; //EXTI外部中断的初始化
    NVIC_InitTypeDef  NVIC_INIT; //中断嵌套向量的初始化


    GPIO_INIT.GPIO_Mode=GPIO_Mode_IPU;
    GPIO_INIT.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
    GPIO_INIT.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(GPIOB,&GPIO_INIT);

	
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);//GPIO具体引脚与外部中断进行绑定
		GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
		
		
		//配置外部中断
    EXTI_INIT.EXTI_Line=EXTI_Line0|EXTI_Line1;
    EXTI_INIT.EXTI_LineCmd=ENABLE;
    EXTI_INIT.EXTI_Mode=EXTI_Mode_Interrupt;
    EXTI_INIT.EXTI_Trigger=EXTI_Trigger_Rising_Falling;

    

    EXTI_Init(&EXTI_INIT);
    

   NVIC_SetPriorityGrouping(2);

   NVIC_INIT.NVIC_IRQChannel=EXTI0_IRQn;
   NVIC_INIT.NVIC_IRQChannelCmd=ENABLE;
   NVIC_INIT.NVIC_IRQChannelPreemptionPriority=1;
   NVIC_INIT.NVIC_IRQChannelSubPriority=1;
	  NVIC_Init(&NVIC_INIT);
	
	 
	 
	 
	 
	 
   NVIC_INIT.NVIC_IRQChannel=EXTI1_IRQn;
   NVIC_INIT.NVIC_IRQChannelCmd=ENABLE;
   NVIC_INIT.NVIC_IRQChannelPreemptionPriority=2;
   NVIC_INIT.NVIC_IRQChannelSubPriority=1;

   NVIC_Init(&NVIC_INIT);
	

   

}


int GETencoder()
{
   int16_t  temp;
   temp=EN_num;
   EN_num=0;
  

  return  temp;



}

void  EXTI0_IRQHandler()//正转的中断函数
{
   

		if(EXTI_GetITStatus(EXTI_Line0)==SET)
		{
		
			
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
		{
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)		//PB0的下降沿触发中断,此时检测另一相PB1的电平,目的是判断旋转方向
			{
				EN_num++;					//此方向定义为反转,计数变量自减
			}
		}
		
		}

	
	
	EXTI_ClearITPendingBit(EXTI_Line0);	



}



void  EXTI1_IRQHandler()
{



	
	if(EXTI_GetITStatus(EXTI_Line1)==SET)
	{
		
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)		//PB0的下降沿触发中断,此时检测另一相PB1的电平,目的是判断旋转方向
			{
				EN_num --;					//此方向定义为反转,计数变量自减
			}
		
	
	}

	EXTI_ClearITPendingBit(EXTI_Line1);	




}
	}


配置PWM信号

PWM (脉冲宽度调制)是利用微处理器的数字输出,来对模拟电路进行控制的一种非常有效的技术,通过对一系列脉冲的宽度进行调制,来等效的获得所需要的波形(含形状和幅值),即通过改变导通时间占总时间的比例,也就是占空比,达到调整电压和频率的目的。简单来说就是我们可以调节某个引脚在电路中占用高电平的宽度,因此我们需要使用到定时器的输出比较功能,基本就是初始化GPIO,初始化TIM的时基单元,初始化输出比较,大概就是这样。

#include "Device/Include/stm32f10x.h"   // Device header

void PWM_INIT()
{
	
	
	//开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//开启TIM3的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	
	//初始化GPIO口
	GPIO_InitTypeDef  GPIO_INIT;
	
  GPIO_INIT.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_INIT.GPIO_Pin=GPIO_Pin_6;
	GPIO_INIT.GPIO_Speed=GPIO_Speed_50MHz;
   
	
	GPIO_Init(GPIOA,&GPIO_INIT);
	
	//初始化时基单元
	TIM_TimeBaseInitTypeDef   TIM_INIT;
	
	TIM_InternalClockConfig(TIM3);
	TIM_INIT.TIM_ClockDivision=TIM_CKD_DIV2;
	TIM_INIT.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_INIT.TIM_Period=7199;
	TIM_INIT.TIM_Prescaler=9;
	TIM_INIT.TIM_RepetitionCounter=DISABLE;
	
	TIM_TimeBaseInit(TIM3,&TIM_INIT);
	
	//初始化输出比较
	TIM_OCInitTypeDef   TIM_OCINIT;
	TIM_OCStructInit(&TIM_OCINIT);
	
	
	TIM_OCINIT.TIM_OCMode=TIM_OCMode_PWM1;
	
	TIM_OCINIT.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCINIT.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCINIT.TIM_Pulse=0;
	
  TIM_OC1Init(TIM3,&TIM_OCINIT);
	//使能定时器
	TIM_Cmd(TIM3,ENABLE);
	

}

void  PWM_setcomper(int Data)
{

   TIM_SetCompare1(TIM3,Data);

}







配置完以上两个后我们就差不多配置完成了,接下来只需要在主函数中使用和写基本的逻辑函数即可。

#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "ENcoder.h"
#include "PWM.h"


int main(void)
{
	EN_INIT();
	OLED_Init();
  PWM_INIT();
	int num=GETencoder();
	
	uint16_t  light[]={0,1000,2500,4000,5500,7199};
  uint16_t  flag=0;//用于区分转动的区间的标志位
	 PWM_setcomper(light[flag]);//初始化默认为不亮


	while(1)
	{
		

		
		   num = GETencoder();  // 读取当前EN_num
				int data=num;
		
		   if(data!=0)
			 {
			    if(data>0)
					{
						if(flag<5)
						{
							flag++;
				PWM_setcomper(light[flag]);
						  
        OLED_ShowNum(1, 2, flag, 3);
						
						}
		 
					
					}
					else if(data<0)
					{
					if(flag>0)
					{
					
					flag--;
				PWM_setcomper(light[flag]);
						  
        OLED_ShowNum(1, 2, flag, 3); 
					
					}

					
					}
            
       switch(flag)
			 {
			 
				 case 0: OLED_ShowString(2,2,"LED_ON"); 	PWM_setcomper(light[0]); break;
				 case 1:	OLED_ShowString(2,2,"LED_1"); break;
				 case 2:	OLED_ShowString(2,2,"LED_2"); break;
				 case 3:	OLED_ShowString(2,2,"LED_3"); break;
				 case 4:	OLED_ShowString(2,2,"LED_4"); break;
				 case 5:	OLED_ShowString(2,2,"LED_5"); break;
			
			 
			 
			 
			 
			 }
					
		  
			}
	}
}

以上就是通过旋转编码器控制PWM 驱动LED的亮暗的程度,如果有错误的地方还请广大网友积极指正,谢谢大家的观看!!!!

Logo

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

更多推荐