您的位置:首页 > 编程语言

STM32F103RCT6 实验代码之舵机+超声波避障小车(二)舵机+超声波

2020-04-23 09:08 921 查看

舵机+超声波简介

补充一下上一篇博客遗漏掉的一个问题,一般电机的PWM都是有一些频率限制的,而我的直流电机是10Khz来进行驱动的。

一.SG90舵机


这个是我买的舵机+超声波模块,这个舵机是SG90模拟舵机,网上有很多的资料
模拟电机与数字电机的区别
SG90的驱动是靠不同占空比的50hz的PWM波来控制
0度——>2.5%
45度——>5%
90度——>7.5%
135度——>10%
180度——>12.5%
不同的占空比对应转过不同的角度
我在网上找了一些文章,大概有两种实现操控舵机的方法,第一种是直接输入不同的占空比来控制转过的角度,第二种是连续改变占空比来改变角度,首先我来初始化一下PWM波:

#include "sg90.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void sg90_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟使能

//设置该引脚为复用输出功能,输出TIM1 CH2的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

TIM_TimeBaseStructure.TIM_Period = 199; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 80K
TIM_TimeBaseStructure.TIM_Prescaler =7199; //设置用来作为TIMx时钟频率除数的预分频值  不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1 ; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高
TIM_OC4Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_CtrlPWMOutputs(TIM1,ENABLE);	//MOE 主输出使能

TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH3预装载使能

TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器

TIM_Cmd(TIM1, ENABLE);  //使能TIM1

}

接下来是两种不同的控制方法:
第一种:
在.h文件里宏定义不同占空比的PWM波

#ifndef __SG90_H
#define __SG90_H
#include "sys.h"

#define   SG90_Right_90     TIM_SetCompare4(TIM1, 195)
#define   SG90_Right_45		TIM_SetCompare4(TIM1, 190)
#define   SG90_Front		TIM_SetCompare4(TIM1, 185)
#define   SG90_Left_45		TIM_SetCompare4(TIM1, 180)
#define   SG90_Left_90		TIM_SetCompare4(TIM1, 175)

void sg90_Init(void);

#endif

之后再main函数里进行操作:

while(1)
{

SG90_Left_90;
delay_ms(700);
SG90_Left_45;
delay_ms(700);
SG90_Front;
delay_ms(700);
SG90_Right_45;
delay_ms(700);
SG90_Right_90;
delay_ms(700);
}

延时时间需要自己调整
第二种:
需要一个for语句来实现
这种方法主要是通过一点点改变占空比来使舵机转动

int i;
for(i=175;i<195;i++)
{
TIM_SetCompare4(TIM1, i);
delay_ms(50);
}

小结一下:
①两种方法均可使舵机转动,如果采用固定角度测距的话推荐第一种,但是在实验过程中发现第二种似乎更稳定一些,这个结论没有仔细推敲。可以根据自己的实验来选择。
②舵机操作的本质就是控制不同占空比的PWM波,其实并不难,重点注意一下延时函数的设置,不恰当的延时函数会导致舵机转过角度的不理想

二.超声波数据处理

超声波的使用我其他的博客提到过,有两种思路。
第一种就是根据HC-SR04的使用说明,在GPIO口检测高电平是开启定时器,低电平再关闭,可以根据这个思路自己写一个函数。
第二种就是采用正点原子的输入捕获例程更改,我这里用的是第二种方法。

我们采用超声波测距的方法来进行判断车的移动,这里我参考了其他人的博客
博客传送门
这里把代码贴出来:

#include "gpio.h"
#include "sys.h"
#include "delay.h"
#include "pwm.h"
#include "pwm2.h"
#include "usart2.h"
#include "timer.h"
#include "sg90.h"

float dis;
float disleft;
float disright;
extern u8  TIM4CH3_CAPTURE_STA;		//输入捕获状态
extern u16	TIM4CH3_CAPTURE_VAL;	//输入捕获值
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
My_USART2_Init();
sg90_Init();

delay_init();
gpio_Init();
TIM3_PWM3_Init(7199,0);//TIM3 输出PWM
TIM3_PWM4_Init(7199,0);//TIM3 输出PWM

TIM_SetCompare3(TIM3,2400);//左轮电机转速
TIM_SetCompare4(TIM3,2530);//右轮电机转速
while(1)
{
dis=count_length();
SG90_Front;
delay_ms(700);
if(dis>60.00)
{
front();

}
else
{
stop();
SG90_Right_45;
delay_ms(900);
disright=count_length();
printf("right:%f cm\r\n",disright);
SG90_Left_45;
delay_ms(900);
disleft=count_length();
printf("left:%f cm\r\n",disleft);
SG90_Front;
delay_ms(900);
if(disleft>=disright)
{
do
{

delay_ms(10);
dis=count_length();	//重复测前方的距离同时左转
delay_ms(10);
left();
}
while(dis<30.00);		//一直转到前方距离大于30cm
}
if(disleft<disright)
{
do
{

delay_ms(10);
dis=count_length();	//重复测前方的距离同时左转
delay_ms(10);
right();
}
while(dis<30.00);		//一直转到前方距离大于30cm
}
}

}

}

这是main函数的代码,主体思路是检测前方距离是否小于规定距离,如果大于就前进,如果小于就左右测距比较大小,之后舵机摆正向距离大的方向转直到前方距离再次大于规定距离。
上一篇博客可以让小车运动起来,这一篇可以根据前方的距离来控制小车的运动。到这里就可以基本实现了 舵机+超声波避障的小车的功能,但是在制作过程中出现了一个问题就是无法正确的控制舵机,舵机的左右转动总是不按我的想法来,而且看上去是执行好几遍while才会让舵机转动起来,这里大概有几种原因:
①功率不太够,最好不要采用单片机的的5V输出有些不太稳定,我这里采用的是L298N的5V输出来给舵机供电。
②注意中断,有可能是中断在某个位置循环不太能出来
③注意一下舵机,我的舵机有些瑕疵手动转动某些地方会有一些卡顿,注意这种情况也许会有影响,而且这个问题比较隐蔽
④延时函数的时间配值,我觉得延时函数的影响还是存在的

dis=count_length();
SG90_Front;
delay_ms(700);

下图是大概的连线图,标注了单片机信号的方向:

关于蓝牙部分之后补充

  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
Physics.k 发布了4 篇原创文章 · 获赞 6 · 访问量 1533 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: