Secuenciador de transmisión

Hola,

Soy Ricardo, Radioaficionado (EA1RJ) y charreador nato :slight_smile:

Anteriormente he hecho bastantes circuitos con pics pero sin programar nada, ahora con arduino y entorno en C me defiendo un poco, pero muy poco.

Mi intención es hacer un secuenciador de transmisión que active y desactive varios componentes de una estación de radioaficionado cuando el PC de la orden de transmisión.

Este circuito lo tengo hecho con un LM724 con 4 operacionales pero quiero hacerlo mas versátil con arduino, os adjunto el enlace de un vídeo del secuenciador que tengo en funcionamiento para ver como funciona:

La cuestión es que he intentado programar el arduino con varios códigos, empece con estructuras if-else, después con switch, después con arrays pero no doy con ello para que una vez que empezamos la secuencia, si deja de estar activada la entrada que dispara la secuencia, vuelva para atrás en orden inverso. Os agradecería mucho cualquier ayuda.

Antes de poner el código, el funcionamiento del secuenciador es que cuando se da la orden de transmisión, el transmisor no empieza a transmitir directamente, sino que desactiva un amplificador de antena, cambia el estado de unos reles, activa el amplificador de potencia y finalmente pone el equipo en transmisión.

Gracias,
Ricardo EA1RJ

int ledPins[] = { 2, 3, 4, 5 }; // an array of pin numbers to which LEDs are attached
int pinCount = 4; // the number of pins (i.e. the length of the array)
int LNAPin = 2;
int RELAYPin = 3;
int PAPin = 4;
int PTTPin = 5;
int PCPin = 11;
int wait=0;
int retrasoTX=0;
int retrasoRX=0;

void setup() {
// the array elements are numbered from 0 to (pinCount - 1).
// use a for loop to initialize each pin as an output:
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
pinMode(ledPins[thisPin], OUTPUT);
}
pinMode(LNAPin, OUTPUT);
pinMode(RELAYPin, OUTPUT);
pinMode(PAPin, OUTPUT);
pinMode(PTTPin, OUTPUT);
pinMode(PCPin, INPUT);
setstate(LOW, HIGH, HIGH, HIGH);
wait=LOW;
}

void loop()
{
retrasoTX=300;
retrasoRX=150;

if (digitalRead(PCPin) == LOW && wait == LOW)
{
for (int thisPin = 0; thisPin < pinCount; thisPin++) {
digitalWrite(ledPins[thisPin], HIGH);
delay(retrasoTX);
// ¿llamar a una función que compruebe que PCPin sigue en LOW para pasar al siguiente pin y sino volver para atras?
wait=HIGH;
}
}

if (digitalRead(PCPin) == LOW && wait == HIGH)
{
setstate(HIGH, LOW, LOW, LOW);
}

if (digitalRead(PCPin) == HIGH && wait == HIGH)
{
for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) {
digitalWrite(ledPins[thisPin], LOW);
delay(retrasoRX);
wait=LOW;
}
}

if (digitalRead(PCPin) == HIGH && wait == LOW)
{
setstate(LOW, HIGH, HIGH, HIGH);
}
}

void setstate(int LNA, int RELAY, int PA, int PTT)
{
digitalWrite(LNAPin, LNA);
digitalWrite(RELAYPin, RELAY);
digitalWrite(PAPin, PA);
digitalWrite(PTTPin, PTT);
}

Por que las tijeras no solo sirven para cortar!! :*

Si tu código es como creo que es, con un break dentro del for() sales del bucle, posiblemente tengas que hacer algún retoque más al código para que funcione como quieres pero lo puedes conseguir.

Buenas Ricardo, no acabo de entender lo que quieres hacer, pero si me lo explicas mejor intento echarte una mano.

Hola, feliz año y gracias por vuestras respuestas,

Intentare explicar mejor lo que quiero hacer:

Con un pin como input se arranca una secuencia de encendido de por ejemplo 4 leds pero una vez encendido uno y antes de encender el siguiente led, hay que comprobar que la señal que inicial la secuencia (input) sigue activada, y en el caso de que ya no esté activada, no se enciende el siguiente led y los que se han encendido se van apagando retrocediendo en la secuencia.

por ejemplo, se activa la secuencia y no se desactiva en un tiempo, entonces se encienden, led1,led2,led3 y led4, cuando se desactiva el input, se empiezan a apagar los led, primero led4, luego led3,led2,led1.

del mismo modo si la señal que activa la secuencia, cesa antes de que se complete, pues hace lo mismo pero desde el led al que llego la secuencia, ejemplo:

input en high, enciende led1, led 2 y si el imput va a LOW, apaga 2, apaga 1.

Este sketch lo hace pero no interrumpe la secuencia:

// Secuenciador

int LNAPin = 2;
int RELAYPin = 3;
int PAPin = 4;
int PTTPin = 5;
int PCPin = 12;
//int CWPin = 11;
//int MICPin = 12;
int retrasoTX=0;
int retrasoRX=0;
int wait=LOW;

void setup()
{
pinMode(LNAPin, OUTPUT);
pinMode(RELAYPin, OUTPUT);
pinMode(PAPin, OUTPUT);
pinMode(PTTPin, OUTPUT);
pinMode(PCPin, INPUT);
//pinMode(CWPin, INPUT);
//pinMode(MICPin, INPUT);
setstate(LOW, HIGH, HIGH, HIGH);
}

void loop()
{
retrasoTX=500;
retrasoRX=250;

if (digitalRead(PCPin) == LOW)
{
if (wait == LOW)
{
setstate(HIGH, LOW, HIGH, HIGH);
delay(retrasoTX);
setstate(HIGH, LOW, LOW, HIGH);
delay(retrasoTX);
setstate(HIGH, LOW, LOW, LOW);
delay(retrasoTX);
wait=HIGH;
}
else if (wait == HIGH)
{
setstate(HIGH, LOW, LOW, LOW);
}
}
else if (digitalRead(PCPin) == HIGH)
{
if (wait == HIGH)
{
setstate(HIGH, LOW, LOW, HIGH);
delay(retrasoRX);
setstate(HIGH, LOW, HIGH, HIGH);
delay(retrasoRX);
setstate(LOW, HIGH, HIGH, HIGH);
delay(retrasoRX);
wait=LOW;
}
else if (wait == LOW)
{
setstate(LOW, HIGH, HIGH, HIGH);
}
}
}

void setstate(int LNA, int RELAY, int PA, int PTT)
{
digitalWrite(LNAPin, LNA);
digitalWrite(RELAYPin, RELAY);
digitalWrite(PAPin, PA);
digitalWrite(PTTPin, PTT);
}

En uno de mis primeros intentos, hice un código con estructuras IF que comprobaban que se podía pasar al siguiente paso y en caso contrario GOTO pero el código era un tanto caótico, si queréis os lo pongo.

Gracias por vuestro interes.

No se si he pillado bien del todo la idea te pongo codigo y lo que hace (o deberia hacer no lo he probado es solo para
mostrar como lo veo yo...).Se trata de que en cada iteracion del loop principal primero se comprueba si el pin de entrada
esta a high o low.mientras la entrada este en high y no se haya llegado al ultimo led ira encendiendo el led siguiente .cuando la entrada pase a low ira apagando los leds desde el ultimo que hubiera encendido de forma decreciente hasta que apague el primero. Alomejor hay que corregir alguna
cosilla pero se ve la "filosofia".

// constantes
const int PIN_PC = 12;
//variables
int arrayPin[4] = {2,3,4,5};
boolean activo = false;
int posActual = 0;
int contador;

void setup() {
  for (contador=0;contador<4;contador ++) {
    pinMode(arrayPin[contador],OUTPUT);  
    digitalWrite (arrayPin[contador],LOW); 
  }
  pinMode(PIN_PC, INPUT);   
}

void loop() {
   activo = (digitalRead(PIN_PC) == HIGH) ? true : false;
   if  (activo) {
     if (posActual < 4) { 
        digitalWrite(arrayPin[posActual],HIGH);
        posActual ++;
     }
   }
   else {
      if (posActual >= 0) { 
        digitalWrite(arrayPin[posActual],LOW);
        posActual --;
     }
   }
}

Hay que mantener input a high antes de iniciar ?
Hay que distanciar las salidas en el tiempo? si es así con delay() o tiene q seguir corriendo el programa?
si estando input a high pasa a low e inicia la secuencia de desactivar, y pasa de nuevo a high que tiene que hacer?

De entrada el codigo que he puesto antes tiene un fallo ya que cuando posActual no cumple las condiciones se sigue
incrementando o decrementando llegando a valer 4 o -1 y falla el digitalWrite(arrayPin[posActual],HIGH) cuando posActual
llega a 4 y digitalWrite(arrayPin[posActual],LOW) cuando posActual llega a -1. A ver si en la version 1.2 sale mejor.......

bueno pues otra vuelta de tuerca en principio tiene un delay de un segundo entre cada lectura de la señal y lo dicho no lo he probado no se si funcionara......

// constantes

const int PIN_PC = 12;

//variables

int arrayPin[4] = {2,3,4,5};
boolean activo = false;
boolean limSup = true;
boolean limInf = false;
int posActual = 0;
int contador;

void setup() {
  for (contador=0;contador<4;contador ++) {
    pinMode(arrayPin[contador],OUTPUT);  
    digitalWrite (arrayPin[contador],LOW); 
  }
  pinMode(PIN_PC, INPUT);   
}

void loop() {
   activo = (digitalRead(PIN_PC) == HIGH) ? true : false;
   if  (activo == true &&  limSup == true) {
     if (posActual == 3 ){
       limSup = false;
       digitalWrite(arrayPin[posActual],HIGH);
     } 
     else {digitalWrite(arrayPin[posActual],HIGH);posActual ++;} 
     limInf = true;
   } 
   if (activo == false && limInf == true){
     if (posActual == 0) {
       limInf = false;
       digitalWrite(arrayPin[posActual],HIGH);
     } 
     else {digitalWrite(arrayPin[posActual],LOW);posActual --; }
     limSup = true;
   }
   delay(1000);
}

Hola Jose,

Gracias por tu sketch, hace correctamente la secuencia, pero he tenido que cambiar una cosilla por que en el void setup se ponen todas las salidas en LOW pero una vez que se inicia la secuencia, el estado del pin2 siempre se queda en HIGH .

Lo que he cambiado es HIGH por LOW en esta parte del codigo:

if (activo == false && limInf == true){
if (posActual == 0) {
limInf = false;
digitalWrite(arrayPin[posActual],LOW); // ponia HIGH y lo he cambiado por LOW

Voy a ver si se puede hacer de forma sencilla (como con una puerta lógica NOT) que la salida del pin2 (posActual==0 creo) este invertida respecto al resto, si os fijais en el video de youtube que subi antes, el 1er rele (el del preamplificador de antena o LNA) está en un estado lógico inverso al resto de reles.

Para marcial:

// Hay que mantener input a high antes de iniciar ?

No, el imput al pasar a HIGH inicia la secuencia, si pasa a low se avandona el encendido pero deshaciendo el camino.

// Hay que distanciar las salidas en el tiempo? si es así con delay() o tiene q seguir corriendo el programa?

No entiendo bien la pregunta, con el Delay que ha puesto Jose va bien,

// si estando input a high pasa a low e inicia la secuencia de desactivar, y pasa de nuevo a high que tiene que hacer?

Continuar la secuencia de encendido desde donde se quedo cuando iba apagando.

Gracias de nuevo.

EA1RJ - Ricardo

Bueno version 1.3 con otra manera de hacerlo.el primer codigo esta hecho para simular la secuencia con el serial monitor ,funciona introduciendo un s para activar la secuencia y una b para desactivarla.cuando pulsas s la señal se mantiene activa hasta que pulses b y viversa cuando pulsas b esta inactiva hasta que vuelvas a pulsar b.el segundo codigo es el mismo pero para funcionar normalmente.

//-----------------------------------------------constantes---------------------------------------------------------------
const int PIN_PC = 12;
//-----------------------------------------------variables----------------------------------------------------------------

int arrayPin[4] = {2,3,4,5};
boolean arrayEstado[4] = {false,false,false,false};
boolean activo = false;
int cont;
char orden;
//------------------------------------------------setup()-----------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  for (cont=0;cont<4;cont ++) {
    pinMode(arrayPin[cont],OUTPUT);  
    digitalWrite (arrayPin[cont],LOW); 
  }
  pinMode(PIN_PC, INPUT);   
}
//-------------------------------------------------loop()-----------------------------------------------------------------
void loop() {
   //activo = (digitalRead(PIN_PC) == HIGH) ? true : false;
   if(Serial.available()>0){orden=Serial.read();if(orden=='s'){activo=true;}else if(orden=='b'){activo=false;};}
   if  (activo) {
     for (cont=0;cont<4;cont++){
       if(arrayEstado[cont]==false){
         digitalWrite(arrayPin[cont],HIGH);
         arrayEstado[cont]=true;
         Serial.print("Pin salida ");Serial.print(arrayPin[cont]);Serial.println(" a HIGH");
         break;
       }
       else{continue;}
     }
   } 
   else {
     for (cont=3;cont>=0;cont--){
       if(arrayEstado[cont]==true){
         digitalWrite(arrayPin[cont],LOW);
         arrayEstado[cont]=false;
         Serial.print("Pin salida ");Serial.print(arrayPin[cont]);Serial.println(" a LOW");
         break;
       }
       else{continue;}
     }
   }
   delay(2000);
}

Y el definitivo:

//-----------------------------------------------constantes---------------------------------------------------------------
const int PIN_PC = 12;
//-----------------------------------------------variables----------------------------------------------------------------

int arrayPin[4] = {2,3,4,5};
boolean arrayEstado[4] = {false,false,false,false};
boolean activo = false;
int cont;
//------------------------------------------------setup()-----------------------------------------------------------------
void setup() {
  for (cont=0;cont<4;cont ++) {
    pinMode(arrayPin[cont],OUTPUT);  
    digitalWrite (arrayPin[cont],LOW); 
  }
  pinMode(PIN_PC, INPUT);   
}
//-------------------------------------------------loop()-----------------------------------------------------------------
void loop() {
   activo = (digitalRead(PIN_PC) == HIGH) ? true : false;
   if  (activo) {
     for (cont=0;cont<4;cont++){
       if(arrayEstado[cont]==false){
         digitalWrite(arrayPin[cont],HIGH);
         arrayEstado[cont]=true;
         break;
       }
       else{continue;}
     }
   } 
   else {
     for (cont=3;cont>=0;cont--){
       if(arrayEstado[cont]==true){
         digitalWrite(arrayPin[cont],LOW);
         arrayEstado[cont]=false;
         break;
       }
       else{continue;}
     }
   }
   delay(2000);
}

No tengo circuito en casa para probar, pero por curiosidad prueba lo tu y dime.
Ponle los pines y el tiempo de demora que uses

La pregunta sobre delay, me refería a que si la demora sirve con delay o tenia que ser sin el para que la ejecución del programa continúe. La diferencia esta en que con delay si estas iniciando la secuencia, mientras estas "esperando", si desaparece la señal de inicio, el pin seguirá activo hasta que finalice el delay, y viceversa al desconectar, no se si puede suponer problema

byte Entrada=12;                                 // Pin señal inicio
byte Pin_Out[]={2,3,4,5};                        // Pines de salida
boolean Senal;                                   // Para amecenar el estado de la entrada
unsigned long T_Espera=1000;                     // Tiempos de espera tras cada señal
int Pin=0;

void setup() 
{   
  pinMode (Entrada, INPUT);                      // Establecer pines de entrada
  for (int x=0;x<4;x++)
  {
    pinMode (Pin_Out[x], OUTPUT);                // Establecer pines de salida
    digitalWrite(Pin_Out[x], LOW);               // Pines de salida a low para iniciar programa
  } 
}

void loop() 
{
  Senal=digitalRead(Entrada);                  // Almacenar el estado del pin de entrada  
  if (Senal && Pin<4)                          // Tenemos señal de encender y no esta todo encendido
  {
    digitalWrite(Pin_Out[Pin],HIGH);           // Activar pin
    delay(T_Espera);                           // Tiempo de espera
    Pin++;                                     // Siguiente pin
  }  
  else if (!Senal && Pin>0)                    // No hay señal y no hemos desconectado todo
  {
    Pin --;                                    // Anterior pin
    digitalWrite(Pin_Out[Pin],LOW);            // Desactivar pin
    delay(T_Espera);                           // Tiempo de espera
  }
}

Jose: mi profesor de metodología (dios lo tenga en su gloria por los siglos de los siglos) siempre decía que en cualquier programa y cualquier lenguaje "break=0" (entendamos lo bien, el break en el código y el 0 en la evaluación) y desde esa me producen urticaria :slight_smile:

Marcial:
Me has quitado la palabra de la boca. Estaba escribiendo un código idéntico (salvando los nombres de las variables). Creo que más sencillo ya no se puede hacer. Tu profesor de metodología te enseñó bien. :slight_smile:
Eso sí, tampoco hay que ser "fundamentalistas anti-break", porque ya me dirás en un switch - case qué hacemos. XD

Noter:
En los case se usa por imperativo legal. :P, y que conste que intento evitar el uso de case

Ricardo:

Una modificación recomendable para el uso de relés, para activar seles con 0 o 1:

#define ON HIGH                                  // Cambiar aqui para logica positiva/negativa
#define OF LOW                                   // Cambiar aqui para logica positiva/negativa
byte Entrada=12;                                 // Pin señal inicio
byte Pin_Out[]={2,3,4,5};                        // Pines de salida
boolean Senal;                                   // Para amecenar el estado de la entrada
unsigned long T_Espera=1000;                     // Tiempos de espera tras cada señal
int Pin=0;

void setup() 
{   
  pinMode (Entrada, INPUT);                      // Establecer pines de entrada
  for (int x=0;x<4;x++)
  {
    pinMode (Pin_Out[x], OUTPUT);                // Establecer pines de salida
    digitalWrite(Pin_Out[x], OF);               // Pines de salida a low para iniciar programa
  } 
}
void loop() 
{
  Senal=digitalRead(Entrada);                  // Almacenar el estado del pin de entrada  
  if (Senal && Pin<4)                          // Tenemos señal de encender y no esta todo encendido
  {
    digitalWrite(Pin_Out[Pin],ON);             // Activar pin
    delay(T_Espera);                           // Tiempo de espera
    Pin++;                                     // Siguiente pin
  }  
  else if (!Senal && Pin>0)                    // No hay señal y no hemos desconectado todo
  {
    Pin --;                                    // Anterior pin
    digitalWrite(Pin_Out[Pin],OF);             // Desactivar pin
    delay(T_Espera);                           // Tiempo de espera
  }
}

Por cierto, las tarjetas que muestras en el vídeo las has hecho tu?
Si es así, mis honorarios por la programacion : HEEEEEEELP =(
Seis intentos con una tarjeta y no lo consegui =(

Un saludo de EB2AIC, ya somo mas de uno los que andamos cacharreando con arduino y nuestros equipos de radio....

Un par de preguntas ester circuito que hace esactamente, ir dandole más potencia al ampli? para que no cargue toda la potencia de golpe?

Por que no conbiene utilizar los case y los break?

pacooca:

La estructura select-case es una estructura que tienen casi todos los lenguajes, y en C necesita un break para indicar donde acaba cada case. A mi personalmente no me gusta mucho, prefiero anidar if, pero por cuestión estética :slight_smile:

Otra cosa es el uso de break, goto o cosas así para salir de un bucle o un condicional, en programación estructurada no se usa, bueno hay que intentar no usarla. Y la programación no estructurada es ... como te diría yo ... una chapuza, pero cuidado, una chapuza que puede funcionar tan bien o mejor.

En resumen, es solo una opinión.

Hola de nuevo,

Disculpad pero he estado unos días sin poder ponerme con el circuito del sequenciador.

El código de Marcial es el mas sencillo para mi, que soy muy novato y que solo recuerdo algo de C que estudie de un libro que se llamaba Programacion en C para ingenierias y ha llovido mucho ya desde aquello :slight_smile: (sude tinta para hacer un tres en raya que corria en MS-DOS.....)

Pacooca, este circuito es casi "fundamental" en una estación seria que funcione de 144 Mhz para arriba y fundamental, sin el casi, si quieres hacer rebote lunar. Lo que hace es que cuando estas recibiendo tienes intercalado un previo de recepción en la linea coaxial, cuando el PC manda transmitir desde el puerto serie, usb etc.. lo que hace es que deja de alimentar al previo, conmuta unos relés que le sacan de la linea coaxial para que la potencia pueda llegar a la antena sin que el previo de recepción se entere, después activa el amplificador y finalmente activa el transmisor.

Cuando pasa a RX de nuevo, lo hace a la inversa: deja de transmitir, apaga el amplificador, mete el previo en la linea coaxial (RELES) y vuelve a alimentar el previo de recepción. Todo esto es necesario para no machacar los HEMTs (transistores con un factor de ruino muy bajo).

Voy a ponerme de nuevo Marcial, a ver si consigo hacer que el primer relé funcione al revés que el resto, el ultimo día casi lo consigo pero al final me quede atascado.

Saludos

Marcial no habia visto lo de las PCB.

Si es casera, me hice una insoladora usando la caja de un scaner, unos fluorescentes pequeños y un cristal translucido blanco.

En mi caso con 6 minutos de exposición me salen bastante bien, revelado con agua mas sosa caustica y al ácido (agua oxigenada 110 vol + salfumant + un poco de agua para rebajar jajajaja, es cosa de pillar el tiempo y aun así, alguna deja un poco que desear.

El diseño de las pistas es otro cantar, nunca me he puesto con ningún programa especifico para ello, las diseño en autocad (por deformación profesional :slight_smile: y solo a una cara.

Saludos

:stuck_out_tongue:

const bool ON[]={LOW,HIGH,HIGH};                 // Cambiar aqui para logica positiva/negativa
const bool OF[]={HIGH,LOW,LOW};                  // Cambiar aqui para logica positiva/negativa
byte Entrada=12;                                 // Pin señal inicio
byte Pin_Out[]={2,3,4,5};                        // Pines de salida
boolean Senal;                                   // Para amecenar el estado de la entrada
unsigned long T_Espera=1000;                     // Tiempos de espera tras cada señal
int Pin=0;

void setup() 
{   
  pinMode (Entrada, INPUT);                     // Establecer pines de entrada
  for (int x=0;x<4;x++)
  {
    pinMode (Pin_Out[x], OUTPUT);               // Establecer pines de salida
    digitalWrite(Pin_Out[x], OF[x]);            // Pines de salida a low para iniciar programa
  } 
}
void loop() 
{
  Senal=digitalRead(Entrada);                  // Almacenar el estado del pin de entrada  
  if (Senal && Pin<4)                          // Tenemos señal de encender y no esta todo encendido
  {
    digitalWrite(Pin_Out[Pin],ON[Pin]);        // Activar pin
    delay(T_Espera);                           // Tiempo de espera
    Pin++;                                     // Siguiente pin
  }  
  else if (!Senal && Pin>0)                    // No hay señal y no hemos desconectado todo
  {
    Pin --;                                    // Anterior pin
    digitalWrite(Pin_Out[Pin],OF[Pin]);        // Desactivar pin
    delay(T_Espera);                           // Tiempo de espera
  }
}

Yo localice un programa para diseño (incluso mullicara) lo localizo y te digo, pero mi problema es el quemado, me salen mal con ganas, ya tire con 6 intentos con ácido, pero me cortan las pistas muy facil.

Buenas noches,

Ya estoy probando el nuevo código y funciona, gracias de nuevo Marcial, pero te agradecería que me explicaras un poco una cosa que no entiendo.

Eso de const bool ON[]={LOW, HIGH,HIGH};

Por lo que he visto, ya que no sabia que eso existía, es un ARRAY BOOLEANO, entonces cuando vas llamando a cada posición del array, toma el valor correspondiente.

¿entonces por que solo hay declarados 3 estados en el array, si resulta que tenemos 4 pines de salida?

Respecto al tema de fusilar una pista posiblemente sea por que el ácido este muy fuerte y se coma rápidamente las pistas mas finas y necesite mas tiempo para superficies mas grandes, yo lo rebajo con agua, prefiero tardar mas :slight_smile: y hacer pistas de 0,4 mm o 0,3 mm ya es jugársela.

De todas formas si necesitas algún PCB que ya este diseñado y sea a una sola cara, te lo hago.

Saludos