martial leyney
Published

Electric Folding Bike

My folding bike becomes an electric bike. 3D printing and laser-cutting to create the case. Electronic board with Arduino and Bluetooth.

AdvancedShowcase (no instructions)1,336
Electric Folding Bike

Things used in this project

Hardware components

MDF 3mm wood boards
×1
PLA
×1
Motor 250W - 36V
×1
Brushless controller
×1
Battery Management System board
×1
Lithium-Ion Batteries
×1
screws, 2A fuse, 15A fuse, ON/OFF switch, LEDs ans all mainboard's components (see schematics)
×1

Software apps and online services

CAO NI Circuit Design
Sketchup8
Android Studio
Android Studio
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Laser cutter (generic)
Laser cutter (generic)
PCB production machines

Story

Read more

Custom parts and enclosures

casev2

case of my b-fold3 bike

Schematics

schematic-part1

schematic-part2

gerber files

main board

Android Studio project

Code

main

C/C++
/*******************************************************************************************/
//              PROGRAMME GESTION VELO VAE PLIANT - VERSION 2                              //
//                                                                                         //
//                                      JUIN 2016                                          //
/*******************************************************************************************/

// Martial LEYNEY
// 14/06/2016
// Projet Vlo VAE Pour B-FOLD pliant
// Gestion vitesse de pdalage (par interruption)
// Gestion PWM pour variation puissance moteur
// Regulation PI en puissance moteur
// Transfert des infos en bluetooth vers IHM Android
/*******************************************************************************************/

#include <SoftwareSerial.h>

#include <avr/wdt.h>    //watchdog
#include <math.h>
/*******************************************************************************************/
//Entres Interruptions
#define INT_BPMode    2               //entree bouton poussoir fonction MODE ASSISTANCE sur pin DIG2
#define INT_Pedalage  3               //entree detection rotation pdalier sur pin DIG3 

//Entres/sorties logiques C
#define MotPin        5               //sortie PWM vers controleur moteur Brushless
#define LEDLEVEL_M    A4              //sortie LED Orange Niveau assistance MIDDLE
#define LEDLEVEL_L    7               //sortie LED Orange Niveau assistance LOW
#define CMD_FEUX      4               //sortie de commande phare avant et feux arrieres
#define SW_CTRLMOT    6               //commande switch Controleur Moteur
#define LEDALERT      A2              //Tmoin LED rouge ALERTE/ERREUR
#define LEDBAT_R      9               //sortie LED RGB cmd rouge
#define LEDBAT_G      10              //sortie LED RGB cmd vert
#define LEDBAT_B      11              //sortie LED RGB cmd bleu
#define RST_BT        8              //Reset module bluetooth
//ADC
#define Imot          A0              //entre analogique image courant moteur
#define Vmot          A1              //entre analogique image tension moteur
#define TempBat       A3              //entre analogique image temperature pack batterie (Thermistance CTN VISHAY NTCLE213E3103FHB0 10Kohms 1%)
#define PhotoR        A5              //entre analogique image luminosit extrieure (LDR NSL4962)


/*******************************************************************************************/
//definitions

//PARAMETRAGE VELO *** A MODIFIER ***
//#define PEDALAGE_DEMARR    2110   //Periode capteur max pour condition de demarrage (environ 1km/h)
#define PEDALE_COMPTEUR_SEUIL   3  // Compteur de filtrage pour capteur de rotation pdalier
#define PEDALAGE_TMAX      422    //Periode capteur max sinon "pas de pedalage" (12 periodes capteur = 1 tour pedalier)  (correspond a environ 3.5km/h)
#define PEDALAGE_DISTCM    478     //longueur au sol en cm pour un tour de pedalier
#define TBATTMAX           70      //Temperature max du pack batterie en C                                
#define VBATTMIN           145      //seuil mini tension batterie
#define VBATTMAX           892      //seuil maxi tension batterie
#define ASSIST_M           190      //Consigne d'assistance en Watts Niveau Medium                     ******   A DEFINIR  ******
#define ASSIST_L           110      //Consigne d'assistance en Watts Niveau Low                        ******   A DEFINIR  ******
#define ASSIST_0           0        //Arret assistance 
#define LUX_SEUIL          580      //Seuil de luminosite allumage Feux Av et AR (- sensible si valeur + grande)
/*******************************************************************************************/
//variables globales
char erreur = 0;            //gestion d'erreur systeme
// =0 si pas d'erreur,
//bit 0=1 si pas de pedalage,
//bit1=1 si ...,
//bit2=1 si ...,
//bit3=1 si ...,
//bit4=1 si pb batterie principale,
//bit5=1 si ...,
//bit6=1 si Pb communication Bluetooth
//bit7=1 si Pb temperature Pack batterie
unsigned long Tpedalage;            //vitesse de pedalage en msec
unsigned long VitVelo;    //vitesse du velo en km/h x10 (pour affichage)
unsigned int MoyVitVelo[4];  //vitesse moyenne sur 1/3 tour de pedalier
unsigned int AffVitVelo = 0;  //vitesse moyenne de pdalage pour affichage appli android
volatile unsigned long Tcapteur, Tcapteurm1;   //calcul periode capteur sur axe pedalier
int LevelAssist;              //consigne d'assistance de rfrence selon choix utilisateur
float Ukm2, Ukm1, Uk, Ekm2, Ekm1, Ek;   //variables pour correcteur
float Cons_Wmot;              //consigne de puissance lectrique envoy au moteur apres prise en compte vitesse de pdalage
float Mes_Wmot;              //puissance consomme par moteur
unsigned int MoyMesWmot[12];  //Puissance moyenne mesure sur 1 tour de pedalier
unsigned int AffMesWmot = 0;  //Mesure Puissance moyenne pour affichage appli android
int Iref;                      //valeur de reference pour mesure courant moteur
int MotMoy[5];                  //buffer pour lissage sortie moteur
boolean refresh;              //demande de maj mesure (true si besoin)
boolean flagMode;              //drapeau appui BP utilisateur
int Vbatt, Tbatt;              //tension image ACD pour pack batterie
int BatMoy[5];                  //buffer pour lissage tension batterie

//variables pour mesure temperature pack batterie
const unsigned char tableHr[] = {0, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 99};
const int tableHrADC[] = {0, 4, 10, 18, 45, 72, 199, 324, 467, 608, 702, 797, 852, 905, 934, 963, 983, 1023};

//Liaison serie Bluetooth RN42
SoftwareSerial IHMSerial(13, 12); // RX, TX bluetooth IHM

/*******************************************************************************************/

char gestion_Pedalage(void);
void gestion_moteur(int w);
void gestion_BT(void);
void gestion_LEDMode(int v);
void gestion_LEDbatt(int v);
unsigned char gestion_erreur(void);


/*******************************************************************************************/
void setup()
{
  char a, b;

  //init E/S
  pinMode(INT_BPMode, INPUT);  //entree interruption bouton poussoir selection assistance par utilisateur
  pinMode(INT_Pedalage, INPUT);  //entree interruption detection rotation pdalier
  pinMode(MotPin, OUTPUT);
  pinMode(LEDLEVEL_M, OUTPUT);
  pinMode(LEDLEVEL_L, OUTPUT);
  pinMode(CMD_FEUX, OUTPUT);
  pinMode(SW_CTRLMOT, OUTPUT);
  pinMode(LEDALERT, OUTPUT);
  pinMode(LEDBAT_R, OUTPUT);
  pinMode(LEDBAT_G, OUTPUT);
  pinMode(LEDBAT_B, OUTPUT);
  pinMode(RST_BT, OUTPUT);
  //
  Serial.begin(115200);           //init UART

  //init interruptions
  attachInterrupt(1, IRQ_Pedalage, FALLING);  //interruption n1 (pin DIG3) sur front descendant
  attachInterrupt(0, IRQ_BPMode, FALLING);  //interruption n0 (pin DIG2) sur front descendant
  //init des entres/sorties et periphriques
  analogWrite(MotPin, 0);  //arret moteur au cas o...
  //digitalWrite(RST_BT, LOW);    //RESET du module Bluetooth ????
  digitalWrite(LEDLEVEL_M, LOW);
  digitalWrite(LEDLEVEL_L, LOW);
  digitalWrite(CMD_FEUX, LOW);
  digitalWrite(SW_CTRLMOT, LOW);
  digitalWrite(LEDBAT_R, HIGH);
  digitalWrite(LEDBAT_G, HIGH);
  digitalWrite(LEDBAT_B, HIGH);

  //Init sofware serial pour liaison bluetooth IHM
  digitalWrite(RST_BT, LOW);  //RESET bluetooth
  delay(100);
  digitalWrite(RST_BT, HIGH);
  delay(100);
  IHMSerial.begin(115200);  // The Bluetooth Mate defaults to 115200bps
  IHMSerial.print("$");  // Print three times individually
  IHMSerial.print("$");
  IHMSerial.print("$");  // Enter command mode
  delay(100);  // Short delay, wait for the Mate to send back CMD
  IHMSerial.println("U,9600,N");  // Temporarily Change the baudrate to 9600, no parity
  IHMSerial.begin(9600);

  //init variables
  refresh = true;
  LevelAssist = ASSIST_L;
  gestion_LEDMode(LevelAssist);    //maj affichage
  Tpedalage = 0;
  Tcapteur = 0;
  Tcapteurm1 = 0;
  Cons_Wmot = 0;
  for (a = 0; a < 5; a++) {
    MotMoy[a] = 0;
  }
  VitVelo = 0; 
  for (a = 0; a < 4; a++) {
    MoyVitVelo[a] = 0;
  }  
  for (a = 0; a < 12; a++) {
    MoyMesWmot[a] = 0;
  }
  //automatisation du dmarrage systme
  delay(200);
  digitalWrite(SW_CTRLMOT, HIGH);  //activation automatique controleur moteur brushless
  delay(200);

  //Animation LED + mesure courant au repos
  Iref = 502;  //TEST : Valeur Fixe  502 car la mesure ci-dessous apportait des imprecisions (delta de 25W selon les allumages)
  //Iref = 0;
  gestion_LEDbatt(300);
  delay(150);
  //Iref += analogRead(Imot);   //recup valeur courant de reference avec moteur arret
  gestion_LEDbatt(600);
  delay(150);
  //Iref += analogRead(Imot);   //recup valeur courant de reference avec moteur arret
  gestion_LEDbatt(800);
  delay(150);
  //Iref += analogRead(Imot);   //recup valeur courant de reference avec moteur arret
  gestion_LEDbatt(1000);
  delay(150);
  //Iref /= 3;    //moyennage du courant de repos
  //Serial.print("IREF = ");
  //Serial.println(Iref);
  
  //Premiere mesure tension batterie  l'arret
  Vbatt = analogRead(Vmot);   //recup valeur
  for (a = 0; a < 5; a++) {
    BatMoy[a] = Vbatt;    //raz moyenne tension batterie
  }
  if ((Vbatt >= VBATTMIN) && (Vbatt <= VBATTMAX)) {
    bitClear(erreur, 4);
  } else {
    bitSet(erreur, 4);
  }
  gestion_LEDbatt(Vbatt);    //maj affichage

  //Init ok
  digitalWrite(LEDALERT, LOW);
  //activation watchdog
  wdt_enable(WDTO_2S);
}


/*******************************************************************************************/
void loop(void)
{
  static int bcl = 0;  //"static" car sinon on perd la valeur a chaque retour de boucle
  unsigned long timeMOT;      //instant ou on applique une consigne moteur
  unsigned long tm;
  char a;
  int mesureW;
  int lux;

  //PRISE INFO PEDALAGE
  if (gestion_Pedalage() == 0) {  // *** pedalage en cours***
    //maj variables dans sous-fonction OK

    //surveillance tension batterie en fonctionnement (tt les 2 secondes)
    if (bcl++ == 40) {

      Vbatt = 0;
      for (a = 0; a < 4; a++) {
        BatMoy[a] = BatMoy[a + 1];  //decalage 5 dernieres mesures
      }
      BatMoy[4] = analogRead(Vmot);   //recup valeur
      for (a = 0; a < 5; a++) {
        Vbatt += BatMoy[a];    //moyenne tension batterie
      }
      Vbatt /= 5;
      if ((Vbatt >= VBATTMIN) || (Vbatt <= VBATTMAX)) {
        bitClear(erreur, 4);
      } else {
        bitSet(erreur, 4);
      }
      gestion_LEDbatt(Vbatt);    //maj affichage
      bcl = 0;
    }
    //
    refresh = true; //demande de maj mesures au prochain arret de pedalage
    bitClear(erreur, 0);
  }
  else {                        // *** pas de pedalage ***

    //GESTION NIVEAU ASSISTANCE (BP MODE)
    if (flagMode == true) {
      delay(500);
      if (digitalRead(INT_BPMode) == LOW) {   //appui long pour anti-rebond par vibration route

        if (LevelAssist == ASSIST_0) {
          LevelAssist = ASSIST_L;
        }
        else if (LevelAssist == ASSIST_L) {
          LevelAssist = ASSIST_M;
        }
        else if (LevelAssist == ASSIST_M) {
          LevelAssist = ASSIST_0;
        }
        else {                            //en cas de pb...
          LevelAssist = 0;
        }
        gestion_LEDMode(LevelAssist);    //maj affichage
      }
      flagMode = false;
    }

    //Suite  un arret de pdalage (1 seule fois) : On en profite pour faire un rafraichissement des infos
    if (refresh == true) {

      //GESTION TEMPERATURE PACK BATTERIE
      float TempP = Thermistor(analogRead(TempBat));   //recup valeur temperature en degr celcius
      //Ajustage supplementaire selon talon
      TempP -= 1;
      if (TempP < 0) TempP = 0; //bornage
      if (TempP >= 100) TempP = 99; //bornage
      Tbatt = (int)TempP;
      if (Tbatt <= TBATTMAX) {
        bitClear(erreur, 7);
      } else {
        bitSet(erreur, 7);
      }

      //GESTION ECLAIRAGE SELON LUMINOSITE
      lux = analogRead(PhotoR);
      if (lux >= LUX_SEUIL) {
        digitalWrite(CMD_FEUX, HIGH);  //Allumage des feux AV et AR
      } else {
        digitalWrite(CMD_FEUX, LOW);  //Extinction des feux AV et AR
      }

      //
      refresh = false;  //une seule demande
    }
    bitSet(erreur, 0);
  }

  //GESTION MOTEUR
  if ((gestion_erreur() == 0) && (bitRead(erreur, 0) == 0)) {    //pas d'erreur majeure ET pedalage en cours

    gestion_moteur(LevelAssist);            // application moteur de la consigne utilisateur

  } else {                           //Sinon...
    //RAZ
    VitVelo = 0;
    for (a = 0; a < 4; a++) {
      MoyVitVelo[a] = 0;
    }
    AffVitVelo = 0;
    for (a = 0; a < 5; a++) {
      MotMoy[a] = 0;
    }
    gestion_moteur(0);  //ARRET moteur
  }

  //GESTION INFOS IHM (liaison bluetooth)
  gestion_BT();  //check si ordre recu de l'IHM

  //CADENCEMENT BOUCLE
  delay(50);
  //RESET WATCHDOG
  wdt_reset();

  //
}


/*******************************************************************************************/
//interruption par entre INT_RxPedale (dig2)
void IRQ_BPMode()
{
  flagMode = true;
}


/*******************************************************************************************/
//interruption par entre INT_Pedalage (dig3)
void IRQ_Pedalage()
{
  Tcapteurm1 = Tcapteur;
  Tcapteur = millis();
}


/*******************************************************************************************/
//Detection pdalage et calcul vitesse de pedale (vitesse vlo en km/h)
// renvoie 0 si pdalage + maj "Tpedalage"
char gestion_Pedalage(void) {
  char a;
  unsigned long timeout;
  static byte pedale_compteur = 0;

  timeout = millis();

  cli();
  timeout -= Tcapteurm1;
  Tpedalage = Tcapteur - Tcapteurm1;
  sei();
  //bitSet(EIFR, INTF1);      //raz flag interruption (on laisse dans le doute)
  //bitSet(EIFR, INTF0);

  if (Tpedalage < PEDALAGE_TMAX && timeout < (PEDALAGE_TMAX + 200))    //Vitesse trop lente ou creneau capteur trop ancien (arret de pedalage)
  {
    //tampon filtrage des tats
    if (pedale_compteur < 2 * PEDALE_COMPTEUR_SEUIL)
      pedale_compteur++;
  }
  else
  {
    //tampon filtrage des tats
    if (pedale_compteur > 0)
      pedale_compteur--;
  }

  if (pedale_compteur < PEDALE_COMPTEUR_SEUIL)      //Etat d'arret de pedalage
  {
    Tpedalage = PEDALAGE_TMAX;
    VitVelo = 0;
    return 1;        //PAS DE PEDALAGE
  }
  else
  {

    //calcul vitesse de pedalage + periode
    Tpedalage *= 12;
    VitVelo = 36 * PEDALAGE_DISTCM;
    VitVelo *= 10;
    VitVelo /= Tpedalage;

    //TEST 06/10/2016: Moyennage vitesse pour affichage plus stable sur appli Android
    if(VitVelo > 350) VitVelo = 350;
    //Moyenne vitesse sur 1/2 tour complet de pdalier (4 dernieres valeurs)
    for (a = 0 ; a < 3 ; a++) {  //decalage
      MoyVitVelo[a] = MoyVitVelo[a + 1];
    }
    MoyVitVelo[3] = (unsigned int) VitVelo;
    AffVitVelo = 0;
    for (a = 0 ; a <= 3 ; a++) {  //calcul moyenne
      AffVitVelo += MoyVitVelo[a];
    }
    AffVitVelo /= 4;
    
    return 0;      //PEDALAGE EN COURS
  }
}


/*******************************************************************************************/
//application tension sur moteur via PWM (moyenn par filtre RC en sortie)
//@param: w = watt a fournir
//De 0  20km/h: 1W electrique = 1W humain
//l'assistance lectrique dcroit progressivement de 20km/h  25km/h pour tre nulle au del de 25km/h (developpement court sur velo pliant...)
void gestion_moteur(int w) {
  char a;
  int pwm;
  int val1, val2;
  float u, i;

  //digitalWrite(OutTest, HIGH);  //pour mesure temps de traitement (env 390s)
  noInterrupts();

  //bornage
  if (w < 0) w = 0;
  if (w > 255) w = 255;
  //correction selon vitesse
  if (VitVelo < 10) {
    pwm = 0;
  }
  else if (VitVelo < 200) {
    pwm = w;

  }
  else if (VitVelo < 250) {    
    pwm = 250 - VitVelo;
    pwm *= w;
    pwm /= 50;

  }
  else {
    pwm = 0;

  }

  //lissage sur les 5 dernieres valeurs
  for (a = 0; a < 4; a++) {
    MotMoy[a] = MotMoy[a + 1];    //backup
  }
  MotMoy[4] = pwm;      //MAJ
  pwm = 0;
  for (a = 0; a < 5; a++) {
    pwm += MotMoy[a];
  }
  Cons_Wmot = (float)(pwm / 5);  //Moyennage sur 5 valeurs



  //

  // **** Regulation PI selon consigne w   **** //
  //Mesure puissance moteur via LEM + conversion en W
  val1 = analogRead(Imot);
  val2 = analogRead(Vmot);

  //bornage
  if (val1 < Iref) val1 = Iref;

  //calcul tension batterie
  //ampli diff : 3.09 x (Vi - Vref) avec Vi = Vbat/8.5 et Vref = 3.53V
  //coeff CAN : 1024 / 5
  u = (float)((42.5 * val2) / 3164.16);
  u += 30, 2;   // + correction 200mV

  //calcul courant mesure
  val1 -= Iref;    //offset LEM
  i = (float)val1 * 5;    //coeff CAN
  i /= 1024;              //
  i /= 0.0625;            //coeff LEM

  Mes_Wmot = u * i;    //puissance mesure
  
  //maj et moyennage mesure pour affichage
  for(a = 0; a < 11; a++){
    MoyMesWmot[a] = MoyMesWmot[a+1];
  }
  float m = Mes_Wmot;
  MoyMesWmot[11] = (int)m;
  AffMesWmot = 0;
  for(a = 0; a < 12; a++){
    AffMesWmot += MoyMesWmot[a];
  }
  AffMesWmot /= 12;  //maj mesure moyenne sur 1 tour pour affichage appli android
  /*
   Serial.print("u=");          //DEBUG
   Serial.println(u);
   Serial.print("i=");
   Serial.println(i);
   Serial.print("Pmot=");
   Serial.println(Mes_Wmot);
  */

  //
  //correcteur
  Ek = Cons_Wmot - Mes_Wmot;    //calcul Erreur en puissance (consigne - mesure)

  Uk = 0.02737806 * Ek - 0.021615667 * Ekm1 - 0.0017801932 * Ekm2 + 1.973477 * Ukm1 - 0.9734774 * Ukm2; //Equ de recurrence (moteur 250W - Test 2)
  //Uk = 9.2067 * Ek - 15.012 * Ekm1 + 5.9004 * Ekm2 + 1.739 * Ukm1 - 0.73903 * Ukm2; //Equ de recurrence (moteur 350W - Test 1)

  //Uk = 0.05193636164421996*Ek - 0.0289217814133178*Ekm1 - 0.007184380500059863*Ekm2 + 1.917763790949064*Ukm1 - 0.9177637909490634*Ukm2; //Equ de recurrence (moteur 250W - Test 1)
  //Uk est la consigne en pas CNA (duty PWM de 0 a 255)
  //application nouvelle consigne + bornage
  if (Cons_Wmot == 0) Uk = 0;     //RAZ pour correction BUG >>> VOIR AVEC JOCELYN
  val1 = (int)Uk;
  if (val1 > 153)                                    // "153 + 51" car la tension maximale est de 4V sur le controleur brushless************/
  {
    val1 = 153;
  }
  if (val1 < 0)
  {
    val1 = 0;
    //Uk = 0;    //RAZ pour correction BUG >>> VOIR AVEC JOCELYN
  }

  //application sur controleur brushless
  analogWrite(MotPin, (val1 + 51));                  // "51" car la tension minimale est de 1V sur le controleur brushless

  //backup
  Ukm2 = Ukm1;
  Ukm1 = Uk;
  Ekm2 = Ekm1;
  Ekm1 = Ek;
  //

  //affichage sur console DEBUG
  /*
  Serial.print(Cons_Wmot);
  Serial.print(",");
  Serial.print(Uk);
  Serial.print(",");
  Serial.print(val1);
  Serial.print(",");
  Serial.print(Mes_Wmot);
  Serial.print(",");
  Serial.println(Ek);
  */
  //digitalWrite(OutTest, LOW);
  interrupts();
}


/*******************************************************************************************/
//Gestion communication IHM <> Superviseur
// Stratgie de communication:
//      1. La tablette envoi priodiquement un ordre "MAJ+crc" de mise  jour
//      2. Le superviseur vrifie toutes les " X " ms si un ordre est arriv
//      3. Si oui, le superviseur transmet la trame "IHM..."
//      4. Si non, on ne fait rien
void gestion_BT(void) {

  char BTdata[] = {
    'I', 'H', 'M', 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 , 0x30 , 0x30, 0
  };  //trame a envoyer
  char RXbuffer[10], buffer[5], a, b, nbrx;
  unsigned char crc, vit;
  unsigned long v;
  static unsigned char cnt_cnx = 0;  //compteur temps de connexion pour gestion erreur 6  (gestion_BT appele tts les 50ms)
  int w, c;

  crc = 0;
  if (++cnt_cnx >= 250) cnt_cnx = 250;
  nbrx = IHMSerial.available();  //ordre recu ??
  if (nbrx > 0) {
    noInterrupts();
    for (b = 0; b < nbrx; b++) {
      RXbuffer[b] = IHMSerial.read();  //reception ordre
    }
    //validit ordre
    if ((RXbuffer[0] == 'M') && (RXbuffer[2] == 'J')) {

      //APPLI pour dbugage  ********************************************************************
      switch (RXbuffer[3])
      {
        case 'O':
          LevelAssist = ASSIST_0;
          BTdata[3] = 'O';
          break;
        case 'L':
          LevelAssist = ASSIST_L;
          BTdata[3] = 'L';
          break;
        case 'M':
          LevelAssist = ASSIST_M;
          BTdata[3] = 'M';
          break;
        default:
          LevelAssist = ASSIST_L;
          BTdata[3] = 'L';
          break;
      }
      gestion_LEDMode(LevelAssist);    //maj affichage
      //
      sprintf(buffer, "%03d", Vbatt);
      for (a = 4; a <= 6; a++)
      {
        BTdata[a] = buffer[(a - 4)];
      }
      //
      sprintf(buffer, "%03d", AffVitVelo);
      for (a = 7; a <= 9; a++)
      {
        BTdata[a] = buffer[(a - 7)];
      }
      //
      if (Tbatt > 99) Tbatt = 99; //bornage
      sprintf(buffer, "%02d", Tbatt);
      for (a = 10; a <= 11; a++)
      {
        BTdata[a] = buffer[(a - 10)];
      }
      //
      w = (int)AffMesWmot;                            // Cons_Wmot ou Mes_Wmot mais moins stable (a voir...)
      if (w > 999) w = 999; //bornage
      sprintf(buffer, "%03d", w);
      for (a = 12; a <= 14; a++)
      {
        BTdata[a] = buffer[(a - 12)];
      }
      //
      BTdata[15] = erreur + 1;      //offset pour eviter erreur =0
      //
      for (a = 0; a <= 15; a++) {
        crc += BTdata[a];
      }
      BTdata[16] = crc;
      //
      //envoi
      IHMSerial.println(BTdata);

      //debug
      //sprintf(buffer, "%03d", crc);
      //Serial.println(buffer);
      //sprintf(buffer, "%03d", nbrx);
      //Serial.println(buffer);
      //Serial.println(BTdata);
      cnt_cnx = 0;
      interrupts();
    }
  }
  //Test absence/perte de connexion avec tlphone
  if (cnt_cnx <= 200) {
    bitClear(erreur, 6);  //liaison Bluetooth OK
  } else {
    bitSet(erreur, 6);  //Pas de reception d'ordre
  }

}


/*******************************************************************************************/
//Gestion des LEDS Niveau d'assistance
void gestion_LEDMode(int v) {
  switch (v) {
    case ASSIST_0:
      digitalWrite(LEDLEVEL_L, LOW);
      digitalWrite(LEDLEVEL_M, LOW);
      break;
    case ASSIST_L:
      digitalWrite(LEDLEVEL_L, HIGH);
      digitalWrite(LEDLEVEL_M, LOW);
      break;
    case ASSIST_M:
      digitalWrite(LEDLEVEL_L, HIGH);
      digitalWrite(LEDLEVEL_M, HIGH);
      break;
    default:
      digitalWrite(LEDLEVEL_L, LOW);
      digitalWrite(LEDLEVEL_M, LOW);
      break;
  }

}

/*******************************************************************************************/
//Gestion des LEDS RGB statut de batterie
void gestion_LEDbatt(int v) {

  if ((v < 145) || (v > 892)) {      //Pb batterie ALLUMAGE BLEU
    digitalWrite(LEDBAT_R, HIGH);
    digitalWrite(LEDBAT_G, HIGH);
    analogWrite(LEDBAT_B, 150);
  } else if (v < 370) {              // 0  30% ALLUMAGE ROUGE
    analogWrite(LEDBAT_R, 150);
    digitalWrite(LEDBAT_G, HIGH);
    digitalWrite(LEDBAT_B, HIGH);
  } else if (v < 610) {              // 30  60% ALLUMAGE ORANGE
    analogWrite(LEDBAT_R, 150);
    analogWrite(LEDBAT_G, 245);
    digitalWrite(LEDBAT_B, HIGH);
  } else {                           // 60  100% ALLUMAGE VERT
    digitalWrite(LEDBAT_R, HIGH);
    analogWrite(LEDBAT_G, 170);
    digitalWrite(LEDBAT_B, HIGH);
  }

}


/*******************************************************************************************/
//Gestion des erreurs systme
// =0 si pas d'erreur majeure, =1 si pb

/*** DETAIL DE LA VARIABLE ERREUR ***/
//bit 0=1 si pas de pedalage,
//bit1=1 si ...,
//bit2=1 si ...,
//bit3=1 si ...,
//bit4=1 si pb batterie principale,
//bit5=1 si ...,
//bit6=1 si Pb communication Bluetooth
//bit7=1 si Pb temperature Pack batterie
/***/
unsigned char gestion_erreur(void) {
  char a;
  static boolean cl;
  //ARRET VELO SI ERREUR MAJEURE (BATTERIE VIDE // TEMPERATURE PACK BATTERIE
  a = erreur & 0b10010000;  //on isole les erreurs mineures
  if (a) {
    //animation stripLED
    cl = !cl;
    if (cl == true) {
      digitalWrite(LEDALERT, HIGH);
    } else {
      digitalWrite(LEDALERT, LOW);
    }
    return 1;
  } else {
    digitalWrite(LEDALERT, LOW);
    return 0;
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Routine de lecture Temperature Interieure (CTN 10K)
float Thermistor(int RawADC) {
  long Resistance;
  float Temp;  // Dual-Purpose variable to save space.
  Resistance = 10000 * ((1024.0 / RawADC) - 1);      //recup valeur CTN en ohms selon mesure ADC
  Temp = log(Resistance / 10000.0); // ln(RT/R25)
  Temp = 1 / (0.0033540164 + (0.000256985 * Temp) + (0.000002620131 * Temp * Temp) + (0.00000006383091 * Temp * Temp * Temp));
  Temp = Temp - 273.15;  // Convert Kelvin to Celsius
  return Temp;                                      // Return the Temperature
}

Credits

martial leyney

martial leyney

1 project • 1 follower

Comments