Select Git revision
Display.class
Forked from
LABOUREL Arnaud / Image Template
Source project has a limited visibility.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
main.c 9.77 KiB
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
//#################################################
#include <zephyr/drivers/adc.h>
#include <zephyr/kernel.h>
#include <stdio.h>
#include <stdint.h>
//------------------------------------------------
//------------------------------------------------
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/sensor.h>
//------------------------------------------------
//------------------------------------------------
/* ADC node from the devicetree. */
#define ADC_NODE DT_ALIAS(adc0)
/* Data of ADC device specified in devicetree. */
static const struct device *adc = DEVICE_DT_GET(ADC_NODE);
/* Configuration of the ADC channel */
static const struct adc_channel_cfg channel_cfg = {
.gain = ADC_GAIN_1_6,
.reference = ADC_REF_INTERNAL,
.acquisition_time = ADC_ACQ_TIME_DEFAULT,
.channel_id = 0,
.input_positive = SAADC_CH_PSELP_PSELP_VDD,
};
#define ADC_RESOLUTION 12
#define BUFFER_SIZE 1 /* We only need one sample */
static int16_t sample_buffer[BUFFER_SIZE];
//#################################################
#define SERVICE_DATA_LEN 15
#define SERVICE_UUID 0xfcd2 /* BTHome service UUID */
#define IDX_TEMPL 4 /* Index of lo byte of temp in service data*/
#define IDX_TEMPH 5 /* Index of hi byte of temp in service data*/
#define IDX_HUML 7 /* Index of lo byte of humidity in service data */
#define IDX_HUMH 8 /* Index of hi byte of humidity in service data */
#define IDX_PRESL 10 /* Index of lo byte of pressure in service data (in hPa */
#define IDX_PRESM 11 /* Index of hi byte of pressure in service data (in hPa)*/
#define IDX_PRESH 12 /* Index of hi byte of pressure in service data (in hPa) */
#define BAT 14 /* Index of hi byte of temp in service data*/
#define ADV_PARAM BT_LE_ADV_PARAM(BT_LE_ADV_OPT_USE_IDENTITY, \
BT_GAP_ADV_SLOW_INT_MIN, \
BT_GAP_ADV_SLOW_INT_MAX, NULL)
static uint8_t service_data[SERVICE_DATA_LEN] = {
BT_UUID_16_ENCODE(SERVICE_UUID),
0x40,
0x02, /* Temperature */
0xc4, /* Low byte */
0x00, /* High byte */
0x03, /* Humidity */
0xbf, /* 50.55% low byte*/
0x13, /* 50.55% high byte*/
0x04, /* Pressure type identifier*/
0x00, /* Low byte of pressure */
0x00, /* Middle byte of pressure */
0x00, /* High byte of pressure */
0x01, /* BATTERY */
0x80,
};
static struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
BT_DATA(BT_DATA_SVC_DATA16, service_data, ARRAY_SIZE(service_data))
};
static void bt_ready(int err)
{
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
/* Start advertising */
err = bt_le_adv_start(ADV_PARAM, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return;
}
}
////////////////////////////////////////////////////////////
double get_Tension(int32_t adc_value) {
// Le gain est toujours égal à 1/6
double gain = 1.0 / 6.0;
double vref = 0.6;
// Calcul de la tension en utilisant l'équation donnée
double tension = ( (adc_value * vref) / ( 4095 * gain) );
return tension;
}
double calculer_capacite_restante_NiMH_2_cells(double tension_batterie) {
double capacite_restante;
// La tension de la batterie est de 2.0V à 2.7V pour 2 cellules NiMH en série
if (tension_batterie >= 2.7) {
capacite_restante = (tension_batterie - 2.7) * (100 - 90) / (2.8 - 2.7) + 90; // Plage 2.7V - 2.8V
} else if (tension_batterie >= 2.6) {
capacite_restante = (tension_batterie - 2.6) * (90 - 80) / (2.7 - 2.6) + 80; // Plage 2.6V - 2.7V
} else if (tension_batterie >= 2.5) {
capacite_restante = (tension_batterie - 2.5) * (80 - 70) / (2.6 - 2.5) + 70; // Plage 2.5V - 2.6V
} else if (tension_batterie >= 2.4) {
capacite_restante = (tension_batterie - 2.4) * (70 - 60) / (2.5 - 2.4) + 60; // Plage 2.4V - 2.5V
} else if (tension_batterie >= 2.3) {
capacite_restante = (tension_batterie - 2.3) * (60 - 50) / (2.4 - 2.3) + 50; // Plage 2.3V - 2.4V
} else if (tension_batterie >= 2.2) {
capacite_restante = (tension_batterie - 2.2) * (50 - 40) / (2.3 - 2.2) + 40; // Plage 2.2V - 2.3V
} else if (tension_batterie >= 2.1) {
capacite_restante = (tension_batterie - 2.1) * (40 - 30) / (2.2 - 2.1) + 30; // Plage 2.1V - 2.2V
} else if (tension_batterie >= 2.0) {
capacite_restante = (tension_batterie - 2.0) * (30 - 20) / (2.1 - 2.0) + 20; // Plage 2.0V - 2.1V
} else {
capacite_restante = 0; // Moins de 10% de charge
}
return capacite_restante;
}
////////////////////////////////////////////////////////////
//--------------------------------------------------
//--------------------------------------------------
static const struct device *get_bme280_device(void) {
const struct device *const dev = DEVICE_DT_GET_ANY(bosch_bme280);
if (dev == NULL) {
/* No such node, or the node does not have status "okay". */
printk("\nError: no device found.\n");
return NULL;
}
if (!device_is_ready(dev)) {
printk("\nError: Device \"%s\" is not ready; "
"check the driver initialization logs for errors.\n",
dev->name);
return NULL;
}
printk("Found device \"%s\", getting sensor data\n", dev->name);
return dev;
}
//--------------------------------------------------
//--------------------------------------------------
int main(void)
{
int err;
const struct device *dev = get_bme280_device();
struct sensor_value temp, humidity, press;
//#################################################
printk("Starting BTHome sensor template\n");
/* Initialize the Bluetooth Subsystem */
err = bt_enable(bt_ready);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return 0;
}
/* Configure the sampling sequence */
struct adc_sequence sequence = {
.channels = BIT(channel_cfg.channel_id),
.buffer = sample_buffer,
.buffer_size = sizeof(sample_buffer),
.resolution = ADC_RESOLUTION,
};
//#################################################
if (!device_is_ready(adc)) {
printf("ADC controller device %s not ready\n", adc->name);
return 0;
}
err = adc_channel_setup(adc, &channel_cfg);
if (err < 0) {
printf("Could not setup ADC channel (%d)\n", err);
return 0;
}
//#################################################
for (;;) {
//#################################################
// Récupération des échantillons du capteur
if (sensor_sample_fetch(dev) < 0) {
printk("Erreur lors de la récupération des données du capteur\n");
continue;
}
err = adc_read(adc, &sequence);
if (err < 0) {
printf("Could not read (%d)\n", err);
continue;
}
// Récupération des différentes valeurs
sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity);
sensor_channel_get(dev, SENSOR_CHAN_PRESS, &press);
// Convertir la température en centi-degrés Celsius (°C * 100) en tenant
// compte de val2
int temperature_centi = (temp.val1 * 100) + (temp.val2 / 10000);
int32_t val_mv = sample_buffer[0]; /* Read raw value */
// Mettre à jour les deux octets dans service_data pour la température
service_data[IDX_TEMPH] = (temperature_centi >> 8) & 0xff; // Partie haute
service_data[IDX_TEMPL] = temperature_centi & 0xff; // Partie basse
// Convertir l'humidité en centi-pourcent (% * 100) en tenant compte de val2
int humidity_centi = (humidity.val1 * 100) + (humidity.val2 / 10000);
// Mettre à jour les deux octets dans service_data pour l'humidité
service_data[IDX_HUMH] = (humidity_centi >> 8) & 0xff; // Partie haute
service_data[IDX_HUML] = humidity_centi & 0xff; // Partie basse
// Convertir la pression et la mettre à jour dans service_data
int pressure_hpa =
100*((press.val1 * 10) + (press.val2 / 10000)); // Convertir en hPa
service_data[IDX_PRESH] =
(pressure_hpa) >> 16; // Haute partie de la pression
service_data[IDX_PRESM] =
(pressure_hpa >> 8) & 0xff; // Partie intermédiaire
service_data[IDX_PRESL] =
(pressure_hpa)&0xff; // Basse partie de la pression
// Affichage des résultats avec les unités
printk("temp: %d.%06d°C; humidity: %d.%06d%%; press: %d hPa\n", temp.val1,
temp.val2, humidity.val1, humidity.val2, pressure_hpa);
// Mettre à jour les données de la publicité
err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Failed to update advertising data (err %d)\n", err);
}
err = adc_raw_to_millivolts(channel_cfg.reference,
channel_cfg.gain,
ADC_RESOLUTION, &val_mv);
/* Simulate temperature from 0C to 25C */
double battery_voltage =(get_Tension(sample_buffer[0]));
service_data[BAT] = calculer_capacite_restante_NiMH_2_cells(battery_voltage);
//service_data[BAT_H] = (battery_voltage >> 8) & 0xff;
//service_data[BAT_L] = battery_voltage & 0xff;
if (err < 0 || channel_cfg.reference == 0) {
printk("Raw value: %d (conversion to mV not available)\n", sample_buffer[0]);
} else {
printk("Raw ADC value: %d\n", service_data[BAT]);
printk("Battery voltage: %f \n", battery_voltage);
}
//#################################################
err = bt_le_adv_update_data(ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Failed to update advertising data (err %d)\n", err);
}
k_sleep(K_MSEC(BT_GAP_ADV_SLOW_INT_MIN));
}
return 0;
}