STM32F103RCT6 实验代码之舵机+超声波避障小车(二)舵机+超声波
舵机+超声波简介
补充一下上一篇博客遗漏掉的一个问题,一般电机的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
- 收藏
- 分享
- 文章举报
- 51单片机智能小车(舵机云台超声波避障+循迹+蓝牙+红外跟随)
- Arduino 传感器 LED点灯、温湿度传感器数据采集、声控灯、红外避障、超声波测距离实验以及代码
- 五个中断智能小车红外遥控循迹超声波避障跟随光电码盘计数测速
- 基于STC89C52RC单片机的蓝牙遥控与超声波避障程序代码
- arduino小车(二):超声波避障
- 基于stm32f103vc的智能小车——超声波避障部分
- 51超声波避障小车
- Arduino学习笔记 超声波避障小车
- TFmini与舵机结合的小车避障应用方案
- 51自动避障小车整体程序
- Linux内核分析 实验二:完成一个简单的时间片轮转多道程序内核代码
- 第六周实验报告(任务二)【补充代码】
- 实验二代码全解
- linux实验:基于mykernel的一个简单的时间片轮转多道程序内核代码分析
- 实验8 统计和输出一次考试中的最高分、最低分、平均分,以及在90~100、 80~89、 70~79、 60~69和60分以下各分数段的人数。程序代码如下(可复制):
- 实验代码之bufdemo.c
- 具有避障和寻线功能的Arduino小车
- 用来检测寻迹小车电路的代码
- 第二周实验(代码 截图 设计思路)
- 利用STM32F407控制US-100超声波模块测距实验