STM32控制PCA9685产生16路PWM波控制SG90舵机
如果你能点开这篇文章,说明你已经知道PCA9685是多么强大,NXP公司原本做这片芯片是为了提供给LED使用,在其官方文档里也能看到所有PWM输出都是写着LED,但是PWM波形不仅仅能够控制一个简单的LED,PWM应用很广泛的一个方面就是电机调速,以及部分舵机控制角度就是通过调节PWM波的占空比来实现,因此本篇博客就来介绍一下这块如何使用这块芯片。
博主采用的是下面这款模块,淘宝上很容易买到。
这款芯片通过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);
来将其转变成具体要写到芯片通道寄存器的值,你可以通过调整这个计算式来调整精度,不过经博主个人测试,输出精度已经足够,能够满足一般使用了。
觉得有用不妨点个赞吧,欢迎点击这里访问博主个人网站,一起交流学习