15
« le: mai 21, 2022, 08:57:45 am »
Bonjour, voilà grâce à des aides précieuses je me suis tenté une petite expérience pour créer une centrale DCC sur esp32.
Ma démarche est elle bonne? mon programme s'inspire des idées de Trimarco.
Si je suis sur le bon chemin est ce que je dois utiliser memcpy pour garder le bit paquet en mémoire ou bien est ce que je peux utiliser une structure pour l'envoyer comme message struct t_message?
en gros dans la fonction d'interruption, le signal pwm se répète tant que le bit ne change pas. Ainsi pour les 20 premiers bit 1, il n'y a pas d interruption. Dès que le bit start est atteint on envoie une interruption et ainsi de suite. ma synchro est elle bonne?
la fonction SpeedAndDir( 3, CRAN_1,128, 1);
permet dans le loop de sélectionner la loco 3, une vitesse sur 28 pas et une marche avant (j ai normé la vitesse a 128 pas discrets avec une interpolation linéaire).
Merci pour votre aide (et je ne suis qu'un humble débutant).
#include "driver/ledc.h"
uint64_t paquet;//=0b... 48 bits
uint64_t NewPacket;//0b.. 48bits;
uint64_t masque;
uint64_t dccBit;
bool alter =1;
bool previous=0;
#define CRAN_0 0
#define CRAN_1 1
#define CRAN_2 2
#define CRAN_IDLE 5
byte dccSpeed;
byte addr;
byte adresse;
byte vitesse;
byte cksum;
uint64_t paquet_start=0b111111111111111111110; // 20 bits + bit start
byte startBit=0;
byte stopBit=1;
const int dcc_pin = 19; // Sortie du signal DCC
// setting PWM properties
#define dcc_sig_1_freq 8621 // = 115,99 microS
#define dcc_sig_0_freq 5000 // 200µs 5000 Hz donne 200 microS
const int dcc_pin_channel = 0; // on ouvre un canal qu on reliera à une sortie PWMN
const int dcc_sig_resolution = 1; // correspond à une résolution de 1 bit => 2^1bit =2 pas discrets0 et 100%.
const int dcc_sig_duty = 1; // correspond à une résolution de 1 bit => 2^1bit =2 pats discrets 0 et 100%.
uint32_t dcc_sig_freq = dcc_sig_1_freq; // on part de la fréquence du bit 1 toutes les trames commencent par une série de 20 bits a 1
void dcc_sig_isr() {
dccBit=!!(paquet&masque); // les bits différents de 0 valent 1
masque>>=1; // le masque permet de parcourir les bits
if (dccBit==previous) { // si le bit parcouru est == 0 alors il faut envoyer une interruption, alter qui valait 1 au début se transforme en 0
alter=!alter;
//Serial.print(alter);
alter?dcc_sig_freq =dcc_sig_1_freq:dcc_sig_freq =dcc_sig_0_freq;
}
ledc_set_freq(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0, dcc_sig_freq); // new -or not - period value
//speed_mode: Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
//timer_num: LEDC timer index (0-3), select from ledc_timer_t
//freq_hz: Set the LEDC frequency
// est ce que je dois laisser cette ligne de code? quelle est son utilité ici? je comprends qu elle permet de selectionner le timer 0 mais pourquoi la mettre ici et pas ailleurs?
}
void setup() {
Serial.begin(115200);
uint64_t paquet =0; // on initialise la trame
uint64_t NewPacket=0; // on utilise une trmne reformatée plus simple pour limiter les interruptions et aider l'esp32
// configuration du canal pwm 0 avec une fréquence et la résolution
ledcSetup(dcc_pin_channel, dcc_sig_freq, dcc_sig_resolution); // on set up le canal avec une résolution de 1 bit cad 50%
ledcAttachPin(dcc_pin, dcc_pin_channel); /// et ensuite on l attache au PIN19
ledcWrite(dcc_pin_channel, dcc_sig_duty);
// programme l'interruption à la fin de la période
// je n'ai pas trouvé de manière élégante pour le faire avec le timer, alors je me suis rabattu pragmatiquement sur une interruption provoquée ... par le basculement de la pin
attachInterrupt(dcc_pin, dcc_sig_isr, RISING); // l'interruption "dcc_sig_isr" provoquée à la fin de chaque période (voire au début de la suivante) =>moi non plus
}
/// Select Cran = 14,28 ou 128
/// Select Speed = 0......128
/// Select Direction 1 Avant, 2 Arriere, 0 Arret
struct __attribute__((packed)) t_message {
byte adresse;
byte vitesse;
byte cksum;
}; t_message unMessage;
// fonction de calcul 3 octets
void SpeedAndDir( byte addr=0b11111111, byte SelectCran=0b00000000, byte SelectSpeed=0b00000000, bool SelectDirection=0) // vecteur de direction et de vitesse
{
byte type;
byte ext;
byte data;
byte cksum=0;
uint64_t paquet=0;
switch(SelectCran) {
case 0: ////DCC_PACKET_TYPE_STEP_14
dccSpeed=map(SelectSpeed,0,128,0,14);
if (dccSpeed) dccSpeed++; // pas de cran 1
data=(SelectDirection?0x60:0x40)|dccSpeed;
cksum=addr^data;
break;
case 1: ///DCC_PACKET_TYPE_STEP_28
dccSpeed=map(SelectSpeed,0,128,0,28);
if (dccSpeed) dccSpeed+=3; // pas de cran 1,2,3
ext=(((dccSpeed&0x01)<<5)|dccSpeed)>>1; ///
data=(SelectDirection?0x60:0x40)|ext;
cksum=addr^data;
break;
case 2: //DCC_PACKET_TYPE_STEP_128;
dccSpeed=map(SelectSpeed,0,128,0,126);
if (dccSpeed) dccSpeed++; // pas de cran 1
data=(SelectDirection?0x60:0x40)|dccSpeed;
cksum=addr^data;
break;
case 5: //IDLE;
data=0b00000000;
cksum=addr^data;
break;
}
//unMessage.adresse=addr;
// unMessage.vitesse=data;
// unMessage.cksum = unMessage.adresse ^ unMessage.vitesse;
//memcpy(payload, &unMessage, sizeof unMessage);
//DccByteCount=sizeof unMessage;
paquet=(paquet_start << 27) |(addr<<19)|(startBit<<18)|(data<<10)|(startBit<<9)|(cksum<<1)|(stopBit<<0);
}
void loop() {
SpeedAndDir( 3, CRAN_1,128, 1);
delay(50000);
}