stm32智能遥控小车项目(2) --- 方向的控制(舵机的使用)

1 前言

种种原因,我的项目耽搁了诸多时辰,现在正式重新启航.

今天,我们深入舵机的使用.

2 舵机的初步使用

对于舵机的使用我们先不管三七二十一,不去管什么原理啊,电路啊,点击啥的,直接上手.

2.1 PWM的初步了解

具鲁迅说过,对于舵机,就是要输出一个PWM信号去控制舵机的旋转.

那么我们怎样得到一个PWM信号呢?

我依稀记得,通过单片机输出PWM信号可以实现呼吸灯,我好久之前写过相关的TIM控制输出PWM信号的代码.

那么PWM信号究竟是啥呢?

哈哈,其实很是简单,就是一直高频率的交替高低电平来控制输出的大小.

比如OLED显示屏,就是现在主流的显示器,基本都是通过PWM调光来控制屏幕亮度.

        用户需要高强度,输出的电平就是大部分的高电平,也就是占空比(是一个脉冲周期内,高电平的时间与整个周期时间的比例)很大;

        而当到了晚上,躺在被窝里面玩手机的时候,是不是需要屏幕变暗呢?所以就需要占空比减小来降低屏幕的亮度了.

        可能你会好奇,当输出的电平是低电平的时候屏幕不是会直接黑了吗?那么我们平时在看手机的时候却没有感觉到?其实啊,这就设计到一个频率的问题了.

pwm的周期:T=1/f (周期=1/频率)
50Hz = 20ms 一个周期

如果频率为50Hz ,也就是说一个周期是20ms 那么一秒钟就有 50次PWM周期

那么可能会好奇啊,我们手机的频率多大呢?

可以算算,在短短的一秒钟,OLED的小灯珠亮了多少次,而我们的眼睛的视觉是有延迟拖影的,生物学上面人眼根本就不能看到屏幕的闪烁,当然如果 你是变异人种或者是有特殊功能那当我没说.如果你使用的是OLED屏幕的手机(尤其是三星和苹果),你可以用另外一个手机照射屏幕,你会惊奇的发现,可以看到在手机的摄像机下就可以看到被拍摄的手机屏幕一闪一闪的.

那为什么我们的人眼看不出,可是手机的摄像头却看得出呢?难道现在的手机摄像头有什么特殊技能?其实不然.据我猜测,是因为拍摄的手机的屏幕也存在频闪,2台手机都是OLED屏幕,都有频闪,难免会重叠,就造成了拍摄下的手机有黑影闪闪.

所以啊还是建议在黑暗环境下尽量少玩电子设备,就算是护眼的LED屏幕,也要控制.

闲话说多了,直接进入正题吧,我们通过STM32的GPIO输出PWM.

2.2 STM32输出PWM信号

我们要通过STM32输出PWM信号毫无疑问就要使用到TIM.

下面就是stm32的TIM的使用与原理

唉,我就简单的用口头语言来说一下吧   

TIM其实就是一个定时器,定时器就是口头意思.

我们可以给TIM一个设定的溢出值,然后设定TIM是自增(自减),当TIM的值到达溢出值的时候,TIM就会返回原始值,开始新一轮的自增.这就是一个周期.

如果我们要输出PWM波形,就可以再设置一个比较的值.比如当TIM自增的值小于比较值的时候就输出低电平,当TIM自增的值大于比较值的时候就输出高电平.

如图所示

画技比较粗糙

原理就是如此的简单

然后就是一个重要的问题:我们该如何设置周期呢,也就是频率呢?

周期是时间,也就是TIM自增值回到初始值的时间,而频率是在一秒中内的周期数,也就是

频率 = 1 / 周期

而我们今天使用的舵机,规定的周期是20ms.所以等一下要将PWM的周期设置为20ms.

在stm32中的TIM使用的频率是怎样设置的呢?

可以看到我们的stm32f103的定时器2-7的时钟的使用地方.时钟可以进行而外的配置,但是一般我们默认的时钟频率是72M(百万),我们细心点可以观察到图中有一个最大的36M,其实系统默认的就是设置成了36M了,APB1预分频系数默认为2了.

然后经过外设时钟使能,时钟的频率乘以2后,定时器的初始频率就是72MHz.也就是一秒钟有72M个周期,可以说是难以想象的速度.而速度快,也是我们stm32强大的重要保证.速度其实就是我们计算机的最大的优势.天下武功唯快不破.

下面就是PWM相关的设置代码了

#include "stm32f10x.h"
#include "Timer.h"

void TIM_Dir_Init()
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef TIM_OCInitStruct;
	GPIO_InitTypeDef GPIO_InitStruct;
	//TIM时基单元的配置,一定要记得配置时钟
	RCC_APB1PeriphClockCmd(TIM_TIME_BASE_CLK,ENABLE);
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 20000 - 1;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;         //预分频  (舵机需要的周期是20ms)
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIMx,&TIM_TimeBaseInitStruct);
	//TIM额外配置
	TIM_InternalClockConfig(TIMx);//选择内部时钟
	TIM_ClearFlag(TIMx,TIM_FLAG_Update);//因为配置好之后会自动置1,所以要清0
	TIM_Cmd(TIMx,ENABLE);//开启TIM3
	//
	TIM_ITConfig(TIMx,TIM_IT_Update,ENABLE);//选择中断模式
	//TIM输出比较输出PWM方波(不需要配置时钟)
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//1和2只是方向不同
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//不翻转
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse = 0;//配置比较寄存器CCR
	TIM_OC2Init(TIMx,&TIM_OCInitStruct);
	
	RCC_APB2PeriphClockCmd(LED_GPIO_CLK,ENABLE);
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//要求此复用GPIO位复用推挽输出
	GPIO_InitStruct.GPIO_Pin = LED_GPIO_PIN;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(LED_GPIOx,&GPIO_InitStruct);
	GPIO_WriteBit(LED_GPIOx,LED_GPIO_PIN,Bit_SET);//上电灯灭状态
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIMx,Compare);//配置比较寄存器CCR的值,改变PWM波形的占空比
}

void tim_PrescalerConfig(uint16_t Prescaler)
{
	//配置预分频(TIM_Prescaler)来改变PWM的频率
	TIM_PrescalerConfig(TIMx,Prescaler,TIM_PSCReloadMode_Update);
}
#ifndef __TIM_BREATHELED_H__
#define __TIM_BREATHELED_H__
#include "stm32f10x.h"  

#define LED_GPIO_CLK        RCC_APB2Periph_GPIOB
#define LED_GPIO_PIN        GPIO_Pin_7
#define LED_GPIOx           GPIOA
#define TIM_TIME_BASE_CLK   RCC_APB1Periph_TIM3
#define TIMx                TIM3

void TIM_Dir_Init();
void PWM_SetCompare2(uint16_t Compare);
void tim_PrescalerConfig(uint16_t Prescaler);
#endif

在设置TIM的过程中,比如选择哪个定时器,哪个通道,通道对应的是哪个GPIO,GPIO要设置为复用模式等问题这里就不会一一解答了.需要自己去查询手册或者学习相关教程.

2.3 舵机的使用

下面就简单了,无非就是给给PWM的代码封装一下

#include "Device/Include/stm32f10x.h"   // Device header
#include "direction.h"
#include "Timer.h"
#include <stdio.h>
#include "Serial.h"
void Dir_Config()
{
	TIM_Dir_Init();
	PWM_SetCompare2(7.5);
}

/**
 * @brief 控制舵机转动角度大小
 * @param 角度大小(0 - 180 (度))
 * @retval
 */
void Dir_Control(uint16_t angle)
{
	PWM_SetCompare2(angle/180*2000+500);
	
}

舵机,无非就是控制方向嘛,就是 0 - 180度的角度控制.

那么舵机自己设定的就是 0 - 180 度对应的就是 20ms 中高电平时间的 2.5 - 12.5ms

上main.c

#include "stm32f10x.h"
#include "OLED.h"
#include "Delay.h"
#include "Timer.h"
#include "LED.h"
#include "direction.h"

int main()
{
	uint16_t a = 0;
	LED_Init();
	Dir_Config();
	while(1)
	{    
		LED_Green_ON();
		a = 0;
		Dir_Control(a);
		Delay_ms(3000);
		LED_Green_OFF();
		a = 180;
		Dir_Control(a);
		Delay_ms(3000);
//		
//		LED_Green_ON();
//		PWM_SetCompare2(2.5);
//		Delay_ms(3000);
//		LED_Green_OFF();
//		PWM_SetCompare2(12.5);
//		Delay_ms(3000);
	}
}



其实也是有一些细节的,想 uint16_t 类型不能出现小数,uint16_t其实就是short int型嘛.

在c语言的运用中,对于数据类型的处理一定要多加注意,昨天经验缺失的我就在这里栽了跟头.

尽量将数据都转化为整数处理.我们的数据在计算机中的存储都是有自己规则,不是按照我们大脑的存储规则.

烧录后,我们就可以看到舵机的头不断的旋转了,从0到180度,再从180度到0度.

3 展望

小车的方向已经确定好了,接下来就是小车的动力了.

我先将小车的底座安装好.

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值