Table of contents
1. The timer part and the button part
3. Motor drive part
3. Encoder interface part (speed measurement)
Recommended STM32 learning courses:
STM32F103C8T6 delay function and OLED display code_HX091624's Blog-CSDN Blog
foreword
A motor encoder is a rotary encoder mounted on a motor that provides a closed-loop feedback signal by tracking the speed and/or position of the motor shaft. The parameters monitored are determined by the type of application and can include speed, distance, RPM, position, etc. Applications that utilize encoders or other sensors to control specific parameters are called closed-loop feedback or closed-loop control systems
1. The timer part and the button part
#include "stm32f10x.h" // Device header
//定时中断->1s
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
/*
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
*/
#include "stm32f10x.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 1;
}
return KeyNum;
}
2. PWM speed regulation
#include "stm32f10x.h"
//定时器3->PWM调速 周期20MS 计一个数->1US
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//电动机PWM输出 PA6 PA7
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//舵机PWM输出 PB0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //PWM输出引脚
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
}
//左右电机输出比较
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM3, Compare);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM3, Compare);
}
//舵机输出比较
void PWM_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM3, Compare);
}
3. Motor drive part
Motor: How the motor is driven was written in my previous article, so I won't explain it here.
#include "stm32f10x.h"
#include "PWM.h"
//左右电机初始化
void Motor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//电机控制模拟输入端
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//控制左电机->PA0 PA1 控制右电机->PA4 PA5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
PWM_Init();
}
//右边电机向前
void Right_moto_go(void)
{
//正转
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}
//右边电机向后
void Right_moto_back(void)
{
//反转
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
}
//右边电机停止
void Right_moto_Stop(void)
{
//停车
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}
//左边电机向前
void Left_moto_go(void)
{
//正转
GPIO_SetBits(GPIOA, GPIO_Pin_0);
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
//左边电机向后
void Left_moto_back(void)
{
//反转
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
//左边电机停止
void Left_moto_Stop(void)
{
//停车
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
#include "stm32f10x.h"
#include "Motor.h"
#include "PWM.h"
//小车调速函数
void Speed_Control(uint16_t Compare)
{
Compare*=200; //100->20000
PWM_SetCompare1(Compare); //调速
PWM_SetCompare2(Compare);
}
//小车前进函数
void run(uint16_t Compare)
{
Speed_Control(Compare);
Left_moto_go(); //左电机往前
Right_moto_go(); //右电机往前
}
//小车后退函数
void backrun(uint16_t Compare)
{
Speed_Control(Compare);
Left_moto_back(); //左电机往后
Right_moto_back(); //右电机往后
}
//小车停车函数
void stop(void)
{
Left_moto_Stop(); //左电机停止
Right_moto_Stop(); //右电机停止
}
3. Encoder interface part (speed measurement)
The encoder interface can receive the signal of the incremental (orthogonal) encoder, and automatically control the CNT self-increment or self-decrement according to the orthogonal signal pulse generated by the encoder rotation, thereby indicating the position, rotation direction and rotation speed of the encoder.
#include "stm32f10x.h" // Device header
//测速
void Encoder_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//TIM1的CH1和CH2
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);
//在TI1和TI2上计数
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInit(TIM1, &TIM_ICInitStructure);
//定时器编码器接口配置 //通道不反相
TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_Cmd(TIM1, ENABLE);
}
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = TIM_GetCounter(TIM1);
TIM_SetCounter(TIM1, 0);
return Temp;
}
Four. Main function
#include "stm32f10x.h"
#include "Key.h"
#include "OLED.h"
#include "Timer.h"
#include "Motor.h"
#include "MotorRun.h"
#include "Encoder.h"
int16_t Speed;
int8_t KeyNum;
int main(void)
{
Key_Init();
OLED_Init();
Timer_Init();
Motor_Init();
Encoder_Init();
OLED_ShowString(1, 1, "Speed:");
while (1)
{
KeyNum=Key_GetNum();
//电机旋转
if(KeyNum==1)
{
run(50);
}
OLED_ShowSignedNum(1, 7, Speed, 5); //显示速度
}
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
//每隔一段时间获取速度
Speed = Encoder_Get();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
Summarize
Note: The two input pins borrow channel 1 and channel 2 of the input capture, but it is useless to connect channel 3 and channel 4.
The above is the code of the encoder motor. You are welcome to leave a message and comment. If you encounter any problems, you can leave a message in the comment area.