OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4335|回复: 3

定时器编码器接口的溢出中断相关问题,求大佬帮忙解答

[复制链接]

1

主题

3

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2023-4-19
在线时间
2 小时
发表于 2023-4-21 17:37:40 | 显示全部楼层 |阅读模式
1金钱
各位大佬,小弟使用STM32F103的定时器编码器接口模式来驱动编码器,想要实现的目的是当TIM_GetCounter(TIM3)==15000时电机反向,代码如下,现象是当到达15000时MOTOR_DIR_PIN控制方向的引脚只有一瞬间切换高低电平,电机不反向,这是什么原因呢?
电机的代码


#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

/* 定义GPIO引脚,用于控制电机的方向和使能 */
#define MOTOR_DIR_PIN  GPIO_Pin_12
#define MOTOR_EN_PIN   GPIO_Pin_14
#define MOTOR_GPIO     GPIOB

// 定义电机的运动状态
enum MotorDirectionState {
  MOTOR_FORWARD,
  MOTOR_BACKWARD,
  MOTOR_STOPPED
};

volatile enum MotorDirectionState DR_State = MOTOR_FORWARD;
void Motor_Init(void)
{
        // 电机方向控制引脚配置
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  // 推挽输出
        GPIO_InitStruct.GPIO_Pin = MOTOR_DIR_PIN;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStruct);       
        GPIO_SetBits(MOTOR_GPIO, MOTOR_DIR_PIN);
}

int16_t encoder_count = 0;

void TIM3_IRQHandler(void) {
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
        int16_t current_count = (int16_t)TIM_GetCounter(TIM3);
        int16_t count_diff = current_count - encoder_count;
        encoder_count = current_count;

        if (count_diff >= 0)
                {
            if(DR_State == MOTOR_FORWARD) // 修改点1:  如果电机的方向是前进,则反转。
                        {
                                DR_State = MOTOR_BACKWARD;
                                GPIO_ResetBits(MOTOR_GPIO, MOTOR_DIR_PIN); // 设置电机的方向引脚为低电平
                        }
                        else if (DR_State == MOTOR_BACKWARD) {
                DR_State = MOTOR_FORWARD;
                GPIO_SetBits(MOTOR_GPIO, MOTOR_DIR_PIN);
            }
        } else if (count_diff < 0)
                {
            if(DR_State == MOTOR_BACKWARD)  // 修改点2: 如果电机的方向是倒退,则将电机方向设为前进
                        {
                                DR_State = MOTOR_FORWARD;
                                GPIO_SetBits(MOTOR_GPIO, MOTOR_DIR_PIN); // 设置电机的方向引脚为高电平
                        }
                        else if (DR_State == MOTOR_FORWARD) {
                DR_State = MOTOR_BACKWARD;
                GPIO_ResetBits(MOTOR_GPIO, MOTOR_DIR_PIN);
            }
        }
                TIM_SetCounter(TIM3, 0);
                TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    }   
}



定时器代码

#include "stm32f10x.h"                  // Device header

/* 定义编码器引脚 */
#define ENCODER_A_PIN  GPIO_Pin_6
#define ENCODER_B_PIN  GPIO_Pin_7
#define ENCODER_GPIO   GPIOA

#define ENCODER_COUNT__PIN  GPIO_Pin_13
#define ENCODER_COUNT_GPIO   GPIOB

void Encoder_Init(void)
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;  // GPIO_Mode_IN_FLOATING  GPIO_Mode_IPU
        GPIO_InitStruct.GPIO_Pin = ENCODER_A_PIN | ENCODER_B_PIN;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ENCODER_GPIO, &GPIO_InitStruct);
        TIM_ICInitTypeDef Tim_ICInitStruct;
        TIM_ICStructInit(&Tim_ICInitStruct);
        Tim_ICInitStruct.TIM_Channel = TIM_Channel_1;
        Tim_ICInitStruct.TIM_ICFilter = 0xF;       
        TIM_ICInit(TIM3, &Tim_ICInitStruct);
        Tim_ICInitStruct.TIM_Channel = TIM_Channel_2;
        Tim_ICInitStruct.TIM_ICFilter = 0xF;       
        TIM_ICInit(TIM3, &Tim_ICInitStruct);
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_TimeBaseStructure.TIM_Prescaler = 0;
        TIM_TimeBaseStructure.TIM_Period = 15000;                // 0xFFFF
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
        TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        NVIC_InitTypeDef NVIC_InitStructer;
        NVIC_InitStructer.NVIC_IRQChannel = TIM3_IRQn;
        NVIC_InitStructer.NVIC_IRQChannelCmd = ENABLE;
        NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructer.NVIC_IRQChannelSubPriority = 0;
        NVIC_Init(&NVIC_InitStructer);
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        TIM_ClearFlag(TIM3, TIM_FLAG_Update);
        TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
        TIM_SetCounter(TIM3, 0);
        TIM_Cmd(TIM3, ENABLE);
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

3281

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8206
金钱
8206
注册时间
2020-5-11
在线时间
3700 小时
发表于 2023-4-22 18:02:58 | 显示全部楼层
count_diff 值显示出来或通过串口发送出来。
我觉得你这编码器的用法不对啊,TIM3_IRQHandler是Update中断,也就是溢出中断,也就是转了一圈,也就是说每次“current_count = (int16_t)TIM_GetCounter(TIM3);”得到的值应该是相同的,真正的用法应该是以比溢出中断更快的速度去读取计数值才对。
专治疑难杂症
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2023-4-19
在线时间
2 小时
 楼主| 发表于 2023-4-23 14:58:04 | 显示全部楼层
LcwSwust 发表于 2023-4-22 18:02
count_diff 值显示出来或通过串口发送出来。
我觉得你这编码器的用法不对啊,TIM3_IRQHandler是Update中断 ...

感谢大佬的回复~
使用OLED显示count_diff的值刚开始是15000,进入中断后显示屏显示乱码。。。。
"真正的用法应该是以比溢出中断更快的速度去读取计数值才对"没太理解,在溢出中断中反转方向不可以吗,我的思路是每次进入更溢出中断后电平反转,然后归0重新计数,进多少次中断就反转多少次,刚入门,不知道怎么调
回复

使用道具 举报

10

主题

3281

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8206
金钱
8206
注册时间
2020-5-11
在线时间
3700 小时
发表于 2023-4-24 09:08:20 | 显示全部楼层
AnsenCH 发表于 2023-4-23 14:58
感谢大佬的回复~
使用OLED显示count_diff的值刚开始是15000,进入中断后显示屏显示乱码。。。。
"真正 ...

显示乱码,说明你的功力不够啊,用串口发出来吧。再看看原子的例子,看是否有个定时器在读取计数值,以及转动方向是怎么判断的。

专治疑难杂症
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 11:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表