黑马 发表于 2012-3-21 14:07:09

我的自平衡小车之第一步——读取九轴姿态传感器并显示到OLED

首先感谢弘毅老大的详细教程和thomas的库文件!

虽然只是开了个微不足道的头,但是总算有个比较完整的输入输出的东西,也算是进了Arduino的门槛。

闲话不多说了,先上联线图:



传感器是一位单片机前辈贴的板子,集成ADXL345+L3G4200D+HMC5883L三个芯片,考虑到以后无论做自平衡车还是做四轴,肯定要逐步升级算法,所以索性先把传感器的部分能弄的先都解决了再说。OLED是一款6pin接口的12864,暂时主要作为运行状态监控。

下面是代码:#include <Wire.h>         // IIC运行库
#include <SSD1306.h>      // OLED运行库

#define OLED_CS 42          // CS脚
#define OLED_CLK 44         // CLK脚
#define OLED_MOSI 46      // MISO脚
#define OLED_RESET 48       // RST脚
#define OLED_DC 50          // D/C脚

SSD1306 oled(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
                            // 定义OLED
#define Acc 0x1D;         // ADXL345的I2C地址
#define Gyr 0x69;         // L3G4200D的I2C地址
#define Mag 0x1E;         // HMC5883L的I2C地址

char str;               // 输出字符串(切勿溢出)
int curve;             // 曲线数据
int i = 0;

void setup() {
    oled.ssd1306_init(SSD1306_SWITCHCAPVCC);
    oled.clear();            // 清空oled屏
    oled.drawstring(0, 0, "Setting up...");
    oled.display();          // 显示到oled
                           // 初始化OLED
    sensor_init();         // 初始化传感器
    delay(2000);
}
void loop() {
int x;
curve = gDat(Gyr, 0);            // 读取传感器,根据需要读取不同传感器数据
if (curve < -26) curve = -26; // 上溢出
if (curve > 26) curve = 26;   // 下溢出
oled.clear();                     // 清空oled屏
sprintf(str, "xGyro= %d", curve);// 输出字符串
oled.drawstring(0, 0, str);         // 输出到到oled
for (x = 0; x < 127; x++) {
    oled.drawline(x, 37 - curve, x+1, 37 - curve, WHITE);
}                                 // 绘制曲线
oled.display();                     // 显示到oled
i++;
if (i == 128) i = 0;
delay(10);
}

int gDat(int device, int axis) {

// 读九轴姿态传感器寄存器函数
// For Arduino, by 黑马
// 调用参数表
//   type    device      axis
//                  0   1   2
// ADXL345   Acc    x   y   z
// L3G4200D    Gyr    x   y   z
// HMC5883L    Mag    x   z   y
// Example
// 00 #include <Wire.h>
// 01 #define Acc 0x1D;
// 02 #define Gyr 0x69;
// 03 #define Mag 0x1E;
// 04
// 05void setup() {
// 06    sensor_init();
// 07    delay(1000);
// 08}
// 09
// 10void loop() {
// 11    Z-Gyroscope = gDat(Gyr, 2);
// 12    delay(50);
// 13}

    int v;
    byte vL, vH, address;               // 存放byte数值
    if (device == Acc) address = 0x32;// ADXL345的读数地址
    if (device == Gyr) address = 0xA8;// L3G4200D的读数地址
    if (device == Mag) address = 0x03;// HMC5883L的读数地址
    address = address + axis * 2;       // 数据偏移-坐标轴
    Wire.beginTransmission(device);   // 开始传输数据
    Wire.send(address);               // 发送指针
    Wire.requestFrom(device, 2);      // 请求2 byte数据
    while(Wire.available() < 2);      // 成功获取前等待
    vL = Wire.receive();
    vH = Wire.receive();                // 读取数据
    Wire.endTransmission();             // 结束传输
    if (device == Mag) v = (vL << 8) | vH;
    else v = (vH << 8) | vL;            // 将byte数据合并为Int
    return v;                           // 返回读书值
}

void sensor_init() {                         // 配置九轴姿态传感器
    writeRegister(Acc, 0x2D, 0b00001000);    // 测量模式
                            // 配置ADXL345
    writeRegister(Gyr, 0x20, 0b00001111);    // 设置睡眠模式、x, y, z轴使能
    writeRegister(Gyr, 0x21, 0b00000000);    // 选择高通滤波模式和高通截止频率
    writeRegister(Gyr, 0x22, 0b00000000);    // 设置中断模式
    writeRegister(Gyr, 0x23, 0b00110000);    // 设置量程(2000dps)、自检状态、SPI模式
    writeRegister(Gyr, 0x24, 0b00000000);    // FIFO & 高通滤波
                            // 配置L3G4200D(2000 deg/sec)
    writeRegister(Mag, 0x02, 0x00);          // 连续测量
                            // 配置HMC5883L
}

void writeRegister(int device, byte address, byte val) {    // 写寄存器
    Wire.beginTransmission(device);
    Wire.send(address);
    Wire.send(val);
    Wire.endTransmission();
}传感器部分的读取写成了一个函数,效率应该还是挺高的,我想调用和移植都比较方便。传感器属于以后会用到比较多的东西,所以我想一次做得稍微完善一些。

<SSD1306.h>是thomas帖子里的,看了.h和.cpp,和网上另一个Adafruit_SSD1306差不多,正在研究两者的区别。

显示效果无非是实时数值和曲线,比较简单,就不放视频了,放个图片吧。

弘毅 发表于 2012-3-21 14:12:50

:o连接图很漂亮ing~~~肿么画出来的。。。

最近忙得吐血。。。等下半年有时间了。。我也学着做一下。。=.=发现半年不玩。。跟不上时代了

弘毅 发表于 2012-3-21 14:18:04

话说。。。。OLED看了后,我已经无心用其他led了。。。。=.=颜色太漂亮了

ChocolateUni 发表于 2012-3-21 14:21:22

好贴,正打算入手这个板子,玩一玩.

Malc 发表于 2012-3-21 21:09:04

我也计划在做平衡车啊
不过我打算用MPU6050,一个芯片集成了加速度和角度,价格比分开买两个传感器便宜。。
指南针就不弄了。。太费钱了

thomas 发表于 2012-3-21 23:34:06

还是OLED漂亮!
刷新的问题解决没?

thomas 发表于 2012-3-22 07:58:02

刚才想起个事,OLED板子是3v3电压的,io口需要做个匹配。正规方法是接4050缓冲器,最简单的是每个io接一个100欧电阻(厂家非官方说法)。我发帖子时还不会做图,忽略了这个,抱歉!

黑马 发表于 2012-3-22 09:33:30

thomas 发表于 2012-3-22 07:58 static/image/common/back.gif
刚才想起个事,OLED板子是3v3电压的,io口需要做个匹配。正规方法是接4050缓冲器,最简单的是每个io接一个1 ...

这个没注意,多亏你提醒,我再看下,谢谢

黑马 发表于 2012-3-22 09:37:54

Malc 发表于 2012-3-21 21:09 static/image/common/back.gif
我也计划在做平衡车啊
不过我打算用MPU6050,一个芯片集成了加速度和角度,价格比分开买两个传感器便宜。。 ...

罗盘是考虑以后做四轴的话可能用的,不过这个片子九十多块也还可以了

黑马 发表于 2012-3-22 09:38:41

弘毅 发表于 2012-3-21 14:12 static/image/common/back.gif
连接图很漂亮ing~~~肿么画出来的。。。

最近忙得吐血。。。等下半年有时间了。。我也学着做一下。。=. ...

Powerpoint 2007……:lol

黑马 发表于 2012-3-22 13:55:02

太粗心了,gDat()函数里的注释有大问题,更正int gDat(int device, int axis) {

// 读九轴姿态传感器寄存器函数
// For Arduino, by 黑马
// 调用参数表
//   type    device      axis
//                  0   1   2
// ADXL345   Acc    x   y   z
// L3G4200D    Gyr    x   y   z
// HMC5883L    Mag    x   z   y
// Example
// 00 #include <Wire.h>
// 01 #define Acc 0x1D
// 02 #define Gyr 0x69
// 03 #define Mag 0x1E
// 04
// 05void setup() {
// 06    sensor_init();
// 07    delay(1000);
// 08}
// 09
// 10void loop() {
// 11    int Z_Gyroscope;
// 12    Z_Gyroscope = gDat(Gyr, 2);
// 13    delay(50);
// 14}

    int v;
    byte vL, vH, address;               // 存放byte数值
    if (device == Acc) address = 0x32;// ADXL345的读数地址
    if (device == Gyr) address = 0xA8;// L3G4200D的读数地址
    if (device == Mag) address = 0x03;// HMC5883L的读数地址
    address = address + axis * 2;       // 数据偏移-坐标轴
    Wire.beginTransmission(device);   // 开始传输数据
    Wire.send(address);               // 发送指针
    Wire.requestFrom(device, 2);      // 请求2 byte数据
    while(Wire.available() < 2);      // 成功获取前等待
    vL = Wire.receive();
    vH = Wire.receive();                // 读取数据
    Wire.endTransmission();             // 结束传输
    if (device == Mag) v = (vL << 8) | vH;
    else v = (vH << 8) | vL;            // 将byte数据合并为Int
    return v;                           // 返回读书值
}

void sensor_init() {                         // 配置九轴姿态传感器
    writeRegister(Acc, 0x2D, 0b00001000);    // 测量模式
                            // 配置ADXL345
    writeRegister(Gyr, 0x20, 0b00001111);    // 设置睡眠模式、x, y, z轴使能
    writeRegister(Gyr, 0x21, 0b00000000);    // 选择高通滤波模式和高通截止频率
    writeRegister(Gyr, 0x22, 0b00000000);    // 设置中断模式
    writeRegister(Gyr, 0x23, 0b00110000);    // 设置量程(2000dps)、自检状态、SPI模式
    writeRegister(Gyr, 0x24, 0b00000000);    // FIFO & 高通滤波
                            // 配置L3G4200D(2000 deg/sec)
    writeRegister(Mag, 0x02, 0x00);          // 连续测量
                            // 配置HMC5883L
}

void writeRegister(int device, byte address, byte val) {    // 写寄存器
    Wire.beginTransmission(device);
    Wire.send(address);
    Wire.send(val);
    Wire.endTransmission();
}

Name_006 发表于 2012-4-5 15:24:16

哈哈 我找到我的板子咯 ~~~~~~~

Randy 发表于 2012-5-2 10:52:00

黑马 发表于 2012-3-22 13:55 static/image/common/back.gif
太粗心了,gDat()函数里的注释有大问题,更正

东西不错,我手上也有一个MPU6050,但是板子自己画的,好像出问题了,现在调试没反应!郁闷中。。。

钩钩 发表于 2012-5-2 11:20:05

链接图美呆了~请问您类似塑料的支架板哪弄的呢?我特想有个,拉风

黑马 发表于 2012-5-3 12:51:03

钩钩 发表于 2012-5-2 11:20 static/image/common/back.gif
链接图美呆了~请问您类似塑料的支架板哪弄的呢?我特想有个,拉风

在淘宝上订做的,有不少做激光切割的,3mm的PMMA板,差不多八块钱一块的样子
页: [1] 2 3 4 5
查看完整版本: 我的自平衡小车之第一步——读取九轴姿态传感器并显示到OLED