La somnolence au volant est un véritable danger : elle peut entraîner des accidents graves mettant en péril la vie des conducteurs et des usagers de la route.
Les solutions existantes sont souvent coûteuses, complexes ou réservées aux véhicules haut de gamme.
💡 L’idéeJe voulais créer une solution simple, portable et accessible : une montre connectée DIY capable de détecter les signes de somnolence et de prévenir l’utilisateur avant qu’il ne s’endorme.Ainsi est née Sleeping Watch – Réveillez-vous !
⚙️ La conception- Capteur MAX30102 → mesure le rythme cardiaque et la saturation en oxygène.
- Capteur BMI160 → analyse les mouvements et l’activité physique.
- Microcontrolleur (NucléoSTM32) → collecte et analyse les données en temps réel.
- Écran OLED → affiche les informations essentielles.
- Système d’alerte → signal sonore quand un état de somnolence est détecté.
Les données combinées permettent de repérer un état de fatigue (ralentissement du rythme cardiaque + mouvements réduits) et d’alerter l’utilisateur.
🔨 Le développementLe plus gros défi a été de calibrer les capteurs pour distinguer un simple moment de "repos" type conduite sur autoroute d’un véritable signe de somnolence, et ce quel que soit l'utilisateur.J’ai travaillé sur l’intégration des bibliothèques (MAX30102, BMI160), la lecture en temps réel et l’affichage clair sur l’écran.
🚀 Ce que j’ai appris
- L’importance de croiser plusieurs capteurs pour fiabiliser la détection.
- Comment optimiser le code pour éviter les temps d'attente inutiles.
- L'utilisation des librairies.
- L'importance d'avoir un code bien clair pour ne pas s'y perdre.
- Utiliser un Microcontrolleur plus petit pour miniaturiser la montre.
- Créer un pcb pour avoir un prototype plus pratique à utiliser
- Ajouter une connectivité Bluetooth pour transmettre les données à un smartphone.
- Ajouter un vibreur
🤖 Utilisation de l'IA
J'ai utilisé l'ia durant ce projet, et ce sur plusieurs points:
- Commenter le code (j'écrivais les commentaire de façon très sommaire, l'ia les rendait plus construits et plus beaux)
- Supprimer les doublons, parties inutiles, lignes polluantes
- Débugger (mieux comprendre les codes d'erreur)
#include <Arduino.h>
#include <Wire.h>
#include <DFRobot_BloodOxygen_S.h>
#include <Arduino_GFX_Library.h>
#include <DFRobot_BMI160.h>
// ==================================================
// ---------- DÉFINITION DES CAPTEURS & ÉCRAN ----------
// ==================================================
// ---------- CAPTEUR MAX30102 ----------
#define I2C_ADDRESS 0x57
DFRobot_BloodOxygen_S_I2C MAX30102(&Wire, I2C_ADDRESS);
// ---------- ÉCRAN ST7789 ----------
#define TFT_DC D9
#define TFT_CS D10
#define TFT_RST D8
#define TFT_BL D7
Arduino_DataBus *bus = new Arduino_HWSPI(TFT_DC, TFT_CS);
Arduino_GFX *gfx = new Arduino_ST7789(bus, TFT_RST, 1, true);
// ---------- CAPTEUR BMI160 ----------
DFRobot_BMI160 bmi160;
const int8_t i2c_addr = 0x69;
// ==================================================
// ---------- VARIABLES GLOBALES ----------
// ==================================================
uint8_t poulsMoyen = 110;
const float SEUIL = 200;
// ==================================================
// ---------- FONCTIONS D'INITIALISATION ----------
// ==================================================
// Initialisation des capteurs et de l'écran
void initialisation()
{
gfx->begin();
gfx->fillScreen(BLACK);
gfx->setTextColor(WHITE);
gfx->setTextSize(2);
gfx->setCursor(40, 60);
gfx->println("Initialisation...");
while (!MAX30102.begin())
{
gfx->fillScreen(RED);
gfx->setCursor(40, 60);
gfx->println("Cpt pouls non detecte");
}
while (bmi160.softReset() != BMI160_OK)
{
gfx->fillScreen(RED);
gfx->setCursor(40, 60);
gfx->println("Cpt accel erreur reset");
}
while (bmi160.I2cInit(i2c_addr) != BMI160_OK)
{
gfx->fillScreen(RED);
gfx->setCursor(40, 60);
gfx->println("Cpt accel init imposs");
}
}
// ==================================================
// ---------- FONCTIONS UTILITAIRES ----------
// ==================================================
// Attente que le doigt / montre soit bien positionné
void attentedoigtoumontre()
{
MAX30102.sensorStartCollect();
MAX30102.getHeartbeatSPO2();
uint16_t pouls = MAX30102._sHeartbeatSPO2.Heartbeat;
gfx->fillScreen(BLACK);
while (pouls > 300)
{
MAX30102.getHeartbeatSPO2();
pouls = MAX30102._sHeartbeatSPO2.Heartbeat;
gfx->setTextColor(WHITE);
gfx->setTextSize(2);
gfx->setCursor(70, 90);
gfx->println("Veuillez mettre ");
gfx->setCursor(105, 120);
gfx->println("la montre");
delay(500);
Serial.println(pouls);
}
}
// Calibration du pouls moyen sur 10 secondes
void calibrationpouls()
{
gfx->fillScreen(BLACK);
gfx->setTextColor(WHITE);
gfx->setTextSize(2);
gfx->setCursor(75, 100);
gfx->println("Calibration...");
Serial.println("Mesure du pouls moyen en cours...");
uint32_t debutMesure = millis();
uint32_t dureeMesure = 10000; // 10 secondes
uint32_t sommePouls = 0;
uint16_t nbMesures = 0;
while (millis() - debutMesure < dureeMesure)
{
MAX30102.getHeartbeatSPO2();
uint16_t mesure = MAX30102._sHeartbeatSPO2.Heartbeat;
if (mesure > 40 && mesure < 300) // On filtre les valeurs aberrantes
{
sommePouls += mesure;
nbMesures++;
}
// Calcul du temps restant
uint8_t tempsRestant = (dureeMesure - (millis() - debutMesure)) / 1000;
// Affichage du temps restant
gfx->fillRect(90, 130, 80, 30, BLACK); // efface l’ancienne valeur proprement
gfx->setCursor(140, 130);
gfx->printf("%2ds", tempsRestant);
Serial.print("Temps restant: ");
Serial.print(tempsRestant);
Serial.println("s");
delay(50); // Échantillonnage toutes les 50 ms
}
if (nbMesures > 0)
{
poulsMoyen = sommePouls / nbMesures;
}
else
{
poulsMoyen = 100; // valeur de secours
}
gfx->fillScreen(BLACK);
gfx->setCursor(50, 120);
gfx->printf("Pouls moyen: %d", poulsMoyen);
Serial.print("Pouls moyen mesure: ");
Serial.println(poulsMoyen);
delay(5000);
// Affichage permanent du pouls moyen
gfx->fillScreen(BLACK);
gfx->setTextColor(WHITE);
gfx->setTextSize(5);
if (poulsMoyen < 100)
{
gfx->setCursor(107, 80);
}
else
{
gfx->setCursor(120, 80);
}
gfx->printf("%3d", poulsMoyen);
}
// Dessin d’un cœur à l’écran
void dessincoeur(int x, int y, int taille, uint16_t couleur)
{
gfx->fillCircle(x - taille / 2, y, taille / 2, couleur);
gfx->fillCircle(x + taille / 2, y, taille / 2, couleur);
gfx->fillTriangle(x - taille * 1, y, x + taille * 1, y, x, y + taille * 1.3, couleur);
}
// Détection de mouvement avec l'accéléromètre
void detectmvmt(uint8_t &compteurImmobile)
{
int16_t data[6];
static int16_t derniereAccelX = 0;
static int16_t derniereAccelY = 0;
static int16_t derniereAccelZ = 0;
if (bmi160.getAccelGyroData(data) == BMI160_OK)
{
int16_t accX = data[0];
int16_t accY = data[1];
int16_t accZ = data[2];
// Vérification mouvement
if (abs(accX - derniereAccelX) > SEUIL || abs(accY - derniereAccelY) > SEUIL || abs(accZ - derniereAccelZ) > SEUIL)
{
derniereAccelX = accX;
derniereAccelY = accY;
derniereAccelZ = accZ;
Serial.println("Mouvement détecté !");
compteurImmobile = 0;
}
else
{
compteurImmobile++;
}
}
}
// ==================================================
// ---------- SETUP ----------
// ==================================================
void setup()
{
Serial.begin(115200);
Wire.begin();
pinMode(TFT_BL, OUTPUT);
pinMode(D6, OUTPUT);
digitalWrite(TFT_BL, HIGH);
initialisation();
attentedoigtoumontre();
calibrationpouls();
}
// ==================================================
// ---------- LOOP PRINCIPALE ----------
// ==================================================
void loop()
{
MAX30102.getHeartbeatSPO2();
static uint16_t poulsPrecedent = 0;
static uint8_t compteurBaisse = 0;
static uint32_t tempsPrecedent = 0;
static uint32_t tempsPrecedentcoeur = 0;
static bool coeurVisible = false;
static bool sommeil = false;
uint32_t tempsActuel = millis();
uint16_t pouls = MAX30102._sHeartbeatSPO2.Heartbeat;
static uint8_t compteurImmobile = 0;
Serial.print("cpt immo");
Serial.println(compteurImmobile);
// --- Détection mouvement ---
detectmvmt(compteurImmobile);
// --- Traitement du pouls ---
if (pouls > 40 && pouls < 200)
{
static float poulsLisse = poulsMoyen; // Valeur de départ
if (abs(pouls - poulsLisse) < 30) // On ignore les sauts > 30 bpm
{
poulsLisse = 0.8 * poulsLisse + 0.2 * pouls; // moyenne glissante
}
uint16_t poulsFiltre = (uint16_t)poulsLisse;
if (tempsActuel - tempsPrecedent > 500)
{
Serial.print("Pouls: ");
Serial.println(poulsFiltre);
tempsPrecedent = tempsActuel;
// Affichage du pouls filtré
if (poulsFiltre != poulsPrecedent)
{
gfx->fillRect(110, 75, 100, 50, BLACK);
gfx->setTextColor(WHITE);
gfx->setTextSize(5);
if (poulsFiltre < 100) gfx->setCursor(107, 80);
else gfx->setCursor(120, 80);
gfx->printf("%3d", poulsFiltre);
}
// Détection baisse anormale
if (poulsFiltre < poulsMoyen - 20)
compteurBaisse++;
else
compteurBaisse = 0;
poulsPrecedent = poulsFiltre;
}
}
// --- Alerte sommeil ---
if (compteurBaisse > 4 || compteurImmobile > 70)
{
sommeil = true;
for (uint8_t i = 0; i < 5; i++)
{
gfx->fillScreen(BLACK);
gfx->setTextColor(RED);
gfx->setTextSize(4);
gfx->setCursor(80, 100);
gfx->println("SOMMEIL...");
analogWrite(D6, 128);
delay(400);
gfx->fillScreen(BLACK);
analogWrite(D6, 80);
delay(200);
}
analogWrite(D6, 0);
compteurBaisse = 0;
compteurImmobile = 0;
}
else
{
sommeil = false;
}
// --- Animation du cœur si pas en sommeil ---
if (!sommeil && (tempsActuel - tempsPrecedentcoeur > 500))
{
coeurVisible = !coeurVisible;
tempsPrecedentcoeur = tempsActuel;
gfx->fillRect(130, 120, 70, 100, BLACK);
if (coeurVisible)
{
dessincoeur(165, 140, 30, (gfx->color565(255, 105, 180))); // cœur rose
}
}
}
DFRobot_BMI160.cpp
C/C++/*!
* @file DFRobot_BMI160.cpp
* @brief Define the basic structure of class DFRobot_BMI160
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @license The MIT License (MIT)
* @author DFRobot_haoJ([email protected])
* @version V1.0
* @date 2017-12-01
* @url https://github.com/DFRobot/DFRobot_BMI160
*/
#include"DFRobot_BMI160.h"
const uint8_t int_mask_lookup_table[13] = {
BMI160_INT1_SLOPE_MASK,
BMI160_INT1_SLOPE_MASK,
BMI160_INT2_LOW_STEP_DETECT_MASK,
BMI160_INT1_DOUBLE_TAP_MASK,
BMI160_INT1_SINGLE_TAP_MASK,
BMI160_INT1_ORIENT_MASK,
BMI160_INT1_FLAT_MASK,
BMI160_INT1_HIGH_G_MASK,
BMI160_INT1_LOW_G_MASK,
BMI160_INT1_NO_MOTION_MASK,
BMI160_INT2_DATA_READY_MASK,
BMI160_INT2_FIFO_FULL_MASK,
BMI160_INT2_FIFO_WM_MASK
};
DFRobot_BMI160::DFRobot_BMI160()
{
Wire.begin();
Obmi160=(struct bmi160Dev *)malloc(sizeof(struct bmi160Dev));
//Obmi160->id = BMI160_I2C_ADDR;
//Obmi160->interface = BMI160_I2C_INTF;
Oaccel= (struct bmi160SensorData*)malloc(sizeof(struct bmi160SensorData));
Ogyro = (struct bmi160SensorData*)malloc(sizeof(struct bmi160SensorData));
}
int8_t DFRobot_BMI160::I2cInit(int8_t i2c_addr)
{
Obmi160->id = i2c_addr;
Obmi160->interface = BMI160_I2C_INTF;
return DFRobot_BMI160::I2cInit(Obmi160);
}
int8_t DFRobot_BMI160::SPIInit()
{
//SPI.begin();
//pinMode(10,OUTPUT);
//Obmi160->id = 0;
//Obmi160->interface = BMI160_SPI_INTF;
return BMI160_OK;
}
int8_t DFRobot_BMI160::SPIInit(struct bmi160Dev *dev)
{
return BMI160_OK;
}
int8_t DFRobot_BMI160::I2cInit(struct bmi160Dev *dev)
{
int8_t rslt=BMI160_OK;
uint8_t chip_id=0;
uint8_t data=0;
if (dev==NULL){
return BMI160_E_NULL_PTR;
}
if (dev->interface == BMI160_SPI_INTF){
rslt = getRegs(BMI160_SPI_COMM_TEST_ADDR, &data, 1, dev);
}
if (rslt == BMI160_OK){
rslt = getRegs(BMI160_CHIP_ID_ADDR, &chip_id, 1, dev);
if ((rslt == BMI160_OK)&&(chip_id==BMI160_CHIP_ID)){
dev->any_sig_sel = eBmi160BothAnySigMotionDisabled;
dev->chipId = chip_id;
rslt = softReset(dev);
if (rslt==BMI160_OK){
rslt = setSensConf(dev);
}
}else{
rslt = BMI160_E_DEV_NOT_FOUND;
}
}
return rslt;
}
int8_t DFRobot_BMI160::softReset()
{
int8_t rslt=BMI160_OK;
if (Obmi160 == NULL){
rslt = BMI160_E_NULL_PTR;
}
rslt = softReset(Obmi160);
return rslt;
}
int8_t DFRobot_BMI160::softReset(struct bmi160Dev *dev)
{
int8_t rslt=BMI160_OK;
uint8_t data = BMI160_SOFT_RESET_CMD;
if (dev==NULL){
rslt = BMI160_E_NULL_PTR;
}
rslt = DFRobot_BMI160::setRegs(BMI160_COMMAND_REG_ADDR, &data, 1, dev);
delay(BMI160_SOFT_RESET_DELAY_MS);
if (rslt == BMI160_OK){
DFRobot_BMI160::defaultParamSettg(dev);
}
return rslt;
}
void DFRobot_BMI160::defaultParamSettg(struct bmi160Dev *dev)
{
/* Initializing accel and gyro params with
* default values */
dev->accelCfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
dev->accelCfg.odr = BMI160_ACCEL_ODR_100HZ;
dev->accelCfg.power = BMI160_ACCEL_SUSPEND_MODE;
dev->accelCfg.range = BMI160_ACCEL_RANGE_2G;
dev->gyroCfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
dev->gyroCfg.odr = BMI160_GYRO_ODR_100HZ;
dev->gyroCfg.power = BMI160_GYRO_SUSPEND_MODE;
dev->gyroCfg.range = BMI160_GYRO_RANGE_2000_DPS;
/* To maintain the previous state of accel configuration */
dev->prevAccelCfg = dev->accelCfg;
/* To maintain the previous state of gyro configuration */
dev->prevGyroCfg = dev->gyroCfg;
}
int8_t DFRobot_BMI160::setSensConf()
{
return DFRobot_BMI160::setSensConf(Obmi160);
}
int8_t DFRobot_BMI160::setSensConf(struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
dev->accelCfg.odr = BMI160_ACCEL_ODR_1600HZ;
dev->accelCfg.range = BMI160_ACCEL_RANGE_2G;
dev->accelCfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
dev->accelCfg.power = BMI160_ACCEL_NORMAL_MODE;
dev->gyroCfg.odr = BMI160_GYRO_ODR_3200HZ;
dev->gyroCfg.range = BMI160_GYRO_RANGE_2000_DPS;
dev->gyroCfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
dev->gyroCfg.power = BMI160_GYRO_NORMAL_MODE;
rslt = DFRobot_BMI160::setAccelConf(dev);
if (rslt == BMI160_OK) {
rslt = DFRobot_BMI160::setGyroConf(dev);
if (rslt == BMI160_OK) {
/* write power mode for accel and gyro */
rslt = DFRobot_BMI160::setPowerMode(dev);
if (rslt == BMI160_OK)
rslt = DFRobot_BMI160::checkInvalidSettg(dev);
}
}
return rslt;
}
int8_t DFRobot_BMI160::setAccelConf(struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t data[2] = {0};
rslt = DFRobot_BMI160::checkAccelConfig(data, dev);
if (rslt == BMI160_OK) {
rslt = DFRobot_BMI160::setRegs(BMI160_ACCEL_CONFIG_ADDR, &data[0], 1, dev);
if (rslt == BMI160_OK) {
dev->prevAccelCfg.odr = dev->accelCfg.odr;
dev->prevAccelCfg.bw = dev->accelCfg.bw;
delay(BMI160_ONE_MS_DELAY);
rslt = DFRobot_BMI160::setRegs(BMI160_ACCEL_RANGE_ADDR, &data[1], 1, dev);
if (rslt == BMI160_OK){
dev->prevAccelCfg.range = dev->accelCfg.range;
}
}
}
return rslt;
}
int8_t DFRobot_BMI160::checkAccelConfig(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt;
/* read accel Output data rate and bandwidth */
rslt = DFRobot_BMI160::getRegs(BMI160_ACCEL_CONFIG_ADDR, data, 2, dev);
if (rslt == BMI160_OK) {
rslt = DFRobot_BMI160::processAccelOdr(&data[0], dev);
if (rslt == BMI160_OK) {
rslt = DFRobot_BMI160::processAccelBw(&data[0], dev);
if (rslt == BMI160_OK)
rslt = DFRobot_BMI160::processAccelRange(&data[1], dev);
}
}
return rslt;
}
int8_t DFRobot_BMI160::processAccelOdr(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t odr = 0;
if (dev->accelCfg.odr <= BMI160_ACCEL_ODR_MAX) {
if (dev->accelCfg.odr != dev->prevAccelCfg.odr) {
odr = (uint8_t)dev->accelCfg.odr;
temp = *data & ~BMI160_ACCEL_ODR_MASK;
/* Adding output data rate */
*data = temp | (odr & BMI160_ACCEL_ODR_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::processAccelBw(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t bw = 0;
if (dev->accelCfg.bw <= BMI160_ACCEL_BW_MAX) {
if (dev->accelCfg.bw != dev->prevAccelCfg.bw) {
bw = (uint8_t)dev->accelCfg.bw;
temp = *data & ~BMI160_ACCEL_BW_MASK;
/* Adding bandwidth */
*data = temp | ((bw << 4) & BMI160_ACCEL_ODR_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::processAccelRange(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t range = 0;
if (dev->accelCfg.range <= BMI160_ACCEL_RANGE_MAX) {
if (dev->accelCfg.range != dev->prevAccelCfg.range) {
range = (uint8_t)dev->accelCfg.range;
temp = *data & ~BMI160_ACCEL_RANGE_MASK;
/* Adding range */
*data = temp | (range & BMI160_ACCEL_RANGE_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::setGyroConf(struct bmi160Dev *dev)
{
int8_t rslt;
uint8_t data[2]={0};
rslt = DFRobot_BMI160::checkGyroConfig(data, dev);
if (rslt == BMI160_OK) {
// Write output data rate and bandwidth
rslt = DFRobot_BMI160::setRegs(BMI160_GYRO_CONFIG_ADDR, &data[0], 1, dev);
if (rslt == BMI160_OK) {
dev->prevGyroCfg.odr = dev->gyroCfg.odr;
dev->prevGyroCfg.bw = dev->gyroCfg.bw;
delay(BMI160_ONE_MS_DELAY);
// Write gyro range
rslt = DFRobot_BMI160::setRegs(BMI160_GYRO_RANGE_ADDR, &data[1], 1, dev);
if (rslt == BMI160_OK)
dev->prevGyroCfg.range = dev->gyroCfg.range;
}
}
return rslt;
}
int8_t DFRobot_BMI160::checkGyroConfig(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt;
/* read gyro Output data rate and bandwidth */
rslt = DFRobot_BMI160::getRegs(BMI160_GYRO_CONFIG_ADDR, data, 2, dev);
if (rslt == BMI160_OK) {
rslt = DFRobot_BMI160::processGyroOdr(&data[0], dev);
if (rslt == BMI160_OK) {
rslt = DFRobot_BMI160::processGyroBw(&data[0], dev);
if (rslt == BMI160_OK)
rslt = DFRobot_BMI160::processGyroRange(&data[1], dev);
}
}
return rslt;
}
int8_t DFRobot_BMI160::processGyroOdr(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t odr = 0;
if (dev->gyroCfg.odr <= BMI160_GYRO_ODR_MAX) {
if (dev->gyroCfg.odr != dev->prevGyroCfg.odr) {
odr = (uint8_t)dev->gyroCfg.odr;
temp = (*data & ~BMI160_GYRO_ODR_MASK);
/* Adding output data rate */
*data = temp | (odr & BMI160_GYRO_ODR_MASK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::processGyroBw(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t bw = 0;
if (dev->gyroCfg.bw <= BMI160_GYRO_BW_MAX) {
bw = (uint8_t)dev->gyroCfg.bw;
temp = *data & ~BMI160_GYRO_BW_MASK;
/* Adding bandwidth */
*data = temp | ((bw << 4) & BMI160_GYRO_BW_MASK);
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::processGyroRange(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t temp = 0;
uint8_t range = 0;
if (dev->gyroCfg.range <= BMI160_GYRO_RANGE_MAX) {
if (dev->gyroCfg.range != dev->prevGyroCfg.range) {
range = (uint8_t)dev->gyroCfg.range;
temp = *data & ~BMI160_GYRO_RANGE_MSK;
/* Adding range */
*data = temp | (range & BMI160_GYRO_RANGE_MSK);
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::setPowerMode(struct bmi160Dev *dev)
{
int8_t rslt = 0;
rslt = DFRobot_BMI160::setAccelPwr(dev);
if (rslt == BMI160_OK){
rslt = DFRobot_BMI160::setGyroPwr(dev);
}
return rslt;
}
int8_t DFRobot_BMI160::setAccelPwr(struct bmi160Dev *dev)
{
int8_t rslt = 0;
uint8_t data = 0;
if ((dev->accelCfg.power >= BMI160_ACCEL_SUSPEND_MODE) &&
(dev->accelCfg.power <= BMI160_ACCEL_LOWPOWER_MODE)) {
if (dev->accelCfg.power != dev->prevAccelCfg.power) {
rslt = DFRobot_BMI160::processUnderSampling(&data, dev);
if (rslt == BMI160_OK) {
/* Write accel power */
rslt = DFRobot_BMI160::setRegs(BMI160_COMMAND_REG_ADDR, &dev->accelCfg.power, 1, dev);
/* Add delay of 5 ms */
if (dev->prevAccelCfg.power == BMI160_ACCEL_SUSPEND_MODE){
delay(BMI160_ACCEL_DELAY_MS);
}
dev->prevAccelCfg.power = dev->accelCfg.power;
}
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::processUnderSampling(uint8_t *data, struct bmi160Dev *dev)
{
int8_t rslt;
uint8_t temp = 0;
uint8_t pre_filter = 0;
rslt = DFRobot_BMI160::getRegs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev);
if (rslt == BMI160_OK) {
if (dev->accelCfg.power == BMI160_ACCEL_LOWPOWER_MODE) {
temp = *data & ~BMI160_ACCEL_UNDERSAMPLING_MASK;
/* Set under-sampling parameter */
*data = temp | ((1 << 7) & BMI160_ACCEL_UNDERSAMPLING_MASK);
/* Write data */
rslt = setRegs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev);
/* disable the pre-filter data in
* low power mode */
if (rslt == BMI160_OK)
/* Disable the Pre-filter data*/
rslt = DFRobot_BMI160::setRegs(BMI160_INT_DATA_0_ADDR, &pre_filter, 2, dev);
} else {
if (*data & BMI160_ACCEL_UNDERSAMPLING_MASK) {
temp = *data & ~BMI160_ACCEL_UNDERSAMPLING_MASK;
/* disable under-sampling parameter
if already enabled */
*data = temp;
/* Write data */
rslt = DFRobot_BMI160::setRegs(BMI160_ACCEL_CONFIG_ADDR, data, 1, dev);
}
}
}
return rslt;
}
int8_t DFRobot_BMI160::setGyroPwr(struct bmi160Dev *dev)
{
int8_t rslt = 0;
if ((dev->gyroCfg.power == BMI160_GYRO_SUSPEND_MODE) || (dev->gyroCfg.power == BMI160_GYRO_NORMAL_MODE)
|| (dev->gyroCfg.power == BMI160_GYRO_FASTSTARTUP_MODE)) {
if (dev->gyroCfg.power != dev->prevGyroCfg.power) {
/* Write gyro power */
rslt = DFRobot_BMI160::setRegs(BMI160_COMMAND_REG_ADDR, &dev->gyroCfg.power, 1, dev);
if (dev->prevGyroCfg.power == BMI160_GYRO_SUSPEND_MODE) {
/* Delay of 81 ms */
delay(BMI160_GYRO_DELAY_MS);
} else if ((dev->prevGyroCfg.power == BMI160_GYRO_FASTSTARTUP_MODE)
&& (dev->gyroCfg.power == BMI160_GYRO_NORMAL_MODE)) {
/* This delay is required for transition from
fast-startup mode to normal mode */
delay(10);
} else {
/* do nothing */
}
dev->prevGyroCfg.power = dev->gyroCfg.power;
}
} else {
rslt = BMI160_E_OUT_OF_RANGE;
}
return rslt;
}
int8_t DFRobot_BMI160::checkInvalidSettg( struct bmi160Dev *dev)
{
int8_t rslt;
uint8_t data = 0;
// read the error reg
rslt = DFRobot_BMI160::getRegs(BMI160_ERROR_REG_ADDR, &data, 1, dev);
data = data >> 1;
data = data & BMI160_ERR_REG_MASK;
if (data == 1)
rslt = BMI160_E_ACCEL_ODR_BW_INVALID;
else if (data == 2)
rslt = BMI160_E_GYRO_ODR_BW_INVALID;
else if (data == 3)
rslt = BMI160_E_LWP_PRE_FLTR_INT_INVALID;
else if (data == 7)
rslt = BMI160_E_LWP_PRE_FLTR_INVALID;
return rslt;
}
int8_t DFRobot_BMI160::getSensorData(uint8_t type, int16_t* data)
{
int8_t rslt=BMI160_OK;
if (type==onlyAccel){
rslt = getSensorData(BMI160_ACCEL_SEL, Oaccel, NULL, Obmi160);
if(rslt == BMI160_OK){
data[0]=Ogyro->x;
data[1]=Ogyro->y;
data[2]=Ogyro->z;
}
}else if(type==onlyGyro){
rslt = getSensorData(BMI160_GYRO_SEL, NULL, Ogyro, Obmi160);
if(rslt == BMI160_OK){
data[0]=Oaccel->x;
data[1]=Oaccel->y;
data[2]=Oaccel->z;
}
}else if(type==bothAccelGyro){
rslt = DFRobot_BMI160::getSensorData((BMI160_ACCEL_SEL | BMI160_GYRO_SEL),Oaccel, Ogyro, Obmi160);
if(rslt == BMI160_OK){
data[0]=Ogyro->x;
data[1]=Ogyro->y;
data[2]=Ogyro->z;
data[3]=Oaccel->x;
data[4]=Oaccel->y;
data[5]=Oaccel->z;
}
}else{
rslt = BMI160_ERR_CHOOSE;
}
return rslt;
}
int8_t DFRobot_BMI160::getAccelData( int16_t* data)
{
int8_t rslt=BMI160_OK;
rslt = getSensorData(BMI160_ACCEL_SEL, Oaccel, NULL, Obmi160);
if(rslt == BMI160_OK){
data[0]=Oaccel->x;
data[1]=Oaccel->y;
data[2]=Oaccel->z;
}
return rslt;
}
int8_t DFRobot_BMI160::getGyroData( int16_t* data)
{
int rslt = BMI160_OK;
rslt = getSensorData(BMI160_GYRO_SEL, NULL, Ogyro, Obmi160);
if(rslt == BMI160_OK){
data[0]=Ogyro->x;
data[1]=Ogyro->y;
data[2]=Ogyro->z;
}
return rslt;
}
int8_t DFRobot_BMI160::getAccelGyroData( int16_t* data)
{
int8_t rslt = BMI160_OK;
rslt = getSensorData((BMI160_ACCEL_SEL | BMI160_GYRO_SEL),Oaccel, Ogyro, Obmi160);
if(rslt == BMI160_OK){
data[0]=Ogyro->x;
data[1]=Ogyro->y;
data[2]=Ogyro->z;
data[3]=Oaccel->x;
data[4]=Oaccel->y;
data[5]=Oaccel->z;
}
return rslt;
}
int8_t DFRobot_BMI160::getSensorData(uint8_t select_sensor, struct bmi160SensorData *accel, struct bmi160SensorData *gyro,struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t time_sel;
uint8_t sen_sel;
uint8_t len = 0;
/*Extract the sensor and time select information*/
sen_sel = select_sensor & BMI160_SEN_SEL_MASK;
time_sel = ((sen_sel & BMI160_TIME_SEL) >> 2);
sen_sel = sen_sel & (BMI160_ACCEL_SEL | BMI160_GYRO_SEL);
if (time_sel == 1)
len = 3;
/* Null-pointer check */
if (dev != NULL) {
switch (sen_sel) {
case eBmi160AccelOnly:
/* Null-pointer check */
if (accel == NULL)
rslt = BMI160_E_NULL_PTR;
else
rslt = DFRobot_BMI160::getAccelData(len, accel, dev);
break;
case eBmi160GyroOnly:
/* Null-pointer check */
if (gyro == NULL)
rslt = BMI160_E_NULL_PTR;
else
rslt = DFRobot_BMI160::getGyroData(len, gyro, dev);
break;
case eBmi160BothAccelAndGyro:
/* Null-pointer check */
if ((gyro == NULL) || (accel == NULL))
rslt = BMI160_E_NULL_PTR;
else
rslt = DFRobot_BMI160::getAccelGyroData(len, accel, gyro, dev);
break;
default:
rslt = BMI160_E_INVALID_INPUT;
break;
}
} else {
rslt = BMI160_E_NULL_PTR;
}
return rslt;
}
int8_t DFRobot_BMI160::getAccelData(uint8_t len, struct bmi160SensorData *accel, struct bmi160Dev *dev)
{
int8_t rslt;
uint8_t idx = 0;
uint8_t data_array[9] = {0};
uint8_t time_0 = 0;
uint16_t time_1 = 0;
uint32_t time_2 = 0;
uint8_t lsb;
uint8_t msb;
float msblsb;
rslt = DFRobot_BMI160::getRegs(BMI160_ACCEL_DATA_ADDR, data_array, 6 + len, dev);
if (rslt == BMI160_OK){
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->x = msblsb; /* Data in X axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->y = msblsb; /* Data in X axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->z = msblsb; /* Data in X axis */
}else{
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
int8_t DFRobot_BMI160::getGyroData(uint8_t len, struct bmi160SensorData *gyro, struct bmi160Dev *dev)
{
int8_t rslt;
uint8_t idx = 0;
uint8_t data_array[15] = {0};
uint8_t time_0 = 0;
uint16_t time_1 = 0;
uint32_t time_2 = 0;
uint8_t lsb;
uint8_t msb;
float msblsb;
if (len == 0) {
/* read gyro data only */
rslt = DFRobot_BMI160::getRegs(BMI160_GYRO_DATA_ADDR, data_array, 6, dev);
if (rslt == BMI160_OK) {
/* Gyro Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->x = msblsb; /* Data in X axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->y = msblsb; /* Data in Y axis */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->z = msblsb; /* Data in Z axis */
} else {
rslt = BMI160_E_COM_FAIL;
}
} else {
/* read gyro sensor data along with time */
rslt = DFRobot_BMI160::getRegs(BMI160_GYRO_DATA_ADDR, data_array, 12 + len, dev);
if (rslt == BMI160_OK) {
/* Gyro Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->x = msblsb; /* gyro X axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->y = msblsb; /* gyro Y axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->z = msblsb; /* gyro Z axis data */
idx = idx + 6;
time_0 = data_array[idx++];
time_1 = (uint16_t)(data_array[idx++] << 8);
time_2 = (uint32_t)(data_array[idx++] << 16);
//gyro->sensortime = (uint32_t)(time_2 | time_1 | time_0);
} else {
rslt = BMI160_E_COM_FAIL;
}
}
return rslt;
}
int8_t DFRobot_BMI160::getAccelGyroData(uint8_t len, struct bmi160SensorData *accel, struct bmi160SensorData *gyro, struct bmi160Dev *dev)
{
int8_t rslt;
uint8_t idx = 0;
uint8_t data_array[15] = {0};
uint8_t time_0 = 0;
uint16_t time_1 = 0;
uint32_t time_2 = 0;
uint8_t lsb;
uint8_t msb;
int16_t msblsb;
/* read both accel and gyro sensor data
* along with time if requested */
rslt = DFRobot_BMI160::getRegs(BMI160_GYRO_DATA_ADDR, data_array, 12 + len, dev);
if (rslt == BMI160_OK) {
/* Gyro Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->x = msblsb; /* gyro X axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->y = msblsb; /* gyro Y axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
gyro->z = msblsb; /* gyro Z axis data */
/* Accel Data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->x = (int16_t)msblsb; /* accel X axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->y = (int16_t)msblsb; /* accel Y axis data */
lsb = data_array[idx++];
msb = data_array[idx++];
msblsb = (int16_t)((msb << 8) | lsb);
accel->z = (int16_t)msblsb; /* accel Z axis data */
if (len == 3) {
time_0 = data_array[idx++];
time_1 = (uint16_t)(data_array[idx++] << 8);
time_2 = (uint32_t)(data_array[idx++] << 16);
//accel->sensortime = (uint32_t)(time_2 | time_1 | time_0);
//gyro->sensortime = (uint32_t)(time_2 | time_1 | time_0);
} else {
//accel->sensortime = 0;
//gyro->sensortime = 0;
;
}
} else {
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
int8_t DFRobot_BMI160::getRegs(uint8_t reg_addr, uint8_t *data, uint16_t len, struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
//Null-pointer check
if (dev == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
//Configuring reg_addr for SPI Interface
if (dev->interface == BMI160_SPI_INTF){
reg_addr = (reg_addr | BMI160_SPI_RD_MASK);
rslt = DFRobot_BMI160::SPIGetRegs(dev, reg_addr, data, len);
}else{
rslt = DFRobot_BMI160::I2cGetRegs(dev, reg_addr, data, len);
}
delay(1);
if (rslt != BMI160_OK){
rslt = BMI160_E_COM_FAIL;
}
}
return rslt;
}
int8_t DFRobot_BMI160::I2cGetRegs(struct bmi160Dev *dev, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
Wire.beginTransmission(dev->id);
Wire.write(reg_addr);
Wire.endTransmission(true);
delay(10);
Wire.requestFrom(dev->id,len);
for(int i = 0; i < len; i++){
data[i]=Wire.read();
delay(1);
}
return BMI160_OK;
}
int8_t DFRobot_BMI160::setRegs(uint8_t reg_addr, uint8_t *data, uint16_t len, struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
uint8_t count = 0;
//Null-pointer check
if (dev == NULL) {
rslt = BMI160_E_NULL_PTR;
} else {
//Configuring reg_addr for SPI Interface
if (dev->interface == BMI160_SPI_INTF){
reg_addr = (reg_addr & BMI160_SPI_WR_MASK);
rslt = DFRobot_BMI160::SPISetRegs(dev,reg_addr,data,len);
}else{
rslt = DFRobot_BMI160::I2cSetRegs(dev,reg_addr,data,len);
}
delay(1);
if (rslt != BMI160_OK)
rslt = BMI160_E_COM_FAIL;
}
return rslt;
}
int8_t DFRobot_BMI160::I2cSetRegs(struct bmi160Dev *dev, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
if ((dev->prevAccelCfg.power == BMI160_ACCEL_NORMAL_MODE)||(dev->prevGyroCfg.power == BMI160_GYRO_NORMAL_MODE)){
Wire.beginTransmission(dev->id);
Wire.write(reg_addr);
for(int i = 0; i < len; i++){
Wire.write(data[i]);
delay(1);
}
Wire.endTransmission(true);
}else{
for(int i = 0; i < len; i++){
Wire.beginTransmission(dev->id);
Wire.write(reg_addr);
Wire.write(data[i]);
Wire.endTransmission(true);
delay(1);
}
}
return BMI160_OK;
}
int8_t DFRobot_BMI160::SPIGetRegs(struct bmi160Dev *dev, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
digitalWrite(10,LOW);
//SPI.transfer(0x6B);
//SPI.transfer(0x10);
uint8_t buff[10]={0};
for(int i = 0; i < 10; i++){
buff[i] = SPI.transfer(0x00);
}
digitalWrite(10,HIGH);
return BMI160_OK;
}
int8_t DFRobot_BMI160::SPISetRegs(struct bmi160Dev *dev, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
return BMI160_OK;
}
int8_t DFRobot_BMI160::setInt(int intNum)
{
return setInt(Obmi160,intNum);
}
int8_t DFRobot_BMI160::setInt(struct bmi160Dev *dev, int intNum)
{
int8_t rslt=BMI160_OK;
if (dev == NULL){
rslt = BMI160_E_NULL_PTR;
}
struct bmi160IntSettg intConfig;
if (intNum == 1){
intConfig.intChannel = BMI160_INT_CHANNEL_1;
}else if(intNum == 2){
intConfig.intChannel = BMI160_INT_CHANNEL_2;
}else{
return BMI160_E_NULL_PTR;
}
/* Select the Interrupt type */
intConfig.intType = BMI160_STEP_DETECT_INT;// Choosing Step Detector interrupt
/* Select the interrupt channel/pin settings */
intConfig.intPinSettg.outputEn = BMI160_ENABLE;// Enabling interrupt pins to act as output pin
intConfig.intPinSettg.outputMode = BMI160_DISABLE;// Choosing push-pull mode for interrupt pin
intConfig.intPinSettg.outputType = BMI160_ENABLE;// Choosing active High output
intConfig.intPinSettg.edgeCtrl = BMI160_ENABLE;// Choosing edge triggered output
intConfig.intPinSettg.inputEn = BMI160_DISABLE;// Disabling interrupt pin to act as input
intConfig.intPinSettg.latchDur =BMI160_LATCH_DUR_NONE;// non-latched output
/* Select the Step Detector interrupt parameters, Kindly use the recommended settings for step detector */
intConfig.intTypeCfg.accStepDetectInt.stepDetectorMode = BMI160_STEP_DETECT_NORMAL;
intConfig.intTypeCfg.accStepDetectInt.stepDetectorEn = BMI160_ENABLE;// 1-enable, 0-disable the step detector
rslt = DFRobot_BMI160::setIntConfig(&intConfig, dev);
return rslt;
}
int8_t DFRobot_BMI160::setIntConfig(struct bmi160IntSettg *intConfig, struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
switch (intConfig->intType) {
case BMI160_ACC_ANY_MOTION_INT:
/*Any-motion interrupt*/
//rslt = set_accel_any_motion_int(intConfig, dev);
break;
case BMI160_ACC_SIG_MOTION_INT:
/* Significant motion interrupt */
//rslt = set_accel_sig_motion_int(intConfig, dev);
break;
case BMI160_ACC_SLOW_NO_MOTION_INT:
/* Slow or no motion interrupt */
//rslt = set_accel_no_motion_int(intConfig, dev);
break;
case BMI160_ACC_DOUBLE_TAP_INT:
case BMI160_ACC_SINGLE_TAP_INT:
/* Double tap and single tap Interrupt */
//rslt = set_accel_tap_int(intConfig, dev);
break;
case BMI160_STEP_DETECT_INT:
/* Step detector interrupt */
rslt = setAccelStepDetectInt(intConfig, dev);
break;
case BMI160_ACC_ORIENT_INT:
/* Orientation interrupt */
//rslt = set_accel_orientation_int(intConfig, dev);
break;
case BMI160_ACC_FLAT_INT:
/* Flat detection interrupt */
//rslt = set_accel_flat_detect_int(intConfig, dev);
break;
case BMI160_ACC_LOW_G_INT:
/* Low-g interrupt */
//rslt = set_accel_low_g_int(intConfig, dev);
break;
case BMI160_ACC_HIGH_G_INT:
/* High-g interrupt */
//rslt = set_accel_high_g_int(intConfig, dev);
break;
case BMI160_ACC_GYRO_DATA_RDY_INT:
/* Data ready interrupt */
//rslt = set_accel_gyro_data_ready_int(intConfig, dev);
break;
case BMI160_ACC_GYRO_FIFO_FULL_INT:
/* Fifo full interrupt */
//rslt = set_fifo_full_int(intConfig, dev);
break;
case BMI160_ACC_GYRO_FIFO_WATERMARK_INT:
/* Fifo water-mark interrupt */
//rslt = set_fifo_watermark_int(intConfig, dev);
break;
default:
break;
}
return rslt;
}
int8_t DFRobot_BMI160::setAccelStepDetectInt(struct bmi160IntSettg *intConfig, struct bmi160Dev *dev)
{
int8_t rslt = BMI160_OK;
/* Null-pointer check */
if (dev == NULL){
rslt = BMI160_E_NULL_PTR;
}
if ((rslt != BMI160_OK) || (intConfig == NULL)) {
rslt = BMI160_E_NULL_PTR;
} else {
/* updating the interrupt structure to local structure */
struct bmi160AccStepDetectIntCfg *stepDetectIntCfg =
&(intConfig->intTypeCfg.accStepDetectInt);
rslt = enableStepDetectInt(stepDetectIntCfg, dev);
if (rslt == BMI160_OK) {
/* Configure Interrupt pins */
rslt = setIntrPinConfig(intConfig, dev);
if (rslt == BMI160_OK) {
rslt = mapFeatureInterrupt(intConfig, dev);
if (rslt == BMI160_OK){
rslt = configStepDetect(stepDetectIntCfg, dev);
}
}
...
This file has been truncated, please download it to see its full contents.






Comments