FFT à reprogrammer Gestion des trames réseaux à améliorer (certaines trames ne se transmettent pas)
Dependencies: mbed SHT21_ncleee HX711 mbed-dsp DS1820
Diff: main.cpp
- Revision:
- 0:4311d41c5fbc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jan 25 10:10:24 2021 +0000 @@ -0,0 +1,581 @@ +/*-------------------------------------*/ +/* Ruche connectée B-Smart V15 */ +/* Contrôle baremetal */ +/* */ +/* BIROLINI Nikolaï */ +/* GOURDET Hadrien */ +/* HULOT Alexandra */ +/* LEBRETON Maxime */ +/* */ +/* Janvier 2021 */ +/* Polytech Sorbonne */ +/*-------------------------------------*/ + +#include "SHT21_ncleee.h" +#include "arm_math.h" +#include "arm_const_structs.h" +#include "DS1820.h" +#include "HX711.h" + +#define DEBUG 1 + + +HX711 Balance(D11,D10); +Serial pc(USBTX,USBRX); +AnalogOut MEAS_ENABLE(A3); + +//=1 VMEAS +//=0 SIGFOX + +Serial sigfox(D1,D0);//TX:PA_2:A7 RX:PA_3:A2 + + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define SIZE 7 +#define TEMPPRESENCE 35 +#define FFT_SIZE 1024 + +DigitalOut TPL5110_DONE(D5); + +typedef struct _frame //champ de bits +{ + unsigned char *field; //tableau de char + int offset; //index + int size; //taille de la trame en bits +} Frame; + +void new_frame(Frame* frame,unsigned char* field) +{ + frame->field = field; + frame->offset = 0; //on part du premier char + frame->size = SIZE*8; +} + + + +int get_bit(Frame *frame) //fonction de debuggage +{ + int char_index = frame->offset / 8; + int bit_index = 7-(frame->offset % 8); + frame->offset++; + + return ((frame->field[char_index] & (1 << bit_index)) > 0) ? 1 : 0; +} +void print_frame(Frame *frame) //fonction de debuggage +{ + int cur_offset = frame->offset; + frame->offset = 0; + pc.printf("Frame {\r\n\ttaille : %d / %d\r\n\tbitfield : ", cur_offset, frame->size); + while (frame->offset < cur_offset) + { + printf(get_bit(frame) == 1 ? "1" : "0"); + if (frame->offset % 8 == 0) + printf(" "); + } + pc.printf("\r\n}\r\n"); +} +void stock_bit(unsigned char bit, Frame *frame) //set le bit n°offset à 1 si bit>0, sinon à 0 +{ + if (frame->offset < frame->size) + { + int char_index = frame->offset / 8; //n° du char + int bit_index = 7 -(frame->offset % 8); //n° du bit + unsigned char char_mask = ~(1 << bit_index); //mask pour garder tous les bits existants sauf celui qui nous intéresse + + frame->field[char_index] = (frame->field[char_index] & char_mask) + ((bit > 0 ? 1 : 0) << bit_index); //place le bit à sa place + frame->offset++; //bit modifié, on se déplace + } +} +void stock_int(unsigned int value, int taille_en_bits, Frame *frame) //stocke les bits d'un int +{ + if(DEBUG) + { + pc.printf(" Mesure %d ,taille = %d\r\n",value,taille_en_bits); + } + + for (int i = 0; i < taille_en_bits; i++){ + stock_bit(value & (1 << (taille_en_bits - i - 1)), frame); + //print_frame(frame); +} +} +void validate_frame(Frame *frame) //on met toute la fin à zéro si pas déjà utilisée +{ + while (frame->offset < frame->size) + stock_bit(0, frame); +} + + + +void send_frame(Frame *frame) //fonction de debuggage +{ + sigfox.printf("AT$SF="); + if(DEBUG) pc.printf("AT$SF="); + for ( int i = 0 ; i < frame->size / 8 ; i++) { + sigfox.printf("%0X", frame->field[i]); + + if(DEBUG) pc.printf("%0X", frame->field[i]); + } + sigfox.printf("\r\n"); + if(DEBUG) pc.printf("\r\n"); +} + +void stock_temp(Frame *frame, float temp) +{ + temp = min(temp, 45.5f); + temp = max(temp, -18); + //temp = max(temp, -10); + int bits = (int)((temp/2. + 36) * 2 + 0.5f); //round(temp+18)*2 + stock_int(bits, 7, frame); +} + +/* Masse test enhanced */ +void stock_masse(Frame *frame, float masse) +{ + /*bib = https://apiarobotics.com/fr/connaissances/poids-dune-ruche */ + /*encadrer la masse entre 15kg et 50 kg*/ + masse = max(masse, 15.f);//masse mini = 15kg + masse = min(masse, 50.f);//masse max = 50kg + + if(debug) pc.printf("[MASSE]masse retenue (kg)= %f\n", masse); + + /*ajout d'offset */ + masse-=15; //masse mini + + /*produit en croix */ + /*10kg = 0x00 */ + /*50kg = 0xff */ + /*précision = 35kg/190 = 184g */ + masse = masse*(255.0-65)/35.0; //produit en croix (35 = masse max - masse mini) + masse += 65; //offset binaire. Si on veux transmettre une valeur <65 = bug !! (valeur obtenue par tatonnement) + + + int bits = (int)masse; + + if(debug) pc.printf("[MASSE]valeur binaire retenue = %d\n", bits); + + stock_int(bits,8,frame); +} + +void stock_vent(Frame *frame, float vent) +{ + vent = min(vent, 70); + vent = max(vent, 0); + int bits = (int)(vent*0.1f + 0.5f); + stock_int(bits, 3, frame); +} +void stock_humidity(Frame *frame,float humidity) +{ + humidity = min(humidity,100); + humidity = max(humidity,20); + int bits = (int)(humidity*31/100+0.5f); + stock_int(bits,5,frame); +} +void stock_battery(Frame *frame,float battery) +{ + battery = min(battery,100); + battery = max(battery,0); + int bits = (int)(battery*63/100+0.5f); + stock_int(bits,6,frame); +} + +InterruptIn anemo(D13);//D13 +//ATTENTION: ne pas oublier de ratacher l'interupt à une fonction (dans le main)! + +AnalogIn analog_battery(A0); +AnalogIn analog_luminosity(A1); +AnalogIn analog_TMP36(A4); +//AnalogIn analog_FFT(A5); + +//I2C i2c(PB_4, PA_7);//SDA:A12, SCL:A6 +I2C i2c(PB_4, PA_7);//SDA:A12, SCL:A6 +SHT21 sht(&i2c); + +Timer t_anemo; +int cpt_anemo; + +void anemo_counter() //IRQ Anémomètre +{ + cpt_anemo++; + if(debug)pc.printf("WIND ! cpt_anemo = %d \n",cpt_anemo); +} + +//FFT + +int FFT_compt; +float fmax; +/* Pour simplifier l'interprétation des mesures, un instant est relié à chaque mesure */ +float FFT_DUREE[FFT_SIZE]; + +/* Signal en entrée analogique */ +float signal_reel[FFT_SIZE+1]; + +/* Signal après dérivation */ +float signal_reelDiff[FFT_SIZE]; + +/* Signal avant la FFT (il contient les composantes réeles et complexes (composante complexe nulle)) */ +float FFT_in[FFT_SIZE*2]; + +/* Spectre à la sortie de FFT */ +float FFT_out[FFT_SIZE*2]; + +/* Reference index at which max energy of bin ocuurs */ +uint32_t testIndex = 0; + +/* Flag FFT complexe. La FFT sera effectuée uniquement sur la composante réele. Donc flag à '0' */ +int ifftFlag = 0; + +int doBitReverse = 1; + +/* Energie maximale */ +float maxValue; +AnalogIn analog_FFT(A5); +float Fe= 4000;//Fréquence echantillonage +float Te = 1/Fe; +int MortReine = 0;//Mort de la reine 0 = vivant, 1=mort +int ToutVaBien = 0;//Si tout va bien= 0 sinon = 1 +int Stress = 0;//Abeille en stress = 1 sinon 0 +int bebe = 0;//Essaimage = 1 sinon 0 +int moyenneAmp=0; +int moyenneNorm=0;//Moyenne amplitude sur tout le spectre +int moyEss=0; //Moyenne amplitude entre 200Hz et 500 Hz + + + +int main(void) +{ + TPL5110_DONE=0; + MEAS_ENABLE = 1; + anemo.disable_irq(); + anemo.rise(&anemo_counter);//attacher une fonction à l'interrupt + //--------------------------------------------- données brutes------------------------------------------ + float temp_ext = 10.; // variable pour la température extérieure + + float temp_int_1 = 20.5; // mesures des 8 sondes de température à l'intérieur de la ruche + float temp_int_2 = 20.5; + float temp_int_3 = 20.5; + float temp_int_4 = 20.5; + float temp_int_5 = 20.5; + //float temp_int_6 = 20.5; + //float temp_int_7 = 20.5; + //float temp_int_8 = 20.5; + float temp_int; //température intérieure moyenne + int luminosity = 2; + float masse = 0; + float force_vent = 50.0; + float battery = 2.0; + float humidity = 56.6; + int cadre_1_2 = 1;//non utilisé mais crash si 0! + int cadre_3 = 0; + int cadre_4 = 0; + int cadre_5 = 0; + int cadre_6 = 0; + int cadre_7 = 0; + int cadre_8 = 1;//remplacer par reine; + int cadre_9_10 = 0;//remplacer par presence_ruche; + int stress = 0; + int essaimage = 0; + int reine = 1; + int abeilles = 0; + //------------ pour la tx + + long masse_valeur_moyenne; + long masse_valeur; + float battery_read; + float luminosity_read; + + if(debug)pc.printf("1.Initialisation DS1820\n"); + DS1820 sensor_DS1820_1(D2); + DS1820 sensor_DS1820_2(D3); + DS1820 sensor_DS1820_3(D6); + DS1820 sensor_DS1820_4(D9); + + if(debug)pc.printf("1a.Lecture DS1820: 1/4\n"); + sensor_DS1820_1.convertTemperature(true, DS1820::all_devices); // start temperature conversion + wait(1); // let DS1820 complete the temperature conversion + temp_int_1 = sensor_DS1820_1.temperature(); + + if(debug)pc.printf("1a.Lecture DS1820: 2/4\n"); + sensor_DS1820_2.convertTemperature(true, DS1820::all_devices); // start temperature conversion + wait(1); // let DS1820 complete the temperature conversion + temp_int_2 = sensor_DS1820_2.temperature(); + + if(debug)pc.printf("1a.Lecture DS1820: 3/4\n"); + sensor_DS1820_3.convertTemperature(true, DS1820::all_devices); // start temperature conversion + wait(1); // let DS1820 complete the temperature conversion + temp_int_3 = sensor_DS1820_3.temperature(); + + if(debug)pc.printf("1a.Lecture DS1820: 4/4\n"); + sensor_DS1820_4.convertTemperature(true, DS1820::all_devices); // start temperature conversion + wait(1); // let DS1820 complete the temperature conversion + temp_int_4 = sensor_DS1820_4.temperature(); + + if(debug)pc.printf("1b.Initialisation et lecture SHT20\n"); + temp_int_5 = sht.readTemp(); + + temp_int = (temp_int_1 + temp_int_5 + temp_int_5 + temp_int_5 + temp_int_5)/5.0; + + if(debug)pc.printf("[TEMP]: temperature interieure moyenne = %f oC\n",temp_int); + + if(debug)pc.printf("1c.Lecture TMP36\n"); + /* https://learn.adafruit.com/tmp36-temperature-sensor */ + temp_ext = analog_TMP36.read(); + temp_ext*=3.3;//mise à l'échelle val analogique 0 à 1 en tension 0 à 3.3V + temp_ext-=0.500; //-500 mV + temp_ext/=0.010; //cf datasheet, div par 10 mV + + + if(debug) pc.printf("[TEMP]: temperature exterieure = %f oC\n",temp_ext); + + if(debug)pc.printf("1.d.Occupation des cadres\n"); + + if(temp_int_1 >= TEMPPRESENCE) cadre_3 = 1; + if(temp_int_2 >= TEMPPRESENCE) cadre_4 = 1; + if(temp_int_3 >= TEMPPRESENCE) cadre_5 = 1; + if(temp_int_4 >= TEMPPRESENCE) cadre_6 = 1; + if(temp_int_5 >= TEMPPRESENCE) cadre_7 = 1; + + + + + if(debug)pc.printf("[Temp] cadre_3 actif = %d \n",cadre_3); + if(debug)pc.printf("[Temp] cadre_4 actif = %d \n",cadre_4); + if(debug)pc.printf("[Temp] cadre_5 actif = %d \n",cadre_5); + if(debug)pc.printf("[Temp] cadre_6 actif = %d \n",cadre_6); + if(debug)pc.printf("[Temp] cadre_7 actif = %d \n",cadre_7); + + if((cadre_3)||(cadre_4)||(cadre_5)||(cadre_6)||(cadre_7)) abeilles = 1; + if(debug)pc.printf("[Temp] abeilles = %d \n", abeilles); + + if(!abeilles) reine=0; + + if(DEBUG)pc.printf("2a.Mesure masse en cours...\n", masse); + + masse_valeur_moyenne = Balance.averageValue(100); + //tare = 8441392 + // printf("value: %ld\r\n",a - 8441392); + //avec tare: 0 = 0kg, 42381 = 2kg + masse_valeur = ( masse_valeur_moyenne - 8441392.0);//Tare + // printf("value: %ld\r\n",valeur); + + masse =(float) masse_valeur*2.113/42381.0; + + if(masse>=10.0) cadre_9_10=1;//presence_ruche + //masse = ((int) masse * 100) / 100; + //2.113 = from balance précise + + if(debug)pc.printf("[Masse] %f kg\n", masse); + + if(DEBUG)pc.printf("3b.Analyse FFT cours...\n"); + + /*---- Début FFT*/ + + for(FFT_compt=0;FFT_compt<FFT_SIZE+1;FFT_compt++) + { + signal_reel[FFT_compt]=analog_FFT.read(); + } + + + //printf("Fréquence échantillonage : %f\n", Fe); + + /*Dérivée du signal d'entrée (dérivée avant) */ + for(FFT_compt=0;FFT_compt<FFT_SIZE;FFT_compt++) + { + signal_reelDiff[FFT_compt]=(signal_reel[FFT_compt+1]-signal_reel[FFT_compt])/Te; + //printf("derivee = %f\n",signal_reelDiff[FFT_compt]); + } + + /*remplissage paire (reel), partie imaginaire nulle*/ + for(FFT_compt=0;FFT_compt<FFT_SIZE;FFT_compt++) + { + FFT_in[FFT_compt*2]=signal_reelDiff[FFT_compt]; + FFT_in[FFT_compt*2+1]=0; + } + + /* Process the data through the CFFT/CIFFT module */ + arm_cfft_f32(&arm_cfft_sR_f32_len1024, FFT_in, ifftFlag, doBitReverse); + + /* Process the data through the Complex Magnitude Module for + calculating the magnitude at each bin */ + arm_cmplx_mag_f32(FFT_in, FFT_out, FFT_SIZE); + + /* Suppression des fréqquences situées entre Fe/2 et Fe */ + for(FFT_compt=FFT_SIZE/2;FFT_compt<FFT_SIZE;FFT_compt++) + { + FFT_out[FFT_compt]=0; + } + + /* Calcul la valeur max dans la liste FFT_out, index = frequence et le contenu c'est l'amplitude */ + arm_max_f32(FFT_out, FFT_SIZE, &maxValue, &testIndex); + + fmax=testIndex*Fe/FFT_SIZE; + //Calcul de la moyenne des amplitude + + for (int z=0; z<1024;z++) + { + moyenneAmp=moyenneAmp+FFT_out[z]; + } + + moyenneNorm=moyenneAmp/1024; + + if(DEBUG) + { + pc.printf("[FFT]moyenne amplitude = %d\n",moyenneNorm); + pc.printf("[FFT]premier quartile = %.2e\n",FFT_out[256]); + } + + if (FFT_out[256] > 400) + { + if (moyenneNorm > 600) reine = 0; + stress = 1; + } + + for (int q= 0; q<77;q++)//Entre 200Hz et 550Hz + { + moyEss=moyEss+FFT_out[51+q]; + } + + moyEss=moyEss/77; + + if ((moyEss > 300)&&(moyenneNorm <600)) essaimage=1; + + moyEss=0; + + moyenneAmp=0; + moyenneNorm=0; + + cadre_8 = reine; + reine = 1;//sinon crash tx + + /*---- Fin FFT*/ + + if(DEBUG)pc.printf("[Son] reine = %\n",reine); + if(DEBUG)pc.printf("[Son] essaimage = %d\n",essaimage); + if(DEBUG)pc.printf("[Son] stress = %d\n",stress); + + if(DEBUG)pc.printf("4a.mesures diverses%\n"); + humidity = sht.readHumidity(); + if(DEBUG)pc.printf("[Humidite] %f HR\n",humidity); + + battery_read = analog_battery.read(); + + battery = 67.;// défaillance + + if(battery_read >= 0.798) battery = 100.; //4,1 V, 100% + else if(battery_read >= 0.773) battery = 97.;//3.97 V, 90% + else if(battery_read >= 0.764) battery = 94.;//3.92 V, 80% + else if(battery_read >= 0.754) battery = 91.;//3.87 V, 70% + else if(battery_read >= 0.747) battery = 88.;//3.83 V, 60% + else if(battery_read >= 0.739) battery = 85.;//3.79 V, 50% + else if(battery_read >= 0.731) battery = 82.;//3.75 V, 40% + else if(battery_read >= 0.722) battery = 79.;//3.70 V, 30% + else if(battery_read >= 0.700) battery = 76.;//3.60 V, 20% + else if(battery_read >= 0.660) battery = 73.;//3.30 V, 10% + else if(battery_read >= 0.550) battery = 70.;//2.80 V, 0% + + if(debug) + { + if(battery_read >= 0.798) pc.printf("[Batterie] 100 / 100\n"); //4,1 V, 100% + else if(battery_read >= 0.773) pc.printf("[Batterie] 90 / 100\n");//3.97 V, 90% + else if(battery_read >= 0.764) pc.printf("[Batterie] 80 / 100\n");//3.92 V, 80% + else if(battery_read >= 0.754) pc.printf("[Batterie] 70 / 100\n");//3.87 V, 70% + else if(battery_read >= 0.747) pc.printf("[Batterie] 60 / 100\n");//3.83 V, 60% + else if(battery_read >= 0.739) pc.printf("[Batterie] 50 / 100\n");//3.79 V, 50% + else if(battery_read >= 0.731) pc.printf("[Batterie] 40 / 100\n");//3.75 V, 40% + else if(battery_read >= 0.722) pc.printf("[Batterie] 30 / 100\n");//3.70 V, 30% + else if(battery_read >= 0.700) pc.printf("[Batterie] 20 / 100\n");//3.60 V, 20% + else if(battery_read >= 0.660) pc.printf("[Batterie] 10 / 100\n");//3.30 V, 10% + else if(battery_read >= 0.550) pc.printf("[Batterie] 0 / 100\n");//2.80 V, 0% + else pc.printf("[Batterie] DEFAILLANCE / DEBRANCHEE\n"); + } + + luminosity_read = analog_luminosity.read(); + luminosity_read *=10.; //max 10 V + + //attention luminosity peut faire crash TX */ + luminosity = 2; //nuit + + if(luminosity_read >= 5) luminosity = 7; + else if(luminosity_read >= 4) luminosity = 6; + else if(luminosity_read >= 3) luminosity = 5; + else if(luminosity_read >= 2) luminosity = 4;//tres lumineux + else if(luminosity_read >= 1) luminosity = 3;//dangereux pour lipo rider pro si cellule solaire > 5 V + + if(DEBUG)pc.printf("[Luminosite] raw = %f / 10 \n",luminosity_read); + if(DEBUG)pc.printf("[Luminosite] %d / 5 \n",luminosity-2); + + if(DEBUG)pc.printf("4b.mesure de la vitesse du vent...\n"); + + /* test luminosity */ + /* + while(1) + { + luminosity_read = analog_luminosity.read(); + luminosity_read *=10.; + if(DEBUG)pc.printf("[Luminosite] raw = %f / 1 \n",luminosity_read); + + luminosity = 2; //nuit + if(luminosity_read >= 5) luminosity = 7; + else if(luminosity_read >= 4) luminosity = 6; + else if(luminosity_read >= 3) luminosity = 5; + else if(luminosity_read >= 2) luminosity = 4;//tres lumineux + else if(luminosity_read >= 1) luminosity = 3;//dangereux pour lipo rider pro si cellule solaire > 5 V + + if(DEBUG)pc.printf("[Luminosite] %d / 5 \n",luminosity-2); + wait(1); + } + */ + + cpt_anemo=0; + anemo.enable_irq(); + wait(2); + anemo.disable_irq(); + //un contact par seconde est égal à une vitesse du vent de 2,4 km/h + //un contact par 2 secondes est égal à une vitesse du vent de 1,2 km/h + + force_vent = cpt_anemo*1.2; + + if(DEBUG)pc.printf("[Anemometre] vitesse du vent = %f km/h \n",force_vent); + + + + + unsigned char field[SIZE]; + Frame frame ; + //for(;;){ + + //temp_int=-255.; + + //masse=997; + + MEAS_ENABLE = 0;//mode SigFox + new_frame(&frame,field); + stock_temp(&frame,temp_ext); + stock_temp(&frame,temp_int); + stock_int(luminosity,4,&frame); + stock_masse(&frame, masse); + stock_vent(&frame,force_vent); + stock_battery(&frame,battery); + stock_humidity(&frame,humidity); + stock_bit(cadre_1_2,&frame);//non utilisé mais crash si 0! + stock_bit(cadre_3, &frame); + stock_bit(cadre_4,&frame); + stock_bit(cadre_5,&frame); + stock_bit(cadre_6,&frame); + stock_bit(cadre_7,&frame); + stock_bit(cadre_8,&frame);//remplacer par reine + stock_bit(cadre_9_10,&frame);//remplacer par presence_ruche; + stock_bit(stress,&frame); + stock_bit(reine,&frame); + stock_bit(essaimage,&frame); + stock_bit(abeilles,&frame); + validate_frame(&frame); + print_frame(&frame); + send_frame(&frame); + wait(8); //15 * 60 secondes = 15 minutes d'intervalle + TPL5110_DONE=1; + + wait(600); + //} + //return EXIT_SUCCESS; +}