STM32F103控制PCA9685产生16路PWM波控制SG90舵机

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

如果你能点开这篇文章,说明你已经知道PCA9685是多么强大,NXP公司原本做这片芯片是为了提供给LED使用,在其官方文档里也能看到所有PWM输出都是写着LED,但是PWM波形不仅仅能够控制一个简单的LED,PWM应用很广泛的一个方面就是电机调速,以及部分舵机控制角度就是通过调节PWM波的占空比来实现,因此本篇博客就来介绍一下这块如何使用这块芯片。

博主采用的是下面这款模块,淘宝上很容易买到。

PCA9685模块·

这款芯片通过IIC总线来控制,如果你想很快上手,可以参考博主的另一篇文章通用软件模拟IIC,只需要改改你要用的引脚就可以了。

闲话少说,上代码

芯片使用可以参考这篇文章,我这里只讲怎么用

#ifndef _PCA9685_H
#define _PCA9685_H

#include "sys.h"
#include "delay.h"
#include "iic.h"

// 这里是你PWM模块的IIC地址,默认是0x80,你需要修改为你使用的地址
#define pca_adrr 0x80
// 芯片工作模式
#define pca_mode1 0x00
// 设置芯片分频
#define pca_pre 0xFE
// 通道地址
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
 
 
//#define jdMIN  115 // minimum
//#define jdMAX  590 // maximum
//#define jd000  130 //0度对应4096的脉宽计数值
//#define jd180  520 //180度对应4096的脉宽计算值

void pca_write(u8 adrr,u8 data);
u8 pca_read(u8 adrr);
void PCA9685_Init(float hz,u8 angle);
void pca_setfreq(float freq);
void pca_setpwm(u8 num, u32 on, u32 off);
void PCA_Set(u8 num,u8 start_angle,u8 end_angle,u8 mode,u8 speed);

#endif

下面是具体实现的代码

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

// 向PCA写数据,adrrd地址,data数据
void pca_write(u8 adrr,u8 data)
{ 
	IIC_Start();
	
	IIC_Write_One_Byte(pca_adrr);
	IIC_Wait_Ack();
	
	IIC_Write_One_Byte(adrr);
	IIC_Wait_Ack();
	
	IIC_Write_One_Byte(data);
	IIC_Wait_Ack();
	
	IIC_Stop();
}

//从PCA读数据
u8 pca_read(u8 adrr)
{
	u8 data;
	IIC_Start();
	
	IIC_Write_One_Byte(pca_adrr);
	IIC_Wait_Ack();
	
	IIC_Write_One_Byte(adrr);
	IIC_Wait_Ack();
	
	IIC_Start();
	
	IIC_Write_One_Byte(pca_adrr|0x01);
	IIC_Wait_Ack();
	
	data=IIC_Read_One_Byte(0);
	IIC_Stop();
	
	return data;
}

//设置PWM频率
void pca_setfreq(float freq)
{
		u8 prescale,oldmode,newmode;
		double prescaleval;
    	// 这里的计算看不懂的话可以去前面看看提到的那篇文章 
		freq *= 0.915; 
		prescaleval = 25000000;
		prescaleval /= 4096;
		prescaleval /= freq;
		prescaleval -= 1;
		prescale =floor(prescaleval + 0.5f);

		oldmode = pca_read(pca_mode1);
	
		newmode = (oldmode&0x7F) | 0x10; // sleep
	
		pca_write(pca_mode1, newmode); // 设置时钟前必须先进入sleep模式
	
		pca_write(pca_pre, prescale); // 设置分频
	
		pca_write(pca_mode1, oldmode); // 写入原先模式
		delay_ms(2);
	
		pca_write(pca_mode1, oldmode | 0xa1); 
}
// 设定通道的PWM
void pca_setpwm(u8 num, u32 on, u32 off)
{
		pca_write(LED0_ON_L+4*num,on);
		pca_write(LED0_ON_H+4*num,on>>8);
		pca_write(LED0_OFF_L+4*num,off);
		pca_write(LED0_OFF_H+4*num,off>>8);
}
/**
 *@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的占空比。
**/

/*
	函数作用:初始化舵机驱动板
	参数:1.PWM频率
		  2.初始化舵机角度
*/
void PCA9685_Init(float hz,u8 angle)
{
	u32 off=0;
    u8 i=0;
	IIC_Init();
	pca_write(pca_mode1,0x0);
	pca_setfreq(hz);//设置PWM频率
	off=(u32)(102+angle*2.2);
    // 初始化所有通道固定为指定的角度angle
	for(i=0;i<=15;i++)
    {
        pca_setpwm(i,0,off);
    }
	
	delay_ms(500);
}

/*
	函数作用:控制舵机转动;
	参数:1.输出端口,可选0~15;
		  2.起始角度,可选0~180;
		  3.结束角度,可选0~180;
		  4.模式选择,0 表示函数内无延时,调用时需要在函数后另外加延时函数,且不可调速,第五个参数可填任意值;
					  1 表示函数内有延时,调用时不需要在函数后另外加延时函数,且不可调速,第五个参数可填任意值;
					  2 表示速度可调,第五个参数表示速度值;
		  5.速度,可填大于 0 的任意值,填 1 时速度最快,数值越大,速度越小;
	注意事项:模式 0和1 的速度比模式 2 的最大速度大;
*/
// 一般使用的话mode选0就可以了,此时start_angle也可以写0,以及speed,只有end_angle是你要输出的角度。
void PCA_Set(u8 num,u8 start_angle,u8 end_angle,u8 mode,u8 speed)
{
	u8 i;
	u32 off=0;
	switch(mode)
	{
		case 0:
		{
			off=(u32)(102+end_angle*2.2);
			pca_setpwm(num,0,off);
		}break;

		case 1:
		{
			off=(u32)(158+end_angle*2.2);
			pca_setpwm(num,0,off);
			if(end_angle>start_angle)
            {
                delay_ms((u16)((end_angle-start_angle)*2.7));  // 若要使用模式1或者2,可以调整这里的倍数2.7为你需要的
            }
			else
            {
                delay_ms((u16)((start_angle-end_angle)*2.7));
            }
		}break;
		case 2:
		{
			if(end_angle>start_angle)
			{
				for(i=start_angle;i<=end_angle;i++)
				{
					off=(u32)(158+i*2.2);
					pca_setpwm(num,0,off);
					delay_ms(2);
					delay_us(speed*250);
				}
			}
			else if(start_angle>end_angle)
			{
				for(i=start_angle;i>=end_angle;i--)
				{
					off=(u32)(158+i*2.2);
					pca_setpwm(num,0,off);
					delay_ms(2);
					delay_us(speed*250);
				}
			}
		}break;
	}
}

代码中使用到的delay和sys,以及iic可以通过另外一篇文章页尾下载,这里就不放链接了。

经测试可以看到舵机的输出角度比较稳定。

这里还是简单说一下舵机SG90吧,这是一款90g舵机,通过周期为50Hz的PWM波控制,也就是20ms,其中0.5ms高电平时舵机输出0度,1ms输出45度,1.5ms输出90度,2ms输出135度,2.5ms输出180度,在代码中通过off=(u32)(158+i*2.2);来将其转变成具体要写到芯片通道寄存器的值,你可以通过调整这个计算式来调整精度,不过经博主个人测试,输出精度已经足够,能够满足一般使用了。

觉得有用不妨点个赞吧,欢迎点击这里访问博主个人网站,一起交流学习

  • 13
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值