Í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 830 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: 2784
Registrado: 19 Ago 2009 20:39
Interesante! Una cosa que no sabía!
l'Alfred, el Fantito.


Desconectado
Mensajes: 10
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: 61
Ubicación: Martorell (Barcelona)
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: 580
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: 1547
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: 102
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: 102
Registrado: 28 Oct 2015 09:35
Gracias Manu13.
Lo tengo en cuenta.
Saludos.


Desconectado
Mensajes: 580
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: 102
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: 102
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.


Volver a Digital, Electricidad e Informática

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