16
Débuter / Re : PCA9685
« le: février 11, 2022, 09:40:57 pm »
hihihi... +1 ! 
(on a tous débuté !)

(on a tous débuté !)
Le forum LOCODUINO est consacré aux discussions ayant trait à l'utilisation de l'Arduino dans les automatismes et les animations pour le train miniature. Nous avons eu récemment quelques inscriptions de personnes ayant des projets plus généraux mais surtout inapplicables au train miniature. Si votre projet ou vos questions ne concernent pas le modélisme ferroviaire, ne vous inscrivez pas, vous perdriez votre temps et nous aussi.
Cette section vous permet de consulter les contributions (messages, sujets et fichiers joints) d'un utilisateur. Vous ne pourrez voir que les contributions des zones auxquelles vous avez accès.
merci de citer vos sources lorsque vous affirmez quelque chose
Où est l'erreur ?
Je suis étonné qu'on puisse utiliser des fréquences élevées comme 32kHz, parce que ça ne doit pas être facile de mesurer la FCEM.La fréquence de PWM est à priori sans la moindre incidence puisque la FCEM ne peut pas se mesurer autrement que courant traction coupé.
/* POUR TESTS DE PERF */
uint16_t count = 0;
uint32_t timerTests = 0;
void setup() {
Serial.begin(115200);
delay(100);
}
void loop() {
for (int f=0; f<1000; f++) {
/* test calculs*/
float sqr = sqrt(f); /* resultat TEENSY : 773 Hz / resultat ESP32 : 244 Hz */
/* test IO */
// digitalWrite(4, HIGH); /* resultat TEENSY : 1390 Hz / resultat ESP32 : 4074 Hz */
// digitalWrite(4, LOW);
/* IO rapide - TENNSY 3.5 */ /*resultat TEENSY : 19633 Hz */
// digitalWriteFast(4, HIGH);
// digitalWriteFast(4, LOW);
/* IO rapide - ESP32 */ /* resultat ESP32: 9384 Hz */
// GPIO.out_w1ts = ((uint32_t)1 << 4); // HIGH
// GPIO.out_w1tc = ((uint32_t)1 << 4); // LOW
}
count++;
if (millis()-timerTests >= 3000) {
Serial.printf("%u Hz \n", count/((millis()-timerTests)/1000));
timerTests = millis();
count = 0;
}
}
const uint16_t PWM_OFF = 300; // 300 microSeconds - temps de coupure du courant traction
const uint16_t PWM_ON = 10000; // ~10 milliSeconds - période "ON", moteur alimenté
uint32_t time_ON;
bool timeToEmitFCEM;
const uint8_t NB_SECTIONS = 4; // ex : 4 sur ce satellite
const uint8_t SECTION_PINOUT[NB_SECTIONS][5] = {.......};
// pour chaque section :
// - numéro de la section (sur le réseau)
// - num de la pin(satellite) de polarisation 1 du pont H qui alimente la section
// - pin de polarisation 2
// - pin analogique de lecture FCEM de la section en polarisation 1
// - pin analogique de lecture FCEM en polarisation 2
uint8_t trainOnSection[NB_SECTIONS] = { 0, 0, 0, 0 }; // contiendra 0 pour libre ou num de train+1 (fourni par ailleurs par le master) si occupée
bool polarization[NB_SECTIONS] = { 0, 0, 0, 0 }; // data fournie par le master en complément du numéro de train
uint8_t trainNum[NB_SECTIONS] = { 0, 0, 0, 0 }; // numéros des trains présents sur les sections du satellite (numérotation "vraie")
uint8_t trains; // nombre de trains différents recensés à l'instant "t"
uint16_t sumFCEM[NB_SECTIONS];
uint16_t count[NB_SECTIONS];
int16_t reading[NB_SECTIONS][6]; // 6 mesures pour chaque section (si occupée)
void mesureFCEM() {
if (timeToEmitFCEM) /*=>*/ sendFCEM(); // LES sats ont reçu (par ailleurs) un message du MASTER enjoignant à transmettre les relevés
if (micros() - time_ON < PWM_ON) /*=>*/ return;
if (trains) {
for (uint8_t i=0; i<NB_SECTIONS; i++) { // au moins un train détecté => tous pins de polarization LOW (=> coupure du courant traction)
digitalWriteFast(SECTION_PINOUT[i][1], LOW);
digitalWriteFast(SECTION_PINOUT[i][2], LOW);
}
delayMicroseconds(PWM_OFF); // attente avant mesures
for (uint8_t i=0; i<NB_SECTIONS; i++) {
if (trainOnSection[i]>0) { // TOUT OU PARTIE du train numéro "trainOnSection[i] occupe la section i
for (uint8_t j=0; j<6; j++) { // 6 mesures
reading[i][j] = analogRead(SECTION_PINOUT[i][3+polarization[i]]);
}
}
}
/* TRAITEMENT DES DONNEES */
int16_t read[NB_SECTIONS] = {0, 0, 0, 0}, maxRead[NB_SECTIONS] = {0, 0, 0, 0}, minRead[NB_SECTIONS] = {0, 0, 0, 0};
for (uint8_t i=0; i<NB_SECTIONS; i++) {
if (trainOnSection[i]) { // il y a un train dans la section i => au moins une section est occupée
if (polarization[i]) /*=>*/ digitalWriteFast(SECTION_PINOUT[i][1], HIGH);
else /*=>*/ digitalWriteFast(SECTION_PINOUT[i][2], HIGH); // rétablissement de la polarization initiale
maxRead[i] = reading[i][0]; // première mesure
minRead[i] = reading[i][0];
read[i] = reading[i][0];
for (uint8_t j=1; j<6; j++) { // on lit les 5 autres mesures et on repère les deux extrêmes
maxRead[i] = max(reading[i][j], maxRead[i]);
minRead[i] = min(reading[i][j], minRead[i]);
read[i] = (read[i] + reading[i][j]); // sommation des SIX lectures
}
read[i] = (read[i] - maxRead[i] - minRead[i])/4; // moyenne des 4 valeurs retenues après élimination des extrêmes
maxRead[i] = 0;
}
}
// si train sur 2 sections (ou plus), on filtre les résultats "fake" (wagons) en comparant les mesures de ce train
for (uint8_t j=0; j<trains; j++) { // à ce stade, "trains" est forcément au moins égal à 1, le numéro du premier train nomenclaturé étant inscrit dans trainNum[0]
for (uint8_t i=0; i<NB_SECTIONS; i++) { // on recherche ce train sur toutes les sections et on repère son read max
if (trainOnSection[i] == trainNum[j]) { // un train a été nomenclaturé à l'indice j (toujours vrai une fois au moins)
maxRead[j] = max(read[i], maxRead[j]); // max-des-max pour le train j de numéro trainNum[j]
}
}
for (uint8_t i=0; i<NB_SECTIONS; i++) { // on compare les résultats section par section, on garde ou non
if (trainOnSection[i]==trainNum[j] && read[i]> maxRead[j]/2) { // écart "normal" => on prend en compte la mesure (maxRead répond à la condition)
sumFCEM[j] = sumFCEM[j] + read[i];
count[j]++; // sumFCEM == première ou nouvelle sommation pour ce train, puis comptage des sommations
}
}
}
}
time_ON = micros();
}
void sendFCEM() {
timeToEmitFCEM=false;
for (uint8_t j=0; j<trains; j++) {
if (count[j]) {
const uint16_t TRAIN = trainNum[j]-1;
messageCAN_FCEM.id = 72 + TRAIN; // EXEMPLE : (64 pour satellite"0", 72 pour sat"1" etc) + n° du train converti en valeur "code"
// /!\ une loco en chevauchement sur 2 sections gérées par 2 sats # pourrait générer 2 messages identiques et simultanés, provoquant
// UN PLANTAGE DU BUS. L'ajout du n° de sat dans l'ID permet,de discriminer les messages (+ autres usages) */
uint16_t fcem = sumFCEM[j]/count[j];
if (fcem < FCEMtrain[TRAIN]/2) /*=>*/ fcem = FCEMtrain[TRAIN]/2; // "passe-bas", bride les points aberrants
messageCAN_FCEM.data16[0] = fcem; // on ne transmet pas la section, c'est une donnée connue du master
const bool OK = ACAN::can0.tryToSend(messageCAN_FCEM);
FCEMtrain[TRAIN] = fcem;
}
sumFCEM[j] = 0; count[j] = 0; trainNum[j] = 0;
}
scanSections(); // AVANT LES PROCHAINES MESURES, ON REFAIT LA NOMENCLATURE DES TRAINS
}
void scanSections() { // inventaire et classement dans trainNum[] des trains présents sur les sections traitées par le sat
bool flag = 1;
trains = 0;
for (uint8_t i=0; i<NB_SECTIONS; i++) {
trainNum[i] = 0;
if (trainOnSection[i]) {
for (uint8_t j=0; j<=trains; j++) {
if (trainOnSection[i] == trainNum[j]) {
flag = 0;
break;
}
}
if (flag) {
trainNum[trains] = trainOnSection[i];
trains++;
}
flag = 1;
}
}
}