【单片机】STM32单片机读取旋转编码器,TIM定时器编码器模式捕获,程序

news2024/11/17 3:50:07

文章目录

  • 旋转编码器介绍
  • 主程序逻辑直接检测
  • 用外部中断检测下降沿
  • 定时器直接解码旋转编码器
    • STM32中文参考手册V10.pdf
    • 定时器的编码器模式
    • TIM2定时器编码器程序
    • TIM3定时器编码器程序
    • TIM4定时器编码器程序

旋转编码器介绍

旋转编码器简单来说,就是会输出2个PWM,依据相位可以知道旋转方向,依据脉冲个数可以知道旋转的角度。一般旋转一圈有一个固定数值的脉冲个数。
旋转编码器广泛用于电机、或者角度传感器,STM32的定时器可以直接接入这两个波形获取到信息。

在这里插入图片描述
前两个引脚(接地和Vcc)用于为编码器供电,我这里采用3.3V的供电。除了以顺时针方向和逆时针方向旋转旋钮外,编码器还有一个开关(低电平有效),按下内部的旋钮可以按下该开关。来自此开关的信号通过引脚3(Switch)获得。最后它有两个输出引脚。

在这里插入图片描述

主程序逻辑直接检测

主程序中不要加延时,否则可能检测不到下降沿。

//旋转编码器
//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。

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));

    }
}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/700542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

d2l_第八章学习_现代卷积神经网络

参考&#xff1a; d2l x.1 AlexNet 研究人员认为&#xff1a; 更大更干净的数据集或是稍加改进的特征提取方法&#xff0c;比任何学习算法带来的进步大得多。认为特征本身应该被学习&#xff0c;即卷积核参数应该是可学习的。创新点在于GPU与更深的网络&#xff0c;使用ReLU…

问题收藏夹——使用mybatisPlusJoin报 NoSuchPropertyException错误

出现问题代码&#xff1a; 报错&#xff1a; 解决方法&#xff1a; MPJLambdaQueryWrapper 类有问题&#xff0c;应该用MPJLambdaWrapper&#xff0c;去看了作者官网&#xff0c;发现已经没有这个类的用法了&#xff0c;但是还能用这个类&#xff08;Copilot直接给我补全这个…

SNMP 计算机网络管理 实验2(三) SNMP服务与常用网管命令之任务五:查看端口流量及实验小结

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

人工智能 --- 吉布斯采样

贝叶斯网络如下图所示&#xff0c;包含 4 个随机变量&#xff0c;每个变量都只有表示是否的两个值。请用吉布斯采样方法回答以下问题。 假设观察到 &#x1d445; &#x1d45f;, 初始化样本中其他变量的赋值为 &#x1d436; &#x1d450;, &#x1d446; −&#x1d460…

四、深度学习的计算

文章目录 前言一、层和块1.1 自定义块1.2 顺序块1.3 在前向传播函数中执行代码1.4 效率问题1.5 小结 二、参数管理2.1 参数访问2.1.1 目标参数2.1.2 访问所有参数2.1.3 从嵌套块中收集参数 2.2 参数初始化2.2.1 内置初始化2.2.2 自定义初始化2.2.3 参数绑定 三、延后初始化四、…

低功耗蓝牙OM6621EM 兼容Nordic 51系列2.4G私有协议

OM6621EM是一个功率优化的系统(SOC).解决蓝牙低功耗和专有的2.4 ghz应用。它集成了一个高具有蓝牙基带和丰富外设的低功耗射频收发器I0扩展。OM6621EM还集成了电源管理单元(PMU)来提供高效的电源管理。它的目标是2.4GHz低功耗蓝牙系统&#xff0c;专有的2.4 ghz系统&#xff0c…

easyX库其他函数(注释版)

本篇是easyX库系列正文最后一篇&#xff0c;依旧是有几个很有价值的函数&#xff0c;我不补充了几个例子&#xff0c;对easyX库中的部分code例子做了修改。 0.其它函数概览 函数或数据类型描述GetEasyXVer获取当前EasyX库的版本信息。BeginBatchDraw开始批量绘图。EndBatchDr…

Java Web HTMLCSS(1)23.6.29

HTML&CSS 1&#xff0c;HTML 1.1 介绍 HTML 是一门语言&#xff0c;所有的网页都是用HTML 这门语言编写出来的&#xff0c;也就是HTML是用来写网页的&#xff0c;像京东&#xff0c;12306等网站有很多网页。 这些都是网页展示出来的效果。而HTML也有专业的解释 HTML(Hy…

Pycharm中打开HTML文件报错:Windows 找不到文件‘chrome‘

问题现象&#xff1a; Pycharm中&#xff0c;打开HTML文件&#xff0c;选择chrome浏览器打开时&#xff0c;报错&#xff1a;Windows 找不到文件’chrome’。请确定文件名是否正确后&#xff0c;再试一次。但实际上你的电脑上是安装了Chrome浏览器的。 解决方案&#xff1a; 原…

【算法】状态机DP 买卖股票系列

文章目录 前期知识股票问题买卖股票的最佳时机 II最佳买卖股票时机含冷冻期买卖股票的最佳时机 IV补充&#xff1a;恰好k次 / 至少k次 怎么做&#xff1f; 相关题目练习买卖股票的最佳时机 https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/解法1——状态机DP解法…

十三、禅道登录/提交版本/编辑版本接口

十三、禅道提交版本/编辑版本接口 1. 禅道的登录接口或者叫获取tokens接口 # -*- coding: utf-8 -*- """ ------------------------------------------------------------------------------- File : zentao_login.py Time : 2023/6/29 13:55 author : …

Java读取Excel第一行数据,获取表头

目录 一、场景 二、代码实现 1、工具类 2、方法调用 3、结果 之前写过一篇关于解析Excel的博客&#xff1a;解析读取Excel文件&#xff08;.xls .xlsx&#xff09;&#xff0c;今天再分享一下&#xff0c;如何获取Excel的表头数据。 一、场景 需要判断导入的Excel文件的列…

什么是AQS

AQS&#xff08;Abstract Queued Synchronizer&#xff09;是一个抽象的队列同步器&#xff0c;通过维护一个共享资源状态&#xff08;Volatile Int State&#xff09;和一个先进先出&#xff08;FIFO&#xff09;的线程等待队列来实现一个多线程访问共享资源的同步框架。 AQS…

今日份分享:三个电脑mp3转换器推荐

有一个音乐爱好者叫小艾。她对音乐充满热爱&#xff0c;每天都会用耳机沉浸在动听的旋律中。然而&#xff0c;她最近遇到了一个问题&#xff1a;她手头有一些喜欢的音乐文件&#xff0c;但格式却是不支持她的音乐播放器。这让她感到非常困扰&#xff0c;因为她希望随时随地欣赏…

适用于Vue 3的最佳开源分页库

从头开始实现分页可能是一项耗时的任务&#xff0c;需要大量的精力和资源。幸运的是&#xff0c;有几个伟大的开源库可以简化这个过程&#xff0c;提高你的效率。使用分页库可以节省你的时间和精力&#xff0c;使你能够专注于建立你的应用程序的其他更重要的功能。 在这篇文章…

如何选择适合自己的专业?

高考季又到了&#xff0c;毕业生们正忙着选填志愿。志愿填报是一个关键的决策&#xff0c;它将对他们未来的学习和就业产生重要影响。在这个关键的时刻&#xff0c;一些相关问题随之而来&#xff1a;如何填报志愿&#xff1f;是选择专业还是学校&#xff1f;哪些专业就业前景好…

全国农信银CTF逆向Baby8or解析

按CTRL X 跳转到main函数&#xff0c;按F5 生成伪代码进行分析。 发现一个加密函数&#xff0c;当加密后的数据和genc[i]数组中的值对比一致则表示正确flag&#xff0c;字符串长度为35。 双击genc[i] 找到genc[i]中的数据&#xff0c;转成10进制得到数组 genc[172,102,148,22…

数据结构--双链表

数据结构–双链表 单链表 VS 双链表 单链表&#xff1a;无法逆向检索&#xff0c;有时候不太方便 双链表&#xff1a;可进可退&#xff0c;存储密度更低一丢丢 双链表的定义 typedef struct DNode {ElemType data;struct DNode *prior, *next; }DNode, *DLinkList;双链表的初…

JavaWeb——2.注解

这篇文章我们来讲一下Java中的注解 其实这部分内容算是Javaweb的补充内容&#xff0c;其中还包括Junit测试和反射的相关内容。 Junit测试是一个比较简单的内容&#xff0c;这里就不写了&#xff1b;而反射的相关内容可以看java基础专栏&#xff0c;那里面有详细的叙述。 目录…

Jvm jmx_exporter Prometheus dubbo Grafana 重点看端口要对应上 单独进程和程序进程内jmx_exporter

目录 JMX Exporter 的两种用法 启动独立进程 jmx_prometheus_httpserver-0.18.0.jar 方式 下载 jmx_exporter 找地方随便一放 创建配置文件 config_jmx_exporter.yaml 增加 启动 jvm 配置 一定要是jvm参数 可别意外写成程序参数 启动jmx_exporter Prometheus yml 配置 …