STM32、GD32驱动PCA9685控制舵机源码分享

news2025/4/27 9:13:07

一、PCA9685介绍

PCA9685是一种16通道PWM(脉宽调制)控制器芯片,由NXP Semiconductors公司生产。它具有高速I2C总线接口,可以通过I2C总线与微控制器或其他设备进行通信。PCA9685广泛应用于各种需要精确控制多路PWM信号的应用,如LED灯控制、舵机控制、电机控制等。

PCA9685芯片具有以下主要特点:

  1. 16个独立的PWM输出通道,每个通道可以独立设置频率和占空比。
  2. 可以设置PWM输出频率的范围从24Hz到1526Hz。
  3. 可以通过I2C接口进行配置和控制,使得系统设计更加简单。
  4. 支持输出使能和禁用功能,方便对PWM信号进行控制。
  5. 高精度的PWM输出,可以实现精确的电平控制。
  6. 内部集成了晶振,无需外部元件。

PCA9685芯片的工作原理是通过调整PWM的占空比来控制输出信号的电平。用户可以设置PWM输出频率和占空比,通过改变占空比来改变输出信号的电平。此外,PCA9685还具有外部触发功能,可以通过外部触发引脚来触发特定的操作或事件。

总之,PCA9685是一款功能丰富且易于使用的PWM控制器芯片,适用于各种需要精确控制多路PWM信号的应用。它的高精度、高可靠性和简单的接口使其成为许多电子设备和机器人应用的理想选择。

二、PCA9685原理图

在这里插入图片描述

三、源码

iic.h

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

//IO方向设置
#define SDA_IN()  {GPIOG->MODER&=~(3<<(13*2));GPIOG->MODER|=0<<13*2;}	//PH5输入模式
#define SDA_OUT() {GPIOG->MODER&=~(3<<(13*2));GPIOG->MODER|=1<<13*2;}  //PH5输出模式
//IO操作
#define IIC_SCL(n)  (n?HAL_GPIO_WritePin(GPIOG,GPIO_PIN_14,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOG,GPIO_PIN_14,GPIO_PIN_RESET)) //SCL
#define IIC_SDA(n)  (n?HAL_GPIO_WritePin(GPIOG,GPIO_PIN_13,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOG,GPIO_PIN_13,GPIO_PIN_RESET)) //SDA
#define READ_SDA    HAL_GPIO_ReadPin(GPIOG,GPIO_PIN_13)  //输入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


iic.c

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


//IIC初始化
void IIC_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_GPIOG_CLK_ENABLE();   //使能GPIOH时钟
    
    //PH4,5初始化设置
    GPIO_Initure.Pin=GPIO_PIN_14|GPIO_PIN_13;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;    //快速
    HAL_GPIO_Init(GPIOG,&GPIO_Initure);
    
    IIC_SDA(1);
    IIC_SCL(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;
}

pca9685.h

#ifndef __NCA9555_H
#define __NCA9555_H
#include "sys.h"
#include "myiic.h"

#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09


void pca9685_init(u8 slaveAddr,float hz,uint8_t angle);
void pca9685_set_servo_angle(u8 slaveAddr,uint8_t num,uint8_t angle);

#endif


pca9685.c

#include "pca9685.h"
#include "delay.h"
#include "math.h"

void pca9685_write(u8 slaveAddr,u8 adrr,u8 data)//向PCA写数据,adrrd地址,data数据
{ 
	IIC_Start();
	
	IIC_Send_Byte(slaveAddr);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(adrr);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(data);
	IIC_Wait_Ack();
	
	IIC_Stop();
}

u8 pca9685_read(u8 slaveAddr,u8 adrr)//从PCA读数据
{
	u8 data;
	IIC_Start();
	
	IIC_Send_Byte(slaveAddr);
	IIC_Wait_Ack();
	
	IIC_Send_Byte(adrr);
	IIC_Wait_Ack();
	
	IIC_Start();
	
	IIC_Send_Byte(slaveAddr|0x01);
	IIC_Wait_Ack();
	
	data=IIC_Read_Byte(0);
	IIC_Stop();
	
	return data;
}
void pca9685_set_freq(u8 slaveAddr,float freq)//设置PWM频率
{
	uint8_t prescale,oldmode,newmode;
	double prescaleval;
	freq *= 0.83f; 			//实际使用过程中存在偏差需要×矫正系数=0.83
	prescaleval = 25000000;
	prescaleval /= 4096;
	prescaleval /= freq;
	prescaleval -= 1;
	prescale =floor(prescaleval + 0.5f);			//floor向下取整函数
	oldmode = pca9685_read(slaveAddr,PCA9685_MODE1);
    newmode = (oldmode&0x7F) | 0x10; // sleep睡眠
	pca9685_write(slaveAddr,PCA9685_MODE1, newmode); // go to sleep(需要进入随眠状态才能设置频率)
	pca9685_write(slaveAddr,PCA9685_PRESCALE, prescale); // 设置预分频系数
	pca9685_write(slaveAddr,PCA9685_MODE1, oldmode);
	HAL_Delay(2);
	pca9685_write(slaveAddr,PCA9685_MODE1, oldmode | 0xA1); 
}


/*num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096,off:PWM下降计数值0~4096*/
void pca9685_set_duty(u8 slaveAddr,uint8_t num, uint32_t on, uint32_t off)
{
	pca9685_write(slaveAddr,LED0_ON_L+4*num,on);
	pca9685_write(slaveAddr,LED0_ON_H+4*num,on>>8);
	pca9685_write(slaveAddr,LED0_OFF_L+4*num,off);
	pca9685_write(slaveAddr,LED0_OFF_H+4*num,off>>8);
}
/*函数作用:初始化舵机驱动板参数:1.PWM频率2.初始化舵机角度*/
void pca9685_init(u8 slaveAddr,float hz,uint8_t angle)
{
	uint32_t off=0;
	pca9685_write(slaveAddr,PCA9685_MODE1,0x0);
	pca9685_set_freq(slaveAddr,hz);//设置PWM频率
	off=(uint32_t)(145+angle*2.4);
	pca9685_set_duty(slaveAddr,0,0,off);
	pca9685_set_duty(slaveAddr,1,0,off);
	pca9685_set_duty(slaveAddr,2,0,off);
	pca9685_set_duty(slaveAddr,3,0,off);
	pca9685_set_duty(slaveAddr,4,0,off);
	pca9685_set_duty(slaveAddr,5,0,off);
	pca9685_set_duty(slaveAddr,6,0,off);
	pca9685_set_duty(slaveAddr,7,0,off);
	pca9685_set_duty(slaveAddr,8,0,off);
	pca9685_set_duty(slaveAddr,9,0,off);
	pca9685_set_duty(slaveAddr,10,0,off);
	pca9685_set_duty(slaveAddr,11,0,off);
	pca9685_set_duty(slaveAddr,12,0,off);
	pca9685_set_duty(slaveAddr,13,0,off);
	pca9685_set_duty(slaveAddr,14,0,off);
	pca9685_set_duty(slaveAddr,15,0,off);

}
/*函数作用:控制舵机转动;参数:1.输出端口,可选0~15; 2.结束角度,可选0~180;*/
void pca9685_set_servo_angle(u8 slaveAddr,uint8_t num,uint8_t angle)
{
	uint32_t off=0;	
	off=(uint32_t)(158+angle*2.2);
	pca9685_set_duty(slaveAddr,num,0,off);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1654820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【启明智显技术分享】基于ESP32-S3方案的彩屏固件烧录指南

前言&#xff1a; 【启明智显】专注于HMI&#xff08;人机交互&#xff09;及AIoT&#xff08;人工智能物联网&#xff09;产品和解决方案的提供商&#xff0c;我们深知彩屏显示方案在现代物联网应用中的重要性。为此&#xff0c;我们一直致力于为客户提供彩屏显示方案相关的技…

ThreeJS:补间动画与Tween.JS

补间动画 补间动画指的是做FLASH动画时&#xff0c;在两个关键帧中间需要做“补间动画”&#xff0c;才能实现图画的运动&#xff1b;插入补间动画后两个关键帧之间的插补帧是由计算机自动运算而得到的。 ——摘自《百度百科&#xff1a;补间动画_百度百科》 Tween.js Tween.js…

JRT失控处理打印和演示

基于JRT完备的脚本化和打印基础&#xff0c;基于JRT的业务可以轻松的实现想要的打效果&#xff0c;这次以质控图的失控处理打印和月报打印来分享基于JRT的打印业务实现。 演示视频链接 失控报告打印 失控处理打印的虚拟M import JRT.Core.DataGrid.GridDto; import JRT.Co…

数据结构(十二)----查找

目录 一.查找的概念 二.查找算法 1.顺序查找 顺序查找的查找效率&#xff1a; 顺序查找的优化&#xff1a; •有序表的优化&#xff08;缩短查找失败的平均查找长度&#xff09; •被查概率不相等的表的优化&#xff08;缩短查找成功的平均查找长度&#xff09; 2.折半…

[Redis] 使用布隆过滤器和分布式锁实现用户注册

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种数据结构&#xff0c;用于快速判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来表示一个集合&#xff0c;当一个元素被加入到集合时&#xff0c;通过哈希函数计算出多个哈希值&#xff0c;并…

「网络流 24 题」最小路径覆盖 【最小路径覆盖】

「网络流 24 题」最小路径覆盖 思路 具体可以看 这篇博客 对于有向无环图&#xff0c;我们只需要将假装将点裂成左点和右点&#xff08;实际没有裂开&#xff09;&#xff0c;然后连边&#xff1b; 在上面跑二分图最大匹配后&#xff0c;剩下没有匹配的左点就是终点&#xff…

【linuxC语言】获取进程信息

文章目录 前言一、getrusage函数二、示例代码总结 前言 在Linux环境下&#xff0c;了解和获取进程的信息对于系统监控、性能优化以及调试等任务至关重要。C语言作为Linux系统编程的主要语言之一&#xff0c;提供了丰富的系统调用和库函数&#xff0c;可以帮助我们轻松地获取进…

嵌入式学习69-C++(Opencv)

知识零碎&#xff1a; QT的两种编译模式 1.debug 调试模式 …

javaWeb入门(自用)

1. vue学习 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script src"https://unpkg.com/vue2"></script> </head> <body><div id"…

Q1保健品线上市场分析(二):头部力量缺失,中高端鱼油高速成长

事实上&#xff0c;我国的鱼油行业相较其他国家来说起步较晚。但随着这几年大众健康意识的增强&#xff0c;保健品行业得到了更加深入的发展&#xff0c;人们对鱼油的认知度大大提升。 鱼油中的DHA、EPA等成分在降血脂、明目益智、抗炎等方面有不可替代的功效&#xff0c;因此…

如何避免在抓取Google时被屏蔽?代理IP的7个使用误区

在当今数字化时代&#xff0c;数据采集和网络爬取已成为许多企业和个人必不可少的业务活动。对于爬取搜索引擎数据&#xff0c;特别是Google&#xff0c;使用代理IP是常见的手段。然而&#xff0c;使用代理抓取Google并不是一件轻松的事情&#xff0c;有许多常见的误区可能会导…

项目经理【过程】原则

系列文章目录 【引论一】项目管理的意义 【引论二】项目管理的逻辑 【环境】概述 【环境】原则 【环境】任务 【环境】绩效 【人】概述 【人】原则 【人】任务 【人】绩效 【过程】概念 【过程】原则 一、质量管理水平、质量管理的发展 1.1 质量管理水平 1.2 质量管理的发展 …

Java | Spring框架 | @Autowired与@Resource

在Spring框架中&#xff0c;依赖注入是一种核心概念&#xff0c;它允许开发者将对象的创建和对象之间的依赖关系的管理交给框架来处理。这样做的目的是为了提高代码的模块化和可测试性。 Spring提供了多种方式来实现依赖注入&#xff0c;其中最常用的方式是通过注解。在本文中…

C++笔试强训day15

目录 1.平方数 2.分组 Check函数的具体实现&#xff1a; 3.拓扑排序 1.平方数 链接 数学找规律&#xff0c;找离 x 最近的完全平方数 y。 先开平方根再利用四舍五入进位即可。 详细代码&#xff1a; #include <cmath> #include <iostream> using namespac…

小猪APP分发:重塑应用分发市场的创新力量

在移动互联网蓬勃发展的今天&#xff0c;应用分发平台作为连接开发者与用户的桥梁&#xff0c;扮演着至关重要的角色。然而&#xff0c;随着市场的饱和&#xff0c;如何在众多平台中脱颖而出&#xff0c;为开发者提供更宽广的舞台&#xff0c;同时确保用户能够便捷、安全地获取…

STC8增强型单片机开发——GPIO

一、理解电灯案例的代码 #include "STC8H.H"int main() {P5M0 0x00;P5M1 0x00;P53 1;while(1) {} } #include "STC8H.H" 引入头文件P5M0 0x00;P5M1 0x00;配置引脚模式P531;配置IO引脚的电平 二、头文件STC8H.H 针对 STC8H 系列芯片的头文件&#xff…

「网络流 24 题」魔术球 【最小路径覆盖】

「网络流 24 题」魔术球 注意这里的球是依次放置&#xff0c;也就是说如果当前放到第 i i i 号球&#xff0c;那么 1 → i − 1 1 \rarr i - 1 1→i−1 号球都已经放好了&#xff0c;否则可以放无数个球 思路 首先我们对于 i < j 且 i j 完全平方数 i < j 且 i j…

啸叫抑制器采用什么处理芯片?ES56031或PH56031

会议系统或卡拉OK最头疼的就是啸叫了吧&#xff0c;来看看啸叫抑制器采用什么芯片 四通道啸叫抑制器&#xff0c;采用了2个电路板&#xff0c;每个板子处理2路信号&#xff0c;每块电路板有2个卡侬输入插座&#xff0c;2个卡侬输出插座 ES56031S&#xff0c;该啸叫抑制器为4通道…

可视化:智慧能源解决方案,降本增效,运筹帷幄。

智慧能源可视化解决方案是一种利用先进的技术和工具&#xff0c;将能源数据以直观、可视的方式呈现出来&#xff0c;帮助企业更好地管理能源使用&#xff0c;降低成本&#xff0c;提高效率的解决方案。 以下是一些智慧能源可视化解决方案可以帮助企业降本增效、智连未来的方式&…

在思科和华为上实现两个主机A,B A能ping通B,B不能ping通A

1.华为实验的topo如下 常规状态下任意两台主机都是可以ping通的 此时的需求是PC4能ping通PC2和PC3但是PC2和PC3不能ping通PC4 这里需要用到ACL策略 在接口上调用 验证&#xff1a; PC4能ping通PC2和PC3 PC2和PC3不能ping通PC4 2.思科类似 正常情况下是都能互相ping通 加上ac…