Hola a todos/as
Dejé esto a medias por estar con otro "lio", que cerré ayer
Como decoder para controlar servos, además de los comerciales, hay muchos montajes en la web con PIC y con Arduino.
Para mover un servo, he optado por la opción de Arduino, usando el “attiny85” de la familia de micros usados en las placas Arduino, pero con un formato DIL8, programable desde el IDE de Arduino
Desde hace tiempo tenía ganas de usar este micro, poco a poco me metí en ello y este es el resultado, le he llamado SERVO_MOTOR_2020
Aquí está todo lo referente a cómo usar este chip
https://teslabem.com/arduino/programar- ... duino-uno/
El montaje se hace sobre un PCB de 35x38 mm, que encaja en el soporte del servo
En un principio el soporte era vertical, aunque simple, lo cambie por los problemas que explico en mi anterior post, cambiando la tapa de la versión final del soporte, el PCB encaja encima, quedando un montaje muy robusto.
En los adjuntos está el esquema y algunas fotos, el proyecto del PCB está aquí
https://circuitmaker.com/Projects#/servo-motor/7//1
Diferencias ATtiny85/UNO
Memoria Flash (KB) - 8/32, para el sketch
SRAM (kB) - 0.5/2, para las variables
Pins I/O - 6/22, sumando digitales y analógicos
Control del servo
La librería “Servo.h” que se instala por defecto al instalar el IDE usa un “timer” de 16 bits, este micro tiene un “timer” de 8 bits, he probado varias librerías para control del servo con este micro, la que me ha dado mejor resultado (y ocupa menos memoria) es la librería “SoftwareServo.h”, cuando movemos el servo hay que añadir una llamada a la función “SoftwareServo::refresh()”
Uso pin “reset”
Este micro tiene un pin de “reset”, también se puede usar como pin analógico o digital, pero es complicado hacerlo ya que hemos de programarlo quemando los fusibles del micro, con esto nos complicamos la vida para hacer marcha atrás y programarlo de nuevo, para no desperdiciar este pin, usaremos un “truco” para que sea fácil de usar en el sketch.
Para forzar un reset, la tensión de este pin ha de ser menor de 2,2V aproximadamente, con un partidor resistivo (ver esquema) mantenemos la tensión a unos 3.8V, cuando pulsamos K1 la tensión sube a 5V
En la función “ResetRead()”, con analogRead() obtenemos el valor digital correspondiente a 3.8V, alrededor de “650” y de “1023” para 5V, este valor lo comparamos con la variable “AnLimit”, si es inferior la tecla no está pulsada, si es superior la tecla está pulsada, con ello retornamos un 1 ó 0, como si de una lectura de un pin digital se tratara
Memoria
Este micro solo tiene 8K de memoria para el sketch, a diferencia de los 32K del UNO o NANO, con 8K se pueden hacer muchas cosas, pero hay que controlar el tamaño del sketch
El sketch
Inicialmente quería hacer un solo sketch para las dos versiones (analógico y digital), aunque hay funciones comunes complica mucho el seguimiento del proceso, terminé por hacer dos sketch
La programación la he hecho sobre un Arduino UNO, para poder tenerlo conectado por el puerto USB y usar el terminar serie como DEBUG, luego he hecho los ajustes sobre el ATTINY, al inicio del sketch hay unas directivas para el compilador (#define), para cambiar la compilación del programa según nos interese
#define ATTINY - habilita la compilación según micro, comentar para usar UNO/NANO
#define SERIAL_DEBUG - habilita Serial.print, usar solo con UNO/NANO
#define RELE - habilita el relé, comentar para no usar el relé
#define DOS_TECLAS - para usar una o dos teclas RECTO/DESVIADO en la versión analógica
El sketch esta comentado para poder seguir el flujo del proceso, al inicio se encuentra un manual de uso
Compilando la versión digital se ocupa el 91% del espacio en memoria para el ATTINY85
Código: Seleccionar todo
/*
Control de versiones
V1 - Funcionamiento para Arduino UNO
V2 - Funcionamiento para ATtiny85
V3 - Version final para ATtiny85, con rele monoestable
V4 - Cambio a rele biestable, pulsador en pin analógico
V5 - Se mejora el control del servo (attach/detach)
V6 - Se optimizan funciones de inicializaciónReducción para reducir el uso de memoria
MANUAL DE FUNCIONAMIENTO
Funcionamiento normal, desde la central se selecciona la dirección DCC programada, con las teclas +/- se cambia la posición del servo
Tecla multifunción K1, se usa para mover el servo manualmente y para la programación de la dirección DCC, la velocidad y los ángulos de desplazamiento del servo
K1 pulsado al arranque > mueve servo a posición central, se detiene el programa, para alinear los espadines en la instalación en la maqueta
K1 multifuncion, depende de la duración de la pulsación se accede a una función diferente, se ha de soltar la tecla en el momento adecuado para pasar a la función deseada
El paso de una funciona a otra se muestra con un parpadeo del LED, cada 3s aproximadamente
Pulsación corta (<3s) cambia la posición del servo, el relé cambia a mitad del recorrido
Pulsación (>3s y <6s), muestra la dirección DCC a base de destellos del LED, se muestran 4 dígitos
Pulsación (>6s y <9s), programación de una nueva dirección DCC, el led parpadea, hasta que se envíe una nueva dirección DCC desde la central
enviando una orden de cambio a la nueva dirección, esta quedará programada, el led de apagará
Pulsación (>9s y <12s), programación de los ángulos de desplazamiento
- El servo se mueve a posición central, el led parpadea
- Desde la central, seleccionando la dirección DCC programada, movemos el servo con las teclas +/-, para ajustar la posición RECTO
- Al pulsar K1, la posición del servo se guarda como posición RECTO del desvío
- El LED hace un parpadeo lento
- Desde la central, seleccionando la dirección DCC programada, movemos el servo con las teclas +/-, para ajustar la posición DESVIADO
- Al pulsar K1, la posición del servo se guarda como posición DESVIADO del desvío
- El LED se apaga
- Durante el ajuste, si el LED deja de parpadear y luce fijo, es el aviso de que se ha llegado al límite máximo/mínimo
- Al seleccionar por separado los angulos para las posiciones RECTO/DESVIADO, no importa la instalación mecánica del servo
Pulsación (>12s y <15s), programación de la velocidad de desplazamiento
- El servo se mueve alternativamente de un lado a otro, el led parpadea
- Desde la central, seleccionando la dirección DCC programada, movemos el servo con las teclas +/- para cambiar la velocidad de desplazamiento
- Al pulsar K1, la velocidad del servo se guarda, el LED se apaga
- Durante el ajuste, si el LED deja de parpadear y luce fijo, es el aviso que se ha llegado al límite máximo/mínimo
Pulsación (>15s)
- Se programan los valores por defecto, la dirección DCC pasa a ser la #1
*/
// configuración para la compilación
#define ATTINY // habilitar compilación según micro, comentar para usar UNO/NANO
//#define SERIAL_DEBUG // para habilitar Serial.print, solo con UNO
#define RELE // comentar para no usar relé
#if defined ATTINY // DEFINICIONES ATTINY85
#include <SoftwareServo.h> // libreria para el Servo 8 bits
SoftwareServo ElServo; // crea objeto servo
#define PinLED 0 // (5) pin LED
#define PinServo 1 // (6) pin servo
#define PinDCC 2 // (7) pin entrada DCC
#define PinKey1 A0 // (A0) pin tecla 1 cambio posición
#else // DEFINICIONES UNO / NANO
#include <Servo.h> // libreria para el Servo
Servo ElServo; // crea objeto servo
#define PinLED 13 // (13) pin LED
#define PinServo 11 // (11) pin servo
#define PinDCC 2 // (2) pin 2 como entrada de señal DCC
#define PinKey1 A0 // (A0) pin tecla 1 cambio de posición
#endif
#if defined RELE
#define PinReleRecto 3 // (2) pin control relé posición recto
#define PinReleDesvi 4 // (3) pin control relé posición desviado
#define RELE_RECTO {digitalWrite(PinReleRecto, LOW); LedOFF; delay(10); digitalWrite(PinReleRecto, HIGH); LedON;}
#define RELE_DESVI {digitalWrite(PinReleDesvi, LOW); LedOFF; delay(10); digitalWrite(PinReleDesvi, HIGH); LedON;}
#endif
// Otras librerias usadas
#include <EEPROM.h> // Se usa la EEPROM para guardar los valores de configuracion
#include <NmraDcc.h> // Gestion DCC
// variables de control y asignacion
NmraDcc Dcc; // objeto control DCC
#define LimitMin 1 // limite minimo de desplazamiento, el valor 0 da problemas con algún servo
#define LimitMax 91 // limite maximo de desplazamiento
#define PosMid (LimitMax - LimitMin) / 2 // posición media según LimitMin y LimitMax
#define VelRet 30 // retardo por defecto para ajustes, a menor valor movimiento más rápido, "SIEMPRE mayor que 0"
#define SrvRetMax 75 // retardo máximo para movimiento del servo, a menor valor movimiento más rápido, "SIEMPRE mayor que 0"
#define SrvRetMin 10 // retardo minimo para movimiento del servo, "SIEMPRE mayor que 0"
#define WaitTime 300 // tiempo de espara para acciones especiales al pulsar una tecla
#define AnLimit 900 // usamos el pin de RESET como pin analógico, este es el límite para leer pulsación
#define LedOFF digitalWrite(PinLED, HIGH)
#define LedON digitalWrite(PinLED, LOW)
#define LedFlashTime 20 // frecuencia de parpadeo de un LED con millis()
#define LedFlash {LedON; delay(LedFlashTime);LedOFF;}
#define LedOnOff {digitalWrite(PinLED, !digitalRead(PinLED)); prevMillis = millis();} // control parpadeo LED
#define WaitNewDirDCC 15000 // tiempo de espera para recibir una nueva direccion DCC
// variables de trabajo para el control del movimiento del servo
int Contador; // variable de uso general como contador
byte PosActual; // posición actual del servo
byte PosRecto; // posición para desvío recto
byte PosDesvi; // posición para desvío desviado
byte Retardo; // valor para velocidad de movimiento
#if defined RELE
byte PosRele; // Posición donde se activa el rele
#endif
long prevMillis = 0; // variable para almacenar valor previo de millis()
boolean NewDirDCC = false; // true = en proceso de capturar nueva dirección
boolean NewSetDCC = false; // true = en proceso de capturar nueva posición/velocidad del servo
byte AjtPosVel = 3; // control para lectura de teclas +/- desde el mando para ajustes de posición/velocidad del servo
int DirDCC = 1; // direccione base DCC a manejar (direccion del accesorio)
int MaxDirDCC = 1020; // maxima direccion DCC posible
int OldDirDCC = 0; // variable para guardar la última direccion DCC recibida
byte OldDirection = 0; // variable para guardar la última posición del accesorío recibida
//------------------------------------------------------------------------------------------------------
void setup() {
#if defined SERIAL_DEBUG
Serial.begin(9600);
#endif
DirDCC = ((EEPROM[3]*256) + EEPROM[4]); //direccione base DCC a manejar (direccion del accesorio)
if (EEPROM[9] != 111 || DirDCC == 0){ // si NO encontramos el valor "111" en la EEPROM, quiere decir que es un micro nuevo
InitialSet(); // inicializamos a valores por defecto
}
PosActual = EEPROM[0]; // posición actual del servo
PosRecto = EEPROM[1]; // posición para desvío recto
PosDesvi = EEPROM[2]; // posición para desvío desviado
Retardo = EEPROM[5]; // Valor para velocidad de movimiento
pinMode(PinDCC, INPUT);
pinMode(PinLED, OUTPUT);
LedOFF;
if (ResetRead() == true) { // con K1 pulsado al arranque, situamos servo en posición media
#if defined SERIAL_DEBUG
Serial.println(">> MOVE MID");
#endif
LedON;
MoveToPos(PosMid);
while(true); // detenemos la ejecución del programa
}
#if defined RELE // si usamos relé, inicializamos pins y variables
pinMode(PinReleRecto, OUTPUT);
pinMode(PinReleDesvi, OUTPUT);
PosRele = (PosRecto + PosDesvi) / 2; // calculamos punto médio para activar el relé
if(PosActual == PosRecto) RELE_RECTO // se actualiza el estado del rele
else RELE_DESVI
#endif
MoveToPos(PosActual); // movemos el servo a la última posición guardada
Dcc.pin(0,2, 1); // inicializamos librería DCC
Dcc.initAccessoryDecoder(MAN_ID_DIY, 1, FLAGS_OUTPUT_ADDRESS_MODE, 0);
#if defined SERIAL_DEBUG
Serial.print("PosActual: "); Serial.println(PosActual);
Serial.print("Retardo : ");Serial.println(Retardo);
Serial.print("Dir DCC : ");Serial.println(DirDCC);
Serial.println("END SETUP --------------------------------------------------");
#endif
LedFlash;
}
//
// FUNCIONES PRINCIPALES
//
void loop() {
Dcc.process(); // lanzamos el proceso de escucha DCC de forma recurrente
if (ResetRead() == true) { // verificamos tecla K1 pulsada
byte OptionNum = 0;
Contador = 0;
while (ResetRead() == true && OptionNum < 5) { // controlamos la duración de la pulsación para seleccionar opción
delay(10);
Contador++;
if(Contador == WaitTime){
OptionNum++;
Contador = 0;
LedFlash; // emitimos un destello para indicar cambio de opción
}
}
#if defined SERIAL_DEBUG
Serial.print("OptionNum ");
Serial.println(OptionNum);
#endif
switch (OptionNum) {
case 0: // Movemos el servo
if(PosActual == PosRecto) { // cambiamos la posición del servo
MoveToPos(PosDesvi);
}
else {
MoveToPos(PosRecto);
}
break;
case 1: // se muestra la dirección DCC con flash del LED
VerNumero(DirDCC);
break;
case 2: // ajustamos nueva direccion DCC
NewDirDCC = true; // activamos flag
GetDDCAddr();
break;
case 3: // ajustamos posicion servo
NewSetDCC = true; // activamos flag
SetPos();
NewSetDCC = false; // desactivamos flag
break;
case 4: // ajustamos velocidad de desplazamiento
NewSetDCC = true; // activamos flag
SetVel();
NewSetDCC = false; // desactivamos flag
break;
case 5: // hacemos reset a valores por defecto
while(ResetRead() == true) {delay(10);} // esperamos a que K1 deje de estar pulsada
LedON;
InitialSet();
MoveToPos(PosRecto);
LedOFF;
break;
}
}
}
void Re_Set(){
while(ResetRead() == true) {delay(10);} // esperamos a que K1 deje de estar pulsada
LedON;
InitialSet();
MoveToPos(PosRecto);
LedOFF;
}
// Control de lectura en pin analógico
// para poder tener una entrada más en el ATTINY85, usamos el pin de reset para leer una tecla
// este pin se puede programar para que sea una entrada digital, pero se complica el proceso de programación del micro
// para no complicarnos, el pin esta a +5V por defecto, conectado a un partidor resistivo y una tecla que al ser pulsada
// hace que el valor sea de unos 3V, la lectura analógica está por debajo del valor de AnLimit
// con esta funcion retornamos 0/1 como si de un pin digital se tratara
boolean ResetRead(){
if(analogRead(PinKey1) > AnLimit) return true;
else return false;
}
// funcion de manejo de las direcciones DCC
void notifyDccAccTurnoutOutput(uint16_t Addr, uint8_t Direction, uint8_t OutputPower){
/* #if defined SERIAL_DEBUG // descomentar para ver las lecturas
Serial.println("LECTURA DCC ---------------------");
Serial.print("Addr ");Serial.println(Addr, DEC);
Serial.print("Dir ");Serial.println(Direction);
Serial.print("Out ");Serial.println(OutputPower);
Serial.print("HByte ");Serial.println(highByte(Addr));
Serial.print("LByte ");Serial.println(lowByte(Addr));
Serial.println("---------------------------------");
#endif */
if (OutputPower != 1) return; // solo ordenes para accesorios
if (NewDirDCC == true){ // si estamos esperando una nueva dirección DCC
#if defined SERIAL_DEBUG
Serial.print("Cur Dir ");Serial.println(DirDCC);
#endif
if (Addr <= MaxDirDCC){ // si la dirección recibida está dentro de los límites
DirDCC = Addr; // actualizamos valor de la variable DirDCC
EEPROM[3] = highByte(DirDCC); // direccion DCC base byte H // actualizamos EEPROM
EEPROM[4] = lowByte(DirDCC); // direccion DCC base byte L
NewDirDCC = false; // deshabilitamos la espera de nueva DirDCC
#if defined SERIAL_DEBUG
Serial.print("New Addr ");Serial.println(DirDCC,DEC);
Serial.print("HByte ");Serial.println(highByte(DirDCC));
Serial.print("LBYTE ");Serial.println(lowByte(DirDCC));
#endif
}
return; // retornamos
} // proceso normal de una dirección DCC
if(Addr == DirDCC){ // si la dirección decibida es la nuestra
if(NewSetDCC == true){ // si estamos en un proceso de ajuste del movimiento del servo
AjtPosVel = Direction; // retornamos el valor para el ajuste en la variable AjtPosVel
return;
}
if(OldDirDCC == Addr && OldDirection == Direction) return; // si es la misma DirDCC y Dirección que la vez anterior, retornamos
if(Direction == true) { // si no hemos retornado anted, movemos el servo
MoveToPos(PosRecto); // movimiento a recto si Direcction = 1
}
else {
MoveToPos(PosDesvi); // movimiento a recto si Direcction = 0
}
OldDirDCC = Addr; // guardamos valores para la próxima vez
OldDirection = Direction;
}
}
// Mueve el servo a una pocición según el parámetro "NewPos"
void MoveToPos(byte NewPos){
#if defined SERIAL_DEBUG
Serial.print("PosActual FROM : ");Serial.println(PosActual);
Serial.print("NewPos TO : ");Serial.println(NewPos);
#endif
if (NewPos == PosActual) return; // si NewPos es la posición actual, cancelamos
LedON;
boolean RelStatus = false;
if (NewPos == PosRecto) RelStatus = true; // calculamos valor para mover relé
ServoActivo(true); // inicializacion el servo
if (NewPos > PosActual) { // movimiento a recto // bucle para movimiento incrementando angulo
for (byte i = PosActual; i <= NewPos; i++) {
MoveServo(i, RelStatus);
}
}
else { // bucle para movimiento decrementando angulo
for (byte i = PosActual; i >= NewPos; i--) {
MoveServo(i, RelStatus);
}
}
ServoActivo(false); // deshabilitamos el servo
PosActual = NewPos; // actualizamos posición
EEPROM[0] = PosActual; // guardamos posicion
LedOFF;
}
// Habilita/deshabilita el servo según parámetro "Estado"
// La idea de de habilitar/deshabilitar el servo la he copiado de PC
void ServoActivo(boolean Estado){
if(Estado == true){
ElServo.attach(PinServo); // inicializacion el servo
}
else{
if (ElServo.attached()){
while (digitalRead(PinServo)== HIGH); // Esperamos a que acabe el pulso
ElServo.detach(); // lo desconectamos
digitalWrite(PinServo,LOW); // nos aseguramos de que esta desconectado
}
}
}
// Desplaza el servo según parámetro "i", controla el estado del relé
void MoveServo(byte i, boolean RelStatus){
ElServo.write(i); // desplaza el servo
#if defined ATTINY
SoftwareServo::refresh(); // si usamos ATTINY refrescamos
#endif
delay(Retardo); // aplicamos retardo
#if defined RELE // si usamos el relé, cambiamos su estado según parámetro "Relstatus"
if(i == PosRele) { // si estamos en el punto de cambio del relé lo actualizamos
if(RelStatus == true) RELE_RECTO
else RELE_DESVI
}
#endif
}
//
// FUNCIONES PARA LA CONFIGURACION DE VALORES, direccion DCC, posiciones, velocidad de desplazamiento y reset de valores
//
// Se espera una nueva dirección DCC
void GetDDCAddr(){
#if defined SERIAL_DEBUG
Serial.println("SetAdr");
#endif
while(NewDirDCC == true){
Dcc.process();
if(millis() - prevMillis > LedFlashTime * 5) LedOnOff // control parpadeo LED
if(digitalRead(PinKey1) == LOW) NewDirDCC = false; // salimos si pulsamos K1
}
LedOFF;
}
// Definimos valores para las posiciones recto/desviado
void SetPos(){
#if defined SERIAL_DEBUG
Serial.println("SetPos");
#endif
LedON; // encendemos LED
while(ResetRead() == true) {delay(10);} // esperamos a que K1 deje de estar pulsada
PosRecto = GetPos(); // definimos posicion RECTO
EEPROM[1] = PosRecto; // guardamos nuevo valor para posición DESVIADO
PosActual = PosRecto;
#if defined SERIAL_DEBUG
Serial.print("RECTO ? ");Serial.println(PosRecto);
#endif
LedOFF; delay(1000);LedON; // parpadeo del LED
PosDesvi = GetPos(); // definimos posicion DESVIADO
EEPROM[2] = PosDesvi; // guardamos nuevo valor para posición DESVIADO
PosActual = PosDesvi; // actualizamos posición actual
#if defined SERIAL_DEBUG
Serial.print("DESVI ? ");Serial.println(PosDesvi);
#endif
#if defined RELE // recalculamos punto de cambio, si usamos relé
PosRele = (PosRecto + PosDesvi)/2;
#endif
LedOFF; // apagamos LED
}
byte GetPos() {
byte Contador = PosMid; // usamos la variable contador para ajustar la posicion del servo
byte PContador = PosMid;
MoveToPos(PosMid); // movemos el servo a posición media
ServoActivo(true); // inicializacion el servo
while(ResetRead() == false){
Dcc.process();
if(Contador == LimitMax || Contador == LimitMin){ // si se ha llagado a algún límite encendemos el LED
LedON;
}
else{
if((millis() - prevMillis) > LedFlashTime * 5) LedOnOff // control parpadeo LED
}
if (AjtPosVel == 1 && Contador < LimitMax) Contador++; // aumentamos angulo
if (AjtPosVel == 0 && Contador > LimitMin) Contador--; // disminuimos angulo
if (PContador != Contador){ // comparamos con valor anterior
ElServo.write(Contador); // movemos servo
#if defined ATTINY
SoftwareServo::refresh(); // si usamos ATTINY refrescamos
#endif
PContador = Contador; // guardamos valor anterior
}
AjtPosVel = 3; // asignamos valos diferente a 0 y 1
}
ServoActivo(false); // deshabilitamos servo
while(ResetRead() == true) {delay(10);} // esperamos desactivación K1
return Contador; // retornamos valor
}
// Definimos velocidad de movimiento del servo
void SetVel(){
#if defined SERIAL_DEBUG
Serial.println("SetVel");
#endif
while(ResetRead() == true) {delay(10);}
NewSetDCC = true;
Contador = VelRet; // inicializamos valor para velocodad de desplazamiento
byte PosMin = min(PosRecto, PosDesvi); // identificamos valores máximo y mínimo para recorrido
byte PosMax = max(PosRecto, PosDesvi);
ServoActivo(true); // inicializacion el servo
while(ResetRead() == false) { // bucle para desplazamiento del serveo entre valores PosMin/PosMax
for (int i = PosMin; i<=PosMax; i++) {
if (ResetRead() == true) break;
if(Contador == SrvRetMax || Contador == SrvRetMin){ // si se ha llegado a los retardos máximos/mínimos, el LED luce fijo
LedON;
}
else{
if((millis() - prevMillis) > Contador * 5) LedOnOff // control parpadeo LED
}
ElServo.write(i);
#if defined ATTINY
SoftwareServo::refresh(); // si usamos ATTINY refrescamos
#endif
GetTime();
}
for (int i = PosMax; i >= PosMin; i--) {
if (ResetRead() == true) break;
if(Contador == SrvRetMax || Contador == SrvRetMin){ // si se ha llegado a los retardos máximos/mínimos, el LED luce fijo
LedON;
}
else{
if((millis() - prevMillis) > Contador * 5) LedOnOff // control parpadeo LED
}
ElServo.write(i);
#if defined ATTINY
SoftwareServo::refresh(); // si usamos ATTINY refrescamos
#endif
GetTime();
}
}
ServoActivo(false);
NewSetDCC = false;
EEPROM[5] = Contador; // guardamos retardo
Retardo = Contador;
MoveToPos(PosActual); // movemos el servo a posición actual
LedOFF;
}
// Obtenemos retardo para ajustar la velocidad de movimiento
void GetTime() {
Dcc.process(); // llamamos proceso DCC
if(AjtPosVel == 0 && Contador < SrvRetMax) Contador++; // según dato recibido incrementamos/decrementamos valor para ajuste
if(AjtPosVel == 1 && Contador > SrvRetMin) Contador--;
AjtPosVel = 3; // asignamos valos diferente a 0 y 1
delay(Contador); // aplicamos retardo
#if defined SERIAL_DEBUG
Serial.println(Contador);
#endif
}
//
// OTRAS FUNCIONES AUXILIARES
//
// Se muestra la dirección DCC con flash del LED
void VerNumero(int VerContador){
#if defined SERIAL_DEBUG
Serial.print("VerNumero : ");
Serial.println(VerContador);
#endif
delay(2000);
byte Millar, Centen, Decena, Unidad; // obtenemos digitos correspondientes
Millar = VerContador/1000;
Centen = (VerContador - Millar*1000)/100;
Decena = (VerContador - Millar*1000 - Centen*100)/10;
Unidad = (VerContador - Millar*1000 - Centen*100 - Decena*10);
BlinkLED(Millar);
delay(2000);
BlinkLED(Centen);
delay(2000);
BlinkLED(Decena);
delay(2000);
BlinkLED(Unidad);
}
// Emite parpadeos en funcion del parámetro "v"
void BlinkLED(int v){
int t= 500;
if (v == 0) {
LedON;
delay (3 * t);
LedOFF;
}
else {
while (v > 0) {
LedON;
delay (t);
LedOFF;
delay(t);
v--;
}
delay(1.5 * t);
}
}
// Inicializa a valores por defecto
void InitialSet(){ // inicializamos valores por defecto
EEPROM[0]=LimitMin; //
PosActual=LimitMin;
EEPROM[1]=LimitMin; // posicion recto
EEPROM[2]=LimitMax; // posicion desviado
EEPROM[3]=0; // direccion DCC base byte H
EEPROM[4]=1; // direccion DCC base byte L
EEPROM[5]=VelRet; // velocidad
EEPROM[9]=111; // control
}
//////////////////////////////////////////////////////////////////////////////////////////
Saludos