1.最近有一个基于STM32的视觉追踪云台项目,这个项目的实现为无线充电项目做铺垫。
2.但是最近又有一个优先级更高的项目,所以只做了一天就放下了,记录一下这个小demo。
PS:同时也实现了驱动步进电机,但是手头上的28步进电机转速有点慢并且力矩不大,不适合项目要求,所以还是选择使用舵机。但是有好用的步进电机我感觉还是步进电机好一些。实现的功能是,输入两路舵机的角度 并且能控制速度;目的是为了后续通过通信模块获取到目标的位置解算之后返回角度值,实现云台视觉追踪
程序实现流程
1.PWM模块:定时器输出比较 生成符合要求频率的方波
2.舵机模块:继承PWM模块 实现舵机调速 输出引脚为PA1 PA2
3.主程序:测试 调试
1.PWM.c
#include "stm32f10x.h" // Device header
//PA1口输出PWM波形
//PWM初始化 1.RCC开启时钟 配置TIM和GPIO口 2.时钟源选择+配置时基单元 3.配置输出比较单元 4.配置GPIO复用推挽输出
void PWM_Init(void)
{
//打开外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//TIM2定时器时钟
//GPIO时钟开启
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO口时钟
//GPIO配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP ;//如果需要定时器控制引脚的话 需要复用开漏/推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//时钟源选择
TIM_InternalClockConfig(TIM2);//为TIM2定时器选择内部时钟源
//时基单元配置
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(TIM2,&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_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OC3Init(TIM2,&TIM_OCInitStructure); //设置两路输出捕获通道
//定时器启动
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare(uint16_t Compare) //第一路舵机 PA1口
{
TIM_SetCompare2(TIM2,Compare);
}
void PWM_SetCompare3(uint16_t Compare) //第二路舵机 PA2口
{
TIM_SetCompare3(TIM2,Compare);
}
2.PWM.h
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare(uint16_t Compare);
void PWM_SetCompare3(uint16_t Compare);
#endif
3.Servo.c
#include "stm32f10x.h" // Device header
#include "PWM.h" //在舵机模块中继承PWM模块
#include "Delay.h"
void Servo_Init(void) //PWM初始化
{
PWM_Init();
}
//1.第1路舵机控制
// 0-500 180-2500 0-180=500-2500 1度等于2000/180
void Servo_SetAngle(float Angle)
{
PWM_SetCompare(Angle * 2000 / 180 + 500);
}
float Cur_Angle = 90;
void Servo_Cotrol(float New_Angle)
{
if(Cur_Angle >= New_Angle)
{
for(int i = Cur_Angle; i >= New_Angle ; i--) //次数
{
Servo_SetAngle(i);
Delay_ms(10);
}
}
if(Cur_Angle < New_Angle)
{
for(int i = Cur_Angle; i <= New_Angle ; i++) //次数
{
Servo_SetAngle(i);
Delay_ms(10);
}
}
Cur_Angle = New_Angle;
}
//第2路舵机控制
void Servo2_SetAngle(float Angle)
{
PWM_SetCompare3(Angle * 2000 / 180 + 500);
}
float Cur_Angle2 = 90;
void Servo2_Cotrol(float New_Angle2)
{
if(Cur_Angle2 >= New_Angle2)
{
for(int i = Cur_Angle2; i >= New_Angle2 ; i--) //次数
{
Servo2_SetAngle(i);
Delay_ms(10);
}
}
if(Cur_Angle2 < New_Angle2)
{
for(int i = Cur_Angle2; i <= New_Angle2 ; i++) //次数
{
Servo2_SetAngle(i);
Delay_ms(10);
} 1.
}
Cur_Angle2 = New_Angle2;
}
//联动控制
void CoordinateServo(float New_Angle,float New_Angle2)//分别输入舵机1 和舵机2 的旋转角度
{
Servo_Cotrol(New_Angle);
Servo2_Cotrol(New_Angle2);
}
4.Servo.h
#ifndef __SERVO_H__
#define __SERVO_H__
void Servo_Init(void); //初始化
void Servo_SetAngle(float Angle);
void Servo_Cotrol(float New_Angle); //第1路舵机控制
void Servo2_SetAngle(float Angle);
void Servo2_Cotrol(float New_Angle2);//第2路舵机控制
void CoordinateServo(float New_Angle,float New_Angle2);//联动控制
#endif
5.main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
uint16_t num = 0;
int i ;
int main(void)
{
OLED_Init(); //OLED初始化
OLED_ShowChar(1,1,'B');
Servo_Init(); //舵机初始化
while(1)
{
CoordinateServo(80,30);
Delay_ms(10);
CoordinateServo(80,50);
Delay_ms(10);
CoordinateServo(90,70);
Delay_ms(10);
CoordinateServo(90,90);
Delay_ms(10);
CoordinateServo(100,120);
Delay_ms(10);
CoordinateServo(100,140);
Delay_ms(10);
CoordinateServo(110,160);
Delay_ms(10);
CoordinateServo(110,90);
Delay_ms(10);
CoordinateServo(110,45);
Delay_ms(10);
}
}
参考文章:【STM32】步进电机及其驱动(ULN2003驱动28BYJ-48丨按键控制电机旋转)_stm32驱动步进电机-CSDN博客