Índice general Foros Digital, Electricidad e Informática Tutorial como mover desvios con servos y arduino con la z21

Tutorial como mover desvios con servos y arduino con la z21

Moderador: 241-2001



Desconectado
Mensajes: 25
Registrado: 19 Abr 2016 10:40
Bueno esta es mi primera aportación al foro, espero hacer el tutorial lo mejor posible :D.
Lo primero es agradecer a Norber toda la información que me a dado para poder hacer este decodificador DCC de accesorios. Sin él me hubiera resultado imposible. Muchas gracias Norber.

Como dice el título, es un circuito con un Arduino Nano que nos permite mover desvíos con servos desde la central XpressNet o la tablet usando la z21.
El decodificador puede mover hasta 6 servos y hasta 11 señales de dos aspectos a la vez.

Para hacer este decodificador necesitaremos:
- 1 Arduino Nano
- 1 Optoacoplador 6N137 (ó 6N135)
- 1 Diodo 1N4004
- 1 LED verde alto brillo
- 1 Resistencia 2K2Ω
- 2 Resistencias 10kΩ
- Zócalos y conectores al gusto.
- 1 Placa de circuito impreso cuyo fotolito se saca del PDF adjunto
- 1 fuente de alimentación 5 V cc de PC.

1ª Parte: la fuente de alimentación de PC.
- Con la fuente de PC podremos disponer de varias tensiones muy útiles para la maqueta: 3.3 V, 5 V, 12 V y otras.
- Para este circuito necesitaremos 5 V que cogeremos de cualquier par de cables rojo y negro.
- Para que arranque la fuente tendremos que unir o ponerle un interruptor al único cable verde con uno negro, (en la web hay muchos tutoriales de como hacerlo).

2ª Parte: el circuito.
- Os adjunto el PDF para imprimir. Hay varios metodos para hacer el circuito. Yo he usado el metodo de la plancha (en la web de Paco Cañadas hay un tutorial de como se hace).
- Soldar los componentes. En el adjunto viene también la posición de la polaridad que tenéis que ponerlos.
- Las resistencias de las señales las ponéis a vuestro gusto, pero nunca serán inferiores a 1 kΩ para que el consumo
que soporte el micro del Arduino no lo dañe.

http://www.forotrenes.com/foro/download/file.php?mode=view&id=422832&sid=497b08a9c1e2e78ace8b4ee4c631edbe
11.png
11.png (470.1 KiB) Visto 7246 veces
http://www.forotrenes.com/foro/download/file.php?mode=view&id=422833&sid=497b08a9c1e2e78ace8b4ee4c631edbe

3ª parte: programar el Arduino Nano:
- Hay que instalar el software del Arduino (Arduino IDE, gratuito).
- Una vez abierto el programa, conectar el Arduino al PC, y sobre un sketch completamente en blanco copiar y pegar el siguiente código:
   /* Arduino Nano Pro as
- DCC accessory decoder
- (x7) Servo controller
- (x10) Two aspects signal controller

Code by German Trinidad and Norber, October 2016
Freely distributable for private, non commercial, use.

Connections for DCC (adapted through 6N137 fast optocoupler):
DCC sig to ARD pin 2
*/

// *****************************************************************
// Ajustar y asignar direcciones desde aqui....
// *****************************************************************

#define ADR_MMAUS_01 30 // Multimaus address for signal 01 on Arduino pin D3
#define ADR_MMAUS_02 31 // Multimaus address for signal 02 on Arduino pin D4
#define ADR_MMAUS_03 32 // Multimaus address for signal 03 on Arduino pin D5
#define ADR_MMAUS_04 33 // Multimaus address for signal 04 on Arduino pin D6
#define ADR_MMAUS_05 34 // Multimaus address for signal 05 on Arduino pin D7
#define ADR_MMAUS_06 35 // Multimaus address for signal 06 on Arduino pin D8
#define ADR_MMAUS_07 36 // Multimaus address for signal 07 on Arduino pin D9
#define ADR_MMAUS_08 37 // Multimaus address for signal 08 on Arduino pin D10
#define ADR_MMAUS_09 38 // Multimaus address for signal 09 on Arduino pin D11
#define ADR_MMAUS_10 39 // Multimaus address for signal 10 on Arduino pin D12

#define ADR_MMAUS_11 42 // Multimaus address for servo 01 on Arduino pin D13
#define ADR_MMAUS_12 43 // Multimaus address for servo 02 on Arduino pin A0
#define ADR_MMAUS_13 44 // Multimaus address for servo 03 on Arduino pin A1
#define ADR_MMAUS_14 45 // Multimaus address for servo 04 on Arduino pin A2
#define ADR_MMAUS_15 46 // Multimaus address for servo 05 on Arduino pin A3
#define ADR_MMAUS_16 47 // Multimaus address for servo 06 on Arduino pin A4
#define ADR_MMAUS_17 48 // Multimaus address for servo 07 on Arduino pin A5

// *****************************************************************
// ...hasta aqui. El resto no hay que tocarlo.
// *****************************************************************

#define NUM_DCC_ADDR 17 // Number of DCC addresses to be processed
#define SI 0
#define NO 1

#define TICKS 180 // Prescaler 8 -> pulso de Timer cada 0.5 µs -> 200 ticks son 100 µs
#define SLOTuS 6660 // Ajuste de servos = 6660 No tocar
#define VEL 20 // Velocidad del movimiento de todos los servos
#define DESV 2000 // Posicion desviada: mínimo 1000 y siempre múltiplo entero de VEL
#define RECT 4000 // Posicion recta: maximo 4500 y siempre múltiplo entero de VEL

volatile byte buf_dcc[6]; // Buffer del último comando recibido
volatile boolean comandoRecibido = false;
volatile byte activeAcc = NUM_DCC_ADDR - 1;
volatile int counter = 0, sumar, dif;

struct Accesorios {
byte address;
byte port;
byte pin;
boolean Serv;
int pNow;
int pTgt;
};

Accesorios miAcc[] = {
//Address , Port , Pin, Serv , pNow, pTgt
{((ADR_MMAUS_01 - 1) / 4) + 128, ((ADR_MMAUS_01 - 1) % 4), 3 , false, DESV, DESV },
{((ADR_MMAUS_02 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 , false, DESV, DESV },
{((ADR_MMAUS_03 - 1) / 4) + 128, ((ADR_MMAUS_03 - 1) % 4), 5 , false, DESV, DESV },
{((ADR_MMAUS_04 - 1) / 4) + 128, ((ADR_MMAUS_04 - 1) % 4), 6 , false, DESV, DESV },
{((ADR_MMAUS_05 - 1) / 4) + 128, ((ADR_MMAUS_05 - 1) % 4), 7 , false, DESV, DESV },
{((ADR_MMAUS_06 - 1) / 4) + 128, ((ADR_MMAUS_06 - 1) % 4), 8 , false, DESV, DESV },
{((ADR_MMAUS_07 - 1) / 4) + 128, ((ADR_MMAUS_07 - 1) % 4), 9 , false, RECT, RECT },
{((ADR_MMAUS_08 - 1) / 4) + 128, ((ADR_MMAUS_08 - 1) % 4), 10 , false, RECT, RECT },
{((ADR_MMAUS_09 - 1) / 4) + 128, ((ADR_MMAUS_09 - 1) % 4), 11 , false, DESV, DESV },
{((ADR_MMAUS_10 - 1) / 4) + 128, ((ADR_MMAUS_10 - 1) % 4), 12 , false, DESV, DESV },
{((ADR_MMAUS_11 - 1) / 4) + 128, ((ADR_MMAUS_11 - 1) % 4), 13 , true , DESV, DESV },
{((ADR_MMAUS_12 - 1) / 4) + 128, ((ADR_MMAUS_12 - 1) % 4), A0 , true , DESV, DESV },
{((ADR_MMAUS_13 - 1) / 4) + 128, ((ADR_MMAUS_13 - 1) % 4), A1 , true , DESV, DESV },
{((ADR_MMAUS_14 - 1) / 4) + 128, ((ADR_MMAUS_14 - 1) % 4), A2 , true , DESV, DESV },
{((ADR_MMAUS_15 - 1) / 4) + 128, ((ADR_MMAUS_15 - 1) % 4), A3 , true , DESV, DESV },
{((ADR_MMAUS_16 - 1) / 4) + 128, ((ADR_MMAUS_16 - 1) % 4), A4 , true , DESV, DESV },
{((ADR_MMAUS_17 - 1) / 4) + 128, ((ADR_MMAUS_17 - 1) % 4), A5 , true , DESV, DESV }
};

void setup() {
pinMode(2, INPUT); // pin2 = DCC
for (int i = 3; i < 19; i++) {
pinMode(i, OUTPUT);
digitalWrite(i, HIGH);
}
attachInterrupt(0, dcc_int, CHANGE); // pin2 = DCC externalInterrupt 0
cli();
// Prescaler 8 (0.5 µs/tick) en Timer0 - DCC
TCCR0A = 0;
TCCR0B = 0;
TCCR0B |= (1 << CS01);
// Fast PWM frecuencia fija, mode 14
TCCR1A = 0;
TCCR1B = 0;
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM13) | (1 << WGM12);
ICR1 = SLOTuS; // Frecuencia fija PWM
// Prescaler 8 (0.5 µs/tick) en Timer1 - Servos
TCCR1B |= (1 << CS11);
// Activar interrupciones Timer1 tipo Compare-Match-A & Overflow
TIMSK1 = 0;
TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1);
sei();
}

void loop() {
static byte servo, estado;
if (comandoRecibido == true) {
byte port = buf_dcc[1];
byte addr = buf_dcc[0];
byte port1 = (port & 0x06) >> 1; // 0x06 = B0000 0110
for (int i = NUM_DCC_ADDR - 1; i > -1; i--) {
if ((addr == miAcc[i].address) && (port1 == miAcc[i].port)) { // De los míos
if (miAcc[i].Serv) { // It's a servo
if (port & 0x01) miAcc[i].pTgt = DESV; // pulsado √
else miAcc[i].pTgt = RECT; // pulsado --
}
else { // Es una señal
if (port & 0x01) { // pulsado √
digitalWrite(miAcc[i].pin, HIGH);
}
else { // pulsado --
digitalWrite(miAcc[i].pin, LOW);
}
}
comandoRecibido = false;
break; // Acabar for-loop aquí
}
}
comandoRecibido = false;
}
}

void dcc_int() { // ISR(INT0_vect) Rutina de interrupción externa en pin2
static int tmp_pulso;
static byte bit_dcc;
static byte preamb;
static byte aux_dcc, x_or, idx, num_bits;
if (PIND & (0x04)) TCNT0 = 0; // pin2 acaba de pasar a HIGH
else { // cuando acaba de pasar a LOW
tmp_pulso = TCNT0; // lee los microsegundos (un byte)
if (tmp_pulso > TICKS) bit_dcc = 0; // duración mayor de XX us => cero
else bit_dcc = 1; // y menor uno
if (preamb == SI) { // preámbulo
if (bit_dcc) { // otro '1'
if (num_bits) num_bits--;
}
else {
if (!num_bits) { // el '0' de inicio de datos
preamb = NO;
num_bits = 9;
x_or = 0;
idx = 0;
}
else num_bits = 10; // no se cumple la trama, vuelta a inicio
}
}
else { // recepción de los bytes
if (--num_bits) aux_dcc = aux_dcc * 2 + bit_dcc;
else { // el separador de bytes
if (!bit_dcc) { // cero, a por el siguiente byte
buf_dcc [idx++] = aux_dcc;
x_or ^= aux_dcc; // actualiza la x_or
num_bits = 9;
}
else { // uno, fin del paquete
preamb = SI;
num_bits = 10; // vuelta a empezar
if (x_or == aux_dcc) comandoRecibido = true; // paquete correcto
}
}
}
}
}

ISR(TIMER1_OVF_vect) { // Interrupción rebose Timer1 para servos cada 3300 µS
if (miAcc[activeAcc].Serv && sumar) {
digitalWrite(miAcc[activeAcc].pin, HIGH);
}
}

ISR(TIMER1_COMPA_vect) { // Interrupción Compare-Match-A del Timer1 para servos
digitalWrite(miAcc[activeAcc].pin, LOW);
if (--activeAcc < 10) activeAcc = NUM_DCC_ADDR - 1;
sumar = 0;
dif = miAcc[activeAcc].pNow - miAcc[activeAcc].pTgt;
if (dif < 0) sumar = VEL;
else if (dif > 0) sumar = -VEL;
if (sumar) {
miAcc[activeAcc].pNow += sumar;
OCR1A = miAcc[activeAcc].pNow;
}
}

Luego pulsar en "Verificar" para comprobar que el código se ha pegado bien, pulsar en "Subir" y ya estará programado el Arduino.

Sobre los ángulos y velocidad de los servos, tenéis que modificar las líneas siguientes del código:

#define VEL 20 // Velocidad del movimiento de todos los servos
#define DESV 2000 // Posición desviada: mínimo 1000 y siempre múltiplo entero de VEL
#define RECT 4000 // Posición recta: máximo 4500 y siempre múltiplo entero de VEL

Para ir a "múltiplos enteros de VEL", que como podéis ver vale "20", varía de veinte en veinte los valores de "DESV" y de "RECT" y vais probando hasta conseguir la posición que necesitáis. Con valores de VEL menores, por ejemplo 10, los servos van más despacio. Pero siempre hay que respetar la regla de que "DESV" y "RECT" sean múltiplos enteros de VEL.

4ª Parte: crear los desvíos y señales en nuestra central, conectar la fuente PC al decodificador (GND, 5V+ ) y la z21 (J K) y todo debería funcionar.
Espero haber sido lo más claro posible.
Última edición por Manu13 el 08 Ago 2018 09:26, editado 1 vez en total


Desconectado
Mensajes: 6372
Registrado: 19 Ago 2009 20:39

Interesante! Una cosa que no sabía!
Si crees que te he servido de ayuda, puedes invitarme a un café alfredpuro (a) telefonica .net

l'Alfred, el Fantito.


Desconectado
Mensajes: 11
Registrado: 04 Dic 2009 00:40
Buen tutorial, muy útil!


Desconectado
Mensajes: 24
Registrado: 27 Dic 2016 10:43
Si no te importa, podrias pasar un archivo con el esquema electrico?


Desconectado
Mensajes: 94
Ubicación: Barcelona, España
Registrado: 16 Feb 2010 23:30
Hola Manu, felicidades por esta trabajo tuyo, resperto a Norber es un autentico maestro.
Queria me aclararas los servos como se accionan ?, me supongo deber a ver algún pulsador pero no he visto donde.

Un saludo
Central Multimaus Roco.
Interface GenLI.
Decos Servopoint Opto.
MicroServos china 9 grs. sg90.
Software ROCRAIL.
Portatil Acer Aspire 5310.
Tablet Samsung.


Desconectado
Mensajes: 751
Ubicación: Salamanca
Registrado: 12 Ene 2012 14:44
Gracias a ti Manu, por el tiempo dedicado a hacer el tutorial.



Sergio-76 escribió:
Si no te importa, podrias pasar un archivo con el esquema electrico?

    - La señal DCC llega al pin 2 del Arduino a través de un optoacoplador según el esquema clásico que verás en mil sitios.
    - Los pines D3 a D12 son para las 10 señales.
    - Los pines D13 y A0 a A5 son para los 6 servos.
No disponemos de esquema eléctrico.
Saludos

[Multimaus + GenLi-S88 + +z21f. + RocRail (MacOsX)]
H0 Renfe, sin catenaria


Desconectado
Mensajes: 25
Registrado: 19 Abr 2016 10:40
Gracias, los servos se accionan desde la misma app de rocoz21 o desde el multimaus.


Desconectado
Mensajes: 1981
Ubicación: Huelva
Registrado: 13 Abr 2014 20:52

Muchas gracias por el tutorial, Manu13. Aunque es algo que me supera ya que no poseo conocimientos de electrónica ni electricidad pero me guardo el hilo para futuros proyectos.

Saludos.


Desconectado
Mensajes: 25
Registrado: 19 Abr 2016 10:40


Desconectado
Mensajes: 262
Registrado: 28 Oct 2015 09:35
Hola Manu13, muchas gracias por compatir esto.
Una pregunta rápida, cada servo puede tener diferentes ángulo de funcionamiento?

Muchas gracias


Desconectado
Mensajes: 25
Registrado: 19 Abr 2016 10:40
Creo que no, que es el mismo ángulo y velocidad para todos los servos, pero es Norber el que ha hecho el código, el te podrá asesorar mejor.
Pero el circuito en si, es muy económico y puedes hacer varios según te convenga, el arduino que es lo más caro lo puedes comprar en China.


Desconectado
Mensajes: 262
Registrado: 28 Oct 2015 09:35
Gracias Manu13.
Lo tengo en cuenta.
Saludos.


Desconectado
Mensajes: 751
Ubicación: Salamanca
Registrado: 12 Ene 2012 14:44
Para que cada servo tenga un ángulo distinto las modificaciones del código no son muchas. Buscad en el código original y cambiadlo conforme a esto que sigue (el resto no habría que tocarlo):


struct Accesorios {
byte address;
byte port;
byte pin;
boolean Serv;
int pNow;
int pTgt;
int posRecta;
int posDesviada;
};

Accesorios miAcc[] = {
//Address , Port , Pin, Serv , pNow, pTgt, posRecta, posDesviada
{((ADR_MMAUS_01 - 1) / 4) + 128, ((ADR_MMAUS_01 - 1) % 4),3 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_02 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4),4 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_03 - 1) / 4) + 128, ((ADR_MMAUS_03 - 1) % 4),5 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_04 - 1) / 4) + 128, ((ADR_MMAUS_04 - 1) % 4),6 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_05 - 1) / 4) + 128, ((ADR_MMAUS_05 - 1) % 4),7 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_06 - 1) / 4) + 128, ((ADR_MMAUS_06 - 1) % 4),8 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_07 - 1) / 4) + 128, ((ADR_MMAUS_07 - 1) % 4),9 , false,RECT, RECT, DESV, RECT },
{((ADR_MMAUS_08 - 1) / 4) + 128, ((ADR_MMAUS_08 - 1) % 4),10 ,false,RECT, RECT, DESV, RECT },
{((ADR_MMAUS_09 - 1) / 4) + 128, ((ADR_MMAUS_09 - 1) % 4),11 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_10 - 1) / 4) + 128, ((ADR_MMAUS_10 - 1) % 4),12 ,false,DESV, DESV, DESV, RECT },

{((ADR_MMAUS_11 - 1) / 4) + 128, ((ADR_MMAUS_01 - 1) % 4), 3 ,true,2000, 2000, 2000, 4000 },
{((ADR_MMAUS_12 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 ,true,2100, 2100, 2100, 3800 },
{((ADR_MMAUS_13 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 ,true,2250, 2250, 2250, 3900 },
{((ADR_MMAUS_14 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 ,true,2400, 2400, 2400, 4200 },
{((ADR_MMAUS_15 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 ,true,1700, 1700, 1700, 3800 },
{((ADR_MMAUS_16 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 ,true,2100, 2100, 2100, 3800 },
{((ADR_MMAUS_17 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 ,true,2000, 2000, 2000, 4350 },
};




if (port & 0x01) miAcc[i].pTgt = miAcc[i].posDesviada; // pulsado √
else miAcc[i].pTgt = miAcc[i].posRecta; // pulsado --






Es importante que respetéis el patrón del ejemplo, en el que cada servo va a tener un ángulo de giro distinto según se programen en el código los valores de 'posRecta' y 'posDesviada'.

He preferido indicaros solo las modificaciones al código original, en lugar de publicar el código entero ya cambiado, para que aquel de vosotros que se anime a incorporarlas sea quien informe de si funcionan o no. Ánimo, que no es tan difícil!!!
Saludos

[Multimaus + GenLi-S88 + +z21f. + RocRail (MacOsX)]
H0 Renfe, sin catenaria


Desconectado
Mensajes: 262
Registrado: 28 Oct 2015 09:35
Gracias Norber, me pondré con ello.
Me gusta bastante el programa sobre todo el tema que al final del recorrido del servo la señal del mismo se queda sin tensión.

Saludos.


Desconectado
Mensajes: 262
Registrado: 28 Oct 2015 09:35
Hola compañeros.
He modificado el programa que nuestros compañeros han colgado y con sus orientaciones, para que cada servo tenga un ángulo
de trabajo diferentes.

Las modificaciones o las líneas que tenemos que Añadir están marcadas.

    /* Arduino Nano Pro as
- DCC accessory decoder
- (x7) Servo controller
- (x10) Two aspects signal controller

Code by German Trinidad and Norber, October 2016
Freely distributable for private, non commercial, use.

Connections for DCC (adapted through 6N137 fast optocoupler):
DCC sig to ARD pin 2
*/

// *****************************************************************
// Ajustar y asignar direcciones desde aqui....
// *****************************************************************

#define ADR_MMAUS_01 30 // Multimaus address for signal 01 on Arduino pin D3
#define ADR_MMAUS_02 31 // Multimaus address for signal 02 on Arduino pin D4
#define ADR_MMAUS_03 32 // Multimaus address for signal 03 on Arduino pin D5
#define ADR_MMAUS_04 33 // Multimaus address for signal 04 on Arduino pin D6
#define ADR_MMAUS_05 34 // Multimaus address for signal 05 on Arduino pin D7
#define ADR_MMAUS_06 35 // Multimaus address for signal 06 on Arduino pin D8
#define ADR_MMAUS_07 36 // Multimaus address for signal 07 on Arduino pin D9
#define ADR_MMAUS_08 37 // Multimaus address for signal 08 on Arduino pin D10
#define ADR_MMAUS_09 38 // Multimaus address for signal 09 on Arduino pin D11
#define ADR_MMAUS_10 39 // Multimaus address for signal 10 on Arduino pin D12

#define ADR_MMAUS_11 42 // Multimaus address for servo 01 on Arduino pin D13
#define ADR_MMAUS_12 43 // Multimaus address for servo 02 on Arduino pin A0
#define ADR_MMAUS_13 44 // Multimaus address for servo 03 on Arduino pin A1
#define ADR_MMAUS_14 45 // Multimaus address for servo 04 on Arduino pin A2
#define ADR_MMAUS_15 46 // Multimaus address for servo 05 on Arduino pin A3
#define ADR_MMAUS_16 47 // Multimaus address for servo 06 on Arduino pin A4
#define ADR_MMAUS_17 48 // Multimaus address for servo 07 on Arduino pin A5

// *****************************************************************
// ...hasta aqui. El resto no hay que tocarlo.
// *****************************************************************

#define NUM_DCC_ADDR 17 // Number of DCC addresses to be processed
#define SI 0
#define NO 1

#define TICKS 180 // Prescaler 8 -> pulso de Timer cada 0.5 µs -> 200 ticks son 100 µs
#define SLOTuS 6660 // Ajuste de servos = 6660 No tocar
#define VEL 10 // Velocidad del movimiento de todos los servos
#define DESV 2000 // Posicion desviada: mínimo 1000 y siempre múltiplo entero de VEL
#define RECT 4000 // Posicion recta: maximo 4500 y siempre múltiplo entero de VEL

volatile byte buf_dcc[6]; // Buffer del último comando recibido
volatile boolean comandoRecibido = false;
volatile byte activeAcc = NUM_DCC_ADDR - 1;
volatile int counter = 0, sumar, dif;

struct Accesorios {
byte address;
byte port;
byte pin;
boolean Serv;
int pNow;
int pTgt;
//------------------------- Añadir ------
int posRecta;
int posDesviada;
//---------------------------------------
};

//------------------------- Añadir ------

Accesorios miAcc[] = {
//Address , Port , Pin, Serv , pNow, pTgt, posRecta, posDesviada
{((ADR_MMAUS_01 - 1) / 4) + 128, ((ADR_MMAUS_01 - 1) % 4),3 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_02 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4),4 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_03 - 1) / 4) + 128, ((ADR_MMAUS_03 - 1) % 4),5 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_04 - 1) / 4) + 128, ((ADR_MMAUS_04 - 1) % 4),6 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_05 - 1) / 4) + 128, ((ADR_MMAUS_05 - 1) % 4),7 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_06 - 1) / 4) + 128, ((ADR_MMAUS_06 - 1) % 4),8 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_07 - 1) / 4) + 128, ((ADR_MMAUS_07 - 1) % 4),9 , false,RECT, RECT, DESV, RECT },
{((ADR_MMAUS_08 - 1) / 4) + 128, ((ADR_MMAUS_08 - 1) % 4),10 ,false,RECT, RECT, DESV, RECT },
{((ADR_MMAUS_09 - 1) / 4) + 128, ((ADR_MMAUS_09 - 1) % 4),11 ,false,DESV, DESV, DESV, RECT },
{((ADR_MMAUS_10 - 1) / 4) + 128, ((ADR_MMAUS_10 - 1) % 4),12 ,false,DESV, DESV, DESV, RECT },

{((ADR_MMAUS_11 - 1) / 4) + 128, ((ADR_MMAUS_11 - 1) % 4), 13 ,true,2000, 2000, 2000, 4000 },
{((ADR_MMAUS_12 - 1) / 4) + 128, ((ADR_MMAUS_12 - 1) % 4), A0 ,true,2100, 2100, 2100, 3800 },
{((ADR_MMAUS_13 - 1) / 4) + 128, ((ADR_MMAUS_13 - 1) % 4), A1 ,true,2250, 2250, 2250, 3900 },
{((ADR_MMAUS_14 - 1) / 4) + 128, ((ADR_MMAUS_14 - 1) % 4), A2 ,true,2400, 2400, 2400, 4200 },
{((ADR_MMAUS_15 - 1) / 4) + 128, ((ADR_MMAUS_15 - 1) % 4), A3 ,true,1700, 1700, 1700, 3800 },
{((ADR_MMAUS_16 - 1) / 4) + 128, ((ADR_MMAUS_16 - 1) % 4), A4 ,true,3100, 1800, 3100, 1800 },
{((ADR_MMAUS_17 - 1) / 4) + 128, ((ADR_MMAUS_17 - 1) % 4), A5 ,true,1800, 1500, 1800, 1500 },
};
//-------------------------------------------------------------------------------------

//
//
//--------------------  Reemplazar o eliminar------------------------------------------
/*Accesorios miAcc[] = {
//Address , Port , Pin, Serv , pNow, pTgt
{((ADR_MMAUS_01 - 1) / 4) + 128, ((ADR_MMAUS_01 - 1) % 4), 3 , false, DESV, DESV },
{((ADR_MMAUS_02 - 1) / 4) + 128, ((ADR_MMAUS_02 - 1) % 4), 4 , false, DESV, DESV },
{((ADR_MMAUS_03 - 1) / 4) + 128, ((ADR_MMAUS_03 - 1) % 4), 5 , false, DESV, DESV },
{((ADR_MMAUS_04 - 1) / 4) + 128, ((ADR_MMAUS_04 - 1) % 4), 6 , false, DESV, DESV },
{((ADR_MMAUS_05 - 1) / 4) + 128, ((ADR_MMAUS_05 - 1) % 4), 7 , false, DESV, DESV },
{((ADR_MMAUS_06 - 1) / 4) + 128, ((ADR_MMAUS_06 - 1) % 4), 8 , false, DESV, DESV },
{((ADR_MMAUS_07 - 1) / 4) + 128, ((ADR_MMAUS_07 - 1) % 4), 9 , false, RECT, RECT },
{((ADR_MMAUS_08 - 1) / 4) + 128, ((ADR_MMAUS_08 - 1) % 4), 10 , false, RECT, RECT },
{((ADR_MMAUS_09 - 1) / 4) + 128, ((ADR_MMAUS_09 - 1) % 4), 11 , false, DESV, DESV },
{((ADR_MMAUS_10 - 1) / 4) + 128, ((ADR_MMAUS_10 - 1) % 4), 12 , false, DESV, DESV },
{((ADR_MMAUS_11 - 1) / 4) + 128, ((ADR_MMAUS_11 - 1) % 4), 13 , true , DESV, DESV },
{((ADR_MMAUS_12 - 1) / 4) + 128, ((ADR_MMAUS_12 - 1) % 4), A0 , true , DESV, DESV },
{((ADR_MMAUS_13 - 1) / 4) + 128, ((ADR_MMAUS_13 - 1) % 4), A1 , true , DESV, DESV },
{((ADR_MMAUS_14 - 1) / 4) + 128, ((ADR_MMAUS_14 - 1) % 4), A2 , true , DESV, DESV },
{((ADR_MMAUS_15 - 1) / 4) + 128, ((ADR_MMAUS_15 - 1) % 4), A3 , true , DESV, DESV },
{((ADR_MMAUS_16 - 1) / 4) + 128, ((ADR_MMAUS_16 - 1) % 4), A4 , true , DESV, DESV },
{((ADR_MMAUS_17 - 1) / 4) + 128, ((ADR_MMAUS_17 - 1) % 4), A5 , true , 3000, 2500 }
};*/
//----------------------------------------------------------------------------------
void setup() {
pinMode(2, INPUT); // pin2 = DCC
for (int i = 3; i < 19; i++) {
pinMode(i, OUTPUT);
digitalWrite(i, HIGH);
}
attachInterrupt(0, dcc_int, CHANGE); // pin2 = DCC externalInterrupt 0
cli();
// Prescaler 8 (0.5 µs/tick) en Timer0 - DCC
TCCR0A = 0;
TCCR0B = 0;
TCCR0B |= (1 << CS01);
// Fast PWM frecuencia fija, mode 14
TCCR1A = 0;
TCCR1B = 0;
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM13) | (1 << WGM12);
ICR1 = SLOTuS; // Frecuencia fija PWM
// Prescaler 8 (0.5 µs/tick) en Timer1 - Servos
TCCR1B |= (1 << CS11);
// Activar interrupciones Timer1 tipo Compare-Match-A & Overflow
TIMSK1 = 0;
TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1);
sei();
}

void loop() {
static byte servo, estado;
if (comandoRecibido == true) {
byte port = buf_dcc[1];
byte addr = buf_dcc[0];
byte port1 = (port & 0x06) >> 1; // 0x06 = B0000 0110
for (int i = NUM_DCC_ADDR - 1; i > -1; i--) {
if ((addr == miAcc[i].address) && (port1 == miAcc[i].port)) { // De los míos
if (miAcc[i].Serv) { // It's a servo

//------------------------------------ Añadir ---------------

if (port & 0x01) miAcc[i].pTgt = miAcc[i].posDesviada; // pulsado √
else miAcc[i].pTgt = miAcc[i].posRecta; // pulsado --

//------------------------------------------------------------

//-------------------------------------- Eliminar -------------
 
// if (port & 0x01) miAcc[i].pTgt = DESV; // pulsado √
//else miAcc[i].pTgt = RECT; // pulsado --

//--------------------------------------------------------------
}


else { // Es una señal
if (port & 0x01) { // pulsado √
digitalWrite(miAcc[i].pin, HIGH);
}
else { // pulsado --
digitalWrite(miAcc[i].pin, LOW);
}
}
comandoRecibido = false;
break; // Acabar for-loop aquí
}
}
comandoRecibido = false;
}
}

void dcc_int() { // ISR(INT0_vect) Rutina de interrupción externa en pin2
static int tmp_pulso;
static byte bit_dcc;
static byte preamb;
static byte aux_dcc, x_or, idx, num_bits;
if (PIND & (0x04)) TCNT0 = 0; // pin2 acaba de pasar a HIGH
else { // cuando acaba de pasar a LOW
tmp_pulso = TCNT0; // lee los microsegundos (un byte)
if (tmp_pulso > TICKS) bit_dcc = 0; // duración mayor de XX us => cero
else bit_dcc = 1; // y menor uno
if (preamb == SI) { // preámbulo
if (bit_dcc) { // otro '1'
if (num_bits) num_bits--;
}
else {
if (!num_bits) { // el '0' de inicio de datos
preamb = NO;
num_bits = 9;
x_or = 0;
idx = 0;
}
else num_bits = 10; // no se cumple la trama, vuelta a inicio
}
}
else { // recepción de los bytes
if (--num_bits) aux_dcc = aux_dcc * 2 + bit_dcc;
else { // el separador de bytes
if (!bit_dcc) { // cero, a por el siguiente byte
buf_dcc [idx++] = aux_dcc;
x_or ^= aux_dcc; // actualiza la x_or
num_bits = 9;
}
else { // uno, fin del paquete
preamb = SI;
num_bits = 10; // vuelta a empezar
if (x_or == aux_dcc) comandoRecibido = true; // paquete correcto
}
}
}
}
}

ISR(TIMER1_OVF_vect) { // Interrupción rebose Timer1 para servos cada 3300 µS
if (miAcc[activeAcc].Serv && sumar) {
digitalWrite(miAcc[activeAcc].pin, HIGH);
}
}

ISR(TIMER1_COMPA_vect) { // Interrupción Compare-Match-A del Timer1 para servos
digitalWrite(miAcc[activeAcc].pin, LOW);
if (--activeAcc < 10) activeAcc = NUM_DCC_ADDR - 1;
sumar = 0;
dif = miAcc[activeAcc].pNow - miAcc[activeAcc].pTgt;
if (dif < 0) sumar = VEL;
else if (dif > 0) sumar = -VEL;
if (sumar) {
miAcc[activeAcc].pNow += sumar;
OCR1A = miAcc[activeAcc].pNow;
}
}



Solamente he realizado las modificaciones que nos han comentado, el trabajo de este programa es de nuestros compañero de Manu13 y Norber.
Lo he estado probando y he mi caso me soluciona algunos problemas que tenía.

Un saludo a todos.


Desconectado
Mensajes: 262
Registrado: 28 Oct 2015 09:35
He realizado esta placa basándome en el esquema que habéis colgado en los primero post.

Imagen

Imagen


Espero que os guste.
Un saludo.


Desconectado
Mensajes: 5
Registrado: 17 Ene 2019 23:48
Me parece genial, muchas gracias por la aportación.
Me surge una duda, la placa es para 6 servos, en mi caso tengo 14. Creo que algunos los podría juntar en el mismo pin ya que me gustaría moverlos a la vez. Mi duda es, como se interconexionan más de una de estas placas?
En mi caso en vez de la z21 lo conectaría a una DR5000, pero creo que da lo mismo en este aspecto.

Gracias de nuevo


Desconectado
Mensajes: 262
Registrado: 28 Oct 2015 09:35
Hola Pochy.
Son placas totalmente independientes, por un conector entra la señal DCC que será para toda la misma lógicamente y por la otra la alimentación a 5V.
Asigna la dirección de cada complemento en el arduino Nano como indican nuestros compañeros al comienzo del post, con lo que puedes activar 7 servos y 10 señales.
El tema de utilizar la misma salida para mover por ejemplo dos servo no te puedo ayudar, ya que en el caso mío tienen siempre una pequeña variación de posicionamiento o desplazamiento y utilizo siempre pines diferentes, lo que si puedes hacer es mover varios servos con una misma dirección de la centralita.
Espero haberte ayudado, un saludo a todos.


Desconectado
Mensajes: 302
Ubicación: Tres Cantos (Madrid)
Registrado: 30 Abr 2009 22:42
Hola:

Necesito ayuda, soy novato en el tema del arduino, y aprovechando el programa de Norber estoy intentando modificar el sketch para que, en una misma dirección, se mueva el servo y cambien las salidas a los leds y no lo logro.

Es para poder polarizar el corazón de los desvíos Peco electrofrog al mismo tiempo que, con el servo, cambio la posición de los espadines..

Una ayudita please.

Cèsar


Desconectado
Mensajes: 751
Ubicación: Salamanca
Registrado: 12 Ene 2012 14:44
No lo he probado nunca, pero se puede arreglar. Espero acertar (sin comprobar).

Mira en las líneas 26 y 28: he asignado al accesorio de dirección "39" tanto la salida 10 como la 11.

asig_direcc_DCC.png
asig_direcc_DCC.png (18.65 KiB) Visto 4574 veces


Como en la línea 75 a la salida 10 se la trata como "señal" (pone false) y en la línea 76 a la salida 11 se la trata como "servo" (pone true)

macros.png
macros.png (17.35 KiB) Visto 4574 veces


cuando en el programa, concretamente en la función void loop() se verifique si el comando DCC recibido (cambio del accesorio "39") se dirige a la salida 10 (y la respuesta será afirmativa, porque esa salida la hemos asignado al accesorio "39") lo siguiente es ver si se trata de la salida para un servo (y la respuesta es no), por lo que no se ejecutan las líneas 152 a 155 sino las líneas 156 a 163 (y se cambia la señal).

void_loop.png
void_loop.png (15.54 KiB) Visto 4574 veces


Pero luego, tocaría ver el si el comando DCC recibido (que sigue siendo cambiar el accesorio "39") se dirige a la salida 11 (y la respuesta también sería afirmativa), y al ver que sí es un servo, se ejecutarían las líneas 152 a 155. ¿Por qué no ocurre así?

La "culpa" está en la línea 165: el programa supone que en cuanto se modifique el accesorio (y se hace al llegar a la salida 10) ya se ha obedecido el comando DCC, y se puede dar por terminada la actuación (y no se comprueba si también hay que modificar la salida 11). El programa ejecuta un break; y se sale del bucle verificador de salidas y de la función entera, quedando a la espera del siguiente comando DCC.

Prueba, por tanto, a eliminar la línea 165.

Para ello no hay que borrarla: basta anteponerle // (dos barras). Con eso el compilador entenderá que no forma parte del código y no la ejecutará nunca. Eso se llama comentar una línea. Si es un comentario, no es código a ejecutar.

La línea 164 también sobraría. Coméntala también.

Y a ver qué pasa. Suerte! :D
Saludos

[Multimaus + GenLi-S88 + +z21f. + RocRail (MacOsX)]
H0 Renfe, sin catenaria

Siguiente

Volver a Digital, Electricidad e Informática

Síguenos en Facebook Síguenos en Youtube Síguenos en Instagram Feed - Nuevos Temas
©2017   -   Información Legal
cron