编码器EC11的理论学习CSDN链接:
3、https://blog.csdn.net/Zach_z/article/details/75095061
在STM32F103上,采用2种方式控制4个编码器和1个主微调编码器
以下代码1:4个编码器中断(单IO)轮询
代码2:微调EC28编码器中断(单IO)轮询+TIM的编码器模式,
头文件:
/******************************************************************************
* Header文件
******************************************************************************/
#ifndef __Drv_EC11_h__
#define __Drv_EC11_h__
/******************************************************************************
* 头文件包含路径
******************************************************************************/
#include "Com_ProjectSetting.h"
#include "Drv_LCD.h"
/******************************************************************************
* 宏定义
******************************************************************************/
#if CVIEW("宏定义")
#define mKnob_LineNumNo 0x00
#define mKnob_LineNum1 0x01
#define mKnob_LineNum2 0x02
#define mKnob_LineNum3 0x03
#define mKnob_LineNum4 0x04
#define Knob_TableRes_Num 0x04
#define mDrv_KnobDlyTmrs_Rcc RCC_APB1ENR_TIM4EN
#define mDrv_KnobDlyTmrs_NvicIrqn TIM4_IRQn
#define mDrv_KnobDlyTmrs_TimTypeDef TIM4
#define mDrv_KnobDlyTmrs_TimItCcx TIM_IT_CC1
#define mDrv_KnobDebounceMsTime 1 //去抖时间
/*硬件连接
* knob1_A: PC12 knob1_B:PC6 //VR5 --line1
* knob2_A: PA8 knob2_B:PC7 //VR1 --line2
* knob3_A: PA2 knob3_B:PC8 //VR7 --line3
* knob4_A: PA3 knob4_B:PC9 //VR8 --line4
*/
#define knob1_A PCin(12)
#define knob1_B PCin(6) //---中断
#define knob2_A PAin(8)
#define knob2_B PCin(7) // ---中断
#define knob3_A PAin(2)
#define knob3_B PCin(8) // ---中断
#define knob4_A PAin(3)
#define knob4_B PCin(9) // ---中断
//#define mknobA_PORT GPIOC|GPIOA
#define mknob1Pin_A GPIO_Pin_12
#define mknob2Pin_A GPIO_Pin_8
#define mknob3Pin_A GPIO_Pin_2
#define mknob4Pin_A GPIO_Pin_3
//B口--中断
#define mknob1PinSource GPIO_PinSource6
#define mknob2PinSource GPIO_PinSource7
#define mknob3PinSource GPIO_PinSource8
#define mknob4PinSource GPIO_PinSource9
#define mknob1Line EXTI_Line6
#define mknob2Line EXTI_Line7
#define mknob3Line EXTI_Line8
#define mknob4Line EXTI_Line9
#define mknobB_PORT GPIOC
#define mknob1Pin_B GPIO_Pin_6
#define mknob2Pin_B GPIO_Pin_7
#define mknob3Pin_B GPIO_Pin_8
#define mknob4Pin_B GPIO_Pin_9
#endif // #if CVIEW("宏定义")
/******************************************************************************
* 枚举定义
******************************************************************************/
#if CVIEW("枚举定义")
typedef enum en_Knob_K1_K4{
Knob_NO= 0, //增加 K0,不发
Knob1_Left,
Knob2_Left,
Knob3_Left,
Knob4_Left,
Knob1_Right,
Knob2_Right,
Knob3_Right,
Knob4_Right,
}E_Knob_K1_K4;
typedef enum en_Knobgroup_ResName{
Knob0= 0, //NULL
Knob1,
Knob2,
Knob3,
Knob4
}E_Knobgroup_ResName;
typedef enum en_miniKnob_Flag{
Knob_noWork= 0,
Knob_Left,
Knob_Right
}E_miniKnob_Flag;
#endif // #if CVIEW("枚举定义")
/******************************************************************************
* 结构体定义
******************************************************************************/
#if CVIEW("结构体定义")
#pragma pack(1)
typedef struct stKnobgroup
{
E_Knobgroup_ResName Knobname;
BOOL WorkFlag;
}T_Knobgroup;
#pragma pack()
#endif // #if CVIEW("结构体定义")
/******************************************************************************
* 外部变量定义
******************************************************************************/
#if CVIEW("外部变量定义")
#endif // #if CVIEW("外部变量定义")
/******************************************************************************
* 外部函数声明
******************************************************************************/
#if CVIEW("外部函数声明")
extern void Drv_Knob_SetKnobgroup_idx(UINT8 ucIdx);
extern void Drv_KnobGpioIsr(void);
extern void Drv_KnobDelayTimersIsr(void);
extern BOOL Drv_KnobProc(void);
extern void Drv_Knob_Init(void);
extern void Drv_Mini_Knob_Init(void);
extern void MiniKnob_speed_calculate(void);
extern BOOL Task_Knob_ScanProc(void);
extern BOOL Task_MiniKnob_ScanProc(void);
#endif // #if CVIEW("外部函数声明")
#endif // #ifndef __Drv_Led_h__
源文件
/******************************************************************************
* Source文件
******************************************************************************/
/******************************************************************************
* 头文件包含路径
******************************************************************************/
#include "Drv_EC11.h"
#include "Com_CommonSource.h"
#include "usb_endp.h"
#include "Drv_Led.h"
/******************************************************************************
* 宏定义
******************************************************************************/
#if CVIEW("宏定义")
#endif // #if CVIEW("宏定义")
/******************************************************************************
* 枚举定义
******************************************************************************/
#if CVIEW("枚举定义")
#endif // #if CVIEW("枚举定义")
/******************************************************************************
* 共用体定义
******************************************************************************/
#if CVIEW("共用体定义")
#pragma pack(1)
#pragma pack()
#endif // #if CVIEW("共用体定义")
/******************************************************************************
* 结构体定义
******************************************************************************/
#if CVIEW("结构体定义")
#pragma pack(1)
// 定义消抖定时器参数结构体
typedef struct stKnobDelayTimers{
BOOL bIsRunning; // 定时器启动运行标志位
BOOL bDebounceDone; // 消抖完成标志位
UINT32 ulDelayMs; // 消抖定时时间
UINT32 ulRuningCnt; // 运行计数器
}T_KnobDlyTmr;
#pragma pack()
#endif // #if CVIEW("结构体定义")
/******************************************************************************
* 内部变量定义
******************************************************************************/
#if CVIEW("内部变量定义")
int A;
int B;
UINT16 Mini_Knob_Count=0;
int AACount=0;
T_KnobDlyTmr tKnobDlyTmr[5]; // 内部消抖定时器参数
volatile BOOL Knob_pressed_flag=FALSE;
E_miniKnob_Flag MiniKnob_TIM2IRQ_Flag=Knob_noWork;
T_Knobgroup Knobgroup_idx_tbl[]={
{Knob0, TRUE}, //初始化
{Knob1, FALSE},
{Knob2, FALSE},
{Knob3, FALSE},
{Knob4, FALSE},
};
UINT16 KnobA_TableRes[Knob_TableRes_Num+1]={mKnob_LineNumNo,mknob1Pin_A,mknob2Pin_A,mknob3Pin_A,mknob4Pin_A};
UINT16 KnobB_TableRes[Knob_TableRes_Num+1]={mKnob_LineNumNo,mknob1Pin_B,mknob2Pin_B,mknob3Pin_B,mknob4Pin_B};
E_Knob_K1_K4 Knob_ValueTable[Knob_TableRes_Num*2+1]={Knob_NO,Knob4_Left,Knob2_Left,Knob1_Left,Knob3_Left,
Knob4_Right,Knob2_Right,Knob1_Right,Knob3_Right};
E_Knob_K1_K4 Knob_value=Knob_NO;
BOOL Knob_NO_WorkFlag=TRUE;
#endif // #if CVIEW("内部变量定义")
/******************************************************************************
* 外部变量定义
******************************************************************************/
#if CVIEW("外部变量定义")
static UINT8 Knobgroup_idx=mKnob_LineNumNo;
volatile static BOOL Knob_Timer_isWorking = FALSE;
#endif // #if CVIEW("外部变量定义")
/******************************************************************************
* 内部函数声明
******************************************************************************/
#if CVIEW("内部函数申明")
#endif // #if CVIEW("内部函数声明")
/******************************************************************************
* 函数实现
******************************************************************************/
#if CVIEW("函数实现")
void Drv_Knob_SetKnobgroup_idx(UINT8 ucIdx)
{
Knobgroup_idx_tbl[ucIdx].WorkFlag = TRUE;
Knob_NO_WorkFlag = FALSE;
}
void Drv_KnobDelayTimers_1MsInit(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能Timer时钟 */
RCC_APB1PeriphClockCmd(mDrv_KnobDlyTmrs_Rcc, ENABLE);
/* 使能Timer的全局中断。次高优先级*/
NVIC_InitStructure.NVIC_IRQChannel = mDrv_KnobDlyTmrs_NvicIrqn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 定时器基础配置 */
TIM_TimeBaseStructure.TIM_Period = 1000;
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(mDrv_KnobDlyTmrs_TimTypeDef, &TIM_TimeBaseStructure);
/* 使能Timer自中断 */
TIM_ITConfig(mDrv_KnobDlyTmrs_TimTypeDef, mDrv_KnobDlyTmrs_TimItCcx, DISABLE);
/* 使能Timer */
TIM_Cmd(mDrv_KnobDlyTmrs_TimTypeDef, DISABLE);
Knob_Timer_isWorking = FALSE;
}
void Drv_KnobDelayTimers_Start(UINT32 ulMs)
{
if(FALSE == Knob_Timer_isWorking){
Knob_Timer_isWorking = TRUE;
TIM_ITConfig(mDrv_KnobDlyTmrs_TimTypeDef, mDrv_KnobDlyTmrs_TimItCcx, ENABLE);//开启timer
TIM_Cmd(mDrv_KnobDlyTmrs_TimTypeDef, ENABLE);
}
if(FALSE == tKnobDlyTmr[Knobgroup_idx].bIsRunning){ //更新状态
tKnobDlyTmr[Knobgroup_idx].bIsRunning = TRUE;
tKnobDlyTmr[Knobgroup_idx].bDebounceDone = FALSE;
tKnobDlyTmr[Knobgroup_idx].ulDelayMs = ulMs;
tKnobDlyTmr[Knobgroup_idx].ulRuningCnt = 0;
}
}
void Drv_KnobDelayTimersIsr(void)
{
if(TRUE == tKnobDlyTmr[Knobgroup_idx].bIsRunning)
{
if(FALSE == tKnobDlyTmr[Knobgroup_idx].bDebounceDone)
{
tKnobDlyTmr[Knobgroup_idx].ulRuningCnt++;
if(tKnobDlyTmr[Knobgroup_idx].ulRuningCnt >= tKnobDlyTmr[Knobgroup_idx].ulDelayMs)
{
tKnobDlyTmr[Knobgroup_idx].bIsRunning = FALSE;
tKnobDlyTmr[Knobgroup_idx].bDebounceDone = TRUE; //消抖标志位
}
}
}
if(TRUE == Knob_Timer_isWorking &&
FALSE == tKnobDlyTmr[1].bIsRunning &&
FALSE == tKnobDlyTmr[2].bIsRunning &&
FALSE == tKnobDlyTmr[3].bIsRunning &&
FALSE == tKnobDlyTmr[4].bIsRunning)
{
Knob_Timer_isWorking = FALSE;
TIM_ITConfig(mDrv_KnobDlyTmrs_TimTypeDef, mDrv_KnobDlyTmrs_TimItCcx, DISABLE);//关闭timer
TIM_Cmd(mDrv_KnobDlyTmrs_TimTypeDef, DISABLE);
}
}
void Drv_KnobGpioIsr(void)
{
Drv_KnobDelayTimers_Start(mDrv_KnobDebounceMsTime);
}
void knobAB_init(void)
{
//A口初始化
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStructure.GPIO_Pin = mknob1Pin_A|mknob2Pin_A|mknob3Pin_A|mknob4Pin_A;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//B口(中断)初始化
GPIO_InitStructure.GPIO_Pin = mknob1Pin_B|mknob2Pin_B|mknob3Pin_B|mknob4Pin_B;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(mknobB_PORT, &GPIO_InitStructure);
}
//外部中断初始化函数
void EXTIXA_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
//EXTI_DeInit();
//中断线以及中断初始化配置
EXTI_ClearITPendingBit(EXTI_Line6);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,mknob1PinSource);
EXTI_ClearITPendingBit(EXTI_Line7);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,mknob2PinSource);
EXTI_ClearITPendingBit(EXTI_Line8);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,mknob3PinSource);
EXTI_ClearITPendingBit(EXTI_Line9);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,mknob4PinSource);
EXTI_InitStructure.EXTI_Line=mknob1Line|mknob2Line|mknob3Line|mknob4Line;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发,上下
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
}
void Drv_Knob_Init(void)
{
knobAB_init();
EXTIXA_Init();
//Drv_KnobDelayTimers_1MsInit();
}
void Knob_scan(UINT8 idx)
{
if(idx==1)
{
if(GPIO_ReadInputDataBit(GPIOC,KnobB_TableRes[1]) == 1)//读取中断线
{
if(GPIO_ReadInputDataBit(GPIOC,KnobA_TableRes[1]) == 1)//PC12
{
Knob_value=Knob_ValueTable[1]; //左边
}
else
{
Knob_value=Knob_ValueTable[1+4];//右边
}
}
}
else
{
if(GPIO_ReadInputDataBit(GPIOC,KnobB_TableRes[idx]) == 1)//读取中断线
{
if(GPIO_ReadInputDataBit(GPIOA,KnobA_TableRes[idx]) == 1)
{
Knob_value=Knob_ValueTable[idx]; //左边
}
else
{
Knob_value=Knob_ValueTable[idx+4];//右边
}
}
}
USB_endpoint3_sendKnob(Knob_value,ON);
//printf("----Knob_value:%d\r\n",Knob_value);
}
void Set_Knobgroup_idx_tbl(void)
{
Knobgroup_idx_tbl[1].WorkFlag = FALSE;
Knobgroup_idx_tbl[2].WorkFlag = FALSE;
Knobgroup_idx_tbl[3].WorkFlag = FALSE;
Knobgroup_idx_tbl[4].WorkFlag = FALSE;
}
BOOL Task_Knob_ScanProc(void)
{
BOOL Knob_Move=FALSE;
//循环判断Knobgroup_idx_tbl-WorkFlag标志位
if(Knob_NO_WorkFlag == TRUE)
{
//do nothing
}
else
{
for(UINT8 i=1;i<5;i++)
{
//
if(Knobgroup_idx_tbl[i].WorkFlag == TRUE)
{
//printf("1-Knobgroup_idx_tbl:%d\r\n",i);
//执行映射
Knob_scan(i);
}
}
//执行后还原无knob动作状态;
Knob_NO_WorkFlag = TRUE;
Set_Knobgroup_idx_tbl();
Knob_Move = TRUE;
//Drv_Led_Blink(300);
}
return Knob_Move;
}
/************************主微调带卡点20转脉冲EC28编码器(增量式)******************************/
/*硬件连接:A相位----PA0,B相位----PA1,AB相差90相位,时间
*软件定时器:TIM2
*定时器模式:在TI1和TI2上编码器滤波--消除毛刺
*硬件性能:带卡点(卡点振荡时间:<3ms),突变时间(<2ms),20个脉冲数,360/20=18度
*/
void Drv_Mini_Knob_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM2_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
TIM_TimeBaseStructure.TIM_Period = 0XFFFF;
TIM_TimeBaseStructure.TIM_Prescaler =0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM2_ICInitStructure.TIM_ICFilter = 0x06;//输入滤波器
TIM_ICInit(TIM2, &TIM2_ICInitStructure);
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM2_ICInitStructure.TIM_ICFilter = 0x06;
TIM_ICInit(TIM2, &TIM2_ICInitStructure);
//TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,
// TIM_ICPolarity_Rising,
// TIM_ICPolarity_Rising);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//允许CC1IE捕获中断
TIM_ITConfig(TIM2,TIM_IT_CC2|TIM_IT_CC1,ENABLE);
TIM_Cmd(TIM2,ENABLE );
}
void Drv_MiniKnob_Set_Flag(E_miniKnob_Flag FlagStatus)
{
MiniKnob_TIM2IRQ_Flag = FlagStatus;
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1|TIM_IT_CC2) != RESET)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET&&PAin(1)==1)
{
Drv_MiniKnob_Set_Flag(Knob_Left);
A=A+1;
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET&&PAin(1)==0)
{
Drv_MiniKnob_Set_Flag(Knob_Right);
B=B+1;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_CC2);
}
}
BOOL Task_MiniKnob_ScanProc(void)
{
BOOL MiniKnob_Move=FALSE;
if(MiniKnob_TIM2IRQ_Flag !=Knob_noWork)
{
if(MiniKnob_TIM2IRQ_Flag ==Knob_Left)
{
Drv_Led_L();
}
else if(MiniKnob_TIM2IRQ_Flag ==Knob_Right)
{
Drv_Led_R();
}
//USB发送
USB_endpoint3_sendminiKnob(MiniKnob_TIM2IRQ_Flag,ON);
MiniKnob_TIM2IRQ_Flag =Knob_noWork;
MiniKnob_Move=TRUE;
}
return MiniKnob_Move;
}
void MiniKnob_speed_calculate(void)
{
Mini_Knob_Count=TIM_GetCounter(TIM2);//- 0x7fff;
if(Mini_Knob_Count !=0)
{
printf("Mini_Knob_Count:%d\r\n",Mini_Knob_Count);
}
//重置编码器计数值
TIM_SetCounter(TIM2, 0x7fff);
}
#endif // #if CVIEW("函数实现")
外部中断文件:
/*****************编码器中断***********************************/
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(mknob1Line) != RESET){ //6
//printf("----mknob1Line\r\n");
Drv_Knob_SetKnobgroup_idx(mKnob_LineNum1);
EXTI_ClearITPendingBit(mknob1Line);
}
else if(EXTI_GetITStatus(mknob2Line) != RESET){ //7
//printf("----mknob2Line\r\n");
Drv_Knob_SetKnobgroup_idx(mKnob_LineNum2);
EXTI_ClearITPendingBit(mknob2Line);
}
else if(EXTI_GetITStatus(mknob3Line) != RESET){ //8
//printf("----mknob3Line\r\n");
Drv_Knob_SetKnobgroup_idx(mKnob_LineNum3);
EXTI_ClearITPendingBit(mknob3Line);
}
else if(EXTI_GetITStatus(mknob4Line) != RESET){ //9
//printf("----mknob4Line\r\n");
Drv_Knob_SetKnobgroup_idx(mKnob_LineNum4);
EXTI_ClearITPendingBit(mknob4Line);
}
}
把以下两个TASK任务放在while轮询或者系统任务;
BOOL Task_MiniKnob_ScanProc(void);
BOOL Task_Knob_ScanProc(void);
经过实测,没有发生丢点;