/* 创建及执行任务三步曲
  1) 定义钥匙(注意:此时钥匙是空的!!!后面必须赋值)及超时时间
  SemaphoreHandle_t xMutex_ = NULL; //创建信号量Handler
  TickType_t timeOut = 1000; //用于获取信号量的Timeout 1000 ticks

  2) 定义任务
  void taskA(void *pvParam) {
  //超级大循环
  for(;;) {
    //注意!只有操作公共变量时才需要抢钥匙。否则可能会导致其它任务无法执行
    if (xSemaphoreTake(xMutex_, timeOut) == pdPASS) {	//抢钥匙
    // 操作公共变量...........

    //完毕后要归还钥匙
    xSemaphoreGive(xMutex_); //释放钥匙
  }

  3) 在setup()里创建任务
  void setup()
  {
  xMutex_ = xSemaphoreCreateMutex(); //给钥匙赋值
  xTaskCreate(taskA, "taskA", 1024 * 8, NULL, 1, NULL);

  }
******************** the end *****************************
*/



/*
   程序:  MPU6050 & MUTEX
   公众号:孤独的二进制
*/
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);

Adafruit_MPU6050 mpu;
Adafruit_Sensor *mpu_temp, *mpu_accel, *mpu_gyro;

typedef struct {
  float temp;
  float accX;
  float accY;
  float accZ;
  float gyroX;
  float gyroY;
  float gyroZ;
} MPU6050;

MPU6050 mpu6050;

SemaphoreHandle_t xMutexMPU6050 = NULL; //创建信号量Handler
TickType_t timeOut = 1000; //用于获取信号量的Timeout 1000 ticks


void mpu6050Task(void *pvParam) {

  mpu.begin();

  mpu_temp = mpu.getTemperatureSensor();
  mpu_temp->printSensorDetails();

  mpu_accel = mpu.getAccelerometerSensor();
  mpu_accel->printSensorDetails();

  mpu_gyro = mpu.getGyroSensor();
  mpu_gyro->printSensorDetails();

  sensors_event_t accel;
  sensors_event_t gyro;
  sensors_event_t temp;

  while (1) {

    if (xSemaphoreTake(xMutexMPU6050, timeOut) == pdPASS) {

      //获取MPU数据
      mpu_temp->getEvent(&temp);
      mpu_accel->getEvent(&accel);
      mpu_gyro->getEvent(&gyro);

      mpu6050.temp = temp.temperature;
      mpu6050.accX = accel.acceleration.x;
      mpu6050.accY = accel.acceleration.y;
      mpu6050.accZ = accel.acceleration.z;
      mpu6050.gyroX = gyro.gyro.x;
      mpu6050.gyroY = gyro.gyro.y;
      mpu6050.gyroZ = gyro.gyro.z;

      xSemaphoreGive(xMutexMPU6050); //释放钥匙
    } else {
      //Unable to obtain MUTEX
    }

    vTaskDelay(500);
  }
}

void lcdTask(void *ptParam) {  //LCD任务主体

  lcd.init();
  lcd.backlight();

  //定义是 2004 LCD
  byte lcdLine = 4;
  byte lcdChar = 20;

  //创建一个二维的的数组
  //注意长度是 lcdChar+1 最后还有一个位置要给换行符
  char line0[lcdChar + 1], line1[lcdChar + 1], line2[lcdChar + 1], line3[lcdChar + 1];
  char * line[] = { line0, line1, line2, line3, };

  while (1) {

    if (xSemaphoreTake(xMutexMPU6050, timeOut) == pdPASS) {

      // 组合数据
      sprintf(line0, "     MPU6050 %d", xTaskGetTickCount() / 100);
      sprintf(line1, " Temperature  %.2f", mpu6050.temp);
      sprintf(line2, " ACC  %.2f %.2f %.2f", mpu6050.accX, mpu6050.accY, mpu6050.accZ);
      sprintf(line3, " GYRO %.2f %.2f %.2f", mpu6050.gyroX, mpu6050.gyroY, mpu6050.gyroZ);

      xSemaphoreGive(xMutexMPU6050); //释放钥匙
    } else {
      //Unable to obtain MUTEX
    }

    // 显示数据
    for (int i = 0; i < 4; i++) {
      lcd.setCursor(0, i);
      lcd.print(line[i]);
    }

    vTaskDelay(1000);
  }
}

void setup()
{
  Serial.begin(115200);

  xMutexMPU6050 = xSemaphoreCreateMutex(); //创建MUTEX

  xTaskCreate(mpu6050Task, "MPU6050", 1024 * 8, NULL, 1, NULL);
  vTaskDelay(1000); //让MPU6050提前先运行一秒获取第一笔数据
  xTaskCreate(lcdTask, "lcd", 1024 * 8, NULL, 1, NULL);

}


void loop() {}