毕业一年后才正式从事STM32干系的开拓,现在的能力也不过入门级别.只想把当前学到的一些东西和大家分享,自己也能巩固下一下,希望能帮到某些须要的朋友.
学习STM32,创造它的定时器是一个难点,至今还有很多地方捉摸不透,当然,如果只是利用普通定时功能就不多说了.掌握直流电机,PWM调速是必备,可是做小车速率一定要做到闭环掌握,以是得有编码器.查阅手册,STM32的定时器还支持AB相正交编码器功能,实在令人高兴,无需再用定时器的输入补获功能来打算速率了.

作为AGV小车,最最少的功能得是循迹吧!低真个便是学校用的光电循迹,白底黑线跑道.轻微高等点的是巡磁轨道,磁感应传感器加磁条的方案,相比拟较稳定,只是本钱要高许多,更高真个该当便是SLAM激光导航模块+惯性导航构建舆图来循迹,这种要繁芜很多,目前也只是理解一些事理,而前两种已经实践过.就目前履历而谈,第一种适宜学习(当初贴轨道可是花了我大把韶光和体力),第二种适宜低级运用,第三种就适宜高等运用处所了. (以前飞思卡尔的摄像头,光电,电磁循迹方案彷佛只是用于竞赛,没把稳到有什么实际运用) 唉!废话说的有点多.......

电机选型:JGB37-545B带AB相编码器直流减速电机
驱动芯片:LMD18200T
MCU:STM32F103VET6
电机PWM接口利用定时器4的通道1和2,编码器接口利用定时器1和定时器2的正交编码器接口.电机初始化函数如下:
void Motor_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE) ;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 , ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_TIM4, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //方向掌握引脚
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_ResetBits(GPIOD,GPIO_Pin_9|GPIO_Pin_10);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 ; //PWM输出引脚
GPIO_Init(GPIOD, &GPIO_InitStructure);
TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Period = 100-1;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1; //周期10K
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig(TIM4, ENABLE);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
TIM_OC2Init(TIM4, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable); //定时器4的2路比较输出功能使能
TIM_Cmd(TIM4, ENABLE);
// 编码器 1 //
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); //利用IO重映射功能
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11 ;
GPIO_Init(GPIOE, &GPIO_InitStructure);
TIM_DeInit(TIM1);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //利用编码器模式1,只能反响出速率 ,如果须要反响出方向,可以利用TIM_EncoderMode_TI12,双向计数模式
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ;
TIM_ICInitStructure.TIM_ICFilter = 15; //
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;
TIM_ICInitStructure.TIM_ICFilter = 15;//选择输入比较滤波器
TIM_ICInit(TIM1, &TIM_ICInitStructure);
TIM_ClearFlag(TIM1, TIM_FLAG_Update);//清TIM更新标志
TIM_SetCounter(TIM1,0);
TIM_Cmd(TIM1, ENABLE);
// 编码器2 //
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_DeInit(TIM2);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
//TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge , TIM_ICPolarity_BothEdge);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1 ;
TIM_ICInitStructure.TIM_ICFilter = 15;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_SetCounter(TIM2,0);
TIM_Cmd(TIM2, ENABLE);
}
设置速率宏定义,这里只是设定占空比,如需设置详细速率(如cm/s)须要重新封装
#define MOTOR_SET_SPEED_R(spd)TIM_SetCompare1(TIM4,spd)
#define MOTOR_SET_SPEED_L(spd)TIM_SetCompare2(TIM4,spd)
实际运用时须要知道一些固定参数,如轮子直径,电机减速比,从而将输出的脉冲(占空比)对应到详细的速率值.
复位编码器值:
#define MOTOR_RESET_ENCODER_R()TIM_SetCounter(TIM1,0)
#define MOTOR_RESET_ENCODER_L()TIM_SetCounter(TIM2,0)
读编码器值:
#define MOTOR_READ_ENCODER_R()-TIM_GetCounter(TIM1)
#define MOTOR_READ_ENCODER_L()TIM_GetCounter(TIM2)
就写到这里吧,写的不是很清楚.底层驱动网上例程很多,很随意马虎调试.运用中更看重方法,思路无非便是调节占空比掌握速率,读编码器单位韶光输入脉冲数得到速率,然后加上PID调节使速率稳定.关于PID方面的个人理解下次再来分享!









