可控制992个舵机-PCA9685驱动分享,可控制992个舵机-PCA9685驱动分享
可控制992个舵机-PCA9685驱动分享,可控制992个舵机-PCA9685驱动分享/* 包含头文件 ----------------------------------------------------------------*/#define __I2C_PCA9685_H__其地址的分配是通过模块右上方的短接焊盘来确定的,从A0-A5表示地址的最低位到最高位,也就是最多可级联2^5=32个模块,地址为: 1 A5 A4 A3 A2 A1 A0 rw。如果不用短接的话Ax=0;短接的话Ax=1;rw为写的话rw=0;rw为读的话rw=1;所以默认地址应为1000 0000 =0x80,许多人包括淘宝商家误以为默认地址是0x40,是错误的!可以利用模拟IIC总线通讯,方便移植,摆脱硬件的限制。#ifndef __I2C_PCA9685_H__
大家好,我是鼎!
PCA9685
PCA9685PCA9685是一款基于IIC总线通信的12位精度16通道PWM波输出的芯片,该芯片最初由NXP推出时主要面向LED开关调光。
目前国内,Arduino在舵机控制领域使用的更广泛,底层驱动库十分完善的,但对于单片机用户来说,则需要自行根据用户手册编写底层的驱动。
优势- 价格非常便宜,10 米。
- 最多可62块板子同时使用,每一块棒子可以驱动多达12个舵机,最多可驱动多达992个舵机,相当可观的数量!
其地址的分配是通过模块右上方的短接焊盘来确定的,从A0-A5表示地址的最低位到最高位,也就是最多可级联2^5=32个模块,地址为: 1 A5 A4 A3 A2 A1 A0 rw。如果不用短接的话Ax=0;短接的话Ax=1;rw为写的话rw=0;rw为读的话rw=1;所以默认地址应为1000 0000 =0x80,许多人包括淘宝商家误以为默认地址是0x40,是错误的!
IIC通信可以利用模拟IIC总线通讯,方便移植,摆脱硬件的限制。
驱动 PCA9685.h#ifndef __I2C_PCA9685_H__
#define __I2C_PCA9685_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
#define PCA9685_adrr 0x80
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x0
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
#define FINGLEMAX 25
#define FINGLEMIN 90
/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void PCA9685_write(unsigned char reg unsigned char data);
uint8_t PCA9685_read(unsigned char reg);
void setPWMFreq(uint8_t freq);
void setPWM(uint8_t num uint16_t on uint16_t off);
void begin();
void Angle(uint8_t num float angle);
#endif /* __I2C_PCA9685_H__ */
/************************END OF FILE************************/
驱动PCA9685.C/* 包含头文件 ----------------------------------------------------------------*/
#include "i2c/bsp_I2C.h"
#include "PCA9685/bsp_i2c_PCA9685.h"
#include "stm32f4xx_hal.h"
#include "i2c/bsp_I2C.h"
#include "math.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
void PCA9685_Delay(void)
{
uint8_t i;
for (i = 0; i < 30; i );
}
void PCA9685_write(uint8_t reg uint8_t date)
{
I2C_Start();
I2C_SendByte(PCA9685_adrr); //PCA9685
I2C_WaitAck();
I2C_SendByte(reg);
I2C_WaitAck();
I2C_SendByte(date);
I2C_WaitAck();
I2C_Stop();
}
//从PCA9685读数据有返回值
uint8_t PCA9685_read(uint8_t reg)
{
uint8_t res;
I2C_Start();
I2C_SendByte(PCA9685_adrr); //PCA9685
I2C_WaitAck();
I2C_SendByte(reg);
I2C_WaitAck();
I2C_Start();
I2C_SendByte(PCA9685_adrr|0x01);
I2C_WaitAck();
res = I2C_ReadByte();
I2C_Stop();
return res;
}
//PCA9685复位
void reset(void)
{
PCA9685_write(PCA9685_MODE1 0x0);
}
void begin(void)
{
reset();
}
//PCA9685修改频率
/**
* 函数功能: 设置PWM频率
* 输入参数: 20MS设置50
* 返 回 值: 无
* 说 明:无
*/
void setPWMFreq(uint8_t freq)
{
uint8_t prescale oldmode newmode;
double prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setTIng
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = (uint8_t)floor(prescaleval 0.5);
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1 newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1 oldmode);
HAL_Delay(2);
PCA9685_write(PCA9685_MODE1 oldmode|0xa1);
}
/*---------------------------------------------------------------
PCA9685修改角度函数
num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096 off:PWM下降计数值0~4096
一个PWM周期分成4096份,由0开始 1计数,计到on时跳变为高电平,继续计数到off时
跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时 当on等于0时,
off/4096的值就是PWM的占空比。
----------------------------------------------------------------*/
/**
* 函数功能: 设置PWM占空比
* 输入参数: num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096 off:PWM下降计数值0~4096
一个PWM周期分成4096份,由0开始 1计数,计到on时跳变为高电平,继续计数到off时
跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时 当on等于0时,
off/4096的值就是PWM的占空比。
* 返 回 值: 无
* 说 明:无
*/
void setPWM(uint8_t num uint16_t on uint16_t off)
{
PCA9685_write(LED0_ON_L 4*num on);
PCA9685_write(LED0_ON_H 4*num on>>8);
PCA9685_write(LED0_OFF_L 4*num off);
PCA9685_write(LED0_OFF_H 4*num off>>8);
}
uint16_t calculate_PWM(float angle){
return (int)(204.8*(0.5 angle*1.0/90));
}
/**
* 函数功能: 舵机角度
* 输入参数: num:舵机通道 angle:舵机角度
* 返 回 值: 无
* 说 明:无
*/
void Angle(uint8_t num float angle)
{
uint16_t pwm = calculate_PWM(angle);
setPWM(num 0 pwm);
PCA9685_Delay();
}
/************************END OF FILE****/
main.cI2C_InitGPIO();
begin();
setPWMFreq(50);