Go Down

Topic: Multiplexar datos que vienen de varias placas de Arduino. (Read 2314 times) previous topic - next topic

Gastonc4

Hola,

Funciona, gracias a las correcciones por fin pude hacer que funcionara, claro que estoy por ahora trabajando con el simulador Proteus y a medida que fui colocando los sensores ultrasónicos con los leds, se fue poniendo un poco más lento, yo diría que cada cambio en los sensores demora unos 10 segundos para reflejarse.
No se que tanto en el montaje real se pueda volver lento ya que el código es bastante largo.
Incluí la parte del multiplexado con 2 displays 7 segmentos de ánodo común, los cuales van a mostrar los puestos disponibles, empieza en 24 y a medida que se enciende un led, la variable "disp" toma el valor de "disp = disp-1". Incluye la librería timerOne, la cual encontré en la web y sólo tuve que hacerle algunas modificaciones, aunque quiero aclarar que no entiendo muy bien esa parte, sólo se que funciona. Hay un video donde el autor del código explica con mucho detalle como se desarrolla, voy a dejar el enlace y tambén donde está el código escrito.

https://www.youtube.com/watch?v=XnAf2ZQS8GY

https://pastebin.com/fsikttET

Y mi código va así por el momento, voy a colocar hasta 4 sensores, pero en realidad queda más largo, ya que va hasta el sensor 24.

Code: [Select]
#include <TimerOne.h>

//Ánodo común
byte num [10]={
  3,    //0 00000011
  159,  //1 10011111
  37,   //2 00100101
  13,   //3 00001101
  153,  //4 10011001
  73,   //5 01001001
  65,   //6 01000001
  31,   //7 00011111
  1,    //8 00000001
  25    //9 00011001

};

const byte DS_1=A11, SHCP=A12, STCP_1=A13, DS_2=A14, STCP_2=A15, displays=2;
unsigned long  i, j=1, sep [displays], disp=24, z, k=0;
float y;
unsigned long int ahora, antes;

unsigned long ocup=0;
long duracion1, distancia1, duracion2, distancia2, duracion3, distancia3, duracion4, distancia4;
long duracion5, distancia5, duracion6, distancia6, duracion7, distancia7, duracion8, distancia8;
long duracion9, distancia9, duracion10, distancia10, duracion11, distancia11, duracion12, distancia12;
long duracion13, distancia13, duracion14, distancia14, duracion15, distancia15, duracion16, distancia16;
long duracion17, distancia17, duracion18, distancia18, duracion19, distancia19, duracion20, distancia20;
long duracion21, distancia21, duracion22, distancia22, duracion23, distancia23, duracion24, distancia24;

const byte latchPinLeds = 53;    //Pin conectado a ST_CP of 74HC595
const byte clockPinLeds = 51;    //Pin conectado a SH_CP of 74HC595
const byte dataPinLeds =  52;     //Pin connected to DS of 74HC595

void setup() {
   pinMode(latchPinLeds, OUTPUT);
   pinMode(clockPinLeds, OUTPUT);
   pinMode(dataPinLeds, OUTPUT);
   pinMode(0, OUTPUT);  pinMode(1, INPUT);  
   pinMode(2, OUTPUT);  pinMode(3, INPUT);  
   pinMode(4, OUTPUT);  pinMode(5, INPUT);  
   pinMode(6, OUTPUT);  pinMode(7, INPUT);
   pinMode(8, OUTPUT);  pinMode(9, INPUT);
   pinMode(10, OUTPUT);  pinMode(11, INPUT);
   pinMode(12, OUTPUT);  pinMode(13, INPUT);
   pinMode(14, OUTPUT);  pinMode(15, INPUT);
   pinMode(16, OUTPUT);  pinMode(17, INPUT);
   pinMode(18, OUTPUT);  pinMode(19, INPUT);
   pinMode(20, OUTPUT);  pinMode(21, INPUT);
   pinMode(22, OUTPUT);  pinMode(23, INPUT);
   pinMode(24, OUTPUT);  pinMode(25, INPUT);
   pinMode(26, OUTPUT);  pinMode(27, INPUT);
   pinMode(28, OUTPUT);  pinMode(29, INPUT);
   pinMode(30, OUTPUT);  pinMode(31, INPUT);
   pinMode(32, OUTPUT);  pinMode(33, INPUT);
   pinMode(34, OUTPUT);  pinMode(35, INPUT);
   pinMode(36, OUTPUT);  pinMode(37, INPUT);
   pinMode(38, OUTPUT);  pinMode(39,INPUT);
   pinMode(40, OUTPUT);  pinMode(41,INPUT);
   pinMode(42, OUTPUT);  pinMode(43, INPUT);
   pinMode(44, OUTPUT);  pinMode(45, INPUT);
   pinMode(46, OUTPUT);  pinMode(47, INPUT);
   pinMode(DS_1, OUTPUT);
   pinMode(SHCP, OUTPUT);
   pinMode(STCP_1, OUTPUT);
   pinMode(DS_2, OUTPUT);
   pinMode(STCP_2, OUTPUT);

   Timer1.initialize(1000);
   Timer1.attachInterrupt(mostrar);
 }

void loop() {
 ocup = 0; // Ponemos a cero todos los bits
  digitalWrite(0, LOW);
  delayMicroseconds(2);
  digitalWrite(0, HIGH); // genera el pulso de 10 us
  delayMicroseconds(10);
  digitalWrite(0, LOW);
  duracion1 = pulseIn(1, HIGH); // capturamos la duración del pulso
  distancia1 = (duracion1/2)/29; // calcula la distancia en cms  
 
    if (distancia1 >=1 && distancia1 <=299){ // No hace falta más para saber que está a nivel alto
        ocup |= 1 << 0; // Ponemos a 1 el bit 0
        disp=disp-1;
 }

  digitalWrite(2, LOW);
  delayMicroseconds(2);
  digitalWrite(2, HIGH); // genera el pulso de 10 us
  delayMicroseconds(10);
  digitalWrite(2, LOW);
  duracion2 = pulseIn(3, HIGH); // capturamos la duración del pulso
  distancia2 = (duracion2/2)/29; // calcula la distancia en cms
    
   if (distancia2 >=2 && distancia2 <=299){
        ocup |= 1 << 1; // Ponemos a 1 el bit 1
        disp=disp-1;
  }

  digitalWrite(4, LOW);
  delayMicroseconds(2);
  digitalWrite(4, HIGH); // genera el pulso de 10 us
  delayMicroseconds(10);
  digitalWrite(4, LOW);
  duracion3 = pulseIn(5, HIGH); // capturamos la duración del pulso
  distancia3 = (duracion3/2)/29; // calcula la distancia en cms
    
    if (distancia3 >=2 && distancia3 <=299){
        ocup |= 1 << 2; // Ponemos a 1 el bit 2
        disp=disp-1;
  }
  
  digitalWrite(6, LOW);
  delayMicroseconds(2);
  digitalWrite(6, HIGH); // genera el pulso de 10 us
  delayMicroseconds(10);
  digitalWrite(6, LOW);
  duracion4 = pulseIn(7, HIGH); // capturamos la duración del pulso
  distancia4 = (duracion4/2)/29; // calcula la distancia en cms  
    
    if (distancia4 >=2 && distancia4 <=299){
        ocup |= 1 << 3; // Ponemos a 1 el bit 3
        disp=disp-1;
  }

   // A continuación se mandan los dos bytes del entero
  digitalWrite(latchPinLeds,LOW);
  shiftOut(dataPinLeds, clockPinLeds, MSBFIRST, (ocup & 0x00ff0000) >> 16);
  shiftOut(dataPinLeds, clockPinLeds, MSBFIRST, (ocup & 0x0000ff00) >> 8); // Primero el byte más significativo
  shiftOut(dataPinLeds, clockPinLeds, MSBFIRST, (ocup & 0x000000ff));
  digitalWrite(latchPinLeds, HIGH);


ahora=millis();
   z=disp;
    for (i=0; i<=(displays-1); i++){
      y=z%10;
      sep [(displays-1-i)]= y;
      z=int((z/10));
    disp=24;  
    }
 
}

void mostrar()
{  
  if(j==pow(2,displays))j=1;
  if(k==displays)k=0;
 
  digitalWrite (STCP_2, LOW);
  shiftOut(DS_2, SHCP, MSBFIRST, 0);
  digitalWrite (STCP_2, HIGH);
 
  digitalWrite (STCP_1, LOW);
  shiftOut(DS_1, SHCP, LSBFIRST, num[ sep[k] ]);
  digitalWrite (STCP_1, HIGH);
 
  shiftOut(DS_1, SHCP, LSBFIRST, 0 >> 8);
 
  digitalWrite (STCP_2, LOW);
  shiftOut(DS_2, SHCP, MSBFIRST, j);
  digitalWrite (STCP_2, HIGH);
  j=j*2; k=k+1;
}
  


Quisiera saber si hay forma de hacer un array o los que sean necesarios para reducir la lectura de los sensores, ya para los leds hay uno que envió @ignoranteAbsoluto, pero ese está basado en lectura de los pines digitales, habría que modificarlo para que lea los sensores y así se vayan encendiendo los leds.
De todos modos, esto para mi ha sido muy provechoso, ya que con cada indicación que he recibido en este foro, he ido avanzando y aprendiendo un poco más. Voy a intentar modificar y buscar la forma de reducir el código, cualquier sugerencia será bienvenida. Estaré informando de como va todo.

surbyte

Que pena que no tomaste la indicación de IgnoranteAbsoluto, primero porque esta muy optimizada en cuanto a un código rápido dentro de lo que tu quieres (ya has visto que la manera mas veloz es la que te sugerí o incluso se puede mejorar) pero partiendo de ahi seguramente tendrías toda la flexibilidad.

A mi la parte que usas PulseIN no me gusta. Si hay algo lento es

Code: [Select]
duracion1 = pulseIn(1, HIGH); // capturamos la duración del pulso

Cuanto tarda eso? no lo se.. hasta que encuentra el pulso en HIGH.
Por eso prefiero las librerias como NewPing.h que te recomiendo incluso tiene un ejemplo para leer 15 sensores ultrasónicos secuencialmente.
Asi que facilmente adaptable a tu caso de 4.

El unico problema que veo es que es timer-interrupted o sea que si usa la misma interrupción que tu TimerOne no servirá.


Porque no subes tu simulacion en un archivo .zip para poder seguirte mejor.
Creo que mas alla que no tengo claro a que apuntas en el proyecto, deberías empezar a prestar atención a los tiempos que consume cada cosa y si algo consume demasiado tiempo entonces hay que ver porque o considerar modificar el enfoque por algo mas rápido.


NOTA: La librería NewPing usa Timer2 para el UNO de modo que no habrá problemas.

Gastonc4

Bueno, aquí voy a subir la simulación en proteus, como dije, anda un poco lenta y a partir del sensor20 se frenaba y me decía que había algo desconectado y por más que lo corregía, siempre se detenía, al fin opté por retirar los sensores del 20al 24, por ahora están trabajando 19 sensores.
En la simulación ya aparecen los 2 displays 7 segmentos, 3 barras de leds y los 19 sensores ultrasónicos, voy a adjuntar la librería del sensor y el código completo con los 24 sensores.

La opción de @IgnoranteAbsoluto no está descartada, sólo que por el momento tendría que estudiarla un poco más para poder adaptarla a la lectura de los sensores.

Quedo atento a todo.



surbyte

Pero claro como no va a estar lento...

A ver mi amigo, un simulador se usa para resolver situaciones digamos lógicas. Has puesto 21 sensores ultrasónicos, 24 leds que me parece bien mas los leds 7 segmentos  por dios hace falta todo eso?

Además tu código.. te hable de NewPing.h que hace las cosas fáciles y en tu código tienes 24 rutinas repetidas una para cada sensor ultrasónico!!!

No te pareció que merece un poco de simplificación?

Bueno le meto mano y tijera por todos lados para reducir ese código.

Aprecio y valoro tu esfuerzo pero insisto!!! En algún punto el sentido común dicta que algo no puede ser... asi que es mejor detenerse y preguntar, Cómo hago para reducir 24 sensores ultrasónicos de modo mas eficiente? Es posible?

Ese es un punto, es posible?

EDITO 1:

El ejemplo de NewPing tiene 15 y tu usas 24. No me cuesta nada copiar y pegar el ejemplo cambiar la variable que define la cantidad de sensores y ponerle 24 pero eso es viable? No lo se en la práctica.

Veré como mejorar tu código e invito a los programadores a que den sus versiones que lógicamente serán mejores que la mía.

Creo que estamos perdiendo el objetivo.
Asi que voy a sugerirte algo aún a pesar de que esto pueda funcionar como está.
Veo un problema de implementación práctica importante:

El montaje de 24 sensores y sus cables a que distincia estarán?
Supongamos un auto que tiene un ancho de 2 mts o menos
Mi camioneta mide 1.5 mts, el de mi Sra mide 1.8 mts con espejos.
Una Camioneta tipo Toyota 4x4 1.8 mts

Asi que si supusieramos 2.5 mts entre sensores estaríamos bien.
Supondré tmb que tienes 12 espacios enfrentados o sea que si pongo el sensor al centro, el mas alejado estará a

11x2.5+1.75 = 29.25 mts
O sea que tus dos sensores mas alejado estarán a casi 30 mts y luego reducimos en 2.5 los siguientes.
Dime como harás para que tu mega envie los los pulsos a esa distancia?

Es momento como te digo de replantear todo.

Vas a tener que distribuir sensore con algun Arduino NANO por ejemplo que envie los datos via Radio al Arduino de tu elección.
Sino me parece que estas condenado a fallar.

EDITO 2: Revisando NewPing.h veo que dice

Quote
Each sensor is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms).
Cada sensor demora 33 mseg en ser chequeado y el loop demora 495 para 15 sensores.

Si pasamos a 24 tendremos 33 x 24 = 792 mseg

Ese tiempo es viable, si claro.. menos de 1 segundo para barrer los 24 sensores si fuera posible no es un tiempo prohibitivo. El problema es las distancias a cada sensor.

Aun suponiendo que estuvieras en el centrol del estacionamiento tendrías a los sensores mas alejados (4) a 15 mts. Sigue siendo una distancia importante y sujeta a ruidos electromagnéticos de todo tipo.


Gastonc4

Wao, esto parece complicarse un poco, pero nadie dijo que sería fácil, yo de algo atrevido u osado dije: yo puedo hacerlo y aquí estoy metido en esta situación.

He tenido situaciones donde las distancias son un pequeño problema, pero aveces en la práctica simplemente me arriesgo y me han funcionado, espero que esta no sea la excepción, contamos con cable utp cat 6E el cual recomienda distacias de hasta 50 mts para algunas situaciones, de todo modos antes de tomar decisiones tengo que ir probando los sensores más alejados a ver como nos va, pero claro que es un tema preocupante.

Con respecto al código, voy a ir probando a ver hasta donde llego, he estado leyendo la librería NewPing y haré el ejemplo ampliándolo a 24 a ver si logro que funcione. De todos modos quisiera preocuparme por ahora más por el código que quede más reducido y eficiente en cuanto a velocidad, si logro algo, no dudaré en mostrarlo y si hay alguna idea de cómo debe quedar, claro que será bienvenida.

Gracias amigo Surbyte por toda esta guía que he recibido de tu parte, aunque con tropiezos, este proyecto va tomando forma superando cada etapa.

surbyte

ya tengo el código con 24. Te lo paso. Lo hice ayer.

Code: [Select]
// ---------------------------------------------------------------------------
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
// would normally process the sensor results in this function (for example, decide if a robot needs to
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
// ---------------------------------------------------------------------------
#include <NewPing.h>

#define SONAR_NUM     22 // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
uint8_t currentSensor   = 0;          // Keeps track of which sensor is active.
unsigned long ocup      = 0;
const byte DS_1 = A11;
const byte latchPinLeds = 53;    //Pin conectado a ST_CP of 74HC595
const byte clockPinLeds = 51;    //Pin conectado a SH_CP of 74HC595
const byte dataPinLeds =  52;     //Pin connected to DS of 74HC595

NewPing sonar[SONAR_NUM] = {     // Sensor object array.
  NewPing( 0,  1, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing( 2,  3, MAX_DISTANCE),
  NewPing( 4,  5, MAX_DISTANCE),
  NewPing( 6,  7, MAX_DISTANCE),
  NewPing(10, 11, MAX_DISTANCE),
  NewPing(12, 13, MAX_DISTANCE),
  NewPing(14, 15, MAX_DISTANCE),
  NewPing(16, 17, MAX_DISTANCE),
  NewPing(18, 19, MAX_DISTANCE),
  NewPing(20, 21, MAX_DISTANCE),
  NewPing(22, 23, MAX_DISTANCE),
  NewPing(24, 25, MAX_DISTANCE),
  NewPing(26, 27, MAX_DISTANCE),
  NewPing(28, 29, MAX_DISTANCE),
  NewPing(30, 31, MAX_DISTANCE),
  NewPing(32, 33, MAX_DISTANCE),
  NewPing(34, 35, MAX_DISTANCE),
  NewPing(36, 37, MAX_DISTANCE),
  NewPing(38, 39, MAX_DISTANCE),
  NewPing(40, 41, MAX_DISTANCE),
  NewPing(42, 43, MAX_DISTANCE),
  NewPing(46, 47, MAX_DISTANCE)
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75;           // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
  pinMode(DS_1, OUTPUT);
}

void loop() {
  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
      if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentSensor = i;                          // Sensor being accessed.
      cm[currentSensor] = 0;                      // Make distance zero in case there's no ping echo for this sensor.
      sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
    }
  }
  // Other code that *DOESN'T* analyze ping results can go here.
}

void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
  // The following code would be replaced with your code that does something with the ping results.
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
      // Serial.print(i);
      // Serial.print("=");
      // Serial.print(cm[i]);
      // Serial.print("cm ");
      if (cm[i] >=2 && cm[i] <= 299){
          ocup |= (unsigned long) 1 << i;
         // disp=disp-1;
      }

  }
  // A continuación se mandan los dos bytes del entero
  digitalWrite(latchPinLeds,LOW);
  shiftOut(dataPinLeds, clockPinLeds, MSBFIRST, (ocup & 0x00ff0000) >> 16);
  shiftOut(dataPinLeds, clockPinLeds, MSBFIRST, (ocup & 0x0000ff00) >> 8); // Primero el byte más significativo
  shiftOut(dataPinLeds, clockPinLeds, MSBFIRST, (ocup & 0x000000ff));
  digitalWrite(latchPinLeds, HIGH);

}



Con esto vi que los leds de las barras funcionaban aparentemente bien.

Mi sugerencia en este punto es que pruebes con 4 sensores Ultrasonicos con la idea de que ATmega este en el centro del estacionamiento y colocas los 4 sensores en los puntos mas alejados. Si funcionan pues adelante.


Gastonc4

Hola Surbyte,
Hay que hacer alguna modificación al código? , porque así como está, no me funciona.
No me he atrevido a modificar algo todavía, ya que esto es un poco avanzado para mi, esto de usar librerías se me dificulta un poco, por ahora sigo con la simulación y veo que en ésta los pines trigger aparecen en gris, no se vuelven azules como sucede con los otros códigos.
Tu idea de empezar con los 4 sensores más alejados me parece genial, es lo primero que haré en la parte física.
Si hay que modificar algo, no dudes en decirme, o si hay que modificar algo en el circuito.

surbyte

La idea de empezar por los 4 mas alejados es probar si es factible que funcione.
Si esa prueba no funciona tendras que usar NANOs (es mi caballito de batalla siempre) y algun medio de Radio como nRF24L01 para subdividir en sectores todo el estacionamiento. Que cada NANO controle la cantidad de sensores primero que pueda y luego que lo haga sin fallas.

Que fallo tuvo el código porque yo lo probé y no fallaba.

Gastonc4

Hola,

Después de unas semanas de receso he vuelto con el proyecto casi terminado en su parte teórica.

Los códigos están funcionando perfectamente, algunos ya en la implementación física y la interacción entre si va por buen camino.

La prueba de los sensores más alejados ya la realizé, éstos son 2 y quedan alejados del circuito principal a una distancia aproimada de 20 mts y su funcionamiento es muy bueno, esta esra la parte más precupante pero utilizando un cable utp cat 6E y una buena fuente de 5V 5A no tuvimos problemas.

La única parte que faltaba era la transmisión de los datos a un servidor por medio de la shield Ethernet W5100, pero ya encontré la forma de hacerlo, hay muchos ejemplos en la web de esta shield y los datos voy a tomarlos desde los leds utilizando las 24 señales que vienen desde los 74595 y ahora hago el proceso a la inversa utilizando el integrado CD4021 que es un registro de desplazamiento paralelo-serie. Envío los datos a los 4021 y la salida son sólo 3 pines, pero para esto voy a hacer un circuito independiente con un Arduino Uno y la Shield Ethernet, así aunque gaste un poco más de dinero me parece la opción más viable ya que contamos con esas tarjetas y sería totalmente independiente del Mega que ya estaría controlado los sensores, los leds y los displays.

La parte física del proyecto se llevará a cabo esta semana, iré contado como va el proceso y dando los detalles que más pueda.

Quiero reiterar mi agradecimiento a Surbyte e Ignorante Absoluto, gracias a ustedes este proceso no lo hubiese podido implementar, aunque no se ha dicho la última palabra en cuanto a su funcionamiento, todo esto ha sido más fácil gracias a sus aportes.


Go Up