快捷搜索:  汽车  科技

可控制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__

大家好,我是鼎!

可控制992个舵机-PCA9685驱动分享,可控制992个舵机-PCA9685驱动分享(1)

PCA9685

PCA9685

PCA9685是一款基于IIC总线通信的12位精度16通道PWM波输出的芯片,该芯片最初由NXP推出时主要面向LED开关调光。

目前国内,Arduino在舵机控制领域使用的更广泛,底层驱动库十分完善的,但对于单片机用户来说,则需要自行根据用户手册编写底层的驱动。

优势
  • 价格非常便宜,10 米。
  • 最多可62块板子同时使用,每一块棒子可以驱动多达12个舵机,最多可驱动多达992个舵机,相当可观的数量!
地址误区讲解

可控制992个舵机-PCA9685驱动分享,可控制992个舵机-PCA9685驱动分享(2)

其地址的分配是通过模块右上方的短接焊盘来确定的,从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.c

I2C_InitGPIO();

begin();

setPWMFreq(50);

猜您喜欢: