极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 163506|回复: 63

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

  [复制链接]
发表于 2012-3-21 14:07:09 | 显示全部楼层 |阅读模式
首先感谢弘毅老大的详细教程thomas的库文件

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

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



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

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

  3. #define OLED_CS 42          // CS脚
  4. #define OLED_CLK 44         // CLK脚
  5. #define OLED_MOSI 46        // MISO脚
  6. #define OLED_RESET 48       // RST脚
  7. #define OLED_DC 50          // D/C脚

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

  13. char str[16];               // 输出字符串(切勿溢出)
  14. int curve[128];             // 曲线数据
  15. int i = 0;

  16. void setup() {
  17.     oled.ssd1306_init(SSD1306_SWITCHCAPVCC);
  18.     oled.clear();            // 清空oled屏
  19.     oled.drawstring(0, 0, "Setting up...");
  20.     oled.display();          // 显示到oled
  21.                              // 初始化OLED
  22.     sensor_init();           // 初始化传感器
  23.     delay(2000);
  24. }
  25. void loop() {
  26.   int x;
  27.   curve[i] = gDat(Gyr, 0);            // 读取传感器,根据需要读取不同传感器数据
  28.   if (curve[i] < -26) curve[i] = -26; // 上溢出
  29.   if (curve[i] > 26) curve[i] = 26;   // 下溢出
  30.   oled.clear();                       // 清空oled屏
  31.   sprintf(str, "xGyro= %d", curve[i]);// 输出字符串
  32.   oled.drawstring(0, 0, str);         // 输出到到oled
  33.   for (x = 0; x < 127; x++) {
  34.     oled.drawline(x, 37 - curve[x], x+1, 37 - curve[x+1], WHITE);
  35.   }                                   // 绘制曲线
  36.   oled.display();                     // 显示到oled
  37.   i++;
  38.   if (i == 128) i = 0;
  39.   delay(10);
  40. }

  41. int gDat(int device, int axis) {

  42. // 读九轴姿态传感器寄存器函数
  43. // For Arduino, by 黑马
  44. // 调用参数表
  45. //   type    device      axis
  46. //                    0   1   2
  47. // ADXL345     Acc    x   y   z
  48. // L3G4200D    Gyr    x   y   z
  49. // HMC5883L    Mag    x   z   y
  50. // Example
  51. // 00 #include <Wire.h>
  52. // 01 #define Acc 0x1D;
  53. // 02 #define Gyr 0x69;
  54. // 03 #define Mag 0x1E;
  55. // 04
  56. // 05  void setup() {
  57. // 06    sensor_init();
  58. // 07    delay(1000);
  59. // 08  }
  60. // 09
  61. // 10  void loop() {
  62. // 11    Z-Gyroscope = gDat(Gyr, 2);
  63. // 12    delay(50);
  64. // 13  }

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

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

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

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

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2012-3-21 14:12:50 | 显示全部楼层
连接图很漂亮ing~~~肿么画出来的。。。

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

使用道具 举报

发表于 2012-3-21 14:18:04 | 显示全部楼层
话说。。。。OLED看了后,我已经无心用其他led了。。。。=.=颜色太漂亮了
回复 支持 反对

使用道具 举报

发表于 2012-3-21 14:21:22 | 显示全部楼层
好贴,正打算入手这个板子,玩一玩.
回复 支持 反对

使用道具 举报

发表于 2012-3-21 21:09:04 | 显示全部楼层
我也计划在做平衡车啊
不过我打算用MPU6050,一个芯片集成了加速度和角度,价格比分开买两个传感器便宜。。
指南针就不弄了。。太费钱了
回复 支持 反对

使用道具 举报

发表于 2012-3-21 23:34:06 | 显示全部楼层
还是OLED漂亮!
刷新的问题解决没?
回复 支持 反对

使用道具 举报

发表于 2012-3-22 07:58:02 | 显示全部楼层
刚才想起个事,OLED板子是3v3电压的,io口需要做个匹配。正规方法是接4050缓冲器,最简单的是每个io接一个100欧电阻(厂家非官方说法)。我发帖子时还不会做图,忽略了这个,抱歉!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-3-22 09:33:30 | 显示全部楼层
thomas 发表于 2012-3-22 07:58
刚才想起个事,OLED板子是3v3电压的,io口需要做个匹配。正规方法是接4050缓冲器,最简单的是每个io接一个1 ...

这个没注意,多亏你提醒,我再看下,谢谢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-3-22 09:37:54 | 显示全部楼层
Malc 发表于 2012-3-21 21:09
我也计划在做平衡车啊
不过我打算用MPU6050,一个芯片集成了加速度和角度,价格比分开买两个传感器便宜。。 ...

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

使用道具 举报

 楼主| 发表于 2012-3-22 09:38:41 | 显示全部楼层
弘毅 发表于 2012-3-21 14:12
连接图很漂亮ing~~~肿么画出来的。。。

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

Powerpoint 2007……
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-3-22 13:55:02 | 显示全部楼层
太粗心了,gDat()函数里的注释有大问题,更正
  1. int gDat(int device, int axis) {

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

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

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

  55. void writeRegister(int device, byte address, byte val) {    // 写寄存器
  56.     Wire.beginTransmission(device);
  57.     Wire.send(address);
  58.     Wire.send(val);
  59.     Wire.endTransmission();
  60. }
复制代码
回复 支持 反对

使用道具 举报

发表于 2012-4-5 15:24:16 | 显示全部楼层
哈哈 我找到我的板子咯 ~~~~~~~  
回复 支持 反对

使用道具 举报

发表于 2012-5-2 10:52:00 | 显示全部楼层
黑马 发表于 2012-3-22 13:55
太粗心了,gDat()函数里的注释有大问题,更正

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

使用道具 举报

发表于 2012-5-2 11:20:05 | 显示全部楼层
链接图美呆了~请问您类似塑料的支架板哪弄的呢?我特想有个,拉风
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-5-3 12:51:03 | 显示全部楼层
钩钩 发表于 2012-5-2 11:20
链接图美呆了~请问您类似塑料的支架板哪弄的呢?我特想有个,拉风

在淘宝上订做的,有不少做激光切割的,3mm的PMMA板,差不多八块钱一块的样子
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 19:03 , Processed in 0.047437 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表