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

一、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);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一种利用MPLS实现IPv4网络向IPv6网络过度的技术

前言 6PE&#xff08;IPv6 Provider Edge&#xff09;是一种利用MPLS&#xff08;(Multi-Protocol Label Switching&#xff09;&#xff0c;实现IPv4网络向IPv6网络过渡的技术。6PE技术能够使得多个IPv6孤岛网络采用MPLS LSP隧道&#xff0c;跨越IPv4 MPLS骨干网相互进行通信…

碳课堂|如何开展碳排放核算? ISO 14064-2 项目层次要点解读

为提高企业组织碳排放报告信誉度&#xff0c;国际标准化组织&#xff08;ISO&#xff09;发布了ISO14064标准&#xff0c;其中《ISO 14064-2 项目层次上对温室气体减排和清除增加的量化、监测和报告的规范及指南》提供了项目策划阶段的原则要求&#xff0c;以及项目实施阶段的量…

VBA中类的解读及应用第十二讲:限制复选选择(上)

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…

Mybatis Plus二级缓存 使用@CacheNamespace 失效@CacheNamespace和@CacheNamespaceRef

1、注解 CacheNamespace(flushInterval 100000,eviction LruCache.class,readWrite false,size 1024)2、xml配置 <cache eviction "LRU" flushInterval "100000" readOnly "true" size "1024"/> 二级缓存&#xff0c;配置文…

基础设施即代码——灵活构建具备弹性和可扩展性的基础设施

本书的初衷是帮助大家更好地编写基础设施即代码(Infrastructure as Code&#xff0c;IaC)&#xff0c;并且能够在不影响关键业务系统的情况下&#xff0c;稳定高效地变更基础设施资源。本书重点介绍了个人、团队或公司在基础设施系统中应用的模式与实践&#xff0c;聚焦能够应用…

【C++】——内存管理

&#x1f600;&#x1f600;前言 好久没更新了&#xff0c;五一小长假&#xff0c;有点玩脱了&#xff0c;今天赶紧补一篇博客&#xff0c;回回状态 一 c/c内存分配 下面看下面一段代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; i…

华为eNSP中型企业局域网网络规划设计(上)

敲半天一个闪退全™给我干没了呜呜呜&#xff0c;eNSP&#xff0c;wcnm&#xff01;wcnm&#xff01;wcnm&#xff01; →b站传送门&#xff0c;感谢大佬← →华为eNSP中型企业局域网网络规划设计&#xff08;下&#xff09;← →拓扑图传送门&#xff0c;可以自己配置着玩←…

抖音小店怎么运营?最全的运营攻略来了?

大家好&#xff0c;我是电商糖果 很多开好店铺的小伙伴&#xff0c;都会遇到一个难题&#xff0c;那就是不会运营店铺。 可能好几个月才出十几单&#xff0c;甚至体验分都没有弄出来。 说实话&#xff0c;这种情况糖果见多了。 糖果做抖音小店也有四年多了&#xff0c;也开…

【全开源】Java淘宝客多商户系统APP源码任务聚合优惠券多商户源码

功能特点&#xff1a; 商户管理&#xff1a;支持多商户入驻&#xff0c;包括商户的注册、审核、信息维护等功能。同时&#xff0c;系统可以对商户进行分类、排序和搜索&#xff0c;方便管理。全行业覆盖√ miui52086商品管理&#xff1a;提供商品发布、编辑、上下架等功能&…

PMP考试没过怎么办?如何补考?(附复核流程)

最近刷小红书&#xff0c;看很多人都在晒PMP通过的成绩截图&#xff0c;一方面为大家开心&#xff0c;终于拿到了期盼已久的PMP&#xff0c;但同时也有宝子发挥失常没通过考试&#xff0c;所以这期针对没考过的宝子们&#xff0c;出一期复盘文章&#xff0c;无论结果如何&#…

QT4-升级到QT5(1)

1.C报错汇总_nafxcwd.lib error lnk2001-CSDN博客1 1.QT3Support QWidget::setShown 改为QWidget::setVisible 2.头文件 #include<QWidget> 3.部分函数替换

印章常见问题如何防?君子签电子印章实现管章、用章、控章一体化

企业公章管理和使用关乎企业经营&#xff0c;近年来&#xff0c;各类印章问题层出不穷&#xff1a;“通过PS、图片章伪造授权、合同等文件”、“冒充公司员工利用假身份、假印章签约”、“管理层私刻印章伪造业务材料”等常见假印章套路&#xff0c;让企业防不胜防&#xff0c;…

内网渗透(二)

预备知识 什么是域&#xff1f; 域是若干台计算机组成的集合&#xff0c;一个电脑也是。域中的电脑是分等级的&#xff0c;分为域控和成员机。 如何安装域&#xff1f; 在服务器管理中添加服务器角色&#xff0c;添加域服务 如何加入域? 首先一定要修改DNS服务器 ip为域…

解密某游戏的数据加密

前言 最近有个兄弟通过我的视频号加我&#xff0c;咨询能否将这个dubo游戏游戏开始前就将数据拿到从而进行押注&#xff0c;于是通过抓包工具测试了下&#xff0c;发现数据有时候是明文&#xff0c;有时候确实密文&#xff0c;大致看了下有这几种加密&#xff1a;Md5aes、Md5&a…

squeeze的用法

squeeze是压缩张量的命令 import torch a torch.randn(1,3) print(a) print(a.shape) 比如说squeeze&#xff08;&#xff1f;&#xff09;括号里是啥 就是在哪个维度上删除维度为1 之后的结果 比如上上面那个里子 a是&#xff08;[[]]&#xff09; 但是在下面那个例子中d…

软胶囊弹性检测:确保药品质量与患者安全的关键步骤

软胶囊弹性检测&#xff1a;确保药品质量与患者安全的关键步骤 在医药领域&#xff0c;软胶囊作为一种常见的药物载体&#xff0c;其质量的优劣直接关系到药物的有效性和患者的安全。软胶囊的弹性作为其质量评估的重要指标之一&#xff0c;不仅影响其储存和运输的稳定性&#x…

社交客户关系管理(SCRM),和传统CRM的区分

一、SCRM是什么 SCRM是社交客户关系管理&#xff08;Social Customer Relationship Management&#xff09;的缩写&#xff0c;是指通过利用社交媒体和社交网络来管理和建立与客户之间的关系。SCRM将传统的客户关系管理&#xff08;CRM&#xff09;与社交媒体的互动和数据整合…

vue+sortablejs来实现列表拖拽——sortablejs的使用

sortablejs官网:https://sortablejs.com/ 最近在看form-builder组件&#xff0c;发现里面有用到sortablejs插件&#xff0c;用于实现拖拽效果。 但是这个官网中的配置&#xff0c;实在是看不懂&#xff0c;太简单又太复杂&#xff0c;不实用。 下面记录一下我的使用&#xff…

光伏设计的核心要素有哪些?

光伏设计是可再生能源领域中的一个重要分支&#xff0c;它涉及到将太阳能转换为电能的整个过程。在光伏系统的设计和构建过程中&#xff0c;有几个核心要素需要被充分考虑和精确计算&#xff0c;以确保系统的性能、可靠性和经济效益。 一、光照条件分析 光照条件是光伏系统设计…

Qwen大模型实践之初体验

Qwen大模型实践之初体验 测试机器, 使用InternStudio提供的开发机&#xff0c;配置如下&#xff1a; 部分资源详细信息&#xff1a; # CPUIntel(R) Xeon(R) Platinum 8369B CPU 2.90GHz# GPU(base) rootintern-studio-50014188:~# studio-smi Running studio-smi by vgpu-smiW…