STM32F429阿波罗驱动PCA9685舵机驱动板

本文修改于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;
        }
    }
}

你可能感兴趣的:(单片机)