本文修改于https://blog.csdn.net/MarkSoviet/article/details/79841366
若有侵权,联系删除
pca9685.c
#include "pca9685.h"
#include "delay.h"
#include "myiic.h"
#include
void PCA9685_write(unsigned char reg,unsigned char data)
{
IIC_Start();
IIC_Send_Byte(PCA9685_adrr);
IIC_Wait_Ack();
IIC_Send_Byte(reg);
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();
}
u8 PCA9685_read(unsigned char reg)
{
u8 res;
IIC_Start();
IIC_Send_Byte(PCA9685_adrr);
IIC_Wait_Ack();
IIC_Send_Byte(reg);
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(PCA9685_adrr|0X01);
IIC_Wait_Ack();
res=IIC_Read_Byte(0);
IIC_Stop();
return res;
}
/*
设置频率
*/
void setPWMFreq(u8 freq)
{
u8 prescale,oldmode,newmode;//预分频值,
double prescaleval;
prescaleval = 25000000.0/(4096*freq*0.92);
prescale = (u8)floor(prescaleval+0.5)-1;
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1, oldmode);
delay_ms(5);
PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}
/*
num为舵机PWM输出引脚,on是PWM上升计数值,off为下降计数值0~4096
PWM周期分为4096份,由0开始+1计数,计数到on时跳变为高电平,计数到off时跳变为低电平
直到计满4096重新开始,on不等于0时可做延时,不等于0时off/4096为PWM的占空比
*/
void setPWM(u16 num, u16 on, u16 off)
{
PCA9685_write(LED0_ON_L+4*num,on);
PCA9685_write(LED0_ON_H+4*num,on>>8);
PCA9685_write(LED0_OFF_L+4*num,off);
PCA9685_write(LED0_OFF_H+4*num,off>>8);
}
/*
输入角度输出相应PWM值(off值) 需针对舵机进行修改
周期20ms,所以在设置频率的时候要设为50;占空比0.5ms~2.5ms分别对应0°~180°,且成线性关系
P W M =204.8×(0.5 + ( 2.5-0.5 ) × a n g l e / 180/20)
*/
u16 calculate_PWM(u8 angle)
{
return (int)(204.8*(0.5+angle*1.0/90));
}
pca9685.h
#ifndef __PCF8574_H
#define __PCF8574_H
#include "sys.h"
#include "myiic.h"
#define PCA9685_adrr 0x80
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x0
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
void PCA9685_write(unsigned char reg,unsigned char data);
u8 PCA9685_read(unsigned char reg);
void setPWMFreq(u8 freq);
void setPWM(u16 num, u16 on, u16 off);
void down();
void up();
u16 calculate_PWM(u8 angle);
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "pca9685.h"
#include "myiic.h"
#include "key.h"
/************************************************
ALIENTEK 阿波罗STM32F429开发板实验8
PWM输出实验-HAL库函数版
技术支持:www.openedv.com
淘宝店铺:http://eboard.taobao.com
关注微信公众平台微信号:"正点原子",免费获取STM32资料。
广州市星翼电子科技有限公司
作者:正点原子 @ALIENTEK
************************************************/
int main(void)
{
u8 dir=1,key;
u16 led0pwmval=0,pwm,pwm1;
HAL_Init(); //初始化HAL库
IIC_Init();
KEY_Init();
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
TIM3_PWM_Init(20000-1,90-1); //90M/90=1M的计数频率,自动重装载为500,那么PWM频率为1M/500=2kHZ
PCA9685_write(PCA9685_MODE1,0x0);//PCA9685复位
setPWMFreq(52);//实测频率为输入值-2
while(1)
{
key=KEY_Scan(0);
// if(dir)led0pwmval++; //dir==1 led0pwmval递增
// else led0pwmval--; //dir==0 led0pwmval递减
// if(led0pwmval>300)dir=0; //led0pwmval到达300后,方向为递减
// if(led0pwmval==0)dir=1; //led0pwmval递减到0后,方向改为递增
TIM_SetTIM3Compare4(18000); //修改比较值,修改占空比
switch(key)
{
case WKUP_PRES:
setPWM(0, 0, calculate_PWM(0));
break;
case KEY2_PRES:
setPWM(0, 0, calculate_PWM(90));
break;
case KEY1_PRES:
setPWM(0, 0, calculate_PWM(45));
break;
case KEY0_PRES:
setPWM(0, 0, calculate_PWM(30));
break;
}
}
}