stm32c8t6 pca9685 16路舵机(固件库)

概述

        项目需要使用多路舵机,为了体型得选择stm32c8t6,同时需要用八个舵机sg90,很麻烦,于是找到了pac9685的拓展驱动板,买回来之后发现了问题,商家给的都是51的代码,网上搜到的都是32其他型号的,或者是c8t6 HAL库的,在网上不是用不了就是要钱,最终找到一个古老的博客。

GitHub - github150620/stm32-pca9685-sg90

这个是接线图,其中建议v+连5v,不然舵机可能动不了,下面给出代码

代码

main.c


#include "sg90.h"

void delay(int i) {
	while (i) {
		i--;
	}
}

int main(void) {
	SG90_Init();
	while(1){
		SG90_SetAngle(0, 0);
		delay(80000000);
		SG90_SetAngle(0, 90);
		delay(80000000);
		SG90_SetAngle(0, 180);
		delay(80000000);
	}
}

里面SG90_SetAngle(id,angle)

id就是连接的号0~15,看原理图,angle是要旋转的角度

pac9685.c

#include "stm32f10x.h"

#define PCA9685_I2C_ADDR 0x40

#define MODE1       0x00
#define MODE2       0x01
#define SUBADR1     0x02
#define SUBADR2     0x03
#define SUBADR3     0x04
#define ALLCALLADR  0x05
#define LED0_ON_L   0x06
#define LED0_ON_H   0x07
#define LED0_OFF_L  0x08
#define LED0_OFF_H  0x09
#define LED1_ON_L   0x0A
#define LED1_ON_H   0x0B
#define LED1_OFF_L  0x0C
#define LED1_OFF_H  0x0D
#define LED2_ON_L   0x0E
#define LED2_ON_H   0x0F
#define LED2_OFF_L  0x10
#define LED2_OFF_H  0x11
#define LED3_ON_L   0x12
#define LED3_ON_H   0x13
#define LED3_OFF_L  0x14
#define LED3_OFF_H  0x15
#define LED4_ON_L   0x16
#define LED4_ON_H   0x17
#define LED4_OFF_L  0x18
#define LED4_OFF_H  0x19
#define LED5_ON_L   0x1A
#define LED5_ON_H   0x1B
#define LED5_OFF_L  0x1C
#define LED5_OFF_H  0x1D
#define LED6_ON_L   0x1E
#define LED6_ON_H   0x1F
#define LED6_OFF_L  0x20
#define LED6_OFF_H  0x21
#define LED7_ON_L   0x22
#define LED7_ON_H   0x23
#define LED7_OFF_L  0x24
#define LED7_OFF_H  0x25
#define LED8_ON_L   0x26
#define LED8_ON_H   0x27
#define LED8_OFF_L  0x28
#define LED8_OFF_H  0x29
#define LED9_ON_L   0x2A
#define LED9_ON_H   0x2B
#define LED9_OFF_L  0x2C
#define LED9_OFF_H  0x2D
#define LED10_ON_L  0x2E
#define LED10_ON_H  0x2F
#define LED10_OFF_L 0x30
#define LED10_OFF_H 0x31
#define LED11_ON_L  0x32
#define LED11_ON_H  0x33
#define LED11_OFF_L 0x34
#define LED11_OFF_H 0x35
#define LED12_ON_L  0x36
#define LED12_ON_H  0x37
#define LED12_OFF_L 0x38
#define LED12_OFF_H 0x39
#define LED13_ON_L  0x3A
#define LED13_ON_H  0x3B
#define LED13_OFF_L 0x3C
#define LED13_OFF_H 0x3D
#define LED14_ON_L  0x3E
#define LED14_ON_H  0x3F
#define LED14_OFF_L 0x40
#define LED14_OFF_H 0x41
#define LED15_ON_L  0x42
#define LED15_ON_H  0x43
#define LED15_OFF_L 0x44
#define LED15_OFF_H 0x45

#define PRE_SCALE  0xFE

#define MODE1_RESTART 0x80
#define MODE1_EXTCLK  0x40
#define MODE1_AI      0x20
#define MODE1_SLEEP   0x10
#define MODE1_ALLCALL 0x01

static void delay(int i) {
	while (i) {
		i--;
	}
}

void I2C2_Init() {
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef  I2C_initStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
	
	I2C_initStructure.I2C_ClockSpeed = 400000; // 400KHz
	I2C_initStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_initStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_initStructure.I2C_OwnAddress1 = 0x77;
	I2C_initStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_initStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_Init(I2C2, &I2C_initStructure);
	
	I2C_Cmd(I2C2, ENABLE);	
}

void PCA9685_WriteReg(u8 addr, u8 value) {
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

	I2C_Send7bitAddress(I2C2, (PCA9685_I2C_ADDR<<1)&0xfe, I2C_Direction_Transmitter);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C2, addr);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C2, value);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_GenerateSTOP(I2C2, ENABLE);	
}

void PCA9685_ReadReg(u8 addr, u8 *value) {
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

	I2C_Send7bitAddress(I2C2, (PCA9685_I2C_ADDR<<1)&0xfe, I2C_Direction_Transmitter);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C2, addr);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));	
	
	I2C_GenerateSTOP(I2C2, ENABLE);	
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
	
	I2C_Send7bitAddress(I2C2, (PCA9685_I2C_ADDR<<1)|0x01, I2C_Direction_Receiver);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

	I2C_AcknowledgeConfig(I2C2, DISABLE);
	
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED));
	*value = I2C_ReceiveData(I2C2);

	I2C_GenerateSTOP(I2C2, ENABLE);	
}

void PCA9685_SetChannelDuty(u8 channel, u32 on, u32 off) {
	I2C_AcknowledgeConfig(I2C2, ENABLE);
	
	I2C_GenerateSTART(I2C2, ENABLE);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

	I2C_Send7bitAddress(I2C2, (PCA9685_I2C_ADDR<<1)&0xfe, I2C_Direction_Transmitter);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	I2C_SendData(I2C2, LED0_ON_L+4*channel);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C2, on&0xff);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C2, (on>>8)&0xff);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_SendData(I2C2, off&0xff);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	
	I2C_SendData(I2C2, (off>>8)&0xff);
	while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	
	I2C_GenerateSTOP(I2C2, ENABLE);
}

void PCA9685_Init() {
	u8 value;
	I2C2_Init();
	
	// The PRE_SCALE register can only be set when the SLEEP bit of MODE1 register is set to logic 1.
	PCA9685_WriteReg(MODE1, MODE1_SLEEP);
	PCA9685_WriteReg(PRE_SCALE, 121); // (25000000/4096/50)-1
	PCA9685_WriteReg(MODE1, 0);
	PCA9685_WriteReg(MODE1, MODE1_RESTART|MODE1_AI|MODE1_ALLCALL);

	while (1) {
		PCA9685_ReadReg(MODE1, &value);
		if ((value&MODE1_RESTART)==0) {	// Restart OK.
			break;
		}
		delay(100000);
	}
}

pca9685.h

#ifndef _PCA9685_H
#define _PCA9685_H

#include "stm32f10x.h"

void PCA9685_Init();

// channel: 0 ~ 15
//      on: 0 ~ 4095
//     off: 0 ~ 4095
void PCA9685_SetChannelDuty(u8 channel, u32 on, u32 off);

#endif

sg90.c

#include "pca9685.h"

void SG90_Init() {
	PCA9685_Init();
}

void SG90_SetAngle(u8 id, u8 angle) {
	PCA9685_SetChannelDuty(id, 0, (u32)(4095*((angle/180.0)*2.0+0.5)/20.0));
}

sg90.h

#ifndef _SG90_H
#define _SG90_H

#include "pca9685.h"

void SG90_Init();
void SG90_SetAngle(u8 id, u8 angle);

#endif

完整测试项目见百度网盘信息

项目链接

链接:https://pan.baidu.com/s/1pV6lL0C0lDvbcEoQoQF-qw?pwd=1234 
提取码:1234 
--来自百度网盘超级会员V3的分享

参考文章

树莓派16路PWM舵机驱动板(PCA9685)_adafruit pca9685-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值