## 利用MPU6050 + OLED屏显示cube3D矩形效果

Posted perseverance52

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了## 利用MPU6050 + OLED屏显示cube3D矩形效果相关的知识,希望对你有一定的参考价值。

利用MPU6050 + OLED屏显示cube3D矩形效果

本次实验移植到ESP8266板子上

  • 更换了所使用到的库
  • 采用的是1.3寸的屏幕显示,也可以切换为0.96寸屏幕显示,只需更改一下接口定义就可以了,程序代码已预留出来了 。
    视频效果:

||ESP8266+MPU6050实现动态调整cube

MPU6050配合OLED


在这里插入图片描述

用到的硬件:
  1. ESP8266 x 1
  2. MPU6050 (Accelerometer + Gyro Sensor) Module x 1
  3. 0.96″或者1.3" I2C OLED Display x 1

arduino 程序代码:


#include "SH1106Wire.h" //1.3寸用这个
//#include "SSD1306Wire.h"    //0.96寸用这个
#include "OLEDDisplayUi.h"
#include <Wire.h>
#if defined(ESP8266)    //OLED引脚定义
const int SDA_PIN = D2; //对应nodemcu接D5或者D1,,wemosD1mini的D2
const int SDC_PIN = D1; //对应nodemcu接D6或者D2,,wemosD1mini的D5
#else
const int SDA_PIN = D1; //对应nodemcu接D5或者D1
const int SCL = D2;     //对应nodemcu接D6或者D2
#endif

const int I2C_DISPLAY_ADDRESS = 0x3c;                      //I2c地址默认

SH1106Wire display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN); // 1.3寸用这个
//SSD1306Wire     display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);   // 0.96寸用这个

 OLEDDisplayUi ui     ( &display );

//MPU 
const int MPU=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

float xx,xy,xz;
float yx,yy,yz;
float zx,zy,zz;

float fact;

int Xan,Yan;

int Xoff;
int Yoff;
int Zoff;

struct Point3d
{
  int x;
  int y;
  int z;
};

struct Point2d
{
  int x;
  int y;
};



int LinestoRender; // lines to render.
int OldLinestoRender; // lines to render just in case it changes. this makes sure the old lines all get erased.

struct Line3d
{
  Point3d p0;
  Point3d p1;
};

struct Line2d
{
  Point2d p0;
  Point2d p1;
};

Line3d Lines[12];  //Number of lines to render
Line2d Render[12];
Line2d ORender[12];

// Sets the global vars for the 3d transform. Any points sent through "process" will be transformed using these figures.
// only needs to be called if Xan or Yan are changed.
void SetVars(void)
{
  float Xan2,Yan2,Zan2;
  float s1,s2,s3,c1,c2,c3;
  
  Xan2 = Xan / fact; // convert degrees to radians.
  Yan2 = Yan / fact;
  
  // Zan is assumed to be zero
    
  s1 = sin(Yan2);
  s2 = sin(Xan2);
  
  c1 = cos(Yan2);
  c2 = cos(Xan2);

  xx = c1;
  xy = 0; 
  xz = -s1;

  yx = (s1 * s2);
  yy = c2;
  yz = (c1 * s2);

  zx = (s1 * c2);
  zy = -s2;
  zz = (c1 * c2);
}

// processes x1,y1,z1 and returns rx1,ry1 transformed by the variables set in SetVars()
// fairly heavy on floating point here.
// uses a bunch of global vars. Could be rewritten with a struct but not worth the effort.
void ProcessLine(struct Line2d *ret,struct Line3d vec)
{
  float zvt1;
  int xv1,yv1,zv1;

  float zvt2;
  int xv2,yv2,zv2;
  
  int rx1,ry1;
  int rx2,ry2;
 
  int x1;
  int y1;
  int z1;

  int x2;
  int y2;
  int z2;
  
  int Ok;
  
  x1=vec.p0.x;
  y1=vec.p0.y;
  z1=vec.p0.z;

  x2=vec.p1.x;
  y2=vec.p1.y;
  z2=vec.p1.z;

  Ok=0; // defaults to not OK

  xv1 = (x1 * xx) + (y1 * xy) + (z1 * xz);
  yv1 = (x1 * yx) + (y1 * yy) + (z1 * yz);
  zv1 = (x1 * zx) + (y1 * zy) + (z1 * zz);

  zvt1 = zv1 - Zoff;


  if( zvt1 < -5){
    rx1 = 256 * (xv1 / zvt1) + Xoff;
    ry1 = 256 * (yv1 / zvt1) + Yoff;
    Ok=1; // ok we are alright for point 1.
  }
  
  
  xv2 = (x2 * xx) + (y2 * xy) + (z2 * xz);
  yv2 = (x2 * yx) + (y2 * yy) + (z2 * yz);
  zv2 = (x2 * zx) + (y2 * zy) + (z2 * zz);

  zvt2 = zv2 - Zoff;


  if( zvt2 < -5){
    rx2 = 256 * (xv2 / zvt2) + Xoff;
    ry2 = 256 * (yv2 / zvt2) + Yoff;
  } else
  {
    Ok=0;
  }
  
  if(Ok==1){
  ret->p0.x=rx1;
  ret->p0.y=ry1;

  ret->p1.x=rx2;
  ret->p1.y=ry2;
  }
 // The ifs here are checks for out of bounds. needs a bit more code here to "safe" lines that will be way out of whack, so they dont get drawn and cause screen garbage.
 
}

void setup()   {
   Wire.begin();
   fact = 180 / 3.14159265358979323846264338327950; // conversion from degrees to radians.
  
  Xoff = 90; // positions the center of the 3d conversion space into the center of the OLED screen. This is usally screen_x_size / 2.
  Yoff = 32; // screen_y_size /2
  Zoff = 750;   //Size of cube, larger no. = smaller cube

// line segments to draw a cube. basically p0 to p1. p1 to p2. p2 to p3 so on.

// Front Face.

  Lines[0].p0.x=-50;
  Lines[0].p0.y=-50;
  Lines[0].p0.z=50;
  Lines[0].p1.x=50;
  Lines[0].p1.y=-50;
  Lines[0].p1.z=50;

  Lines[1].p0.x=50;
  Lines[1].p0.y=-50;
  Lines[1].p0.z=50;
  Lines[1].p1.x=50;
  Lines[1].p1.y=50;
  Lines[1].p1.z=50;

  Lines[2].p0.x=50;
  Lines[2].p0.y=50;
  Lines[2].p0.z=50;
  Lines[2].p1.x=-50;
  Lines[2].p1.y=50;
  Lines[2].p1.z=50;

  Lines[3].p0.x=-50;
  Lines[3].p0.y=50;
  Lines[3].p0.z=50;
  Lines[3].p1.x=-50;
  Lines[3].p1.y=-50;
  Lines[3].p1.z=50;


//back face.

  Lines[4].p0.x=-50;
  Lines[4].p0.y=-50;
  Lines[4].p0.z=-50;
  Lines[4].p1.x=50;
  Lines[4].p1.y=-50;
  Lines[4].p1.z=-50;

  Lines[5].p0.x=50;
  Lines[5].p0.y=-50;
  Lines[5].p0.z=-50;
  Lines[5].p1.x=50;
  Lines[5].p1.y=50;
  Lines[5].p1.z=-50;

  Lines[6].p0.x=50;
  Lines[6].p0.y=50;
  Lines[6].p0.z=-50;
  Lines[6].p1.x=-50;
  Lines[6].p1.y=50;
  Lines[6].p1.z=-50;

  Lines[7].p0.x=-50;
  Lines[7].p0.y=50;
  Lines[7].p0.z=-50;
  Lines[7].p1.x=-50;
  Lines[7].p1.y=-50;
  Lines[7].p1.z=-50;

// now the 4 edge lines.

  Lines[8].p0.x=-50;
  Lines[8].p0.y=-50;
  Lines[8].p0.z=50;
  Lines[8].p1.x=-50;
  Lines[8].p1.y=-50;
  Lines[8].p1.z=-50;

  Lines[9].p0.x=50;
  Lines[9].p0.y=-50;
  Lines[9].p0.z=50;
  Lines[9].p1.x=50;
  Lines[9].p1.y=-50;
  Lines[9].p1.z=-50;

  Lines[10].p0.x=-50;
  Lines[10].p0.y=50;
  Lines[10].p0.z=50;
  Lines[10].p1.x=-50;
  Lines[10].p1.y=50;
  Lines[10].p1.z=-50;

  Lines[11].p0.x=50;
  Lines[11].p0.y=50;
  Lines[11].p0.z=50;
  Lines[11].p1.x=50;
  Lines[11].p1.y=50;
  Lines[11].p1.z=-50;

  LinestoRender=12;
  OldLinestoRender=LinestoRender;
 
  // Initialize MPU
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
   
  Serial.begin(9600);
  display.init();
  display.clear();
  display.display();
  //    display.flipScreenVertically(); //屏幕翻转
  // display.mirrorScreen();//使用分光棱镜显示需要用到此函数
  display.setContrast(100,5,0); //屏幕亮度
  delay(1000);
 ui.setTargetFPS(80);                   //刷新频率
  ui.disableAllIndicators();             //不显示页码小点。
 ui.enableAutoTransition();
  ui.setFrameAnimation(SLIDE_LEFT);           //切屏方向
  ui.setAutoTransitionForwards();//设置自动过渡方向,
 // ui.setFrames(frames, numberOfFrames);       // 设置框架和显示屏幕内容数
  //ui.setTimePerFrame(5000);                   //设置切换时间
  ui.setTimePerTransition(500);//设置转场大约所需要时间
  // ui.setOverlays(overlays, numberOfOverlays); //设置覆盖的画面数  
  ui.init();// UI负责初始化显示

}


/***********************************************************************************************************************************/
void RenderImage( void)
{
  // renders all the lines after erasing the old ones.
  // in here is the only code actually interfacing with the OLED. so if you use a different lib, this is where to change it.

 for (int i=0; i<OldLinestoRender; i++ )
  {
   display.drawLine(ORender[i].p0.x,ORender[i].p0.y,ORender[i].p1.x,ORender[i].p1.y); // erase the old lines.
     display.display();
  }

    
  for (int i=0; i<LinestoRender; i++ )
  {
   display.drawLine(Render[i].p0.x,Render[i].p0.y,Render[i].p1.x,Render[i].p1.y);
     display.display();
  }
  OldLinestoRender=LinestoRender;
  
  
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(true);
  Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  // text display tests
  display.clear();
  display.setFont(ArialMT_Plain_12)以上是关于## 利用MPU6050 + OLED屏显示cube3D矩形效果的主要内容,如果未能解决你的问题,请参考以下文章

Aduino ESP9266通过I2C接口读取MPU6050模块数据+OLED显示

单核无操作系统如何实现任务并行运行demo之ardiuno读取MPU6050进行oled显示和控制ws2812B灯阵模式显示

STM32+MPU6050设计便携式Mini桌面时钟(自动调整时间显示方向)

STM32+MPU6050设计便携式Mini桌面时钟(自动调整时间显示方向)

MicroPython ESP32ssd1306驱动0.96“I2C屏幕+mpu6050图形控制

Arduino ESP32网页同步更新MPU6050数据模型化显示