//******************************************************************************************//
// Programme pour Arduino NANO //
// Contrôle de la vitesse et la sens d'un moteur courant continu DOUBLE //
// Un Joystick est utilisé pour accélérer ou ralentir par pas allant de 1 à 5 //
// et pour indiquer la sens avant = 0 neutre = 2 arriere = 5 //
// Un écran LCD de 16 par 2 indique la sens choisie et la vitesse atteinte //
// Programme réécrit par Daniel pour Denis le 03/07/2023 //
// Modifié le: 22/10/2025 par Denis //
// Amélioration de l'affichage sur LCD indication du sens sur la première ligne //
// Supression des caractères centaines et dizaines au ralentissement //
// Introduction d' arret d'urgence par interruption si on appuie sir le joystick //
// //
//******************************************************************************************//
const char Titre[] = "TEST_cmde_train_Denis2"; // titre
const char Version[] = "3"; // numéro de version
const char derModif[] = "22/10/2025"; // date de dernière modification
// LIBRAIRIES
//#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// paramètres Outil1.h
const int nb_tempo = 1; // nombre de tempos utilisées +1
const int nb_FM = 1; // nombre de FM utilisés +1
const int nb_visu = 6; // nombre de visu utilisées +1
//#include <Outils1.h> // bibliothèque outils1 de Daniel
LiquidCrystal_I2C lcd1(0x27, 16, 2); // afficheur à l'adresse 0x27, 16 caractères sur 2 lignes
LiquidCrystal_I2C lcd2(0x26, 16, 2); // afficheur à l'adresse 0x26, 16 caractères sur 2 lignes
// Variables globales réseau 1
//*******************
int change1 = 0;
int vitesse1 = 0;
byte avant_arriere1 = 0;
int sens1 = 0;
int pas1 = 0;
int pinterupt1 = 2;
// Variables globales réseau 2
//*******************
int change2 = 0;
int vitesse2 = 0;
byte avant_arriere2 = 0;
int sens2 = 0;
int pas2 = 0;
int pinterupt2 = 3;
// Association des entrées du L298N, aux sorties utilisées sur notre Arduino Nano
//*******************************************************************************
const byte borneENA = 10; // On associe la borne "ENA" du L298N à la pin D10 de l'arduino
const byte borneIN1 = 9; // On associe la borne "IN1" du L298N à la pin D9 de l'arduino
const byte borneIN2 = 8; // On associe la borne "IN2" du L298N à la pin D8 de l'arduino
const byte borneIN3 = 7; // On associe la borne "IN3" du L298N à la pin D7 de l'arduino
const byte borneIN4 = 6; // On associe la borne "IN4" du L298N à la pin D6 de l'arduino
const byte borneENB = 5; // On associe la borne "ENB" du L298N à la pin D5 de l'arduino
// Entrées analogiques 1
//********************
const byte SENS1 = A0; // avant arriere
const byte VITESSE1 = A1; // Accélérer Ralentir
// Entrées analogiques 2
//********************
const byte SENS2 = A2; // avant arriere
const byte VITESSE2 = A3; // Accélérer Ralentir
void setup()
{
Serial.begin(115200);
Serial.println(Titre);
Serial.print("Version n° ");
Serial.print(Version);
Serial.print(" du ");
Serial.println(derModif);
Serial.println("__________________________");
// Configuration de toutes les pins de l'Arduino en "sortie" (car elles attaquent les entrées du module L298N)
pinMode(borneENA, OUTPUT); // va recevoir le signal PWM selon la vitesse
pinMode(borneIN1, OUTPUT);
pinMode(borneIN2, OUTPUT);
// pinMode(borneIN3, OUTPUT); // inutilisée car un seul moteur
// pinMode(borneIN4, OUTPUT); // inutilisée car un seul moteur
// pinMode(borneENB, OUTPUT); // inutilisée car un seul moteur
pinMode(pinterupt1, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinterupt1), arretUrgence1, CHANGE);
// initialize the lcd
lcd1.init();
delay(50);
lcd1.backlight();
// Print a message to the LCD.
lcd1.setCursor(0,0);
lcd1.print("bonjour");
delay ( 2000);
lcd1.clear();
// initialize the lcd
lcd2.init();
delay(50);
lcd2.backlight();
// Print a message to the LCD.
lcd2.setCursor(0,0);
lcd2.print("bonjour");
delay ( 2000);
lcd2.clear();
}
void loop()
{
Lecture_analogique1();
Lecture_analogique2();
Sens1();
Sens2();
Vitesse1();
Vitesse2();
LancerRotationMoteurPontA(vitesse1); // On active le moteur A
LancerRotationMoteurPontB(vitesse2); // On active le moteur B
Afficheur1();
//Afficheur2();
//Visu();
}
void Lecture_analogique1()
{
sens1 = analogRead(SENS1);
pas1 = analogRead(VITESSE1);
}
void Lecture_analogique2()
{
sens2 = analogRead(SENS2);
pas2 = analogRead(VITESSE2);
}
void arretUrgence1 ()
{
vitesse1 = 0 ;
}
void arretUrgence2 ()
{
vitesse2 = 0 ;
}
void Sens1()
{
// Lecture des entrées pour sens
avant_arriere1 = map(sens1,1023,0, 0,5);
// On obtient uniquement 3 niveaux interssants
// pour indiquer le sens: avant = 0, neutre = 2, arriere = 5
// Deux tests pour faire basculer les sorties A dans un sens ou dans l'autre
//***************************************************************************
// Configuration du L298N en "marche avant", pour le moteur connecté au pont A.
if(avant_arriere1 == 0) //Selon sa table de vérité, il faut que :
{
digitalWrite(borneIN1, HIGH); // L'entrée IN1 doit être au niveau haut
digitalWrite(borneIN2, LOW); // L'entrée IN2 doit être au niveau bas
}
// Puis on configure le L298N en "marche arrière", pour le moteur câblé sur le pont A.
if(avant_arriere1 == 5) //Selon sa table de vérité, il faut que :
{
digitalWrite(borneIN1, LOW); // L'entrée IN1 doit être au niveau bas
digitalWrite(borneIN2, HIGH); // L'entrée IN2 doit être au niveau haut
}
}
void Sens2()
{
// Lecture des entrées pour sens
avant_arriere2 = map(sens1,1023,0, 0,5);
// On obtient uniquement 3 niveaux interssants
// pour indiquer le sens: avant = 0, neutre = 2, arriere = 5
// Deux tests pour faire basculer les sorties A dans un sens ou dans l'autre
//***************************************************************************
// Configuration du L298N en "marche avant", pour le moteur connecté au pont A.
if(avant_arriere2 == 0) //Selon sa table de vérité, il faut que :
{
digitalWrite(borneIN3, HIGH); // L'entrée IN1 doit être au niveau haut
digitalWrite(borneIN4, LOW); // L'entrée IN2 doit être au niveau bas
}
// Puis on configure le L298N en "marche arrière", pour le moteur câblé sur le pont A.
if(avant_arriere2 == 5) //Selon sa table de vérité, il faut que :
{
digitalWrite(borneIN3, LOW); // L'entrée IN1 doit être au niveau bas
digitalWrite(borneIN4, HIGH); // L'entrée IN2 doit être au niveau haut
}
}
void Vitesse1()
{
// on gere la vitesse par pas pour avoir une accélaration progressive
change1 = map(pas1,10,1000,5,-5);
// Valeurs positives pour accélerer et négatives pour ralentir
// en position centrale change = 0 on conserve la vitesse atteinte
vitesse1 = vitesse1 + change1;
if(vitesse1 > 255)
vitesse1 = 255;
if(vitesse1 < 0)
vitesse1 = 0;
constrain(vitesse1, 0, 255); // double précaution
}
void Vitesse2()
{
// on gere la vitesse par pas pour avoir une accélaration progressive
change2 = map(pas2,10,1000,-5,5);
// Valeurs positives pour accélerer et négatives pour ralentir
// en position centrale change = 0 on conserve la vitesse atteinte
vitesse2 = vitesse2 + change2;
if(vitesse2 > 255)
vitesse2 = 255;
if(vitesse2 < 0)
vitesse2 = 0;
constrain(vitesse2, 0, 255); // double précaution
}
void Afficheur1()
{
lcd1.setCursor(0,0);
lcd1.print("Direct");
lcd1.setCursor(9,0);
if (avant_arriere1 == 0){
lcd1.print("AVANT ");
}
if (avant_arriere1 == 5){
lcd1.print("ARRIERE");
}
lcd1.setCursor(0,1);
lcd1.print("Vitesse");
if (vitesse1 <10){
lcd1.setCursor(10,1);
lcd1.print(char(20));
lcd1.setCursor(11,1);
lcd1.print(char(20));
lcd1.setCursor(12,1);
lcd1.print(vitesse1);
}
else if (vitesse1 <100) {
lcd1.setCursor(10,1);
lcd1.print(char(20));
lcd1.setCursor(11,1);
lcd1.print(vitesse1);
}
else {
lcd1.setCursor(10,1);
lcd1.print(vitesse1);
}
}
/*void Afficheur2()
{
lcd2.setCursor(0,0);
lcd2.print("Direction");
lcd2.setCursor(11,0);
if (avant_arriere2 == 0){
lcd1.print("AVANT ");
}
else {
lcd1.print("ARRIERE");
}
lcd2.setCursor(0,1);
lcd2.print("Vitesse");
if (vitesse2 <10){
lcd2.setCursor(10,1);
lcd2.print(char(20));
lcd2.setCursor(11,1);
lcd2.print(char(20));
lcd2.setCursor(12,1);
lcd2.print(vitesse2);
}
else if (vitesse2 <100) {
lcd2.setCursor(10,1);
lcd2.print(char(20));
lcd2.setCursor(11,1);
lcd2.print(vitesse2);
}
else {
lcd2.setCursor(10,1);
lcd2.print(vitesse2);
}
}*/
int LancerRotationMoteurPontA(int vite)
{
analogWrite(borneENA, vite); // Active l'alimentation du moteur A
}
int LancerRotationMoteurPontB(int viteb)
{
analogWrite(borneENB, viteb); // Active l'alimentation du moteur B
}
byte tempo(String nom_Tempo,unsigned long duree,int valide)
{
//const int nb_tempo = 15; // nombre à augmenter si insuffisant
static String nom[nb_tempo ];
static int flag_temp_pulse[nb_tempo ] = {0};
static unsigned long temps1[nb_tempo ] = {0};
static unsigned long temps2[nb_tempo ] = {0};
static unsigned long tempo_pulse[nb_tempo ] = {0};
static int pulse[nb_tempo ] = {0};
static byte i = 0;
static byte retour = 0;
for(i=0;i <= nb_tempo ;)
{
if(nom_Tempo== nom[i])
{
break;
}
if(nom[i] == NULL)
{
nom[i] = nom_Tempo;
break;
}
i++;
}
if(flag_temp_pulse[i] == false && valide)
{temps1[i] = millis(); flag_temp_pulse[i] = true;}
temps2[i] = millis();
switch(valide)
{
case 0:
temps1[i] = 0;
temps2[i] = 0;
tempo_pulse[i] = 0;
flag_temp_pulse[i] = false;
pulse[i] = 0;
break;
case 1:
tempo_pulse[i] = temps2[i] - temps1[i];
if(tempo_pulse[i] > duree)
{
temps1[i] = 0;
temps2[i] = 0;
tempo_pulse[i] = 0;
flag_temp_pulse[i] = false;
pulse[i] = 1;
}
else {pulse[i] = 0;}
break;
}
return pulse[i];
}
/******************************************************************
Lignes à inserrer dans le programme
FM("variable = ",variable);
nota: remplacer "Variable" par le nom de la variable à détecter
sur front montant.
exemples: 1/ if(FM("variable",variable)
2/ variable1 = FM("variable",variable);
variable1 passera à 1 sur un tour programme puis à 0 à chaque
à nouveau passage à 1 de variable
IMPORTANT: FM doit toujours être lu
******************************************************************/
byte FM(String nom_FM,int variable)
{
//const int nb_FM = 15; // nombre de FM à augmenter si insuffisant
static String nom[nb_FM];
static int i = 0;
static int retour = 0;
static int flag[nb_FM] = {0};
static int derEtat[nb_FM] = {0};
for(i=0;i <= nb_FM;)
{
if(nom_FM == nom[i])
break;
if(nom[i] == NULL)
{
nom[i] = nom_FM;
break;
}
i++;
}
if(nom_FM == nom[i] && variable)
{
if(variable && derEtat[i])
return 0;
flag[i] = 1;
if(flag[i] && !derEtat[i])
{
derEtat[i] = flag[i];
retour = 1;
}
}
if(nom_FM == nom[i] && !variable)
{
flag[i] = 0;
derEtat[i] = 0;
retour = 0;
}
return retour ;
}
/******************************************************************
Lignes à inserrer dans le programme après la variable à lire
visu("variable_1 = ",variable_1);
nota: remplacer "Variable" par le nom de la variable à lire.
******************************************************************/
void visu(String nom_visu,int variable)
{
//const int nb_visu = 20; // nombre de visu à augmenter si insuffisant
static String nom[nb_visu];
static int visuVar[nb_visu] = {0};
static int i = 0;
for(i=0;i <= nb_visu;)
{
if(nom_visu == nom[i])
break;
if(nom[i] == NULL)
{
nom[i] = nom_visu;
break;
}
i++;
}
if(nom_visu == nom[i])
{
if(visuVar[i] != variable)
{
Serial.print(nom[i]);
Serial.print(" = ");
Serial.println(variable);
Serial.println("_________________");
}
visuVar[i] = variable;
}
}
void Visu()
{
visu(F("sens"),sens1);
visu(F("avant_arriere"),avant_arriere1);
visu(F("pas"),pas1);
visu(F("pas_mod"),change1);
visu(F("vitesse"),vitesse1);
}