基於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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章