STM32--PCA9685驱动(16路舵机驱动模块)

这篇具有很好参考价值的文章主要介绍了STM32--PCA9685驱动(16路舵机驱动模块)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

PCA9685接线:

PCA9685简介:

PCA9685地址位寄存器:

MODE1寄存器,地址0x00,可读、可写:

寄存器地址:

PCA9685代码注解:

1.PCA9685数据写入:

 2.PCA9685数据读取:

3.PCA9685的频率设置:

4.PCA9685的PWM设置:

舵机转动角度置换:

PCA9685驱动代码:

main.c程序:

IIC驱动:(正点原子IIC实验代码)  

IIC.c文件

IIC.h文件 

PCA9685.c配置:

PCA9685.h配置:


PCA9685接线:

pca9685 stm32,stm32,嵌入式硬件,单片机

序号 1 2 3 4 5 6 7 8 9 10
指代 GND OE(模块使能端口) SCL SDA VCC V+ 电源输入端口 PCA9685 pwm通道编号 舵机接口

OE使能端口:低电平使能,内部已经拉低,可以不用接线。

SCL和SDA端口:IIC接口。

V+端口:如果使用少量舵机(两三个舵机),可以通过V+接入电源。(Max电压:6V)

电源输入端口:如果使用多个舵机(五六个舵机),或者大扭矩舵机,最好使用电源输入端口单独

供电不要使用V+端口供电。(Max电压:6V)


PCA9685简介:

PCA9685 是一种常用的 PWM(脉冲宽度调制)驱动器芯片,通常用于控制舵机、电机和其他需要精确控制的设备。该芯片可以通过 I2C 总线与微控制器或单片机通信,以实现对多路 PWM 信号的生成和控制。

16 路 PWM 输出:PCA9685 可以同时控制最多 16 路 PWM 输出,每路输出的占空比都可以独立设置,但是16路PWM频率一样。

12 位分辨率:PCA9685 提供了 12 位分辨率的 PWM 输出,可以实现精细的输出控制。

内部振荡器:芯片内部集成了振荡器,可以产生稳定25MHz的时钟信号,无需外部晶振。

可编程频率:可以通过配置寄存器来设置 PWM 输出的频率,范围从 24 Hz 到 1526 Hz。

I2C 接口:使用标准的 I2C 串行总线接口与主控设备通信,方便集成到各种微控制器系统中。

输出驱动能力:每路 PWM 输出都具有较强的驱动能力,可以直接驱动舵机或者其他负载。


PCA9685地址位寄存器:

地址位的寄存器一共8位,通过地址寄存器来设置芯片的I2C地址。

pca9685 stm32,stm32,嵌入式硬件,单片机

位7 位6 位5 位4 位3 位2 位1 位0
1 A5 A4 A3 A2 A1 A0 R/W
固定值 “ 1 ” 可定义 可定义 可定义 可定义 可定义 可定义 读/写控制

往PCA9685写程序的时候,发送的地址位是0x80,bit[7~0]:1000 0000   位0置“ 0 ”  表示写入;

                   读程序的时候,发送的地址位是0x81,bit[7~0]:1000 0001   位0置“ 1 ”  表示读取;


MODE1寄存器,地址0x00,可读、可写:

pca9685 stm32,stm32,嵌入式硬件,单片机

寄存器地址:

pca9685 stm32,stm32,嵌入式硬件,单片机

照片引用地址:PCA9685--16路 PWM模块舵机驱动板--STM32 IIC接口模块 (baidu.com)


PCA9685代码注解:

1.PCA9685数据写入:

void PCA9685_Write(u8 addr,u8 data)    //   addr 表示要写入数据的寄存器地址,data 表示要写入的数据
{
	IIC_Start();                         //   发送 I2C 起始信号,开始 I2C 通信。
	
	IIC_Send_Byte(PCA_Addr);             //   发送 PCA_Addr = 0x80 ,告诉设备我们要写入数据
	IIC_NAck();                          //   发送不应答信号,表示主控器不需要从设备接收更多数据。
	
	IIC_Send_Byte(addr);                 //   发送要写入数据的寄存器地址。
	IIC_NAck();                          //   发送不应答信号。
	
	IIC_Send_Byte(data);                 //   发送要写入的数据。
	IIC_NAck();                          //   发送不应答信号。
	
	IIC_Stop();                          //   发送 I2C 停止信号,结束本次通信。
	
}

 2.PCA9685数据读取:

u8 PCA9685_Read(u8 addr)                //   addr 表示要读取数据的寄存器地址
{
	u8 data;                           //   声明一个无符号 8 位整数变量 data,用于存储读取到的数据。
	
	IIC_Start();                       //   发送 I2C 起始信号,开始 I2C 通信。
	
	IIC_Send_Byte(PCA_Addr);           //   发送 PCA_Addr = 0x80 ,告诉设备我们要写入数据

	IIC_NAck();                        //   发送不应答信号,表示主控器不需要从设备接收更多数据。
	 
	IIC_Send_Byte(addr);                  //   发送要读取数据的寄存器地址。
	IIC_NAck();                           //   发送不应答信号。
	
	IIC_Stop();                           //   发送 I2C 停止信号,结束本次通信。
	
	delay_us(10);                         //   延时 10 微秒,等待芯片准备好数据。

	
	IIC_Start();                          //   发送 I2C 起始信号,开始另一次 I2C 通信。

	IIC_Send_Byte(PCA_Addr|0x01);         //   发送 PCA9685 的地址,并设置最低位为 1,
                                          //   PCA_Addr|0x01 = 0x81 表示要进行读取操作。

	IIC_NAck();                           //   发送不应答信号。
	 
	data = IIC_Read_Byte(0);              //   通过 I2C 从 PCA9685 读取一个字节的数据,并存储到变量 data 中。
	
	IIC_Stop();                           //   发送 I2C 停止信号,结束本次通信。
	
	return data;                          //   返回读取到的数据。
	
}

3.PCA9685的频率设置:

void PCA9685_setFreq(float freq)
{
	u8 prescale,oldmode,newmode;               //定义了三个无符号 8 位整型变量 用于存储预分频器值、旧的模式寄存器值和新的模式寄存器值
	   
	double prescaleval;                        //定义了一个双精度浮点型变量 prescaleval,用于计算预分频器的值。
	
	freq *= 0.98;                             //将传入的频率值乘以 0.98,这是为了微调频率值以适应 PCA9685 的实际需求
	prescaleval = 25000000;                   //这是 PCA9685 内部振荡器的频率
	prescaleval /= 4096;                      //每个周期从0计数到4095,除以 4096,得到每个计数器周期的时间,
	prescaleval /= freq;                      //除以所需的频率值,得到预分频器的值。
	prescaleval -= 1;                         //减去 1,得到最终的预分频器值
	prescale = floor(prescaleval+0.5f);       //将计算得到的预分频器值四舍五入取整,并将其赋值给 prescale 变量。
	oldmode = PCA9685_Read(PCA_Model);        //通过调用 PCA9685_Read 函数读取当前 PCA9685 寄存器中的模式值,并将其存储在 oldmode 变量中。
	
	newmode = (oldmode&0x7F)|0x10;            //根据旧的模式值计算出新的模式值,将最高位清零(bit 7)并将第 5 位设为1(bit 4),表示将 PCA9685 设置为睡眠模式。
	PCA9685_Write(PCA_Model,newmode);         //将新的模式值写入 PCA9685 的模式寄存器。
	PCA9685_Write(PCA_Pre,prescale);          //将计算得到的预分频器值写入 PCA9685 的预分频器寄存器。
	PCA9685_Write(PCA_Model,oldmode);         //恢复旧的模式值。
	delay_ms(5);                              // 延时 5 毫秒,等待 PCA9685 完全启动。
	PCA9685_Write(PCA_Model,oldmode|0xa1);    //将模式值的最高位和第 1 位设为1,表示将 PCA9685 设置为正常工作模式。
	
}

pca9685 stm32,stm32,嵌入式硬件,单片机

理论计算(预分配值):prescaleval  = ( 25000000 / 4096 / 50 )- 1  =  121 .0703125

实际计算(预分配值):prescaleval  = ( 25000000 / 4096 / 50 *0.98)- 1 = 118.62890625

double prescaleval;                    //定义了一个双精度浮点型变量 prescaleval,用于计算预分频器的值。
	
	freq *= 0.98;                      //将传入的频率值乘以 0.98,这是为了微调频率值以适应 PCA9685 的实际需求
	prescaleval = 25000000;                   //这是 PCA9685 内部振荡器的频率
	prescaleval /= 4096;                      //每个周期从0计数到4095,除以 4096,得到每个计数器周期的时间,
	prescaleval /= freq;                      //除以所需的频率值,得到预分频器的值。
	prescaleval -= 1;                         //减去 1,得到最终的预分频器值
	

内部振荡器的精度限制,设置预分频器值时无法完全达到所需的输出频率,将传入的频率值freq 乘以0.98,是为了微调频率值,以弥补 PCA9685 内部振荡器的偏差,使最终输出的频率更接近预期值。(0.98是经验值,实际使用中可自行调整)

freq *= 0.98;   //将传入的频率值乘以 0.98,这是为了微调频率值以适应 PCA9685 的实际需求

对预分频值prescaleval,进行四舍五入。

例如prescaleval=118.3,则 prescale = floor(prescaleval+0.5f); = floor(118.3+0.5)=118

       prescaleval=118.8,则 prescale = floor(prescaleval+0.5f); = floor(118.8+0.5)=119

prescaleval+0.5f 是为了模拟四舍五入的效果

floor () 函数对浮点数进行向下取整操作,返回不大于该浮点数的最大整数部分。

prescale = floor(prescaleval+0.5f);       //将计算得到的预分频器值四舍五入取整,并将其赋值给 prescale 变量。

oldmode = PCA9685_Read(PCA_Model);        //通过调用 PCA9685_Read 函数读取当前 PCA9685 寄存器中的模式值,并将其存储在 oldmode 变量中。
	
	newmode = (oldmode&0x7F)|0x10;            //根据旧的模式值计算出新的模式值,将最高位清零(bit 7)并将第 5 位设为1(bit 4),表示将 PCA9685 设置为睡眠模式。
	PCA9685_Write(PCA_Model,newmode);         //将新的模式值写入 PCA9685 的模式寄存器。
	PCA9685_Write(PCA_Pre,prescale);          //将计算得到的预分频器值写入 PCA9685 的预分频器寄存器。PCA_Pre = 0xFE

	PCA9685_Write(PCA_Model,oldmode);         //恢复旧的模式值。
	delay_ms(5);                              // 延时 5 毫秒,等待 PCA9685 完全启动。
	PCA9685_Write(PCA_Model,oldmode|0xa1);    //将模式值的最高位和第 1 位设为1,表示将 PCA9685 设置为正常工作模式。

pca9685 stm32,stm32,嵌入式硬件,单片机

pca9685 stm32,stm32,嵌入式硬件,单片机


4.PCA9685的PWM设置:

void PCA9685_setPWM(u8 num,u32 on,u32 off)   //num 表示 PWM 通道号,on 表示 PWM 的起始位置,off 表示 PWM 的结束位置(即从高电平切换到低电平的时刻)
{
	IIC_Start();                              //发送 I2C 起始信号,开始 I2C 通信。
	
	IIC_Send_Byte(PCA_Addr);                  //发送 PCA9685 的地址,告诉设备我们要和 PCA9685 进行通信。
	IIC_Wait_Ack();                           //等待应答信号,确保设备准备好接收数据。

	IIC_Send_Byte(LED0_ON_L+4*num);           //发送 LED 寄存器的地址,根据 PWM 通道号计算出相应的寄存器地址。
	IIC_Wait_Ack();                           //
	
	IIC_Send_Byte(on&0xFF);                   //发送 PWM 的起始位置低 8 位。
	IIC_Wait_Ack();                           //等待应答信号。
	 
	IIC_Send_Byte(on>>8);                     //发送 PWM 的起始位置高 8 位。
	IIC_Wait_Ack();                           //等待应答信号。
	
	IIC_Send_Byte(off&0xFF);                  //发送 PWM 的结束位置低 8 位。
	IIC_Wait_Ack();                           //等待应答信号。
	
	IIC_Send_Byte(off>>8);                    //发送 PWM 的结束位置高 8 位。
	IIC_Wait_Ack();                           //等待应答信号。
	
	IIC_Stop();                              //发送 I2C 停止信号,结束本次通信。
	
}

void PCA9685_setPWM(u8 num,u32 on,u32 off)函数传入:通道编号“ num”、“ on ”的值,“ off ”的值

当PCA9685的12位计数ACK,与“ on ”值进行比较,等于“ on ”值输出高电平

                                                 与“ off ”值进行比较,等于“ off ”值输出低电平

每路 PWM 有 4 个 8 位控制寄存器, LEDX_ON_L、LEDX_ON_H、LEDX_OFF_L、LEDX_OFF_H 四个寄存器。

通道0的LED0_ON_L:0x06,LED0_ON_H:0x07,LED0_OFF_L:0x08,LED0_OFF:0x09

所以输出通道的起始地址为:0x06+4*X (X为通道号)

pca9685 stm32,stm32,嵌入式硬件,单片机


舵机转动角度置换:

可以先了解一下:舵机驱动原理

PCA9685,每个周期都是从0计数到4095;设置  “ on ” = 0 , “  off ” = ?

脉冲宽度 on off
0.5ms 0 0.5/20*4096=102.4
1.5ms 0 1.5/20*4096=307.2
2.5ms 0 2.5/20*4096=512

                           取0.5ms时,off=102  ; 2.5ms时,off=512      

舵机类型 每转动“ 1 ”度,计数个数
90 410/90 = 4.56
180 410/180 = 2.28
270 410/270 = 1.52
360 410/270 = 1.14

个人觉得转化为角度,驱动舵机转动偏差较大,所以直接输入“ off ”值控制舵机转动就好;

因为PCA9685精准度有限,所以理论计算出的的数值与实际存在一定偏差。

所以void setAngle(u8 num,u16 angle)函数和void PCA9685_Init(float hz,u16 angle)函数

根据个人意愿修改参数。

void setAngle(u8 num,u16 angle)
{
	u32 off = 0;                
	off = (u32)(103+angle*1.13);  //360度舵机,每转动一度=1.14   0.5ms -180度起始位置:103
	PCA9685_setPWM(num,0,angle);
}




void PCA9685_Init(float hz,u16 angle)
{
	u32 off = 0;
	IIC_Init();
	PCA9685_Write(PCA_Model,0x00);
	PCA9685_setFreq(hz);
    off = (u32)(103+angle*1.14);  //360度舵机,每转动一度=1.14    0.5ms -180度起始位置:103
	PCA9685_setPWM(0,0,off);
	PCA9685_setPWM(1,0,off);
	PCA9685_setPWM(2,0,off);
	PCA9685_setPWM(3,0,off);
	PCA9685_setPWM(4,0,off);
	PCA9685_setPWM(5,0,off);
	PCA9685_setPWM(6,0,off);
	PCA9685_setPWM(7,0,off);
	PCA9685_setPWM(8,0,off);
	PCA9685_setPWM(9,0,off);
	PCA9685_setPWM(10,0,off);
	PCA9685_setPWM(11,0,off);
	PCA9685_setPWM(12,0,off);
	PCA9685_setPWM(13,0,off);
	PCA9685_setPWM(14,0,off);
	PCA9685_setPWM(15,0,off);
	delay_ms(100);
	
}

PCA9685驱动代码:

main.c程序:

#include "sys.h"
#include "delay.h"
#include "myiic.h"
#include "PCA9685.h"
int main(void)
{ 
    delay_init(168);  //初始化延时函数
	PCA9685_Init(50,360);	
  
   
	while(1)
	{
	      setAngle(4,210);  // 输入pwm通道号、舵机转动角度
		  delay_ms(500);   //添加延时,确定舵机运动到指定位置
		  setAngle(4,120);  // 输入pwm通道号、舵机转动角度
		  delay_ms(500);   //添加延时,确定舵机运动到指定位置
	}

IIC驱动:(正点原子IIC实验代码)  

IIC.c文件

#include "myiic.h"
#include "delay.h"

//初始化IIC
void IIC_Init(void)
{			
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

  //GPIOB8,B9初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
	IIC_SCL=1;
	IIC_SDA=1;
}
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//发送I2C总线结束信号
	delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;delay_us(1);	   
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

IIC.h文件 

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h" 

   	   		   
//IO方向设置
#define SDA_IN()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}	//PB9输入模式
#define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
//IO操作函数	 
#define IIC_SCL    PBout(8) //SCL
#define IIC_SDA    PBout(9) //SDA	 
#define READ_SDA   PBin(9)  //输入SDA 

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif

PCA9685.c配置:

(代码引用于GItcode开源社区)

PCA9685模块使用(Arduino和STM32)_stm32_阿中廋不了-GitCode 开源社区 (csdn.net)文章来源地址https://www.toymoban.com/news/detail-843168.html

#include "PCA9685.h"
#include "myiic.h"
#include "delay.h"
#include <math.h>
#include "led.h"
#include "usart.h"

void PCA9685_Init(float hz,u16 angle)
{
	u32 off = 0;
	IIC_Init();
	PCA9685_Write(PCA_Model,0x00);
	PCA9685_setFreq(hz);
    off = (u32)(103+angle*1.14);  //360度舵机,每转动一度=1.14   0度起始位置:103
	PCA9685_setPWM(0,0,off);
	PCA9685_setPWM(1,0,off);
	PCA9685_setPWM(2,0,off);
	PCA9685_setPWM(3,0,off);
	PCA9685_setPWM(4,0,off);
	PCA9685_setPWM(5,0,off);
	PCA9685_setPWM(6,0,off);
	PCA9685_setPWM(7,0,off);
	PCA9685_setPWM(8,0,off);
	PCA9685_setPWM(9,0,off);
	PCA9685_setPWM(10,0,off);
	PCA9685_setPWM(11,0,off);
	PCA9685_setPWM(12,0,off);
	PCA9685_setPWM(13,0,off);
	PCA9685_setPWM(14,0,off);
	PCA9685_setPWM(15,0,off);
	delay_ms(100);
	
}

void PCA9685_Write(u8 addr,u8 data)
{
	IIC_Start();
	
	IIC_Send_Byte(PCA_Addr);
	IIC_NAck();
	
	IIC_Send_Byte(addr);
	IIC_NAck();
	
	IIC_Send_Byte(data);
	IIC_NAck();
	
	IIC_Stop();
	
	
}

u8 PCA9685_Read(u8 addr)
{
	u8 data;
	
	IIC_Start();
	
	IIC_Send_Byte(PCA_Addr);
	IIC_NAck();
	
	IIC_Send_Byte(addr);
	IIC_NAck();
	
	IIC_Stop();
	
	delay_us(10);

	
	IIC_Start();

	IIC_Send_Byte(PCA_Addr|0x01);
	IIC_NAck();
	
	data = IIC_Read_Byte(0);
	
	IIC_Stop();
	
	return data;
	
}

void PCA9685_setPWM(u8 num,u32 on,u32 off)
{
	IIC_Start();
	
	IIC_Send_Byte(PCA_Addr);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(LED0_ON_L+4*num);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(on&0xFF);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(on>>8);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(off&0xFF);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(off>>8);
	IIC_Wait_Ack();
	
	IIC_Stop();
	
}

void PCA9685_setFreq(float freq)
{
	u8 prescale,oldmode,newmode;
	
	double prescaleval;
	
	freq *= 0.98;
	prescaleval = 25000000;
	prescaleval /= 4096;
	prescaleval /= freq;
	prescaleval -= 1;
	prescale = floor(prescaleval+0.5f);
	oldmode = PCA9685_Read(PCA_Model);
	
	newmode = (oldmode&0x7F)|0x10;
	PCA9685_Write(PCA_Model,newmode);
	PCA9685_Write(PCA_Pre,prescale);
	PCA9685_Write(PCA_Model,oldmode);
	delay_ms(5);
	PCA9685_Write(PCA_Model,oldmode|0xa1);
	
	
}

void setAngle(u8 num,u16 angle)
{
	u32 off = 0;                
	off = (u32)(103+angle*1.13);  //360度舵机,每转动一度=1.14   0度起始位置:103
	PCA9685_setPWM(num,0,angle);
}



 PCA9685.h配置:

#ifndef __PCA9685_H
#define __PCA9685_H
#include "sys.h"
#define PCA_Addr 0x80
#define PCA_Model 0x00
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define PCA_Pre 0xFE

void PCA9685_Init(float hz,u16 angle);

void PCA9685_Write(u8 addr,u8 data);

u8 PCA9685_Read(u8 addr);

void PCA9685_setPWM(u8 num,u32 on,u32 off);

void PCA9685_setFreq(float freq);

void setAngle(u8 num,u16 angle);
#endif

到了这里,关于STM32--PCA9685驱动(16路舵机驱动模块)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32外设芯片驱动学习记录 —— (二) PCA9555 IO扩展芯片驱动开发

    一、芯片介绍 二、Datasheet解读 1.硬件说明 2.寄存器说明 3.通信过程 三、驱动代码编写 1.软件I2C驱动 2. PCA9555芯片驱动函数 总结         PCA9555可设置16路输入或输出口,I2C接口,用于IO扩展,3个硬件地址引脚寻址,工作电压:VCC(2.3V 至 5.5V)。 1)框图   INT:中断输出 A0,

    2024年02月11日
    浏览(49)
  • 基于STM32的pca9535、pca9555IO扩展板开发

    之前使用的pca9535由于芯片本身有些中断问题和采购问题,目前换成了pca9555的IO扩展芯片来使用,本文章适用于这两款芯片。 编译器: keil5 工程库: HAL库 芯片型号:STM32F072 pca9535和pca9555基本一样,这里我就主要说9535的手册了。 手册下载地址网上有很多,直接去百度搜索就行

    2024年02月11日
    浏览(40)
  • pca9685使用教程以及proteus仿真

    pca9685可以通过i2c通信产生16路频率相同的pwm波形,这16路pwm的脉冲宽度可以从0-100任意调整,而且一旦将数据写入寄存器后,单片机无需再关注,能极大减轻单片机的工作任务,常用于驱动由多路舵机组成的机械结构。下面通过51单片机和stm32的实例程序介绍pca9685的使用方法以

    2023年04月08日
    浏览(40)
  • STM32--舵机驱动

    目录 舵机接线: 数字舵机与模拟舵机的区别: 舵机驱动(90度、180度、270度、360度): 90度舵机驱动: 180度舵机驱动: 270度舵机驱动: 360度舵机驱动: STM32定时器配置: stm32f4为例(时钟频率为84Mhz): stm32f1为例(时钟频率为72Mhz): STM32定时器PWM输出配置要点: STM32定时

    2024年04月15日
    浏览(28)
  • STM32驱动SG90舵机

    SG90是一种小型伺服电机,通常用于模型制作和小型机械应用中: 问题 答案 SG90的工作电压是多少 SG90的工作电压通常为3V至7.2V SG90最大扭矩是多少 SG90的最大扭矩约为1.5kg/cm SG90的工作温度范围是多少 SG90的工作温度范围通常为0°C至55°C SG90的控制方式是什么 SG90的控制方式通常为

    2024年02月12日
    浏览(35)
  • stm32HAL库学习笔记----pwm驱动舵机

    目录 一、目标 二、准备 三、原理 四、cubemx 五、程序 实现stm32驱动舵机旋转0°,45°,90°,135°,180°等角度。 stm32f103(c8t6),舵机(SG90 9g),杜邦线 接线:舵机红线-----------5V(mcu)            舵机棕线-----------GND(mcu)            舵机黄线-----------PA1(视情况而定

    2023年04月26日
    浏览(36)
  • stm32——pwm驱动LED灯、舵机、直流电机

    改为PA15,选择重映射方式1或完全重映射 在时钟开启后写入 PWM频率=计数器更新频率 比如要产生一个频率为1KHz,占空比为50%,分辨率为1%的PWM波形 72M/(PSC+1)/ (ARR+1)=1000 CCR/(ARR+1)=0.5 1/(ARR+1)=0.01 计算得:ARR=99,CCR=50, PSC=720-1; 常用模式为 PWM1模式1 PWM.c PWM.h main.c 参数计算 PWM.c Servo.

    2024年02月04日
    浏览(41)
  • stm32f407驱动20KG 270度舵机

    在学习的过程中发现,及时复习是一个好的学习习惯,本文记录使用STM32F407ZGT6控制20KG 270度舵机的学习过程,以便日后复习。 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。广

    2024年02月14日
    浏览(33)
  • K_A16_001 基于STM32等单片机驱动HX711称重模块 串口与OLED0.96双显示

    单片机型号 测试条件 模块名称 代码功能 STC89C52RC 晶振11.0592M HX711称重模块 STC89C52RC驱动HX711称重模块 串口与OLED0.96双显示 STM32F103C8T6 晶振8M/系统时钟72M HX711称重模块 STM32F103C8T6驱动HX711称重模块参数 串口与OLED0.96双显示 其他资料目录 直戳跳转 HX711参数 1.两路可选择差分输入

    2023年04月27日
    浏览(66)
  • STM32CubeIDE学习笔记——使用HAL库PWM输出驱动舵机

    目录 PWM驱动简介 工程配置 代码编写 这里我采用的是STM32F103C8T6最小系统板,SG-90舵机实现功能。 舵机驱动角度和PWM占空比有关系,具体对应为50--0度  150--90度  250--180度,通过STM32的定时器功能输出PWM波来控制舵机进行转动。  时钟选择外部高速时钟 系统映射配置 时钟树设

    2024年02月13日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包