上次将我需要的材料全部列出来了,但是可能会有些变化。
在我做这个项目的过程中,根据遇到的实际情况来进行调整自己需要的具体模块。
本次将整个控制系统的控制逻辑简单写一下:
电机驱动器
我所用到的电机驱动器就是根据在公司定制的电机配套的电机驱动器,如下
各个接口引脚说明如下
注意:其中的ALARM端子这里是控制器输出报警的引脚,给的使用手册上有问题。
我主要是用到了其中的SV、F/R、EN、BAK、COM、端子。其中电机的电枢两端的电压是通过PWM进行调速,而转速反馈的信号本来是可以通过驱动器的SPEED接口输出的信号直接得到,但是不知道为什么这个端子的输出波形不是标准的方波信号,我通过示波器进行观察后,一直不能得到对自己有用的信号,所以最后我选择了通过与电机同轴连接一个增量式编码器来进行转速反馈(不带Z相的那种),最后得到了较好的结果。
在前文中我提到处理转速信号我是通过将STM32单片机的引脚设置为外部触发的模式进行,但是现在我又发现一个问题,当我查到STM32F103ZET6的data sheet时,这款单片机只有三个外部触发模式的引脚,就是可以将定时器2、3、4设置为外部触发模式,通用定时器5是不可以设置的。所以我又不不得不改变我对于转速信号的处理方式,在本文中,我是通过将通用定时器设置为编码器接口模式来进行的。下面会介绍。
原理图
电机驱动模块
中间的四个就是BLDC,我只是为了到时候连线方便,就通过AD画出了简单的原理图,处于两边的就是四个电机驱动器的简化图。
编码器模块
通过四个增量式编码器得到转速反馈信号。
接收器模块
接收器模块主要是通过工业遥控器模块来进行对整个割草机进行控制,根据控制继电器的通断,当STM32F103ZET6单片机得到对应的电平信号后,在内部进行处理得到相应的电机控制信号。
注:单片机对于使用者还是要有一定的使用基础,要是连最基本的跑马灯都不会的话,最好还是先学一下,我觉得使用标准库还是HAL库没有特别大的区别,主要看个人的习惯,要是想要偷懒或者怎样,HAL是一个不错的选择,但是怎么样实现自己的控制逻辑还是要自己写。最好还是老老实实的自己写,不仅可以熟练使用KEIL软件,还可以更加理解标准库的结构,内部函数的调用过程(以上全是个人看法,不要争,争就是你赢。)
单片机的配置
1、基本定时器配置
基本定时器我在这主要是用来在定时器中断函数中读取各个编码器的编码值。
还有就是几种定时器的区别一定要好好看看data sheet(数据手册),不然以为自己是对的,但在调试过程中,不知道在哪就错了
基本定时器配置
基本定时器中断配置
static void BASIC_TIM_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// ÉèÖÃÖжÏ×éΪ0
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
// ÉèÖÃÖжÏÀ´Ô´
NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQ ;
// ÉèÖÃÖ÷ÓÅÏȼ¶Îª 0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// ÉèÖÃÇÀÕ¼ÓÅÏȼ¶Îª3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
基本定时器的配置
static void BASIC_TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// ¿ªÆô¶¨Ê±Æ÷ʱÖÓ,¼´ÄÚ²¿Ê±ÖÓCK_INT=72M
BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
// ×Ô¶¯ÖØ×°ÔؼĴæÆ÷µÄÖµ£¬ÀÛ¼ÆTIM_Period+1¸öƵÂʺó²úÉúÒ»¸ö¸üлòÕßÖжÏ
TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;
// ʱÖÓÔ¤·ÖƵÊýΪ
TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;
TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
// Çå³ý¼ÆÊýÆ÷Öжϱê־λ
TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
// ¿ªÆô¼ÆÊýÆ÷ÖжÏ
TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);
// ʹÄܼÆÊýÆ÷
TIM_Cmd(BASIC_TIM, ENABLE);
}
通用定时器配置
编码器模式对应的IO引脚配置
void GPIO_TIM5_Encoder_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(MOTOR_ENCODER_LEFT_FRONT_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin=MOTOR_ENCODER_LEFT_FRONT_A|MOTOR_ENCODER_LEFT_FRONT_B;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;///±àÂëÆ÷ģʽ¶ÔÓ¦Òý½ÅÉèÖÃΪ¸¡¿ÕÊäÈëģʽ
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(MOTOR_ENCODER_LEFT_FRONT_PORT,&GPIO_InitStruct);
}
定时器的配置
void TIM5_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstructure;
TIM_ICInitTypeDef TIM_ICInitTypetructure;
TIM_TimeBaseStructInit(&TIM_TimeBaseInitstructure);
TIM_TimeBaseInitstructure.TIM_ClockDivision=0;
TIM_TimeBaseInitstructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitstructure.TIM_Period=65535-1;
TIM_TimeBaseInitstructure.TIM_Prescaler=0;
/*³õʼ»¯¶¨Ê±Æ÷2*/
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitstructure);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
/*ÅäÖñàÂëÆ÷ģʽ½Ó¿Ú*/
/*¶¨Ê±Æ÷2ÉèÖÃΪ±àÂëÆ÷ģʽ£¬Á½¸ö·½Ïò£¬Ï½µÑز¶»ñ*/
TIM_EncoderInterfaceConfig(TIM5,TIM_EncoderMode_TI12,TIM_ICPolarity_Falling,TIM_ICPolarity_Falling);
/*ÌîÈëȱʡֵ*/
TIM_ICStructInit(&TIM_ICInitTypetructure);
TIM_ICInitTypetructure.TIM_ICFilter=6;
TIM_ICInit(TIM5, &TIM_ICInitTypetructure);
//¼ÆÊýÆ÷ÊýÖµ³õʼ»¯
TIM_SetCounter(TIM5, 32768);
/*¶¨Ê±Æ÷ʹÄÜ*/
TIM_Cmd(TIM5, ENABLE)