lunes, 16 de enero de 2012

Detector de nivel de agua con Atmega

Detector sin Arduino
En casa tenemos un riego automático que funciona aceptablemente bien. El problema es que la bomba está sumergida en un depósito de unos 5 litros y hay que rellenarlo con cierta frecuencia.

En septiembre del 2010 busqué la forma de hacer un detector que avisara cuando el nivel estuviera demasiado bajo. Me basé en "Detector de nivel para un depósito de agua". Pero yo quería justo lo contrario. Es decir que se encendiese un led al bajar el nivel, no que se fuesen apagando. Por dos razones, para que llamase la atención... y para que "gastase menos". El caso es que al 4066 (switch analógico digital) le añadí un 7404 (NOT) y el circuito me quedó así:


Funcionar funcionaba, pero las tres pilas AAA que tenía de alimentación se las comía en tres días...
Ya conocía Arduino, peor me parecía una pasada gastarme 35€ en el asunto.

 De Arduino a microcontrolador con consumo reducido.
En varios sitios....:

Hay que ponerla también en el duemilanove!!!:

El producto final.
En varios sitios....:
3 pilas AAA nuevas han durado al más de 7 días, desde el El 6/1/2012 a las 17:10 al 14/01/2012.


Tengo que calcular cuánto chupa un led encendido siempre. Una modificación plausible sería poner un pulsador para comrpobar que sigue con pilas en vez de tener el led encendido siempre...

Vuelvo a ponerle pilas el 15/01/2012 a las 20:30

Circutio en eagle o kicad: ofú...
Fotos:

código:

//****************************************************************

/*

 * Water level test (based in Watchdog Sleep)

 * Probes  on analog0 and  pin 10
 
 * Indicator LED in pin 13
 

 */

//****************************************************************



#include <avr/sleep.h>

#include <avr/wdt.h>



#ifndef cbi

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

#endif

#ifndef sbi

#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

#endif



int nint;        // interaction number

int ntimes=255;     // the longest time whatchdog can manage is 9= 8sec but it is enough to read the level each 30 minutes. So here we put 225 (=30x60/8)

int pinLed=13;  //

int pinFeeder=10;



volatile boolean f_wdt=1;



void setup(){

  Serial.begin(9600);

  pinMode(pinLed,OUTPUT);

  pinMode(pinFeeder,OUTPUT);

  Serial.println("Water level test");



  // CPU Sleep Modes 

  // SM2 SM1 SM0 Sleep Mode

  // 0    0  0 Idle

  // 0    0  1 ADC Noise Reduction

  // 0    1  0 Power-down

  // 0    1  1 Power-save

  // 1    0  0 Reserved

  // 1    0  1 Reserved

  // 1    1  0 Standby(1)



  cbi( SMCR,SE );      // sleep enable, power down mode

  cbi( SMCR,SM0 );     // power down mode

  sbi( SMCR,SM1 );     // power down mode

  cbi( SMCR,SM2 );     // power down mode



  setup_watchdog(9); // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec

}



byte del;

int cnt;

byte state=0;

int water=0; 





//****************************************************************

//****************************************************************

//****************************************************************

void loop(){



  int modulo=0;

  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs

    f_wdt=0;       // reset flag

    // Read only each ntimes times
    modulo=nint%ntimes;
    
    if (modulo==0){
      digitalWrite(pinFeeder,1);  // send voltage in the water
      
      delay(10);
    
      water=analogRead(0);  // reading probes
      
      digitalWrite(pinFeeder,0);  // stop voltage in the water
     
  
      Serial.print("water: " );
  
      Serial.println(water );
  
  
  
      switch (state){
  
      case 0:     // probes are in the water
  
        if (water < 900) {  // if there is no currente between the probes
  
          state=1;
          digitalWrite(pinLed,1);  // switch on the warning light
        }
  
        break;
  
      case 1:  // probes out of the water
  
        if (water > 1000)  { // if some current go through the probes
  
          state=0;
          digitalWrite(pinLed,0);  // switch off the warning light
  
  
        }
  
        break;
  
      }

    }

    nint++;

    



    Serial.print("Sleep " );

    Serial.println(nint );

    delay(2);               // wait until the last serial character is send

    



  //  pinMode(pinLed,INPUT); // set all used port to intput to save power

    pinMode(pinFeeder,INPUT); // set feeder port to intput to save power



    system_sleep();



  // pinMode(pinLed,OUTPUT); // set all ports into state before sleep

    pinMode(pinFeeder,OUTPUT); // set feeder port into state before sleep





  }



}




//****************************************************************  

// set system into the sleep state 

// system wakes up when wtchdog is timed out

void system_sleep() {



  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF



  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here

  sleep_enable();



  sleep_mode();                        // System sleeps here



    sleep_disable();                     // System continues execution here when watchdog timed out 

    sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON



}



//****************************************************************

// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms

// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec

void setup_watchdog(int ii) {



  byte bb;

  int ww;

  if (ii > 9 ) ii=9;

  bb=ii & 7;

  if (ii > 7) bb|= (1<<5);

  bb|= (1<<WDCE);

  ww=bb;

  Serial.println(ww);





  MCUSR &= ~(1<<WDRF);

  // start timed sequence

  WDTCSR |= (1<<WDCE) | (1<<WDE);

  // set new watchdog timeout value

  WDTCSR = bb;

  WDTCSR |= _BV(WDIE);





}

//****************************************************************  

// Watchdog Interrupt Service / is executed when  watchdog timed out

ISR(WDT_vect) {

  f_wdt=1;  // set global flag

}

Fin código

domingo, 8 de enero de 2012

Leonardo, vinciduino...

Pues resulta que parece que están haciendo otro Arduino con el ATMega 32U4... que lo único que se diferencia con el ATmega328 es que tiene el USB integrado.
Por otra parte, una gente del foro español de Arduino se han hecho un Vinciduino basado en el anterior..

Todo esto lo he sacado de un twitter del cenatic que me ha llevado a la pagina del C.I.r.E , que es realmente interesante

sábado, 7 de enero de 2012

EDA. Electronic design automation

y eso qué es lo que es.... Pues dibujar circuiticos en el ordenador.

Un par de artículos comparando diversas herramientas:

Parece que KiCad como Opensource y Eagle como comercial (pero gratis con ciertas limitaciones que no afectan a la hora de hacer cosas caseras) son las que más se utilizan

martes, 27 de diciembre de 2011

Más cosas con las que jugar!!!


Tamaño inicial Raspberry Pi
Tamaño de producción... como una tarjeta de crédito.

  • Desde que anunciaron el Raspberry pi hace unos meses estoy siguiendo cómo va la cosa... y aunque han aumentado bastante el tamaño (del tamaño de un pendrive al de una tarjeta de crédito) tiene muy buena pinta... Dicen que para enero del 2012 lo ponen a la venta... a ver si es verdad. Se me ocurren un par de cosas para hacer con el cacharro:
    • Liberar al NAS que tengo en la terraza (WD mybookworld) de ciertas tareas (servidor ssh/tunel ssh, cliente de transmission/torrents). El NAS ya funciona con un procesador ARM... y va de miedo.
    • Para poner en marcha el sistema de seguridad casero descrito por Bultza que ya probé con el EEEPc y funcionaba... pero con este cacharrito sería más discreto.
  • Buscando "conexiones" de este cacharro con Arduino he llegado a este otro: Nanode es un "clon" de arduino, pero ya tiene la conectividad Ethernet integrada, por £25.00 (unos 30€ al cambio, casi más barato que un arduino). Eso sí, parece que para programarlo se necesita un arduino...
Muchos cacharros y poco tiempo!!!

martes, 29 de noviembre de 2011

Peluche RFID

Me he puesto a hacer el proyecto "Charlie's Bear" de la revista MAKE número 28  he seguido las instrucciones paso por paso y ha funcionado a la primera.

El cacharro:

Un vídeo con el cacharro dentro de la vaca peluche:


Ya aparecieron los problemas:

Soluciones:
  • Añadirle un amplificador (el de velleman p.ej. en venta en todoelectronica y conectrol)
  • Utilizar un altavoz amplificado
  • Amplificar el volumen de los wavs, aunque parece que no ayuda mucho, debe ser lo más inmediato. Sí que es suficiente con  amplificar el wav con audicity.
Quiero hace un par de modificaciones al soft del proyecto:
  • Nombrar el fichero de sonido con los últimos 8 caracteres de la etiqueta rfid en vez de los 8 primeros. Coge bien los 8 últimos... pero luego dice que no puede reproducir el fichero... ¿por qué?
  • No reproducir un fichero hasta que no se haya terminado el actual (utilizando "while (wave.isplaying)" ). Esto funciona bien sin mayor problema. -> Hecho
  • Parar la reproducción si se acerca la tarjeta "silenciadora". -> Hecho
A nivel hard habría que hacer las siguientes modificaciones:
  • Añadir un interruptor. -> Añadido
El código me ha quedado así:

/ An interactive bear for Charlie -- RFID triggered sound responses

#include <FatReader.h>
#include <SdReader.h>
#include "WaveHC.h"
#include "WaveUtil.h"

SdReader memcard;
FatVolume vol;
FatReader root;
FatReader file;
WaveHC wave;

#define ENABLE 7      // Set the pin number for enabling the RFID reader. The Audio Shield uses pins 2-5.
#define STOPTAG "3D001EDA94" // Code of the TAG that stops any sound 


int  val = 0; 
char code[10];
int bytesread = 0; 

char filename[1][13];

void setup() { 
  //////// Set up RFID reader to collect tag information /////////////////////
  Serial.begin(2400);         // RFID reader SOUT pin connected to Serial RX pin at 2400bps 
  pinMode(ENABLE,OUTPUT);     // Set digital pin 7 as OUTPUT to connect it to the RFID /ENABLE pin 
  digitalWrite(ENABLE, LOW);  // Activate the RFID reader
  
  //////// Set the pins to output for driving the Audio Shield
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  
  ////////// Set up the Audio Shield by initializing the memory card for reading ////////
  if (!memcard.init()) {
    // If something went wrong sdErrorCheck prints out the error check
    putstring_nl("Card init. failed!"); 
    cardErrorCheck();
    return;
  }
  
  //This will optimize the reading of the memory card -- remove it if it times out
  memcard.partialBlockRead(true);
  
  // Find a FAT formatted partition by looking in teh first five slots. Remember your memory card should be FAT16 or FAT32 formatted
  uint8_t partition;
  for (partition = 0; partition < 5; partition++) {
    if (vol.init(memcard, partition))
      break;
  }
  if (partition == 5)
  {
    putstring_nl("No valid FAT partition");
    cardErrorCheck();
    while(1); // This is a point of no return. Format your memory card properly and try again.
  }

  // Open the root directory for reading the files
  if (!root.openRoot(vol))
  {
    putstring_nl("Can't open root directory");
    while(1); // Something went wrong here so investigate the file system on your memory card.
  }
  
  // If you got this far then the card is ready to read
  /*Serial.println("STOP TAG is :  ");
  Serial.println(STOPTAG);
  putstring_nl("Ready to go");*/
}

// If we find an error, check what the error is and show it on the serial terminal
void cardErrorCheck(void)
{
  if(!memcard.errorCode()) return;
  putstring("\n\rSD I/O error:");
  Serial.print(memcard.errorCode());
  putstring(", ");
  Serial.print(memcard.errorData());
  while(1); // Stick here if there is an error
}

void loop() { 

  if(Serial.available() > 0) {          // if data available from reader  
    if((val = Serial.read()) == 10) {   // check for header 
      bytesread = 0; 
      while(bytesread<10) {              // read 10 digit code 
        if( Serial.available() > 0) { 
          val = Serial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          } 
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit  
        } 
      } 
      if(bytesread == 10) {              // if 10 digit read is complete 

        if(memcmp(code,STOPTAG,10) == 0  ){ // check if the TAG is the STOP TAG
           silence();                
           //Serial.println("STOP TAG ");
        } else if (! wave.isplaying){    // do nothing if a file is alredy playing
          playsound(code);
         // Serial.print("TAG code is: ");   // possibly a good TAG 
         // Serial.println(code);            // print the TAG code 
          Serial.flush();                  // Flush the serial buffer before trying to read a new code
        }
       
      } 
      bytesread = 0; 
    }
  }

} 

void playsound(char codetoplay[]) {
  
  Serial.print("File name is: ");   // possibly a good TAG 
  //for(int i = 2; i<10; i++) {    // Make a filename from the first 8 characters of the RFID tag number NOT WORKING
  for(int i = 0; i<8; i++) {    filename[0][i]=codetoplay[i];
    //Serial.print(codetoplay[i]);            // print the name code 
  }
  filename[0][8]='.';
  filename[0][9]='w';
  filename[0][10]='a';
  filename[0][11]='v';
  //Serial.println(".wav");            // print the name code 
  silence(); //shut down anything that is currently playing and close that file
  playfile(filename[0]);
  
}

void playfile(char *name) {
  
        
  if (!file.open(root, name)) {
      putstring_nl("Couldn't open file"); 
      return;
   }
   if (!wave.create(file)) {
     putstring_nl("Not a valid WAV"); 
     return;
   }
  wave.play();
  
}

void silence() {
  if(wave.isplaying) {
    wave.stop();
  }
}