一、硬件及接线说明
本实验所基于的硬件分别为:
- STM32F103C8T6 主控板
- TB6612FNG 直流电机驱动模块
- 6线正交编码器电机(带AB相)
其中硬件接线为:
- PWMA —— PA8
- AIN1 —— PB14
- AIN2 —— PB15
- STBY —— 5V
- 编码器A相 —— PA1
- 编码器B相 —— PA0
STM32定时器资源分配:
- 定时器1(TIM1):产生PWM波,作为TB6612的输入,控制电机进行调速;
- 定时器2(TIM2):读取编码器的波形;
- 定时器3(TIM3):产生周期为10ms的定时器中断,为控制系统提供稳定的时间基准。
【说明】上述硬件平台和接线仅给读者提供参考,更换主控或接线方式,请自行对示例程序进行微调。本文对于编码器的工作原理不加赘述,对于其原理请读者自行查阅相关资料。
二、速度闭环控制程序逻辑
【说明】下述程序中 control.c 最为重要,包含了速度闭环控制器的详细代码。其他程序模块供读者初始化参考。
main.c (主函数)
u8 flag_Stop=1; //停止标志位
int Encoder; //编码器的脉冲计数
int moto; //电机PWM变量
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(); //=====延时初始化
LED_Init(); //=====初始化与 LED 连接的硬件接口
uart_init(115200); //=====初始化串口1
MOTO_Init(); //初始化控制电机所需的IO
pwm_Init(7199,0); //初始化pwm输出
Encoder_Init_TIM2(); //初始化计数器(定时器)
TIM3_Int_Init(99,7199); //10ms一次中断
while(1)
{
printf("Encoder:%d \r\n",Encoder);
}
}
moto.c (电机初始化相关函数)
void MOTO_Init(void)//初始化控制电机所需的IO
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//PORTB12 13 14 15推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
void pwm_Init(u16 arr,u16 psc) //初始化pwm输出引脚
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //使能定时器1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA的时钟
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //复用输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11; //PA8 PA11
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseInitStruct.TIM_Period = arr; //设定计数器自动重装值
TIM_TimeBaseInitStruct.TIM_Prescaler = psc; //设定预分频器
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInitStruct.TIM_ClockDivision = 0; //设置时钟分割
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct); //初始化定时器
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2; //选择PWM2模式
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStruct.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //设置输出极性
TIM_OC1Init(TIM1,&TIM_OCInitStruct); //初始化输出比较参数
TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //CH1使能预装载寄存器
TIM_CtrlPWMOutputs(TIM1,ENABLE); //高级定时器输出必须设置这句
TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIM1在ARR上的预装载寄存器
TIM_Cmd(TIM1,ENABLE); //使能定时器1
}
encoder.c (编码器初始化函数)
#include "encoder.h"
/**************************************************************************
函数功能:把TIM2初始化为编码器接口模式
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM2(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure