Bonsoir
Je reprends un peu me travaux avec le retour des jours de pluie et les quelques progrès que j'ai pu faire depuis quelques temps.
Pour ceux qui ne connaissent pas cette très bonne bibliothèque pour traiter le signal DCC voici le lien qu'il vous faut:
https://github.com/aikoprasPlus spécifiquement la libraire
https://github.com/aikopras/AP_DCC_libraryet le projet de décodeur:
https://github.com/aikopras/AP_DCC_Decoder_CoreIntéressons nous aussi a ce dont nous avons besoin "bloc par bloc".
Le décodage du signal DCC est confié à la librairie d AIKO PRA.: transcodage signal-instructions, écriture, lecture CV.
Il nous faut compléter notre base avec idéalement:
une classe "LED" pour gérer nos effets lumineux
pour une decodeur de loco en sus il faut
une classe "MOTOR" pour traiter la partie pilotage moteur
Afin de gérer la PWM SOFTWARE sur les sorties utilisée des CPU nous devons faire un travail de codage.
Comme nous voulons pouvoir utiliser n'importe quelle sortie du CPU pour gérer du PWM nous devons avoir recours a du "bit banging" et ne pas nous reposer uniquement sur les seules sorties capable de générer du PWM HARDWARE.
Cela peut entre autre reposer sur l'utilisation de solution pré packagées.
Par exemple celles de KHOI HUANG et de ses nombreuses librairies:
https://github.com/khoih-progprincipalement celle gérant les TIMER_ INTERRUPT et les SLOW_PWM pour différents CPU bien connus. ( AVR séries 0 1 2, ATMEGA, ATTINY série 0 1 2, ...) peuvent être d'une grande utilité.
Néanmoins je m'interroge sur la structuration et l'articulation de certaines des briques pour y parvenir.
Concentrons nous sur un décodeur de fonction embarqué pour gérer des éclairages dans une voiture voyageur.
Notre "PROGRAMME CORE" ( sur le TIMER B0 par défaut) traite le signal DCC, nous actualisons des variables dont les états sont ensuite consommés par la classe LED qui gère les différents types d'effets lumineux (ON/OFF, FADE, NEON START,...)
A défaut un "digitalWrite" sur la sortie à piloter donnera un résultat immédiat. La classe LED enrichie cette base de fonctionnement.
Jusque la nous allumons et éteignons nos leds en tout ou rien avec le "digitalWrite"
Pour produire des effets lumineux on va alors rafraichir périodiquement un état HAUT puis BAS sur une broche ce qui constitue un "PWM SOFTWARE" (autrement appelé bit banging").
Nous pouvons ainsi gérer visuellement une intensité lumineuse donnée à nos leds.
Le recours à une programmation objet et la definition d une classe "LED" facilite la mise en oeuvre.
Je pense utile de dédier un autre TIMER de type B ( par exemple le B1) pour les calculs d'actualisation de ces variables pour générer ensuite le PWM.
J'envisage de faire appel à la librairie de KHOI TimerInterrupt du type de processeur à utiliser coté HARDWARE pour générer une interruption à intervalle de temps régulier (ex 20 millisecondes). durant cette étape les valeurs de pilotage du PWM sont actualisées ( le LEVEL qui indique l intensité lumineuse attendue en sortie).
On a alors plus qu'a consommer un "LEVEL" à transformer en PWM SOFT.
La question que je me pose est de savoir si le PWM est géré dans le "handler" (que l on appelle dans la loop principale du programme ou non? Les paramètres de LEVEL sont rafraichis par les valeurs poussées post interruptions dans des variables qui actualisent l'état des sorties )
Comme on peut le voir dans les exemples qui sont fournis pour illustrer les utilisations de ces librairies et donc m'assurer que l'on tourne sur le TIMER hard sélectionné ou bien s il faut revenir sur le "PROGRAMME CORE" et donc le timer B0 initial. ( qui a en charge le traitement du DCC rappelons le)
Formuler autrement cela revient à identifier:
qui porte la charge de la génération du PWM soft ( exclusivement le trimer B1?) ou la boucle du programme principale dans une fonction qui y est placée (qui tourne avec le TIMER B0.)
mon approche est elle correcte? J ai encore un petit peu de mal à mesurer la pertinence/validité de cette structuration.
Est ce bien l'optimal à mettre en œuvre ainsi?
Pour illustrer le BIT BANGING voici l exemple de code utilisable:
_TMP_PWM_LVL est la valeur calculée de l intensité lumineuse, rafraichie par lors des ISR, et dont la valeur va de 0 à 100 ( ce qui correspond au niveau de PWM à générer)
turn_on() et turn_off() pilotent directement le port de sortie de la pin concernée (mais à titre de demo un digitalWrite ou digitalfastwrite peut y etre substitué.*)
(*: par efficacité et optimisation des timings d'exécution la commande native du port est préférée)
pwminterval est la fréquence avec laquelle nous allons travailler. Disons 50hz ce qui devrait réduire assez bien le scintillement.
invert est la pour indiquer si le montage est a anode ou cathode commune pour le driving des leds.
noter que de manière autonome ce code (complété dans son environnement fonctionne très bien et produit le résultat attendu.
Maintenant où le placer idéalement:
dans une fonction et appeler celle ci dans la boucle principale? avec le timer B1 et l ISR comme "handler"...?
// Below the code for PWM:
uint32_t PWM_Interval = micros() - last_pwm_time;
///brightnessLevel = _TMP_PWM_LVL;
if(_TMP_PWM_LVL > 0 && _TMP_PWM_LVL < 100)
{
pwmOnTime = pwmInterval / 100 * _TMP_PWM_LVL;
pwmOffTime = pwmInterval - pwmOnTime;
if (OutIsOn)
{
if (PWM_Interval > pwmOnTime)
{
// pwmOnTime is over: LED has been on long enough
last_pwm_time = micros();
if (_invert)
{
turn_on();
}
else
{
turn_off();
}
OutIsOn = false;
}
}
else
{
if (PWM_Interval > pwmOffTime)
{
// pwmOffTime is over: LED has been off long enough
last_pwm_time = micros();
if(_invert)
{
turn_off();
}
else
{
turn_on();
}
OutIsOn = true;
}
}
}
if (_TMP_PWM_LVL == 100)
{
if(_invert)
{
turn_off();
}
else
{
turn_on();
}
}
if (_TMP_PWM_LVL == 0)
{
if (_invert)
{
turn_on();
}
else
{
turn_off();
}
}