【シングルチップマイコン】STM32シングルチップマイコンによるロータリーエンコーダ、TIMタイマエンコーダモードキャプチャ、プログラムの読み取り

ロータリーエンコーダの紹介

簡単に言うと、ロータリーエンコーダは2つのPWMを出力し、位相で回転方向が分かり、パルス数で回転角度が分かります。一般に、1 回転あたりのパルス数は固定されています。
ロータリー エンコーダはモーターや角度センサーで広く使用されており、STM32 タイマーはこれら 2 つの波形に直接アクセスして情報を取得できます。

ここに画像の説明を挿入
最初の 2 つのピン (グランドと Vcc) はエンコーダに電力を供給するために使用され、ここでは 3.3V 電源を使用します。エンコーダーにはノブを時計回りと反時計回りに回すだけでなく、内部のノブを押すと押されるスイッチ(アクティブ ロー)があります。このスイッチからの信号は、ピン 3 (スイッチ) を通じて取得されます。最後に、出力ピンが 2 つあります。

ここに画像の説明を挿入

メインプログラムロジック直接検出

メインプログラムに遅延を付加しないでください。遅延を付加すると、立ち下がりエッジが検出できない可能性があります。

//ロータリーエンコーダ
//CLK–PA0
//DT—PA1
//SW—PA2

3.3V電源。


#include "sys.h"
#include "usart.h"

//旋转编码器
//CLK--PA0
//DT---PA1
//SW---PA2
#define CLK_in  PAin(0)
#define DT_in   PAin(1)
#define SW_in  PAin(2)

u32 encoder_cnt = 100000;//旋转脉冲计数
u8 direction = 0;//旋转方向 1正传

u8 dt_high_flag = 0;

void rotary_encoder_Init(void) {
    
    
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);                          /* 使能时钟 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;            /* 设置成上拉输入 */
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO口速度为50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);                     //根据设定参数初始化PC13
}


int main(void) {
    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
    delay_init();                                                   /* 延时函数初始化 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
    delay_ms(500);                                                /* 等待稳定 */
    uart_init(115200);

    rotary_encoder_Init();

    while (1) {
    
    
        if (SW_in == 0) {
    
    
            delay_ms(10);
            if (SW_in == 0) {
    
    
                printf("SW_in=0\r\n");
                while (SW_in == 0);
            }
        }

        //DT_in是下降沿的时候,如果CLK_in是高电平,那么就是正转,如果CLK_in是低电平,那么就是反转
        if (DT_in == 1 && dt_high_flag == 0) {
    
    
            dt_high_flag = 1;
        }
        if (DT_in == 0 && dt_high_flag == 1) {
    
    
            dt_high_flag = 0;
            if (CLK_in == 1) {
    
    
                direction = 0;
            } else {
    
    
                direction = 1;
            }
            if (direction == 1) {
    
    
                encoder_cnt++;
            } else {
    
    
                encoder_cnt--;
            }
            printf("direction=%d\r\n", (int) direction);
            printf("encoder_cnt=%d\r\n", encoder_cnt);
        }
				

    }
}



時計回りに 1 回回すとある程度の効果が得られ、ノブには独特の感触があります。目盛を時計回りに回すと 1 が加算され、反時計回りに回すと 1 が減ります。

direction=1
encoder_cnt=100001
direction=1
encoder_cnt=100002
direction=1
encoder_cnt=100003
direction=1
encoder_cnt=100004
direction=1
encoder_cnt=100005
direction=1
encoder_cnt=100006
direction=1
encoder_cnt=100007
direction=1
encoder_cnt=100008
direction=1
encoder_cnt=100009
direction=0
encoder_cnt=100008
direction=1
encoder_cnt=100009
direction=1
encoder_cnt=100010
direction=1
encoder_cnt=100011
direction=1
encoder_cnt=100012
direction=1
encoder_cnt=100013
direction=1
encoder_cnt=100014
direction=1
encoder_cnt=100015
direction=1
encoder_cnt=100016
direction=1
encoder_cnt=100017
direction=1
encoder_cnt=100018
direction=1
encoder_cnt=100019
direction=1
encoder_cnt=100020

外部割り込みによる立ち下がりエッジ検出

DT 入力を立ち下がりエッジによってトリガーされる外部割り込みとして設定すると、明らかにはるかに使いやすくなります。


#include "sys.h"
#include "usart.h"

//旋转编码器
//CLK--PA0
//DT---PA1
//SW---PA2
#define CLK_in  PAin(0)
#define DT_in   PAin(1)
#define SW_in  PAin(2)

u32 encoder_cnt = 100000;//旋转脉冲计数
u8 direction = 0;//旋转方向 1正传

u8 dt_high_flag = 0;


void rotary_encoder_Init(void) {
    
    
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
		GPIO_InitTypeDef GPIO_InitStructure;
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);                           /* 使能时钟 */
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);                       /* 关闭JTAG功能 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);                          /* 使能时钟 */

    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;            /* 设置成上拉输入 */
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO口速度为50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //将DT_in PAin(1)设置为外部中断,下降沿触发
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
    EXTI_InitStructure.EXTI_Line = EXTI_Line1;                /* 外部中断线1 */
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;       /* 设置为中断请求 */
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;   /* 下降沿触发 */
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                 /* 使能中断 */
    EXTI_Init(&EXTI_InitStructure);                           /* 配置 */

    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;          /* 外部中断1 */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;   /* 抢占优先级2 */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;          /* 子优先级2 */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                /* 使能中断 */
    NVIC_Init(&NVIC_InitStructure);                                /* 配置 */

}
void EXTI1_IRQHandler(void) {
    
    
    if (CLK_in == 1) {
    
    
        direction = 0;
    } else {
    
    
        direction = 1;
    }
    if (direction == 1) {
    
    
        encoder_cnt++;
    } else {
    
    
        encoder_cnt--;
    }
    printf("direction=%d\r\n", (int) direction);
    printf("encoder_cnt=%d\r\n", encoder_cnt);
    EXTI_ClearITPendingBit(EXTI_Line1);                         /* 清除LINE1上的中断标志位 */
}


int main(void) {
    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
    delay_init();                                                   /* 延时函数初始化 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
    delay_ms(500);                                                /* 等待稳定 */
    uart_init(115200);

    rotary_encoder_Init();

    while (1) {
    
    
        if (SW_in == 0) {
    
    
            delay_ms(10);
            if (SW_in == 0) {
    
    
                printf("SW_in=0\r\n");
                while (SW_in == 0);
            }
        }

    }
}



もちろん、ライブラリ ファイルを忘れずに追加する必要があります。
ここに画像の説明を挿入

ロータリーエンコーダのタイマーダイレクトデコード

次の図はタイマー関連のピンです。

ここに画像の説明を挿入

STM32 中国語リファレンスマニュアル V10.pdf

通常のタイマ TIM2~TIM5 には次のような機能があります。
ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

タイマーのエンコーダーモード

次のように構成すると、この図は非常に重要になります。

TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式1

TIM_EncoderMode_TI1 はエンコード モード、TIM_ICPolarity_Rising および TIM_ICPolarity_Rising は信号キャプチャ エッジの選択です。

この図は、エンコーダが同期対象の AB 位相を受信した場合にのみカウントし、グリッチがある場合はカウントしないことを示しています。

また、エンコーダが時計回りと反時計回りに回転すると、それに応じてカウンタが増加または減少することもわかります。

ここに画像の説明を挿入

TIM2タイマエンコーダプログラム

ここに画像の説明を挿入

#include "sys.h"
#include "usart.h"

//旋转编码器
//CLK--PA0
//DT---PA1
#define CLK_in  PAin(0)
#define DT_in   PAin(1)

/**************************************************************************
函数功能:把TIM2初始化为编码器接口模式
**************************************************************************/
void Encoder_Init_TIM2(u16 arr, u16 psc) {
    
    
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能TIM4时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;       //选择你要设置的IO口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //设置传输速率
    GPIO_Init(GPIOA, &GPIO_InitStructure);          /* 初始化GPIO */

    TIM_TimeBaseStructure.TIM_Period = arr;   //自动装载值
    TIM_TimeBaseStructure.TIM_Prescaler = psc; //分频系数
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1
    TIM_ICInitStructure.TIM_ICFilter = 0x03;  //滤波
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //分频系数
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA0直接映射到TI1
    TIM_ICInit(TIM2, &TIM_ICInitStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //通道1
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA1直接映射到TI2
    TIM_ICInit(TIM2, &TIM_ICInitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);
		
		TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式1
		//TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
    TIM_ICStructInit(&TIM_ICInitStructure); //将结构体中的内容缺省输入
    TIM_ICInitStructure.TIM_ICFilter = 10;
    TIM_ICInit(TIM2, &TIM_ICInitStructure);
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//运行更新中断

    TIM_SetCounter(TIM2, 10000);//初始化计数器初值

    TIM_Cmd(TIM2, ENABLE); //使能定时器

}


// 计数超过arr就会产生溢出中断
// 也可以把NVIC_Init(&NVIC_InitStructure);注释掉就不要开启中断
void TIM2_IRQHandler(void) {
    
    
    if (TIM2->SR & 0X0001)//溢出中断
    {
    
    
        printf("interrupt\r\n");
    }
    TIM2->SR &= ~(1 << 0);//清除中断标志位
}


short Read_Encoder(u8 TIMX) {
    
    
    unsigned Encoder_TIM;
    switch (TIMX) {
    
    
        case 2:
            Encoder_TIM = (short) TIM2->CNT;
            TIM2->CNT = 0;
            break;
        case 3:
            Encoder_TIM = (short) TIM3->CNT;
            TIM3->CNT = 0;
            break;
        case 4:
            Encoder_TIM = (short) TIM4->CNT;
            break;
        default:
            Encoder_TIM = 0;
    }
    return Encoder_TIM;
}


int main(void) {
    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
    delay_init();                                                   /* 延时函数初始化 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
    delay_ms(500);                                                /* 等待稳定 */
    uart_init(115200);

    Encoder_Init_TIM2(0xffff, 0); //初始化TIM2为编码器接口模式

    while (1) {
    
    
        printf("%d \r\n", (int) TIM_GetCounter(TIM2));

    }
}	



エンコーダーを回転させてカウンターの変化を確認します。
ここに画像の説明を挿入

TIM3タイマーエンコーダプログラム

同様にプログラムを書くことができます。

ここに画像の説明を挿入

#include "sys.h"
#include "usart.h"

//旋转编码器
//CLK--PA6
//DT---PA7
#define CLK_in  PAin(6)
#define DT_in   PAin(7)

/**************************************************************************
函数功能:把TIM3初始化为编码器接口模式
**************************************************************************/
void Encoder_Init_TIM3(u16 arr, u16 psc) {
    
    
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能TIM4时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;       //选择你要设置的IO口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //设置传输速率
    GPIO_Init(GPIOA, &GPIO_InitStructure);          /* 初始化GPIO */

    TIM_TimeBaseStructure.TIM_Period = arr;   //自动装载值
    TIM_TimeBaseStructure.TIM_Prescaler = psc; //分频系数
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1
    TIM_ICInitStructure.TIM_ICFilter = 0x03;  //滤波
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //分频系数
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA6直接映射到TI1
    TIM_ICInit(TIM3, &TIM_ICInitStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //通道1
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA7直接映射到TI2
    TIM_ICInit(TIM3, &TIM_ICInitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;//中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);

    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式1
    //TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
    TIM_ICStructInit(&TIM_ICInitStructure); //将结构体中的内容缺省输入
    TIM_ICInitStructure.TIM_ICFilter = 10;
    TIM_ICInit(TIM3, &TIM_ICInitStructure);
    TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//运行更新中断

    TIM_SetCounter(TIM3, 10000);//初始化计数器初值

    TIM_Cmd(TIM3, ENABLE); //使能定时器

}



// 计数超过arr就会产生溢出中断
// 也可以把NVIC_Init(&NVIC_InitStructure);注释掉就不要开启中断
void TIM3_IRQHandler(void) {
    
    
    if (TIM3->SR & 0X0001)//溢出中断
    {
    
    
        printf("interrupt\r\n");
    }
    TIM3->SR &= ~(1 << 0);//清除中断标志位
}


short Read_Encoder(u8 TIMX) {
    
    
    unsigned Encoder_TIM;
    switch (TIMX) {
    
    
        case 2:
            Encoder_TIM = (short) TIM2->CNT;
            TIM2->CNT = 0;
            break;
        case 3:
            Encoder_TIM = (short) TIM3->CNT;
            TIM3->CNT = 0;
            break;
        case 4:
            Encoder_TIM = (short) TIM4->CNT;
            break;
        default:
            Encoder_TIM = 0;
    }
    return Encoder_TIM;
}


int main(void) {
    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
    delay_init();                                                   /* 延时函数初始化 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
    delay_ms(500);                                                /* 等待稳定 */
    uart_init(115200);

    Encoder_Init_TIM3(0xffff, 0); //初始化TIM2为编码器接口模式

    while (1) {
    
    
        printf("%d \r\n", (int) TIM_GetCounter(TIM3));

    }
}



TIM4タイマーエンコーダプログラム

同様にプログラムを書くことができます。
ここに画像の説明を挿入

#include "sys.h"
#include "usart.h"

//旋转编码器
//CLK--PB6
//DT---PB7
#define CLK_in  PBin(6)
#define DT_in   PBin(7)

/**************************************************************************
函数功能:把TIM4初始化为编码器接口模式
**************************************************************************/
void Encoder_Init_TIM4(u16 arr, u16 psc) {
    
    
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能TIM4时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;       //选择你要设置的IO口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //设置传输速率
    GPIO_Init(GPIOB, &GPIO_InitStructure);          /* 初始化GPIO */

    TIM_TimeBaseStructure.TIM_Period = arr;   //自动装载值
    TIM_TimeBaseStructure.TIM_Prescaler = psc; //分频系数
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1
    TIM_ICInitStructure.TIM_ICFilter = 0x03;  //滤波
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //分频系数
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA6直接映射到TI1
    TIM_ICInit(TIM4, &TIM_ICInitStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //通道1
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA7直接映射到TI2
    TIM_ICInit(TIM4, &TIM_ICInitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);

    TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式1
    //TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
    TIM_ICStructInit(&TIM_ICInitStructure); //将结构体中的内容缺省输入
    TIM_ICInitStructure.TIM_ICFilter = 10;
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
    TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位
    TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);//运行更新中断

    TIM_SetCounter(TIM4, 10000);//初始化计数器初值

    TIM_Cmd(TIM4, ENABLE); //使能定时器

}



// 计数超过arr就会产生溢出中断
// 也可以把NVIC_Init(&NVIC_InitStructure);注释掉就不要开启中断
void TIM4_IRQHandler(void) {
    
    
    if (TIM4->SR & 0X0001)//溢出中断
    {
    
    
        printf("interrupt\r\n");
    }
    TIM4->SR &= ~(1 << 0);//清除中断标志位
}




int main(void) {
    
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
    delay_init();                                                   /* 延时函数初始化 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);      /* 关闭jtag,使能SWD,可以用SWD模式调试 */
    delay_ms(500);                                                /* 等待稳定 */
    uart_init(115200);

    Encoder_Init_TIM4(0xffff, 0); //初始化TIM2为编码器接口模式

    while (1) {
    
    
        printf("%d \r\n", (int) TIM_GetCounter(TIM4));

    }
}



おすすめ

転載: blog.csdn.net/x1131230123/article/details/131446830