树莓派使用PCA9685扩展(一)之PWM驱动舵机入坑指南

您所在的位置:网站首页 pca9685供电不稳定 树莓派使用PCA9685扩展(一)之PWM驱动舵机入坑指南

树莓派使用PCA9685扩展(一)之PWM驱动舵机入坑指南

2024-05-31 14:13| 来源: 网络整理| 查看: 265

         从床底下拖出这个老版的树莓派B+,仅支持1路PWM,正好最近有空,就研究下之前买的PWM扩展板,这次使用bcm2835-1.71的I2C和PCA9685通讯(之前的MPU6500则使用SPI通讯)。

        bcm2835-1.71默认关闭对老版本Pi的I2C支持,需要修改驱动源码,在bcm2835.c中找到如下行取消注释编译即可:

#define I2C_V1

        好了,剩下的就看代码了,是仿着别人的python代码修改位C/C++的。我的Pi上的I2C设备地址是0x40。

#include #include #include #include #include #define PCA9685_ADDRESS 0x40 #define PCA9685_SUBADR1 0x2 #define PCA9685_SUBADR2 0x3 #define PCA9685_SUBADR3 0x4 #define PCA9685_MODE1 0x00 #define PCA9685_PRESCALE 0xFE #define LED0_ON_L 0x06 #define LED0_ON_H 0x07 #define LED0_OFF_L 0x08 #define LED0_OFF_H 0x09 #define ALLLED_ON_L 0xFA #define ALLLED_ON_H 0xFB #define ALLLED_OFF_L 0xFC #define ALLLED_OFF_H 0xFD #define BAUDRATE 100000 #define SERVOMIN 115 // this is the ‘minimum’ pulse length count (out of 4096) #define SERVOMAX 590 // this is the ‘maximum’ pulse length count (out of 4096) #define SERVO000 130 //0度 #define SERVO180 520 //180度 #define SERVO80 284 //80度 #define SERVO110 340//110度 void setPWM(uint16_t ch, uint16_t on, uint16_t off) { printf("channel: %d LED_ON: %d LED_OFF: %d\n" ,ch,on,off); char buf[2]; uint8_t ret; buf[0]=LED0_ON_L+4*ch; buf[1]=on; ret = bcm2835_i2c_write(buf,2); printf("ret = 0x%02X, val = 0x%02X\n", buf[0],buf[1]); buf[0]=LED0_ON_H+4*ch; buf[1]=on>>8; ret = bcm2835_i2c_write(buf, 2); printf("ret = 0x%02X, val = 0x%02X\n", buf[0],buf[1]); buf[0]=LED0_OFF_L+4*ch; buf[1]=off; ret = bcm2835_i2c_write(buf,2); printf("ret = 0x%02X, val = 0x%02X\n", buf[0],buf[1]); buf[0]=LED0_OFF_H+4*ch; buf[1]=off>>8; ret = bcm2835_i2c_write(buf,2); printf("ret = 0x%02X, val = 0x%02X\n", buf[0],buf[1]); } /** * 设置脉宽,需要mode1设置为sleep模式,对PCA9685_PRESCALE进行设置 */ void setFreq(float freq){ char buf[2]={0,0}; char reg[1]={0}; uint8_t ret; // Constrain the frequency float prescaleval = 25000000.0; prescaleval /= 4096.0; prescaleval /= freq; prescaleval -= 1.0; printf("Estimated pre-scale: %d\n", (int)prescaleval); float prescale = floor((int)prescaleval + 0.5); printf("Final prescale = %d\n", (int)floor(prescale)); buf[0]=PCA9685_MODE1; buf[1]=0x00; ret=bcm2835_i2c_write(buf, 2); printf("Write 0x%02X to register 0x%02X\n", buf[1],buf[0]); ret=bcm2835_i2c_write(reg, 1); ret=bcm2835_i2c_read(buf, 1); printf("Device 0x%02X returned 0x%02X from reg 0x%02X\n", PCA9685_ADDRESS, buf[0],reg[0]); uint8_t oldmode = buf[0]; uint8_t newmode = (oldmode & 0x7F) | 0x10; // sleep buf[0]=PCA9685_MODE1; buf[1]=newmode; ret=bcm2835_i2c_write(buf, 2); printf("Write 0x%02X to register 0x%02X\n", buf[1], buf[0]); buf[0]=PCA9685_PRESCALE; buf[1]=(int)floor(prescale); ret = bcm2835_i2c_write(buf,2); // go to sleep printf("Write 0x%02X to register 0x%02X\n", buf[1],buf[0]); buf[0]=PCA9685_MODE1; buf[1]=oldmode; ret=bcm2835_i2c_write(buf, 2); printf("Write 0x%02X to register 0x%02X\n", buf[1],buf[0]); bcm2835_delay(5); buf[0]=PCA9685_MODE1; buf[1]=oldmode|0x80; ret=bcm2835_i2c_write(buf, 2); printf("Write 0x%02X to register 0x%02X\n", buf[1],buf[0]); } void setServoPulse(uint16_t channel, int pulse){ //"Sets the Servo Pulse,The PWM frequency must be 50HZ" printf("setServoPulse = %d\n", pulse); pulse = (int)(pulse*4096/20000); //PWM frequency is 50HZ,the period is 20000us printf("setServoPulse 2 = %d\n", pulse); setPWM(channel, 0, pulse); } int main() { char buf[2]; uint8_t data; char reg; int i,ret; if (!bcm2835_init()) { printf("bcm2835_init failed. Are you running as root??\n"); return -1; } if(!bcm2835_i2c_begin()) { printf("bcm2835_i2c_begin failedg. Are you running as root??\n"); return -1; } bcm2835_i2c_setSlaveAddress(PCA9685_ADDRESS); //bcm2835_i2c_setClockDivider(BCM2835_I2C_CLOCK_DIVIDER_2500); setFreq(50.0); int a[3]={500,2500,10}; int b[3] ={2500,500,-10}; int k,j; while(1) { for(k=500;k500;j-=10){ setServoPulse(0, j); bcm2835_delay(20); } } bcm2835_delay(1000); bcm2835_i2c_end(); bcm2835_close(); return 0; }

        完整的示例代码,就不注释了。本文章仅供初学者参考,如有任何问题可以随时交流。

        bcm2835开发文档:

        bcm2835: Examples

坑0

        上面讲了,bcm2835的pi上驱动认版本,写完代码调试,发现都返回NACK。怀疑代码问题半天,最后感谢谷歌。。。

坑1

        PCA9685单独使用3.3V供电VCC貌似不工作,还需要将V+管脚接到Pi上的5V管脚才行。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3