【SG90模拟舵机控制及PCA9685模块的使用】[通俗易懂]

【SG90模拟舵机控制及PCA9685模块的使用】[通俗易懂]一.模拟舵机控制1.简介9g模拟舵机在市面上十分常见,价格也比较便宜。可用于航模,机器人或智能小车等。如上图所示,一个舵机有三条线:VCC、GND和信号线。只要通过信号线给予规定的控制信号即可实现舵机码盘的转动。2.控制信号对于此种模拟舵机的控制是通过发送PWM。…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

一.模拟舵机控制

在这里插入图片描述
在这里插入图片描述
网上不乏对此种舵机的介绍,比如下面这篇文章:
浅谈用单片机控制SG90舵机(原理+编程)

1.简介

SG90模拟舵机在市面上十分常见,价格也比较便宜。常用于航模,机器人或智能小车等。
如上图所示,一个舵机有三条线:VCC、GND和信号线。只要通过信号线给予规定的控制信号即可实现舵机码盘的转动。

2.控制信号

对于此种模拟舵机的控制是通过向信号线持续发送PWM信号,直到舵机转到指定位置(对于数字舵机只需发送一次目标角度的信号)。透过蓝色的舵机外壳可以看到里面有一块很小的电路板,它便是用来将PWM信号转换成舵机的实际转动。

一般PWM信号的周期为20ms(50Hz的频率),想要控制角度只需控制一个周期中高电平持续的时间。以180°舵机为例,对应关系如下:

一个周期中高电平持续时间 舵机保持的角度
0.5ms
1ms 45°
1.5ms 90°
2ms 135°
2.5ms 180°

其他在0°~180°之间的角度通过上表类推即可。(但需要注意舵机的死区时间
需要理解注意的是:对于舵机而言,所有提到的角度均为绝对角度,而非相对角度。即每个角度所对应的是一个固定的位置,并而不是像步进电机那样相对当前位置转动一定角度。

二.PCA9685模块

也可参考下面这篇博客:
16路12位PWM控制器 PCA9685
后续的介绍借鉴了此篇文章。

1.简介

通过之前对舵机的介绍会发现,控制一个舵机需要占用三个引脚,其中一个为单片机的I/O脚。当所需使用的舵机数量较多时,十分占用引脚资源。此时PCA9685模块便可以发挥作用。

PCA9685芯片设计之初是用来控制多路LED灯,后来发现在控制多路舵机上也可发挥很大作用。因此网上所购买的PCA9685模块大都是以控制多路舵机而设计的。如下图所示:
在这里插入图片描述
PCA9685芯片内置了25MHz的晶振,同时也提供外部晶振输入引脚(但是模块中一般不引出此脚,只能使用内部晶振)

2.模块接口介绍:

★1.PCA9685模块的通信使用的是IIC协议,如上图模块左右两侧的SDA数据线和SCL时钟线

★2.OE是芯片的使能引脚,低电平时使能芯片。模块中已经下拉保持低电平,因此使用时可不连接。

★3. 上图中红色线连接的V+引脚是舵机的驱动电压,与PCA9685芯片本身无关。可通过左右两侧的排针接到最小系统板的标准3.3V/5V。当发现驱动电压不够,舵机无法转动或者扭力不够时,可通过上方的接线端子接入外接电源,如锂电池。但需要注意,接入的最大电压不能大于左上角电解电容的耐压值,一般为10V

★4.绿色方框便是舵机的接口,一块PCA9685芯片最多可以控制16路舵机

3.模块器件地址

在这里插入图片描述
模块的器件地址构成如上。其中最高位固定为1,最低位为读/写控制位A0~A5决定了其硬件地址,当采用多个此模块时可借此用于分别的控制。模块中对于A0~A5的设置可见上图的右上角紫色方框。6个引脚通过下拉电阻接地,因此默认全为低电平(即器件地址默认0x80。有些地方说是0x40是因为不考虑读写位,也是正确的),如果焊上框中上方的连接点,便会接到VCC,从而变为高电平。

4.相关寄存器

PCA9685的寄存器较多,使用也相对复杂,此处仅介绍控制舵机需要用到的。

①寄存器总览
寄存器地址 名称
00H MODE1
01H MODE2
02H SUBADR1
03H SUBADR2
04H SUBADR3
05H ALLCALLADR
06H LED0_ON_L
07H LED0_ON_H
08H LED0_OFF_L
09H LED0_OFF_H
··· ···
06H+4*X LEDX_ON_L
06H+4*X+1 LEDX_ON_H
06H+4*X+2 LEDX_OFF_L
06H+4*X+3 LEDX_OFF_H
FA ALL_LED_ON_L
FB ALL_LED_ON_H
FC ALL_LED_OFF_L
FD ALL_LED_OFF_H
FE PRE_SCALE
FF TestMode
②MODE1模式配置寄存器1
SFR name Address bit B7 B6 B5 B4 B3 B2 B1 B0
MODE1 00H name RESTART EXTCLK AI SLEEP SUB1 SUB2 SUB3 ALLCALL

RESTART:0—不复位,1—复位,完成复位后会自动清零;要在SLEEP置0后至少500us以后才能进行复位。

EXTCLK:0—使用内部时钟,1—使用外部时钟;修改此位时,需要先将SLEEP位置1

AI:0—读写后寄存器地址不自动递增,1—读写后寄存器地址自动递增;一般设置自动递增

SLEEP:0—退出SLEEP模式,1—进入SLEEP模式。设置EXTCLK位和PRE_SCALE寄存器前都需先进入SLEEP模式

ALLCALL:0—不响应0x70通用IIC地址,1—相应0x70通用IIC地址。

③PRE_SCALE寄存器

p r e s c a l e   v a l u e = r o u n d ( o s c _ c l o c k 4096 ∗ u p d a t e _ r a t e ) − 1 prescale ~value=round(\frac{osc\_clock}{4096*update\_rate})-1 prescale value=round(4096update_rateosc_clock)1

osc_clock为选用的时钟频率,如使用内部25MHz时钟,即为25 000 000。
update_rate为PWM的频率,如前面说舵机PWM周期为20ms,则update_rate=50Hz。
4096是因为计数器是12位。

经过上式计算可发现,PRE_SCALE中所存的值实际是计数器ACK每自加1,需要的时钟脉冲个数。其实就是时钟分频后计数。和51或stm32的定时器原理类似。

④每个通道的四个寄存器

由之前的寄存器总览表中可看出:16个通道中,每个都有LEDX_ON_L、LEDX_ON_H、LEDX_OFF_L、LEDX_OFF_H 四个寄存器

芯片中12位的计数器ACK,会根据PRE_SCALE设置的值进行计数。
当LEDX_ON_H[3:0]:LEDX_ON_L < ACK < LEDX_OFF_H[3:0]:LEDX_OFF_L时,输出高电平;
当LEDX_OFF_H[3:0]:LEDX_OFF_L < ACK < 4096时,输出低电平;

实际应用中有误差,需要校准,把update_rate乘0.915

5.以stc15单片机为例代码

以上提到的一些要点均会体现在下方的代码中。

★需要注意的是:此模块同一时刻只能改变一个PWM输出,因此控制多个舵机时,只能依次控制,并不能实现多个同步控制。当然,如果使用上面寄存器表中给出的ALL_LED_ON/OFF_L/H四个寄存器,也可以实现所有舵机一起转动,但是转动角度只能是全部相同。

#include <stc15.h> 
#include <intrins.h> 
#include <stdio.h>
#include <math.h>

typedef  unsigned char  u8;        
typedef  unsigned int   u16;        

sbit SCL=P2^0;                   //时钟线
sbit SDA=P2^1;                   //数据线

#define DELAY_TIME 5 //延时时间
#define PCA9685_adrr 0x80 //1+A5+A4+A3+A2+A1+A0+w/r 

#define PCA9685_SUBADR1 0x02
#define PCA9685_SUBADR2 0x03
#define PCA9685_SUBADR3 0x04

#define PCA9685_MODE1 0x00 //MODE1寄存器地址
#define PCA9685_PRESCALE 0xFE //PRE_SCALE寄存器地址

#define LED0_ON_L 0x06 //通道0的四个控制寄存器
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09

#define ALLLED_ON_L 0xFA //全部通道的四个控制寄存器
#define ALLLED_ON_H 0xFB //舵机控制时一般不用
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD

#define SERVO000 130 //0度对应4096的脉宽计数值
#define SERVO180 520 //180度对应4096的脉宽计算值
								//每个舵机都会有一定差异,需要实际测试。

/*-----------------------IIC协议-------------------------*/

/********************************************************* 函数功能:毫秒延时函数 *********************************************************/
void delayms(u16 z)
{ 
   
  u16 x,y;
  for(x=z;x>0;x--)
      for(y=148;y>0;y--);
}

/********************************************************* 函数功能:IIC微秒延时函数,晶振12M,指令周期1T *********************************************************/
void IIC_Delay(unsigned char i)
{ 
   
    do
	{ 
   
		_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
	}while(i--);      
}

/********************************************************* 函数功能:IIC启动 *********************************************************/
void IIC_Start(void)
{ 
   
	SDA = 1;
	SCL = 1;				
	IIC_Delay(DELAY_TIME);
	SDA = 0;
	IIC_Delay(DELAY_TIME);
	SCL = 0;	
}

/********************************************************* 函数功能:IIC停止 *********************************************************/
void IIC_Stop(void)
{ 
   
	SDA = 0;
	SCL = 1;				
	IIC_Delay(DELAY_TIME);
	SDA = 1;
}

/********************************************************* 函数功能:等待从机应答 *********************************************************/
bit IIC_WaitAck(void)
{ 
    
	SDA = 1;
	IIC_Delay(DELAY_TIME);
	SCL = 1;
	IIC_Delay(DELAY_TIME);
	if(SDA)    
	{ 
      
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{ 
    
		SCL = 0;
		return 1;
	}
}

/********************************************************* 函数功能:IIC发送一个字节 *********************************************************/
void IIC_SendByte(unsigned char byt)
{ 
   
	unsigned char i;
	for(i=0;i<8;i++)
	{ 
      
		if(byt&0x80) 
		{ 
   	
			SDA = 1;
		}
		else 
		{ 
   
			SDA = 0;
		}
		IIC_Delay(DELAY_TIME);
		SCL = 1;
		byt <<= 1;
		IIC_Delay(DELAY_TIME);
		SCL = 0;
	}
}

/********************************************************* 函数功能:IIC接收一个字节 *********************************************************/
unsigned char IIC_RecByte(void)
{ 
   
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{ 
      
		SCL = 1;
		IIC_Delay(DELAY_TIME);
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		IIC_Delay(DELAY_TIME);
	}
	return da;
}

/*-----------------------PCA9685模块相关函数-------------------------*/

/********************************************************* 函数功能:向PCA9685的一个地址写数据 *********************************************************/
void PCA9685_write(u8 address,u8 date)
{ 
   
	IIC_Start();
	IIC_SendByte(PCA9685_adrr);   //PCA9685的片选地址
	IIC_WaitAck();                          
	IIC_SendByte(address);  	  //写地址控制字节
	IIC_WaitAck();
	IIC_SendByte(date);           //写数据
	IIC_WaitAck();
	IIC_Stop();
}

/********************************************************* 函数功能:从PCA9685的一个地址读数据 *********************************************************/
u8 PCA9685_read(u8 address)
{ 
   
	u8 date;
	IIC_Start();
	IIC_SendByte(PCA9685_adrr); //PCA9685的片选地址
	IIC_WaitAck();
	IIC_SendByte(address);
	IIC_WaitAck();

	IIC_Start();
	IIC_SendByte(PCA9685_adrr|0x01);        //地址的第八位控制数据流方向,就是写或读
	IIC_WaitAck();
	date=IIC_RecByte();
	IIC_Stop();
	return date;
}

/********************************************************* 函数功能:PCA9685的MODE1寄存器清零 *********************************************************/
void reset(void) 
{ 
   
	PCA9685_write(PCA9685_MODE1,0x00);
}

/********************************************************* 函数功能:PCA9685频率修改 入口参数:freq-输出PWM频率 *********************************************************/
void setPWMFreq(float freq) 
{ 
   
	u16 prescale,oldmode,newmode;
	float prescaleval;
	
	freq *= 0.92;   							//纠正频率设置中的过冲,进行校准 
	prescaleval = 25000000;						//根据公式计算prescale的值
	prescaleval /= 4096;						//prescaleval=round(osc_cloc/4096/freq)-1;
	prescaleval /= freq;
	prescaleval -= 1;
	prescale = floor(prescaleval + 0.5);		
                
	oldmode = PCA9685_read(PCA9685_MODE1);		  //获得MODE1寄存器值
	newmode = (oldmode&0xEF) | 0x10; 			  //SLEEP位 置1
	PCA9685_write(PCA9685_MODE1, newmode);  	  //进入SLEEP模式
	PCA9685_write(PCA9685_PRESCALE, prescale);    //设置频率
	PCA9685_write(PCA9685_MODE1, oldmode);		  //退出SLEEP模式
	delayms(2);
	PCA9685_write(PCA9685_MODE1, oldmode | 0xa1); //RESTART、AI、ALLCALL三个位 置1
}

/********************************************************* 函数功能:改变通道PWM占空比 输入参数:num-使用的通道0~15 on-高电平开始时计数器ACK值 off-高电平结束时计数器ACK值 *********************************************************/
void setPWM(u16 num, u16 on, u16 off) 
{ 
   
	PCA9685_write(LED0_ON_L+4*num,on);		//LED0_ON_L保存on低8位
	PCA9685_write(LED0_ON_H+4*num,on>>8);	//LED0_ON_H保存on高4位
	PCA9685_write(LED0_OFF_L+4*num,off);
	PCA9685_write(LED0_OFF_H+4*num,off>>8);
 }
 
/*-----------------------主函数-------------------------*/
void main()
{ 
   
	reset();
	setPWMFreq(50);  //设置频率50Hz
	//以转动到60°位置为例:
	//60度对应的脉宽=0.5ms+(60/180)*(2.5ms-0.5ms)=1.1666ms
	//利用占空比=1.1666ms/20ms=off/4096,off=239,50hz对应周期20ms
	//setPWM(num,0,239);
	while(1) 
	{ 
   
		setPWM(0, 0, 239);
		setPWM(1, 0, SERVO000);
	}                
}

Jetbrains全家桶1年46,售后保障稳定

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/203716.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • ASF(传感器)

    ASF(传感器)

  • Flink的sink实战之三:cassandra3

    Flink的sink实战之三:cassandra3

    2020年11月19日
  • 代价函数的意义

    代价函数的意义我们来复习上一节的知识:假设函数:hθ(x)=θ0+θ1xh_\theta(x)=\theta_0+\theta_1xhθ​(x)=θ0​+θ1​x参数:θ0,θ1\theta_0,\theta_1θ0​,θ1​代价函数:J(θ0,θ1)=12m∑i=1i=m(h(xi)−yi)2J(\theta_0,\theta_1)=\frac{1}{2m}\sum_{i=1}^{i=m}(h(x^i)…

  • makefile文件编写「建议收藏」

    makefile文件编写「建议收藏」makefile文件用于管理和组织代码工程的编译和链接,其不是可执行文件,其被make工具解析并完成相关动作,下面笔者将介绍makefile中常用的一些语法说明:1、文件包含:语法:include文件名作用:将其它makefile文件包含进来,组成一个更大的makefile文件,这样有利于makefile模块化编程。通常我们将一些配置选项分开成一个独立的makefile文件,这…

  • py爬取图片_Python爬取图片

    py爬取图片_Python爬取图片疲惫的生活里总要有些温柔梦想吧目标URL:http://www.win4000.com/meinvtag4_1.html爬取美桌网某个标签下的美女壁纸,点进详情页可以发现,里面是一组套图一…

  • Qt 音乐播放器「建议收藏」

    Qt 音乐播放器「建议收藏」一、实现功能:1、读取歌曲文件,实现歌曲的播放;2、采用QtDesigner实现歌曲的暂停和播放,歌曲名列表和当前播放歌曲名的显示,上一曲和下一曲歌曲的更换,播放模式的设置,音量的改变,歌曲播放进度的改变;3、读取歌词文件,实现歌词的显示;4、利用QSetting增加歌曲文件和歌词文件的设置功能;5、界面汉化;6、使用CSS进

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号