基于stm32单片机的Grayhill编码器/开关软件设计

1、初识编码器,像示波器的旋转按钮,可左旋右旋,还可以按下,我们使用的是Grayhill编码器,如下图所示:

从图中可以看出,该编码器一共有6个IO,从1-6分别为GND,GND,C,B,A,VCC,。

其中VCC和GND接3.3V和GND,A、B对应旋转时电平的跳变IO,C对应按下时电平的跳变IO。

 

(1) 硬件电路设计上,为了方便代码编写与理解,最好把编码器的A、B接到单片机相邻的GPIO中,即使用同一个中断处理函数,比如本设计A、B分别接到PB12和PB11。C接任一个GPIO,当成中断使用。

(2) 顺时针和逆时针旋转编码器时,慢慢旋转一个单位(手指头会有明显旋转到位的感觉),用万用表测量A、B对应的IO电平,并记录下来。旋转一圈为止。如下表是我使用的编码器,在顺、逆时针旋转一圈时所记录下的IO电平(旋4次即满一圈):

(实际使用中,旋转了24小格才满一圈,这里只记录方法,不记录确切的值,需要自己测量)

旋转前

旋1/4圈

旋2/4圈

旋3/4圈

旋4/4圈

顺时针

A电平

0

1

1

0

0

B电平

0

0

1

1

0

逆时针

A电平

0

0

1

1

0

B电平

0

1

1

0

0

                                    表1         顺、逆时针旋转编码器时A、B对应IO电平

2、A、B对应的IO初始化成中断双边沿触发方式,如下所示:

void KeyA_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

EXTI_InitTypeDef EXTI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

/* Enable the EXTI_PB1 Clock */

RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB , ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //浮空输入   

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);   //配置PB12管脚为外部中断线路用

  

EXTI_InitStructure.EXTI_Line = EXTI_Line12;      //配置为外部中断线2

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;        //配置为中断请求

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;      //输入线路下降沿为中断请求

EXTI_InitStructure.EXTI_LineCmd = ENABLE;   //使能中断

   EXTI_Init(&EXTI_InitStructure);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //NVIC_Group:先占优先级2位,从优先级2位  

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;   //配置为外部中断2中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //先占优先级为1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;   //从优先级为2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      //使能中断通道

NVIC_Init(&NVIC_InitStructure);

}

void KeyB_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

EXTI_InitTypeDef EXTI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

/* Enable the EXTI_PB1 Clock */

RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB , ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    //浮空输入   

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource11);   //配置PB11管脚为外部中断线路用

  

EXTI_InitStructure.EXTI_Line = EXTI_Line11;      //配置为外部中断线11

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;        //配置为中断请求

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;      //输入线路下降沿为中断请求

EXTI_InitStructure.EXTI_LineCmd = ENABLE;   //使能中断

   EXTI_Init(&EXTI_InitStructure);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //NVIC_Group:先占优先级2位,从优先级2位  

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;   //配置为外部中断2中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //先占优先级为1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;   //从优先级为2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      //使能中断通道

NVIC_Init(&NVIC_InitStructure);

}

3、根据表1设计的中断处理函数如下所示,使用TurningDir变量来标识检测到的旋转方向,TurnLeft表示逆时针(对应数值可以理解为减),TurnRight表示顺时针(对应数值可以理解为加):

typedef enum {TurnNone=0,TurnRight , TurnLeft}TurnDir ;

TurnDir TurningDir=TurnNone;//default turning dir = none

void EXTI15_10_IRQHandler(void)

{

u8 KeyAValue=0;

u8 KeyBValue=0;

 

//key left & right  

if (EXTI_GetITStatus(EXTI_Line12) != RESET)

{

EXTI_ClearITPendingBit(EXTI_Line12);   

  KeyAValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12);

KeyBValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);

// printf("AB=%d,%d\r\n",KeyAValue,KeyBValue);

 

 

if(KeyAValue==1)

{

if(KeyBValue==0)

{

TurningDir=TurnLeft;

}

else

{

TurningDir=TurnRight;

}

}

else if(KeyAValue==0)

{

if(KeyBValue==1)

{

TurningDir=TurnLeft;

}

else

{

TurningDir=TurnRight;

}

}

}

 

if (EXTI_GetITStatus(EXTI_Line11) != RESET)

{

EXTI_ClearITPendingBit(EXTI_Line11);

 

  KeyAValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12);

KeyBValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);

if(KeyBValue==1)

{

if(KeyAValue==0)

{

TurningDir=TurnRight;

}

else

{

TurningDir=TurnLeft;

}

}

else if(KeyBValue==0)

{

if(KeyAValue==1)

{

TurningDir=TurnRight;

}

else

{

TurningDir=TurnLeft;

}

}

  }

}

 

编码器旋钮的按下功能,即C,可以把它当成一个普通的按键,软件设置成上拉输入,按下时为低电平,弹起时为高,同样也使用中断操作,这里就不再描述。

 

至此,编码器软件设计完成。经过实测,能完美检测左旋右旋。

如果你有什么问题,欢迎留言。

我们还建了一个QQ群,可以讨论相关内容,群号是:597254771

 

发布了25 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/masterbee/article/details/88676410