目录
三、电机驱动部分
总结
推荐STM32学习课程:
STM32F103C8T6延时函数和OLED显示屏代码_HX091624的博客-CSDN博客
前言
电机编码器是安装在电机上的旋转编码器,它通过跟踪电机轴的速度和/或位置来提供闭环反馈信号。监视的参数由应用的类型确定,可以包括速度,距离,RPM,位置等。利用编码器或其他传感器控制的特定参数的应用称为闭环反馈或闭环控制系统
一、定时器部分和按键部分
#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;
}
二、PWM调速
#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);
}
三、电机驱动部分
电机:电机如何驱动在我之前的文章有写,这里就不再解释了。
#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(); //右电机停止
}
三、编码器接口部分(测速)
编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。
#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;
}
四.主函数
#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);
}
}
总结
注意:两个输入引脚借用了输入捕获的通道1和通道2,而接通道3和通道4是没有用的。
以上就是编码器电机的代码,欢迎大家留言评论,遇到问题都可以在评论区留言。