#include <SPI.h>
#include <Wire.h> //Підключення бібліотеки для використання інтерфейсу I2C
#include <LiquidCrystal_I2C.h> //Підключення бібліотеки для роботи з дисплеєм
#define ledRed 7
#define RGB1 8
#define RGB2 9
#define RGB3 10
bool RGB1_mode = false;
bool RGB2_mode = false;
bool RGB3_mode = false;
/*
NLSF595
MOSI - SI
SCLK - SCK
SS - RCK
*/
//I2C адреси Slave-пристроїв
#define MPU_ADDR 0x68 //Адреса за замовчуванням для MPU6050 це 0x68
void UART_example();
void SPI_example();
void I2C_example();
void checkMessageUART();
LiquidCrystal_I2C lcd1(0x48, 20, 4); // Дисплей 1 (address, columns, lines)
LiquidCrystal_I2C lcd2(0x49, 16, 2); // Дисплей 2 (address, columns, lines)
String incomingMessage;
void setup()
{
//Ініціалізація UART
Serial.begin(115200); //Встановлення зв'язку з послідовним портом
Serial.println("Hello, Serial Monitor!");
//Ініціалізація SPI
pinMode(RGB1, OUTPUT);
pinMode(RGB2, OUTPUT);
pinMode(RGB3, OUTPUT);
SPI.beginTransaction(SPISettings(14000000, LSBFIRST, SPI_MODE0));
//Ініціалізація I2C
Wire.begin();
Wire.beginTransmission(MPU_ADDR); //першим байтом, що пересилається, є адерса Slave-пристрою
Serial.println("I2C GOOD");
/*
Зв'язок з MPU6050 розпочато, надалі за допомогою функції Wire.write()
відбувається звернення до внутрішнього регістру MPU6050,
а саме регістру із номером 0x6B, цей регістр відповідає
за режим живлення та налаштування схеми
*/
Wire.write(0x6B); //Передача номера регістру по шині
Wire.write(0x00); //За замовчуванням усі біти залишаються встановленими у 0
Wire.endTransmission(true); //Для уникнення непередбачуваних ситуацій тимчасово закривається зв'язок із шиною
delay(50); //затримка 0,05 сек
Wire.beginTransmission(MPU_ADDR); //зв'язок із шиною відновлюється
/*
за адресою 0x1C розташовується регістр, що відповідає за налаштування акселерометру
що є одним із пристроїв, функції якого поряд із гіроскопом та термометром
виконує MPU6050
*/
Wire.write(0x1C); //Передача адреси цього регістру, що сповіщає про запис даних до нього
Wire.write(0x00); //За замовчуванням для акселерометра встановлено точність +- 2g, що відповідає показникам у симуляторі та цілком достатня
Wire.endTransmission(true); //Передачу завершено.
lcd1.begin(20,4); //Ініціалізація lcd1
lcd2.begin(16,2); //Ініціалізація lcd2
pinMode(ledRed, OUTPUT);
}
void loop()
{
UART_example();
SPI_example();
I2C_example();
}
/*********************** UART **********************/
void UART_example()
{
if (Serial.available())
{
incomingMessage = Serial.readString();
Serial.print("Отримано: ");
Serial.println(incomingMessage);
incomingMessage.toUpperCase();
checkMessageUART();
incomingMessage = "";
}
}
/*********************** SPI ***********************/
void SPI_example()
{
//ABCDEFGH
if(RGB1_mode)
{
// On
digitalWrite(RGB1, LOW);
SPI.transfer(0xDF); //~0x20
digitalWrite(RGB1, HIGH);
// Off
digitalWrite(RGB2, LOW);
digitalWrite(RGB3, LOW);
SPI.transfer(0xFF);
digitalWrite(RGB2, HIGH);
digitalWrite(RGB3, HIGH);
}
else if (RGB2_mode)
{
// On
digitalWrite(RGB2, LOW);
SPI.transfer(0xEF); //~0x10
digitalWrite(RGB2, HIGH);
// Off
digitalWrite(RGB1, LOW);
digitalWrite(RGB3, LOW);
SPI.transfer(0xFF);
digitalWrite(RGB1, HIGH);
digitalWrite(RGB3, HIGH);
}
else if (RGB3_mode)
{
// On
digitalWrite(RGB3, LOW);
SPI.transfer(0xF7); //~0x08
digitalWrite(RGB3, HIGH);
// Off
digitalWrite(RGB1, LOW);
digitalWrite(RGB2, LOW);
SPI.transfer(0xFF);
digitalWrite(RGB1, HIGH);
digitalWrite(RGB2, HIGH);
}
else
{
// Off
digitalWrite(RGB1, LOW);
digitalWrite(RGB2, LOW);
digitalWrite(RGB3, LOW);
SPI.transfer(0xFF);
digitalWrite(RGB1, HIGH);
digitalWrite(RGB2, HIGH);
digitalWrite(RGB3, HIGH);
}
}
/*********************** I2C ***********************/
void I2C_example()
{
/*
Для наочності роботи інтерфейсу I2C, дані показники прискорення по осі X
будуть зчитуватися по половині, оскільки результат прискорення, який
видає акселерометр вміщається у 16 біт, а зберігається у MPU6050 у двох регістрах:
ACCEL_XOUT_H, ACCEL_XOUT_L, що мають розрядність 8 біт
до того ж порція даних, що передаються I2C також 8 біт
*/
byte xAxis = 0; //Змінна, що зберігає першу частину прискорення по осі X
Wire.beginTransmission(MPU_ADDR); //Початок роботи з MPU
Wire.write(0x3B); //Передача адреси регістра ACCEL_XOUT_H
//Зв'язок не переивається, наступною командою буде йти кількість байтів для читання
Wire.endTransmission(false);
/*
Від MPU6050 запитується один байт, після читання доступ до шини закривається,
оскільки третій параметр true
*/
Wire.requestFrom(MPU_ADDR, 1, true);
xAxis = Wire.read(); //Читання байту
byte xAxisL = 0; //Змінна, що зберігає другу частину прискорення по осі X
Wire.beginTransmission(MPU_ADDR); //Встановлення зв'язку з MPU
Wire.write(0x3C); //Передача номера регістру ACCEL_XOUT_L
Wire.endTransmission(false);
Wire.requestFrom(MPU_ADDR, 1, true); //Запитується друга частина виміру
xAxisL = Wire.read(); //Читання цього байту
int16_t xAxisFull = xAxis << 8 | xAxisL;
/*
Перша частина виміру прискорення по осі X
зберігається у 16 бітній змінній, потім це значення зсувається із молодших біт у
старші, наостанок молодші 8 біт результату фактично заміщуються другою
частиною вимірів за допомогою побітової операції OR.
Ділення результату на число із документації для забезпечення точності у +-2g
*/
float xAxisFinal = (float) xAxisFull / 16384.0;
// Y та Z дані з акселерометра
Wire.beginTransmission(MPU_ADDR); //Встановлюється зв'язок з MPU
/*
Передається номер першого із регістрів, що зберігає виміри прискорення по осі Y,
за наступними адресами йдуть друга частина Y, перша Z, друга Z
*/
Wire.write(0x3D);
Wire.endTransmission(false);
Wire.requestFrom(MPU_ADDR, 4, true); //Запитуються 4 байти, по 2 на кожну вісь
//За допомогою побітових операцій виконується додавання старших та молодших 8 бітів результатів прискорення
int16_t yAxisFull = (Wire.read() << 8 | Wire.read());
int16_t zAxisFull = (Wire.read() << 8 | Wire.read());
//Ці дані оброблюються, для забезпечення обраного рівня точності
float yAxisFinal = (float) yAxisFull / 16384.0;
float zAxisFinal = (float) zAxisFull / 16384.0;
//Температура
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x41); //Регістр TEMP_OUT_H
Wire.endTransmission(false);
Wire.requestFrom(MPU_ADDR, 2, true);
int16_t Temperature_int = Wire.read() << 8 | Wire.read();
float Temperature = (float) Temperature_int / 340 + 36.53;
//Виведення отриманих даних на дисплей
lcd1.setCursor(4, 0);
lcd1.print("ACCELERATION");
lcd1.setCursor(0, 1);
lcd1.print("X Axis = " + String(xAxisFinal) + " g ");
lcd1.setCursor(0, 2);
lcd1.print("Y Axis = " + String(yAxisFinal) + " g ");
lcd1.setCursor(0, 3);
lcd1.print("Z Axis = " + String(zAxisFinal) + " g ");
lcd2.setCursor(0, 0);
lcd2.print("TEMPERATURE IN C");
lcd2.setCursor(5, 1);
lcd2.print(String(Temperature) + " ");
}
void checkMessageUART()
{
if (incomingMessage.indexOf("ON") != -1)
digitalWrite(ledRed, HIGH);
else if (incomingMessage.indexOf("OFF") != -1)
digitalWrite(ledRed, LOW);
else if (incomingMessage.indexOf("RGB1") != -1)
{
RGB1_mode = !RGB1_mode;
RGB2_mode = false;
RGB3_mode = false;
}
else if (incomingMessage.indexOf("RGB2") != -1)
{
RGB1_mode = false;
RGB2_mode = !RGB2_mode;
RGB3_mode = false;
}
else if (incomingMessage.indexOf("RGB3") != -1)
{
RGB1_mode = false;
RGB2_mode = false;
RGB3_mode = !RGB3_mode;
}
}