TA的每日心情 | 慵懒 2024-5-31 23:20 |
---|
签到天数: 302 天 连续签到: 2 天 [LV.8]以坛为家I
|
本帖最后由 day_day 于 2017-10-23 21:46 编辑
(一)舵机控制原理
20ms的周期长度、0.6-2.4ms的占空比。不过对于楼主使用的sg90舵机,通常的介绍占空比一般在0.5ms-1.5ms之间,不过楼主实测是在0.5ms-2.2ms之间,所以以后者为准。
(二)pca9685介绍
pca9685模块基于pca9685pw芯片,可以同时控制16路舵机,而控制线为iic,只占两路io口。还可以通过焊接改变读写地址,从而实现级联。
寄存器:
:第一第二位是模式控制; 从第七位(06)开始,每四位控制一路舵机信号。当ON匹配时,输出高电平(LEDX_ON_L==LEDX_ON_H);当OFF匹配时,输出低电平。 FE位控制占空比,计算公式:
所以说,如果我们想得到上述的占空比形式,LEDX_ON_L=0,PRE_SCALE=osc_clock/4096*T - 1;
(三)wiringPi操作函数
初始化:wiringPiI2CSetup
写:wiringPiI2CWriteReg8
读:wiringPiI2CReadReg8
(四)代码
读写模块:- #include "iic_pwm.h"
- #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
- int pca9685_init(unsigned char addr) // addr是7位的i2c从机地址,返回的是linux标准的设备描述符,调用它的地方视作pca9685的设备描述符
- //因为可以多个pca9685级联,通过设备描述符区别它们
- //此驱动仅作为驱动舵机使用,周期固定死位20ms,不允许外部设置
- {
- int pca9685;
- pca9685 = wiringPiI2CSetup(addr);
- {
- //初始化pca9685芯片
- double T = 20000; //周期,单位是us
- unsigned char prescale;
- double osc_clock = 25000000;
- unsigned char oldmode, newmode;
- T /= 0.915; //不知道为什么,会有所偏差,这里校准一下就ok了,从网上找的arduino代码也进行了校准。
- T /= 1000000; //把T转换成秒
- prescale = (unsigned char)(osc_clock / 4096 * T - 1);
- // printf("prescale = 0x%x", prescale);
- oldmode = wiringPiI2CReadReg8(pca9685, PCA9685_MODE1);
- newmode = (oldmode & 0x7f) | 0x10; //准备进入sleep,设置时钟前必须先进入sleep模式
- wiringPiI2CWriteReg8(pca9685, PCA9685_MODE1, newmode);
- wiringPiI2CWriteReg8(pca9685, PCA9685_PRESCALE, prescale);
- oldmode &= 0xef; //清除sleep位
- wiringPiI2CWriteReg8(pca9685, PCA9685_MODE1, oldmode);
- delay(0.005);
- wiringPiI2CWriteReg8(pca9685, PCA9685_MODE1, oldmode | 0xa1);
- }
- return pca9685;
- }
- void pca9685_setmk(int fd, int num, int mk) //设置指定通道的脉宽。fd是在pca9685_init时获得的设备描述符,num是通道号(从0开始),mk是脉宽单位是us。周期已经固定为20ms了
- {
- unsigned int ON, OFF;
- ON = 0; //每次周期一开始就输出高电平
- OFF = (unsigned int)((((double)mk) / 20000 * 4096)*1.0067114); //最后的1.0067114是校准用的
- // printf("off = 0x%x", OFF);
- wiringPiI2CWriteReg16(fd, LED0_ON_L + 4 * num, ON);
- wiringPiI2CWriteReg16(fd, LED0_OFF_L + 4 * num, OFF);
- }
复制代码 ui与控制设计:- #include "widget.h"
- #include "ui_widget.h"
- #include <QtGui>
- #include <QGridLayout>
- #include <QDebug>
- #include <QErrorMessage>
- Widget::Widget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::Widget)
- {
- ui->setupUi(this);
- iic_fd = pca9685_init(0x40);
- lineEdit = new QLineEdit("600");
- slider = new QSlider(Qt::Horizontal);
- slider->setMinimum(500);
- slider->setMaximum(2200);
- slider->setValue(600);
- connect(slider, SIGNAL(sliderReleased()), this, SLOT(sendValue()));
- connect(slider, SIGNAL(valueChanged(int)), this, SLOT(setLineEditValue()));
- connect(lineEdit, SIGNAL(editingFinished()), this, SLOT(setSliderValue()));
- QGridLayout *layout = new QGridLayout();
- layout->addWidget(lineEdit, 0, 0, 1, 3);
- layout->addWidget(slider, 0, 3, 1, 1);
- this->setLayout(layout);
- this->resize(500, 100);
- this->setWindowTitle("QSliderDemo");
- }
- Widget::~Widget()
- {
- delete ui;
- }
- void Widget::setLineEditValue()
- {
- int pos = slider->value();
- QString str = QString("%1").arg(pos);
- lineEdit->setText(str);
- }
- void Widget::sendValue()
- {
- pca9685_setmk(iic_fd, 0, slider->value());
- qDebug() << "no time" << endl;
- }
- void Widget::setSliderValue()
- {
- bool ok;
- int dec = lineEdit->text().toInt(&ok, 10);
- if (dec<500 || dec>2200)
- {
- QErrorMessage *errordialog = new QErrorMessage(this);
- errordialog->setWindowTitle(tr("over value!"));
- errordialog->showMessage(tr("over value!"));
- }
- else
- slider->setValue(dec);
- pca9685_setmk(iic_fd, 0, dec);
- qDebug() << "once" << endl;
- }
复制代码 (五)编译
对于bananapi的wiringpi函数库,编译的时候要在pro文件中加入-lwiringPi和-lcrypt两个库:- LIBS += -lwiringPi -lcrypt
复制代码 (六)硬件接线:
这里使用SDA1、SCL1,对应的是系统第二条iic总线
(七)视频效果和工程分享
|
-
-
one.rar
716.9 KB, 阅读权限: 10, 下载次数: 5
|