아두이노 나노와 블루투스 통신 HC-06, MPU6050 센서를 통해
요즘 유행하는 샤오미 스마트밴드을 구현해보자.
연결 방법은 간단하게 설명하겠다.
-----------------------
MPU6050
3.3V - VCC
GND - GND
A4 - SDA (데이터)
A5 - SCL (클럭)
여기서 MPU6050센서는 I2C통신을 한다.
I2C통신은 데이터틀 주고 받기 위한 선 (SDA)와 송수신 타이밍 동기화를 위한 클럭 선(SCL)로 이루어진다.
시그널 핀 2개를 사용하여 여러 장치들과 통신하게 해주는 1:N 통신 방식이다.
--------------------------
HC-06
5V - VCC
GND - GND
D2 - TX
D3 - RX
------------
#include <math.h>
#include <Wire.h>
#include <SoftwareSerial.h>
/* Bluetooth */
SoftwareSerial BTSerial(2, 3); //Connect HC-06. Use your (TX, RX) settings
// 소프트웨어 시리얼 통신을 통해 RX,TX의 포트를 설정해준다.
/* time */
#define SENDING_INTERVAL 1000
#define SENSOR_READ_INTERVAL 50
unsigned long prevSensoredTime = 0;
unsigned long curSensoredTime = 0;
//센서의 측정 값에 대한 간격 시간
/* Data buffer */
#define ACCEL_BUFFER_COUNT 125
byte aAccelBuffer[ACCEL_BUFFER_COUNT];
int iAccelIndex = 2;
/* MPU-6050 sensor */
#define MPU6050_ACCEL_XOUT_H 0x3B // R
#define MPU6050_PWR_MGMT_1 0x6B // R/W
#define MPU6050_PWR_MGMT_2 0x6C // R/W
#define MPU6050_WHO_AM_I 0x75 // R
#define MPU6050_I2C_ADDRESS 0x68
typedef union accel_t_gyro_union {
struct {
uint8_t x_accel_h;
uint8_t x_accel_l;
uint8_t y_accel_h;
uint8_t y_accel_l;
uint8_t z_accel_h;
uint8_t z_accel_l;
uint8_t t_h;
uint8_t t_l;
uint8_t x_gyro_h;
uint8_t x_gyro_l;
uint8_t y_gyro_h;
uint8_t y_gyro_l;
uint8_t z_gyro_h;
uint8_t z_gyro_l;
} reg;
struct {
int x_accel;
int y_accel;
int z_accel;
int temperature;
int x_gyro;
int y_gyro;
int z_gyro;
} value;
};
void setup() {
int error;
uint8_t c;
Serial.begin(9600);
Wire.begin();
BTSerial.begin(9600); // set the data rate for the BT port
// default at power-up:
// Gyro at 250 degrees second
// Acceleration at 2g
// Clock source at internal 8MHz
// The device is in sleep mode.
//
error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);
Serial.print(F("WHO_AM_I : "));
Serial.print(c,HEX);
Serial.print(F(", error = "));
Serial.println(error,DEC);
// According to the datasheet, the 'sleep' bit
// should read a '1'. But I read a '0'.
// That bit has to be cleared, since the sensor
// is in sleep mode at power-up. Even if the
// bit reads '0'.
error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1);
Serial.print(F("PWR_MGMT_2 : "));
Serial.print(c,HEX);
Serial.print(F(", error = "));
Serial.println(error,DEC);
// Clear the 'sleep' bit to start the sensor.
MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);
initBuffer();
}
void loop() {
curSensoredTime = millis();
// Read from sensor
if(curSensoredTime - prevSensoredTime > SENSOR_READ_INTERVAL) {
readFromSensor(); // Read from sensor
prevSensoredTime = curSensoredTime;
// Send buffer data to remote
if(iAccelIndex >= ACCEL_BUFFER_COUNT - 3) {
sendToRemote();
initBuffer();
Serial.println("------------- Send 20 accel data to remote");
}
}
}
/**************************************************
* BT Transaction
**************************************************/
void sendToRemote() {
// Write gabage bytes
BTSerial.write( "accel" );
// Write accel data
BTSerial.write( (char*)aAccelBuffer );
// Flush buffer
//BTSerial.flush();
}
/**************************************************
* Read data from sensor and save it
**************************************************/
void readFromSensor() {
int error;
double dT;
accel_t_gyro_union accel_t_gyro;
error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) &accel_t_gyro, sizeof(accel_t_gyro));
if(error != 0) {
Serial.print(F("Read accel, temp and gyro, error = "));
Serial.println(error,DEC);
}
// Swap all high and low bytes.
// After this, the registers values are swapped,
// so the structure name like x_accel_l does no
// longer contain the lower byte.
uint8_t swap;
#define SWAP(x,y) swap = x; x = y; y = swap
SWAP (accel_t_gyro.reg.x_accel_h, accel_t_gyro.reg.x_accel_l);
SWAP (accel_t_gyro.reg.y_accel_h, accel_t_gyro.reg.y_accel_l);
SWAP (accel_t_gyro.reg.z_accel_h, accel_t_gyro.reg.z_accel_l);
SWAP (accel_t_gyro.reg.t_h, accel_t_gyro.reg.t_l);
SWAP (accel_t_gyro.reg.x_gyro_h, accel_t_gyro.reg.x_gyro_l);
SWAP (accel_t_gyro.reg.y_gyro_h, accel_t_gyro.reg.y_gyro_l);
SWAP (accel_t_gyro.reg.z_gyro_h, accel_t_gyro.reg.z_gyro_l);
// Print the raw acceleration values
Serial.print(F("accel x,y,z: "));
Serial.print(accel_t_gyro.value.x_accel, DEC);
Serial.print(F(", "));
Serial.print(accel_t_gyro.value.y_accel, DEC);
Serial.print(F(", "));
Serial.print(accel_t_gyro.value.z_accel, DEC);
Serial.print(F(", at "));
Serial.print(iAccelIndex);
Serial.println(F(""));
if(iAccelIndex < ACCEL_BUFFER_COUNT && iAccelIndex > 1) {
int tempX = accel_t_gyro.value.x_accel;
int tempY = accel_t_gyro.value.y_accel;
int tempZ = accel_t_gyro.value.z_accel;
/*
// Check min, max value
if(tempX > 16380) tempX = 16380;
if(tempY > 16380) tempY = 16380;
if(tempZ > 16380) tempZ = 16380;
if(tempX < -16380) tempX = -16380;
if(tempY < -16380) tempY = -16380;
if(tempZ < -16380) tempZ = -16380;
// We dont use negative value
tempX += 16380;
tempY += 16380;
tempZ += 16380;
*/
char temp = (char)(tempX >> 8);
if(temp == 0x00)
temp = 0x7f;
aAccelBuffer[iAccelIndex] = temp;
iAccelIndex++;
temp = (char)(tempX);
if(temp == 0x00)
temp = 0x01;
aAccelBuffer[iAccelIndex] = temp;
iAccelIndex++;
temp = (char)(tempY >> 8);
if(temp == 0x00)
temp = 0x7f;
aAccelBuffer[iAccelIndex] = temp;
iAccelIndex++;
temp = (char)(tempY);
if(temp == 0x00)
temp = 0x01;
aAccelBuffer[iAccelIndex] = temp;
iAccelIndex++;
temp = (char)(tempZ >> 8);
if(temp == 0x00)
temp = 0x7f;
aAccelBuffer[iAccelIndex] = temp;
iAccelIndex++;
temp = (char)(tempZ);
if(temp == 0x00)
temp = 0x01;
aAccelBuffer[iAccelIndex] = temp;
iAccelIndex++;
}
// The temperature sensor is -40 to +85 degrees Celsius.
// It is a signed integer.
// According to the datasheet:
// 340 per degrees Celsius, -512 at 35 degrees.
// At 0 degrees: -512 - (340 * 35) = -12412
// Serial.print(F("temperature: "));
// dT = ( (double) accel_t_gyro.value.temperature + 12412.0) / 340.0;
// Serial.print(dT, 3);
// Serial.print(F(" degrees Celsius"));
// Serial.println(F(""));
// Print the raw gyro values.
// Serial.print(F("gyro x,y,z : "));
// Serial.print(accel_t_gyro.value.x_gyro, DEC);
// Serial.print(F(", "));
// Serial.print(accel_t_gyro.value.y_gyro, DEC);
// Serial.print(F(", "));
// Serial.print(accel_t_gyro.value.z_gyro, DEC);
// Serial.println(F(""));
}
/**************************************************
* MPU-6050 Sensor read/write
**************************************************/
int MPU6050_read(int start, uint8_t *buffer, int size)
{
int i, n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS);
n = Wire.write(start);
if (n != 1)
return (-10);
n = Wire.endTransmission(false); // hold the I2C-bus
if (n != 0)
return (n);
// Third parameter is true: relase I2C-bus after data is read.
Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
i = 0;
while(Wire.available() && i<size)
{
buffer[i++]=Wire.read();
}
if ( i != size)
return (-11);
return (0); // return : no error
}
int MPU6050_write(int start, const uint8_t *pData, int size)
{
int n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS);
n = Wire.write(start); // write the start address
if (n != 1)
return (-20);
n = Wire.write(pData, size); // write data bytes
if (n != size)
return (-21);
error = Wire.endTransmission(true); // release the I2C-bus
if (error != 0)
return (error);
return (0); // return : no error
}
int MPU6050_write_reg(int reg, uint8_t data)
{
int error;
error = MPU6050_write(reg, &data, 1);
return (error);
}
/**************************************************
* Utilities
**************************************************/
void initBuffer() {
iAccelIndex = 2;
for(int i=iAccelIndex; i<ACCEL_BUFFER_COUNT; i++) {
aAccelBuffer[i] = 0x00;
}
aAccelBuffer[0] = 0xfe;
aAccelBuffer[1] = 0xfd;
aAccelBuffer[122] = 0xfd;
aAccelBuffer[123] = 0xfe;
aAccelBuffer[124] = 0x00;
}
'임베디드' 카테고리의 다른 글
지능형 자동차 3일차 (망한듯..) (0) | 2016.08.16 |
---|---|
지능형 자동차 2일차 (0) | 2016.08.16 |
지능형 자동차 만들기 1일차 (0) | 2016.08.16 |
댓글