1
Débuter / Re : utilisation LMD18200 et mesure du courant
« le: juin 22, 2023, 03:29:24 pm »
merci!
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.
#include <NmraDcc.h>
#define DCC_PIN 2
NmraDcc Dcc;
void notifyDccAccTurnoutOutput(uint16_t Addr, uint8_t Direction, uint8_t OutputPower) {
Serial.print("Addr: ");Serial.print(Addr);
Serial.print("Direction: ");Serial.print(Direction);
Serial.print("OutputPower: ");Serial.print(OutputPower);
Serial.println("-----------------------------");
}
void setup() {
Serial.begin(115200);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
Dcc.pin(digitalPinToInterrupt(DCC_PIN),DCC_PIN, false);
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
}
void loop() {
Dcc.process();
}
#include <Arduino.h>
#include "driver/ledc.h"
volatile uint8_t schedule_p3[16], schedule_p3n=0; // variable volatile stockée dans RAM
volatile uint8_t schedule_p2[16], schedule_p2n=0;
volatile uint8_t schedule_p1[16], schedule_p1n=0;
volatile uint8_t schedule_p0[128], schedule_p0p=1,schedule_p0n=0 ;
volatile uint8_t packet_bits[128];
volatile uint8_t packets_length[128], packet_bit_pointer, packet_to_send=0;
volatile int scheduler_case;
volatile int prio;
// DEFINITION DE LA SORTIE PWM
#define DCC_PIN 22
// ON DEFINIT LES PULSIONS PWM
const uint16_t DCC_BIT_1_FREQ = 8621; // 116 microsecondes
const uint16_t DCC_BIT_0_FREQ = 5000; // 200 microsecondes
const int dcc_pin_channel = 0; // CANAL PWM 0
const int dcc_sig_resolution =1; // on est sur 1 bit de resolution 2^1 2 valeurs possibles
const int dcc_sig_duty=1; // on est sur 1 bit de resolution 1/2^1 50%
//initialisation de la frequence
uint32_t dcc_sig_freq=DCC_BIT_1_FREQ;
void example(void) {
packet_bits[0]=(uint64_t)0b111111111011111111011111111011111111111111111111; // case 0
packet_bits[1]=(uint64_t)0b111001111011101111011110011011111111111111011111; // case 4
packet_bits[2]=(uint64_t)0b111001111011101111011110011011111111111101111111; // case 3 on le renvoie 3 fois de suite
packet_bits[3]=(uint64_t)0b111001111011101111011110011011111111110111111111; // case 3
packet_bits[4]=(uint64_t)0b111001111011101111011110011011111110111111111111; // case 6
packet_bits[5]=(uint64_t)0b111001111011101111011110011011111110111111111111; // case 6
packets_length[0]=48;
//schedule_p0n++;schedule_p0[schedule_p0n]=1;
packets_length[1]=48;
//schedule_p0n++;schedule_p0[schedule_p0n]=2;
packets_length[2]=48;
//schedule_p0n++;schedule_p3[schedule_p3n]=3;
packets_length[3]=48;
schedule_p3n++;schedule_p0[schedule_p0n]=4;
packets_length[4]=48;
//schedule_p0n++;schedule_p0[schedule_p0n]=5;
packets_length[5]=48;
//schedule_p0n++;schedule_p0[schedule_p0n]=5;
scheduler_case=(schedule_p3n)?3:0;
}
// declration des voids
void scheduler(void);
void dcc_sig_isr();
void setup_ledc(void);
//static uint8_t parti=0; // test packet parti
void setup() {
// put your setup code here, to run once:
Serial.begin(460800);
setup_ledc();
example();
// pour commencer
//packet_to_send=0;
Serial.print("packet bit pointer:");Serial.println(packet_bit_pointer);
}
void loop() {
// if (packet_bit_pointer>48){
// packet_bit_pointer=0;
// Serial.print("err_pbp>5: ");Serial.print(packet_bit_pointer);
// }else if (packet_bit_pointer != 0) {
scheduler();
packet_bit_pointer=packets_length[packet_to_send];
//Serial.print("packet: ");Serial.print(packet_to_send); Serial.print(" pbp :"); Serial.println(packet_bit_pointer);
// }
//Serial.print(packet_bit_pointer);
//delay(1000);
}
void dcc_sig_isr() {
//if (dcc_sig_freq ==DCC_BIT_0_FREQ) dcc_sig_freq = DCC_BIT_1_FREQ ; // inverse la valeur du bit dcc précédent
//else dcc_sig_freq = DCC_BIT_0_FREQ;
static uint32_t old_dcc_sig_freq ; // fréquence précédente
if (packet_bit_pointer==0) {
dcc_sig_freq=DCC_BIT_1_FREQ; //on continue d envoyer des 1 tant qu on recoit rien
}else{
--packet_bit_pointer;
Serial.println(packet_bit_pointer);
uint64_t bit_pointer_mask=(uint64_t)1<<packet_bit_pointer;
if (bit_pointer_mask&packet_bits[packet_to_send]) {
dcc_sig_freq=DCC_BIT_1_FREQ; // si tu pointes 1 envoie 1
}else{
dcc_sig_freq=DCC_BIT_0_FREQ; // si tu pointes 0 envoie 0
}
}
if (dcc_sig_freq !=old_dcc_sig_freq) {
ledc_set_freq(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0,dcc_sig_freq);
dcc_sig_freq=old_dcc_sig_freq;
}
}
void setup_ledc() {
ledcSetup(dcc_pin_channel,dcc_sig_freq,dcc_sig_resolution);
ledcAttachPin(DCC_PIN,dcc_pin_channel);
ledcWrite(dcc_pin_channel,dcc_sig_duty);
attachInterrupt(DCC_PIN,dcc_sig_isr,RISING);
}
void scheduler(void) {
switch (scheduler_case) {
case 0:
switch (prio) {
case 0:
//Serial.println("prio 0 send 1");
packet_to_send=0;
prio=4;
break;
case 4:
// Serial.println("prio 0 send 1");
packet_to_send=1;
prio=5;
break;
case 5:
// Serial.println("prio 0 send 2");
packet_to_send=2;
prio=6;
break;
case 6:
// Serial.println("prio 0 send 2");
packet_to_send=4;
prio=7;
break;
case 7:
// Serial.println("prio 0 send 3");
packet_to_send=5;
scheduler_case = 3;
break;
}
//scheduler_case = 3;
break;
case 1:
// Serial.println("prio 1 send 3");
scheduler_case = 0;
packet_to_send=3;
prio=0;
break;
case 2:
// Serial.println("prio 1 send 2");
packet_to_send=3;
scheduler_case = 1;
break;
case 3:
// Serial.println("prio 1 send 1");
packet_to_send=3;
scheduler_case=2;
break;
}
}
#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);
}