STM32控制PCA9685产生16路PWM波控制舵机

 本文借鉴了这篇文章STM32--PCA9685驱动(16路舵机驱动模块)-CSDN博客,文章基础知识的介绍已经很详细了。本文采用江科大的软件I2C实现对于芯片的控制,具体代码如下所示:

MyI2C.c文件

#include "stm32f10x.h"                  // Device header
#include "Delay.h"/*引脚配置层*//*** 函    数:I2C写SCL引脚电平* 参    数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1* 返 回 值:无* 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平*/
void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);		//根据BitValue,设置SCL引脚的电平Delay_us(10);												//延时10us,防止时序频率超过要求
}/*** 函    数:I2C写SDA引脚电平* 参    数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~1* 返 回 值:无* 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue为1时,需要置SDA为高电平*/
void MyI2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);		//根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性Delay_us(10);												//延时10us,防止时序频率超过要求
}/*** 函    数:I2C读SDA引脚电平* 参    数:无* 返 回 值:协议层需要得到的当前SDA的电平,范围0~1* 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1*/
uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);		//读取SDA电平Delay_us(10);												//延时10us,防止时序频率超过要求return BitValue;											//返回SDA电平
}/*** 函    数:I2C初始化* 参    数:无* 返 回 值:无* 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化*/
void MyI2C_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//开启GPIOB的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB10和PB11引脚初始化为开漏输出/*设置默认电平*/GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);			//设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
}/*协议层*//*** 函    数:I2C起始* 参    数:无* 返 回 值:无*/
void MyI2C_Start(void)
{MyI2C_W_SDA(1);							//释放SDA,确保SDA为高电平MyI2C_W_SCL(1);							//释放SCL,确保SCL为高电平MyI2C_W_SDA(0);							//在SCL高电平期间,拉低SDA,产生起始信号MyI2C_W_SCL(0);							//起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
}/*** 函    数:I2C终止* 参    数:无* 返 回 值:无*/
void MyI2C_Stop(void)
{MyI2C_W_SDA(0);							//拉低SDA,确保SDA为低电平MyI2C_W_SCL(1);							//释放SCL,使SCL呈现高电平MyI2C_W_SDA(1);							//在SCL高电平期间,释放SDA,产生终止信号
}/*** 函    数:I2C发送一个字节* 参    数:Byte 要发送的一个字节数据,范围:0x00~0xFF* 返 回 值:无*/
void MyI2C_SendByte(uint8_t Byte)
{uint8_t i;for (i = 0; i < 8; i ++)				//循环8次,主机依次发送数据的每一位{/*两个!可以对数据进行两次逻辑取反,作用是把非0值统一转换为1,即:!!(0) = 0,!!(非0) = 1*/MyI2C_W_SDA(!!(Byte & (0x80 >> i)));//使用掩码的方式取出Byte的指定一位数据并写入到SDA线MyI2C_W_SCL(1);						//释放SCL,从机在SCL高电平期间读取SDAMyI2C_W_SCL(0);						//拉低SCL,主机开始发送下一位数据}
}/*** 函    数:I2C接收一个字节* 参    数:无* 返 回 值:接收到的一个字节数据,范围:0x00~0xFF*/
uint8_t MyI2C_ReceiveByte(void)
{uint8_t i, Byte = 0x00;					//定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到MyI2C_W_SDA(1);							//接收前,主机先确保释放SDA,避免干扰从机的数据发送for (i = 0; i < 8; i ++)				//循环8次,主机依次接收数据的每一位{MyI2C_W_SCL(1);						//释放SCL,主机机在SCL高电平期间读取SDAif (MyI2C_R_SDA()){Byte |= (0x80 >> i);}	//读取SDA数据,并存储到Byte变量//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0MyI2C_W_SCL(0);						//拉低SCL,从机在SCL低电平期间写入SDA}return Byte;							//返回接收到的一个字节数据
}/*** 函    数:I2C发送应答位* 参    数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答* 返 回 值:无*/
void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);					//主机把应答位数据放到SDA线MyI2C_W_SCL(1);							//释放SCL,从机在SCL高电平期间,读取应答位MyI2C_W_SCL(0);							//拉低SCL,开始下一个时序模块
}/*** 函    数:I2C接收应答位* 参    数:无* 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答*/
uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;							//定义应答位变量MyI2C_W_SDA(1);							//接收前,主机先确保释放SDA,避免干扰从机的数据发送MyI2C_W_SCL(1);							//释放SCL,主机机在SCL高电平期间读取SDAAckBit = MyI2C_R_SDA();					//将应答位存储到变量里MyI2C_W_SCL(0);							//拉低SCL,开始下一个时序模块return AckBit;							//返回定义应答位变量
}

MyI2C.h文件

#ifndef __MYI2C_H
#define __MYI2C_Hvoid MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);#endif

 Pca9685.c

#include "Pca9685.h"
#include "MyI2C.h"
#include "Delay.h"
#include "math.h"#define PCA_ADDRESS 0x80void PCA_WriteReg(uint8_t RegAddress, uint8_t Data)//向PCA写数据,adrrd地址,data数据
{ MyI2C_Start();						//I2C起始MyI2C_SendByte(PCA_ADDRESS);	//发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck();					//接收应答MyI2C_SendByte(RegAddress);			//发送寄存器地址MyI2C_ReceiveAck();					//接收应答MyI2C_SendByte(Data);				//发送要写入寄存器的数据MyI2C_ReceiveAck();					//接收应答MyI2C_Stop();						//I2C终止
}uint8_t PCA_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();						//I2C起始MyI2C_SendByte(PCA_ADDRESS);	//发送从机地址,读写位为0,表示即将写入MyI2C_ReceiveAck();					//接收应答MyI2C_SendByte(RegAddress);			//发送寄存器地址MyI2C_ReceiveAck();					//接收应答MyI2C_Start();						//I2C重复起始MyI2C_SendByte(PCA_ADDRESS | 0x01);	//发送从机地址,读写位为1,表示即将读取MyI2C_ReceiveAck();					//接收应答Data = MyI2C_ReceiveByte();			//接收指定寄存器的数据MyI2C_SendAck(1);					//发送应答,给从机非应答,终止从机的数据输出MyI2C_Stop();						//I2C终止return Data;
}void PCA_setfreq(float freq)//设置PWM频率
{u8 prescale, oldmode, newmode;double prescaleval;freq *= 0.98; prescaleval = 25000000;prescaleval /= 4096;prescaleval /= freq;prescaleval -= 1;prescale = floor(prescaleval + 0.5f);oldmode = PCA_ReadReg(PCA_MODE1);newmode = (oldmode&0x7F) | 0x10; // sleepPCA_WriteReg(PCA_MODE1, newmode); // go to sleepPCA_WriteReg(PCA_PRE, prescale); // set the prescalerPCA_WriteReg(PCA_MODE1, oldmode);Delay_ms(5);PCA_WriteReg(PCA_MODE1, oldmode | 0xa1); 
}void PCA_setpwm(u8 channel, u32 on, u32 off)
{PCA_WriteReg(LED0_ON_L + 4 * channel, on & 0xFF);PCA_WriteReg(LED0_ON_H + 4 * channel, on >> 8);PCA_WriteReg(LED0_OFF_L + 4 * channel, off & 0xFF);PCA_WriteReg(LED0_OFF_H + 4 * channel, off >> 8);
}
/*
channel:舵机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的占空比。
*//*函数作用:初始化舵机驱动板参数:1.PWM频率2.初始化舵机角度
*/
void PCA_MG9XX_Init(float hz, u16 angle)
{u32 off = 0;u8 i=0;MyI2C_Init();	PCA_WriteReg(PCA_MODE1, 0x00);    // 软件复位PCA_setfreq(hz);//设置PWM频率off = (u32)(102.4 + angle*1.14);for(i=0;i<=0;i++){PCA_setpwm(i,0,off);}Delay_ms(500);
}void PCA_MG9XX(u8 channel, u8 end_angle)
{u32 off = 0;off = (u32)(102.4 + end_angle * 1.14);PCA_setpwm(channel, 0, off);
}

 Pca9685.h

#ifndef __PCA9685_H
#define __PCA9685_H	#include "stm32f10x.h"#define PCA_MODE1 0x00
#define PCA_PRE 0xFE#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9void PCA_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t PCA_ReadReg(uint8_t RegAddress);
void PCA_MG9XX_Init(float hz,u16 angle);
void PCA_setfreq(float freq);
void PCA_setpwm(u8 num, u32 on, u32 off);
void PCA_MG9XX(u8 channel, u8 end_angle);#endif


 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单元测试3.0+ @RunWith(JMockit.class)+mock+Expectations

Jmockit使用笔记_基本功能使用Tested_Injectable_Mocked_Expectations_jmockit.class-CSDN博客 测试框架Jmockit集合junit使用 RunWith(JMockit.class) 写在测试案例类上的注解 Tested 在测试案例中,写在我们要测试的类上面, 一般用实现类 Injectable 在测试案例中声明…

保姆级教程Docker部署ClickHouse镜像

目录 1、安装Docker及可视化工具 2、创建挂载目录 3、获取配置文件 4、运行ClickHouse容器 5、Compose运行ClickHouse容器 6、查看ClickHouse运行状态 7、安装包部署 1、安装Docker及可视化工具 Docker及可视化工具的安装可参考&#xff1a;Ubuntu上安装 Docker及可视化…

如何通过深度学习提升大分辨率图像预测准确率?

随着科技的不断进步&#xff0c;图像处理在各个领域的应用日益广泛&#xff0c;特别是在医疗影像、卫星遥感、自动驾驶、安防监控等领域中&#xff0c;大分辨率图像的使用已经成为了一项不可或缺的技术。然而&#xff0c;大分辨率图像带来了巨大的计算和存储压力&#xff0c;同…

Spring实现Logback日志模板设置动态参数

版权说明&#xff1a; 本文由博主keep丶原创&#xff0c;转载请保留此块内容在文首。 原文地址&#xff1a; https://blog.csdn.net/qq_38688267/article/details/144842327 文章目录 背景设计日志格式实现配置动态取值logback-spring.xml 背景 多个单体服务间存在少量交互&…

【无线传感网】无线传感器网络拓扑控制技术

文章目录 拓扑控制的意义影响整个网络的生存时间减小节点间通信干扰&#xff0c;提高网络通信效率为路由协议、时间同步提供基础影响数据融合弥补节点失效的影响 拓扑控制的设计目标能量消耗覆盖度连通性算法的分布式程度网络延迟&#x1f6a9;干扰和竞争对称性鲁棒性和可扩展性…

如何在没有 iCloud 的情况下将联系人从 iPhone 传输到 iPhone

概括 近期iOS 13.5的更新以及苹果公司发布的iPhone SE在众多iOS用户中引起了不小的轰动。此外&#xff0c;不少变化&#xff0c;如暴露通知 API、Face ID 增强功能以​​及其他在 COVID-19 期间与公共卫生相关的新功能&#xff0c;吸引了 iPhone 用户尝试新 iPhone 并更新到最…

matlab 设计滤波器

滤波器可视化工具 fvtool 与 filterAnalyzer 设计滤波器&#xff1a; matlab 菜单栏 APP - 滤波器设计

Keil中的gcc

文章目录 一、IDE背后的命令1.1 IDE是什么1.2 IDE的背后是命令1.3 有两套主要的编译器 二、准备工作2.1 arm-linux-gcc和gcc是类似的2.2 Code::Blocks2.2.1 设置windows环境变量2.2.2 命令行示例 三、gcc编译过程详解3.1 程序编译4步骤3.2 gcc的使用方法3.2.1 gcc使用示例3.2.2…

SQL-Server链接服务器访问Oracle数据

SQL Server 链接服务器访问 Oracle 离线安装 .NET Framework 3.5 方法一&#xff1a;使用 NetFx3.cab 文件 下载 NetFx3.cab 文件&#xff0c;并将其放置在 Windows 10 系统盘的 C:Windows 文件夹中。 以管理员身份运行命令提示符&#xff0c;输入以下命令并回车&#xff1a; …

关于easy-es对时间范围查询遇到的小bug

前言&#xff1a;在使用easy-es之前作为一个小白的我只有es原生查询的基础&#xff0c;在自己通过查看官方文档自学easy-es遇到了一个挫折&#xff0c;其他的还好语法和MybatisPlus差不多&#xff0c;正以为我觉得很快就能入手&#xff0c;在对时间范围的判断就给我当头一棒&am…

typora+picgo core+minio自动上传图片

1. 在服务器上安装docker版本minio 创建/docker/minio文件夹 mkdir -p /docker/minio在此文件夹创建docker-compose.yml version: "3.5" services:minio:image: quay.io/minio/minio:latestcontainer_name: minioprivileged: truerestart: alwaysports:# API接口访…

WebRTC线程的启动与运行

WebRTC线程运行的基本逻辑&#xff1a; while(true) {…Get(&msg, …);…Dispatch(&msg);… }Dispatch(Message *pmsg) {…pmsg->handler->OnMessage(pmsg);… }在执行函数内部&#xff0c;就是一个while死循环&#xff0c;只做两件事&#xff0c;从队列里Get取…

【OceanBase】使用 Superset 连接 OceanBase 数据库并进行数据可视化分析

文章目录 前言一、前提条件二、操作步骤2.1 准备云主机实例2.2 安装docker-compose2.3 使用docker-compose安装Superset2.3.1 克隆 Superset 的 GitHub 存储库2.3.2 通过 Docker Compose 启动 Superset 2.4 开通 OB Cloud 云数据库2.5 获取连接串2.6 使用 Superset 连接 OceanB…

我们能否使用 ANSYS SPEOS 测量水质?

介绍 Ansys SPEOS 是动态环境科学领域的尖端工具&#xff0c;可为围绕水质管理的复杂问题提供深入的见解和创新解决方案。通过其光学系统功能&#xff0c;它为理解和改善不同环境的生态动态提供了一个强大的框架。 主要特点和优势 多材质建模&#xff1a; 为了准确模拟环境…

简易屏幕共享工具-基于WebSocket

前面写了两个简单的屏幕共享工具&#xff0c;不过那只是为了验证通过截屏的方式是否可行&#xff0c;因为通常手动截屏的频率很低&#xff0c;而对于视频来说它的帧率要求就很高了&#xff0c;至少要一秒30帧率左右。所以&#xff0c;经过实际的截屏工具验证&#xff0c;我了解…

论文分享 | PromptFuzz:用于模糊测试驱动程序生成的提示模糊测试

大语言模型拥有的强大能力可以用来辅助多种工作&#xff0c;但如何有效的辅助仍然需要人的精巧设计。分享一篇发表于2024年CCS会议的论文PromptFuzz&#xff0c;它利用模型提示生成模糊测试驱动代码&#xff0c;并将代码片段嵌入到LLVM框架中执行模糊测试。 论文摘要 制作高质…

2024年底关于期货的工作总结

十几年程序猿出身&#xff0c;因几年前的懵懂无畏闯入期货市场&#xff0c;盈了&#xff0c;感觉期货太简单&#xff0c;飘然裸辞&#xff0c;想当财务自由者&#xff0c;全职做交易。当深入学习时&#xff0c;却亏了&#xff0c;原来市场是让人敬畏的&#xff0c;也是反人性的…

mybatis 和 mybatisPlus 兼容性问题

项目采用的是 mybatis&#xff0c; 后续引入了 mybatisPlus&#xff0c;用 mybatisX 创建的四个类一直报错&#xff0c;提示找不到符号&#xff0c;意识到 mybatis 和 mybatisPlus 的兼容性问题&#xff0c;通过修改配置 两者的配置如下 #配置mybatis配置 mybatis:type-aliase…

使用maven-mvnd替换maven大大提升编译打包速度

先上结论&#xff01;&#xff01;&#xff01; 多模块清理并打包提升&#xff1a;约3.5倍 多模块不清理打包提升&#xff1a;约5.5倍 单模块提升&#xff1a;约2倍 从计算结果来看&#xff0c;多模块提升的效率更高。在使用mvnd package打包多模块式&#xff0c;可在控制台…

【数据结构】(Python)差分数组。差分数组与树状数组结合

差分数组&#xff1a; 基于原数组构造的辅助数组。用于区间修改、单点查询。区间修改的时间复杂度O(1)。单点查询的时间复杂度O(n)。差分数组的元素&#xff1a;第一个元素等于原数组第一个元素&#xff0c;从第二个元素开始是原数组对应下标的元素与前一个元素的差&#xff0…