ELECT 22: Sensor de temperatura amb arduino, display LCD i data logging

De wikijoan
Salta a la navegació Salta a la cerca

sistema similar: http://www.cannabiscafe.net/foros/showthread.php?t=89605

Sensor de temperatura LM335

LM335.jpg

Com a sensor de temperatura utilitzo el LM335.

Features

  • Directly calibrated in °Kelvin
  • 1°C initial accuracy available
  • Operates from 400 μA to 5 mA
  • Less than 1Ω dynamic impedance
  • Easily calibrated
  • Wide operating temperature range
  • 200°C overrange
  • Low cost

Description:

The LM135 series are precision, easily-calibrated, integrated circuit temperature sensors. Operating as a 2-terminal zener, the LM135 has a breakdown voltage directly proportional to absolute temperature at +10 mV/°K. With less than 1Ω dynamic impedance the device operates over a current range of 400 μA to 5 mA with virtually no change in performance. When calibrated at 25°C the LM135 has typically less than 1°C error over a 100°C temperature range. Unlike other sensors the LM135 has a linear output.

Applications for the LM135 include almost any type of temperature sensing over a −55°C to 150°C temperature range. The low impedance and linear output make interfacing to readout or control circuitry especially easy.

Connexions Des de sota, els pins són: esquerre: output; mig: Vcc; dreta: GND Compte!! Això no és el que diu, llegir bé!!:

  • esquerra: ADJ. Ajustament per calibrar (mirar full 4 del datasheet)
  • mig: output, i que va connectat a Vcc a través d'una resistència que polaritza el diode Zener.
  • dreta: GND

Calibració Nominalment el sensor es calibra a 10mV/ºK.

La calibració en principi és molt fàcil: This single point calibration works because the output of the LM135 is proportional to absolute temperature with the extrapolated output of sensor going to 0V output at 0°K (−273.15°C). Per tant, la gràfica T-V és una línia que sé que passa per l'origen: 0V=0K=-273.15ºC).

Mirant el datasheet es pot veure la manera correcta de fer una calibració més acurada.

Càlcul de la resistència R1 Un altre es va fer la mateixa pregunta: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1204583768

La solució està estudiant bé el datasheet: http://www.ortodoxism.ro/datasheets/nationalsemiconductor/DS005698.PDF

If you want to try the typical application (first example - basic temperature sensor), you must use a 2k ohms, if the +Vcc is 5volts. The commercial value will be 2.2kohms. If you want to be more accurate, you can use two 1kohm resistors in series.
If the +Vcc is different, use this:
Resistor=(Vcc-3)/1000

If Vcc=5volts, resistor=2k
If Vcc=9volts, resistor=6k (use 10k in parallel with 15k) 

I considered it works near 3 volts/1mA. If you have Vcc=5 volts, the Vr=2volts (Resistor voltage). If you need I=1mA:
R=Vr/I

Mirant el datasheet es pot veure que el Operating Output Voltage és típicament de 3V en condicions normals (T=25ºC; I=1mA). Això és el que s'ha d'esperar per un diode Zener. Per tant, la sortida serà d'uns 3V, i si vull que circuli típicament 1mA he de polaritzar el diode zener amb una resistència de: R=(5-3)/1 = 2Kohms

llegir magnituds analògiques amb l'arduino

http://www.arduino.cc/playground/CourseWare/AnalogInput Arduino pot distingir 1024 valors diferents entre 0 i 5 volts: resolució de 10 bits.

El nostre sensor de temperatura LM335 dóna una sortida típica de 3V, i té una resolució linial de 1ºC/10mV.

Arduino divideix el rang de 0-5V en 1024 valors diferents. Té un ADC de 10 bits. Físicament, el ADC està en una part molt petita del microcontrolador Atmel que hi ha dins la placa arduino. Llegim un valor analògic amb la funció analogRead. La sortida típic que jo llegeixo és de 282. Anem a a fer la comprovació. Amb el multímetre llegeixo 1.37V (i comprovo també que la caiguda dins el diode Zener són 3V).(compte amb les connexions del LM335, el output és la pota de l'esquerra mirant per sota!)

Per tant, 282*(5/1024)=1,377V, clavat!!

Ara senzillament he de calibrar. 1ºC són 10mV, que es correspon a 1,387*1024/5=284,06. D'altra banda, sé que 281 es correspon a 23ºC=296,15K. Necessito una fórmula que em converteixi directament la sortida del ADC a temperatura.

La temperatura és proporcional a la diferència de tensió, que a l'hora és proporcional a la diferència de valors que dóna el ADC. Si tingués dues temperatures de referència, podria trobar el pendent, però com que no és així, em guio pel data sheet que diu que 1ºC són 10mV.

T-To=m(ADC-ADCo)
m=1/(284,06-282)=1/2,06=0,48
T=To+0,48(ADC-ADCo)=23+0,48(ADC-282)
T=0,48*ADC-112,36

i aquesta és la fórmula que he de ficar en el arduino

Però això suposo que es pot millorar. Fixem-nos que el pendent és de 0,48. Això vol dir que si el valor del ADC canvia en una sola unitat, això representa quasi mig grau. Per fer-ho bé, s'hauria d'acondicionar el senyal. Suposant que el rang de temperatures va de -5ºC a 35ºC. Doncs hauria d'aconsegui que fos aquest marge de tensions el que variés de forma linial amb la temperatura. D'aquesta manera aconsegueixo més resolucio.

2a manera de calibrar Disposo de dues temperatures suficientment diferents, i el valor que em dóna el sensor. Aleshores es pot calcular el pendent:

282: 23.5ºC
276 19.0 ºC

m=4.5/6=0.75
T-23.5 = 0.75*(ADC-282)
T=0,75*ADC-188

Calibració correcta El LM335 té la poteta ADJ per ajustar. La idea és mesurar la tensió entre ground i Vout a una temperatura coneguda. Per ex, a T=25C la sortida és 2.80V. Aleshores fico un potenciòmetre de 10K entre Vout i GND, i l'ajusto fins que mesuri 2.80V. Aleshores, el LM335 ja està calibrat amb temperatures absolutes, que vol dir que la sortida està referida a T=0K i que són 10mV per ºC o ºK.

Una altra cosa important és el rang dinàmic de la sortida. Com que està referenciat a -273ºC, el rang dinàmic entre 5ºC i 25ºC és pobre. He de referenciar a 5V (lo normal) i no puc referenciar-ho amb AREF. A més a més, la idea d'utilitzar un amplificador diferencial o un amplificador d'instrumentació m'ha donat problemes (LM392, LM308).

Molt millor utilitzar el sensor de temperatura LM335 que mesura directament ºC. el codi: sensor_temperatura_lcd.pde

 #include <LiquidCrystal.h>

 // initialize the library with the numbers of the interface pins
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 int sensorPin = 0;
 int sensorValue = 0;
 float temperatura;
 
 void setup() {
    Serial.begin(9600);
   // set up the LCD's number of rows and columns: 
   lcd.begin(16, 2);
   lcd.setCursor(0, 0);
   lcd.print("Temperatura");
   delay(1000);
 }

 void loop() {
   lcd.setCursor(0, 0);
   lcd.print("Temperatura");

   sensorValue = analogRead(sensorPin); //conversor analògic-digital. 0=0v; 1024=5V
   //T=0,48*ADC-112,36 (veure wiki per saber com he arribat a aquest resultat)
   temperatura=0.48*sensorValue-112.36;
   lcd.setCursor(0,1);
   Serial.print(sensorValue);
   Serial.print("\t");
   Serial.print(temperatura);
   Serial.print(" ºC\n");
   lcd.print(temperatura);
   lcd.print(" C");
   delay(1000);
 }

Com a millores, ara que sé guardar informació en una memòria EEPROM, hauria de fer un registre de tot un dia i fer una gràfica.

Nota: al final això no em cal per acabar el projecte. Utilitzo el LM35 en comptes del LM335.

Sensor de temperatura LM35

El sensor LM35 està referenciat directament a graus celsius. Parteix d'aquest projecte (tan fàcil) i no funciona!. I el problema és que els pins ANALOG IN 0 i 1 del meu Arduino Mega no funcionen, estan espatllats! Per tant, utilitzo el ANALOG IN 2 (o qualsevol altre).

El codi l'adapto amb vàries modificacions:

  • elimino tota la part de Fahrenheit, Temp max i temp mínima.
  • Utilitzo analogReference(INTERNAL); per tal de refereciar els pins analògics a 2.5V. Comprovo que aquest és el valor mesurant la sortida del pin AREF. Podria canviar la referencia fincant aquí un valor de tensió. Aquest és un fet molt important per tal de millorar la precisió. D'aquesta manera (i també pel fet de canviar el LM335 pel LM35) elimino la necessitat d'utilitzar amplificadors diferencials per millorar el rang dinàmic de la sortida.
  • de fet, ara ja tinc el valor amb una precisió de dos decimals. Com que això no és real, amb un decimal n'hi ha prou, vull tenir la sortida a un sol decimal. Això m'ha costat una mica, com es veu en el codi.

Explicació de la fórmula:

samples[i] = ( 2.50 * analogRead(pin) * 100.0) / 1024.0;

1024 és la resolució dels 10 bits del ADC. 2.50 Volts és la tensió de referència.

Imaginem que la temperatura són 22ºC. Això vol dir que el sensor (que té una referència absoluta a 0ºC i són 10mV/ºC) donarà una sortida de 220mV o 0.22V. Per tant, 0.22V*1024/2.5V = 90 és el valor que obtinc en el pin 2. Per tant, el 100 en la fórmula ve de què 22ºC són 0,22V.


sensor_temperatura_lcd2.pde

/*
An open-source LM35DZ Temperature Sensor for Arduino. This project will be enhanced on a regular basis
(cc) by Daniel Spillere Andrade , http://www.danielandrade.net
http://creativecommons.org/license/cc-gpl
*/

#include <math.h> //http://www.nongnu.org/avr-libc/user-manual
 
int pin = 2; // analog pin
//COMPTE!! els pins analog IN 0 i 1 estan espatllats amb el meu Arduino Mega (!!!)
double temp = 0; // temperature variables
int tempenter,tempdecimal;
float samples[8]; // variables to make a better precision
float maxi = -100,mini = 100; // to start max/min temperature
int i;

void setup()
{
analogReference(INTERNAL);
Serial.begin(9600); // start serial communication
}

void loop()
{
//Serial.println(analogRead(pin));

for(i = 0;i<=7;i++){ // gets 8 samples of temperature

//samples[i] = ( 5.0 * analogRead(pin) * 100.0) / 1024.0;
samples[i] = ( 2.50 * analogRead(pin) * 100.0) / 1024.0; //el 2.50 ve perque AREF=2.5 per defecte amb el Arduino Mega, i utilitzo analogReference(INTERNAL);

temp = temp + samples[i];
delay(1000);

}

//Serial.println(tempc/8.0);
//http://www.nongnu.org/avr-libc/user-manual/group__avr__math.html
temp=round(temp*10/8.0); //a temp tinc dos decimals, i la gràcia i lo difícil és obtenir només un decimal que s'ajusta més a la realitat.
tempenter=temp/10;
tempdecimal=fmod(temp,10);

Serial.print(tempenter);
Serial.print(".");
Serial.print(tempdecimal);
Serial.println(" C");


temp = 0;

delay(1000); // delay before loop
}

analogReference(INTERNAL)

the 0 to 1024 now represents 0 to 1.1V (ATmega168)

could be changed for simplicity to
samples[i] = ( analogRead(pin) * 500.0) / 1024.0;

and so you would update to
samples[i] = ( analogRead(pin) * 110.0) / 1024.0;

En el ATmega1280 (Arduino Mega) la referència són 2.5V, però això es pot canviar amb el pin AREF

D'aquesta manera obtinc una precisió fantàstica


The Mega has 16 analog inputs, each of which provide 10 bits of resolution (i.e. 1024 different values). By default they measure from ground to 5 volts, though is it possible to change the upper end of their range using the AREF pin and analogReference() function.

Pin AREF. Reference voltage for the analog inputs. Used with analogReference().

  • DEFAULT: the default analog reference of 5 volts.
  • INTERNAL: an built-in reference, equal to 1.1 volts on the ATmega168 and 2.56 volts on the ATmega8.
  • EXTERNAL: the voltage applied to the AREF pin is used as the reference.

Datasheet del ATMEGA1280: www.atmel.com/dyn/resources/prod_documents/doc2549.PDF

Vull saber quina és la referència de voltatge intern per al analogReference(INTERNAL). No sé si és 1.1V o 2.56V. En teoria és la lectura que trobaré si llegeixo amb el voltimetre el pin AREF. Una altra possibilitat és aplicar directament 1.1 V al pin AREF.

llegeixo en el datasheet:

Internal reference voltages of nominally 1.1V, 2.56V or AVCC are provided On-chip. The volt-
age reference may be externally decoupled at the AREF pin by a capacitor for better noise
performance.

The ADC converts an analog input voltage to a 10-bit digital value through successive approxi- mation. The minimum value represents GND and the maximum value represents the voltage on the AREF pin minus 1 LSB. Optionally, AVCC or an internal 1.1V or 2.56V reference voltage may be connected to the AREF pin by writing to the REFSn bits in the ADMUX Register.

26.5.2 ADC Voltage Reference

The reference voltage for the ADC (VREF) indicates the conversion range for the ADC. Single ended channels that exceed VREF will result in codes close to 0x3FF. VREF can be selected as either AVCC, internal 1.1V reference, internal 2.56V reference or external AREF pin.
AVCC is connected to the ADC through a passive switch. The internal 1.1V reference is generated from the internal bandgap reference (VBG) through an internal amplifier. In either case, the external AREF pin is directly connected to the ADC, and the reference voltage can be made more immune to noise by connecting a capacitor between the AREF pin and ground. VREF can also be measured at the AREF pin with a high impedant voltmeter. Note that VREF is a high impedant source, and only a capacitive load should be connected in a system. The Internal 2.56V reference is generated from the 1.1V reference.
If the user has a fixed voltage source connected to the AREF pin, the user may not use the other reference voltage options in the application, as they will be shorted to the external voltage. If no external voltage is applied to the AREF pin, the user may switch between AVCC, 1.1V and 2.56V as reference selection. The first ADC conversion result after switching reference voltage source may be inaccurate, and the user is advised to discard this result.

data logging a la EEPROM

el valor de analogRead, com que va de 0-1023, necessita 10 bits, i per tant necessito dos bytes per emmagatzemar aquesta informació (word).

Si vull escriure directament a la EEPROM de l'arduino és més fàcil, doncs existeix la funció EEPROM.write(address, value), on address va de 0 a 511, doncs el Arduino (el bàsic) té 512 bytes en la seva memòria EEPROM. Però nosaltres escriurem a una EEPROM externa.

El primer que he de fer és convertir el valor que trobo a 2 bytes.

Per ex, 281 = 
281/2=140 -> 1
140/2 = 70 -> 0
70/2=35 -> 0
35/2=17 -> 1
17/2=8 -> 1
8 -> 0
4 -> 0
2 -> 0
1 -> 1
100011001
9+16+256=281
00000001 00011001 = 1 25 (dec) = 01 19 (hex)
per tant, 281 = 1 25 (dec) = 01 19 (hex)

però els caràcters 1 i 25, en la taula ASCII, veig que no es poden pintar. Escullo un altre valor per fer l'exemple.

333 = 000000101001101 (bin) = 0000001 01001101 (bin) = 2 77 (dec) = 14D (hex)

i precisament el valor 77 en la taula ASCII és la lletra M (i el valor 2 no és representable).

En la referència de l'Arduino m'apunto les funcions que puc necessitar:

  • byte data type: A byte stores an 8-bit unsigned number, from 0 to 255.
byte b = B10010;  // "B" is the binary formatter (B10010 = 18 decimal) 
  • word data type: A word stores a 16-bit unsigned number, from 0 to 65536. Same as an unsigned int.
  • byte() Converts a value to the byte data type.
  • word() Convert a value to the word data type or create a word from two bytes.
Syntax:
word(x)
word(h, l)

Parameters:
x: a value of any type
h: the high-order (rightmost) byte of the word
l: the low-order (leftmost) byte of the word 

Els Bitwise Operators són

  • Bitwise AND (&)
    int a =  92;    // in binary: 0000000001011100
    int b = 101;    // in binary: 0000000001100101
    int c = a & b;  // result:    0000000001000100, or 68 in decimal.
  • Bitwise OR (|)
    int a =  92;    // in binary: 0000000001011100
    int b = 101;    // in binary: 0000000001100101
    int c = a | b;  // result:    0000000001111101, or 125 in decimal.
  • Bitwise XOR (^)
    int x = 12;     // binary: 1100
    int y = 10;     // binary: 1010
    int z = x ^ y;  // binary: 0110, or decimal 6
  • Bitwise NOT (~)
    int a = 103;    // binary:  0000000001100111
    int b = ~a;     // binary:  1111111110011000 = -104
  • bitshift left (<<),bitshift right (>>)

These operators cause the bits in the left operand to be shifted left or right by the number of positions specified by the right operand.

    int a = 5;        // binary: 0000000000000101
    int b = a << 3;   // binary: 0000000000101000, or 40 in decimal
    int c = b >> 3;   // binary: 0000000000000101, or back to 5 like we started with

When you shift a value x by y bits (x << y), the leftmost y bits in x are lost, literally shifted out of existence:

    int a = 5;        // binary: 0000000000000101
    int b = a << 14;  // binary: 0100000000000000 - the first 1 in 101 was discarded

Anem doncs a imprimir pel serial.print els dos bytes:

int i;
word w;
byte b1,b2;

i =  333;
w=word(i);
Serial.print(w);
Serial.print("\n");
b1=byte(w);
Serial.print(b1);
Serial.print("\t");
b2 = w >> 8;
Serial.print(b2);
Serial.print("\n");

ens apareix una M i un caràcter no-representable.

Ara aquest valor (word, 2 bytes) els he d'escriure i llegir en la EEPROM

 void setup() {
   
  Serial.begin(9600);

int i;
word w;
byte b1,b2;
int addr=0;

i =  333;
w=word(i);
Serial.print(w);
Serial.print("\n");
b1=byte(w);
Serial.print(b1);
Serial.print("\t");
b2 = w >> 8;
Serial.print(b2);
Serial.print("\n");
<pre>
I ara ja podem escriure i llegir aquest word (2 bytes) en la EEPROM:
<pre>
  Wire.begin();
  
  i2c_eeprom_write_byte(0x50, addr, b1);
  delay(10); //pequeña pausa despues de escribir en la memoria
  addr++;
  i2c_eeprom_write_byte(0x50, addr, b2);
  delay(10); //pequeña pausa despues de escribir en la memoria
  
  //i ara llegeixo
  addr=0; //direccion a leer
  byte b = i2c_eeprom_read_byte(0x50, 0); //acceso a la primera posicion de memoria
  
  while (b!=0) {
    Serial.print((char)b); //enviar al ordenador
    addr++; //siguiente direccion
    b = i2c_eeprom_read_byte(0x50, addr); //acceso a posicion de memoria
  } 
  
  delay(1000);
 }

Resultat:

333
M	�
M�aaaaaaa:

Recordem que 'M' és el 1r byte (el menys significatiu, el de la dreta), i l'altre és el de l'esquerra (el més significatiu). Les a's és informació que ja hi havia grabada en la EEPROM. Així doncs, si vull escriure molts bytes els he d'anar posant un darrere l'altre (addr++).


Calculem què es triga en fer el reset:

512Kb=64KB=65536 bytes * 10 ms/byte = 655360 ms = 655 segons = 11 minuts

això és correcte fent un delay de 10ms, que podria ser un valor més petit o més gran.

Amplificador diferencial LM392

LM392.JPG

La sortida del sensor en el rang de temperatures que em moc (posem 16-23ºC) em dóna molt poc rang dinàmic, i la gràfica és molt pobra. Això es pot millorar utilitzant un amplificador diferencial. He optat pel LM392 (que he trobat a Onda Radio), i tot i que en principi és fàcil de configurar per mi no ho ha sigut tant.

El LM392 és alhora un comparador (pins de l'esquerre) i un Amp Op (pins de la dreta). En tota la literatura es pot veure com és un amplificador operacional que treballa en mode amplificador diferencial. Si faig R1=R3 i R2=R4, queda molt simplificat, i la sortida és:

Vo = R2/R1 (Vref - Vin)

on Vref és la tensió de referència a partir de la qual vull l'origen dels outputs, i Vin és la tensió que em ve del sensor de temperatura.

A efectes pràctics, jo escullo Vref=0 (connecto al GND, tot i que també podria utilitzar un divisor de tensió), R1=10K i R2=33K. D'aquesta manera s'aconsegueix una amplificació de 3,3 que augmenta el rang dinàmic.

Aquesta és la teoria. A la pràctica no ho sé, però la qüestió és que configurat d'aquesta manera puc obtenir una gràfica d'una variació diària de la temperatura decent.

Nota: al final això no em cal per acabar el projecte. Això de fer referència a ground no és del tot correcte. També he fet proves amb el LM308. No he obtingut resultats evidents.

llegir el port sèrie amb llenguatge C

Quan tingui la memòria EEPROM plena d'informació, s'ha de posar el arduino en mode lectura, i el que fa és volcar-ho sobre el port sèrie. Es poden fer dues coses: a) tenir la consola sèrie oberta, i aleshores faig control-C control-V; b) o bé, més elegant, tenir una petita aplicació C que llegeixi el port sèrie i volqui el contingut en un fitxer.

Em baso en el Linux serial port test program (http://www.comptechdoc.org/os/linux/programming/c/linux_pgcserial.html), que em funciona. A partir d'aquest codi, l'hauré de modificar per tal de només escoltar el que m'arribi del port /dev/ttyUSB0 a 9600 bps, i volcar el contingut a fitxer.

Carpeta: /home/joan/llegir_port_serie

Al final no cal fer res d'això. Millor utilitzar la consola sèrie de l'Arduino, o bé utilitzar el minicom. En el cas del minicom hi ha l'opció d'enviar a un fitxer tot el que llegeixi pel port sèries

Nota: al final això no em cal per acabar el projecte

Alimentació externa de l'Arduino

llegir

Els reguladors de tensió tenen un drop-out, que vol dir que per aconseguir 5 V s'han d'alimentar almenys amb 6,6-7V. Ara bé, compte que les piles alcalines de 9V tindran poca autonomia. En aquest sentit, és millor les piles AA de NiMh. Tot això fa que no hi hagi una solució elegant i barata...

En els detalls del Arduino Mega (http://arduino.cc/en/Main/ArduinoBoardMega) veig que:

Operating Voltage	5V
Input Voltage (recommended)	7-12V
Input Voltage (limits)	6-20V

El que sí que és factible és utilitzar un alimentador de 220V AC as 12-9V DC, amb l'inconvenient que aleshores ja no és un sistema autònom.

The Arduino Mega can be powered via the USB connection or with an external power supply. The power source is selected automatically.

External (non-USB) power can come either from an AC-to-DC adapter (wall-wart) or battery. The adapter can be connected by plugging a 2.1mm center-positive plug into the board's power jack. Leads from a battery can be inserted in the Gnd and Vin pin headers of the POWER connector.

The board can operate on an external supply of 6 to 20 volts. If supplied with less than 7V, however, the 5V pin may supply less than five volts and the board may be unstable. If using more than 12V, the voltage regulator may overheat and damage the board. The recommended range is 7 to 12 volts.

Nota: al final això no em cal per acabar el projecte

sensor_temperatura_lcd3.pde

Ara ajunto tot el coneixement que he adquirit per fer el projecte final: LM35, memòria EEPROM i pantalla LCD.

Hi ha tres modes:

  • esborrar: esborra tota la informació de la EEPROM
  • escriptura: mode normal. Escriu la informació de la temperatura en la EEPROM, port sèrie i pantalla LCD
  • lectura: volca la informació de la EEPROM en el port sèrie.
 /* ********************************
 Joan Quintana Compte - nov 2009
 joanqc@gmail.com
 www.joanillo.org
 
 -menu per accedir als diferents modes:
   0) esborrar totalment la memòria (mode=0)
   1) mode escriptura (mode=1)
   2) mode lectura: (mode=2).
************************************ */

 #include <LiquidCrystal.h>
 #include <Wire.h> //llibreria I2C

 // initialize the library with the numbers of the interface pins
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 
 int mode=0;
 int sensorPin = 2;
 int sensorValue = 0;
 float temperatura;
 int addr=0;
 word w;
 byte b1,b2;
 double temp = 0; // temperature variables
 int tempenter,tempdecimal;
 float samples[8];
 
 void setup() {
   
  Serial.begin(9600);
  analogReference(INTERNAL);
  
  Wire.begin();
  
  char cadena[] = "Temp:"; //capçalera
  if (mode==1){ //mode escriptura
  i2c_eeprom_write_page(0x50, 0, (byte *)cadena, sizeof(cadena));
  delay(10);
  addr=sizeof(cadena)-1;
  }
  
   // set up the LCD's number of rows and columns: 
   lcd.begin(16, 2);
   lcd.setCursor(0, 0);
   lcd.print("Temperatura");
   delay(1000);
   
    //lectura: per quan vull recuperar la informació que hi ha a la EEPROM
    if (mode==2){ //mode lectura
      lcd.setCursor(0, 0);
      lcd.print("Lectura      ");
      addr=0; //direccion a leer
      byte b1 = i2c_eeprom_read_byte(0x50, 5); //accés a les posicions on comencen les dades (5 i 6 bytes, al començament hi ha 'Temp:'
      byte b2 = i2c_eeprom_read_byte(0x50, 6);

      addr=5;
      while (b1!=0) {
        w=word(b2,b1);
        Serial.print((addr-3)/2);
        Serial.print("\t");
        Serial.print((int)w);
        Serial.print("\t");
        Serial.print(( 2.50 * (double)w * 100.0) / 1024.0);
        //temperatura = ( 2.50 * sensorValue * 100.0) / 1024.0;
                
        Serial.print("\n");
        addr=addr+2; //llegim de 2 en 2
        b1 = i2c_eeprom_read_byte(0x50, addr);
        b2 = i2c_eeprom_read_byte(0x50, addr+1);
      } 
   
   }
    
    if (mode==0){ //mode reset
        addr=0;
        lcd.setCursor(0, 0);
        lcd.print("memory clear");
        for (long i = 0; i<65536; i++) //dura una mitja hora...
        {
          i2c_eeprom_write_byte(0x50, addr, 0);
          Serial.print(i);
          Serial.print("\n");
          delay(5);
          addr++;
        }
        lcd.setCursor(0, 1);
        lcd.print("clear OK");
    }
 }

 void loop() {
   if (mode==1){ //mode escriptura

  
     //càlculs
     
     for(int i = 0;i<=7;i++){ // gets 8 samples of temperature
        sensorValue = analogRead(sensorPin); //conversor analògic-digital. 0=0v; 1024=2.5V -> no són 5V perquè utilitzo AREF
        temperatura = ( 2.50 * sensorValue * 100.0) / 1024.0;
     
        //samples[i] = ( 5.0 * sensorValue * 100.0) / 1024.0;
        samples[i] = ( 2.50 * sensorValue * 100.0) / 1024.0; //el 2.50 ve perque AREF=2.5 per defecte amb el Arduino Mega, i utilitzo analogReference(INTERNAL);
    
        temp = temp + samples[i];
        delay(1000);
    
    }
    

    temp=round(temp*10/8.0); //a temp tinc dos decimals, i la gràcia i lo difícil és obtenir només un decimal que s'ajusta més a la realitat.
    tempenter=temp/10;
    tempdecimal=fmod(temp,10);

    //escriputra port sèrie
    Serial.print("sensor:");
    Serial.println(sensorValue);
    Serial.print(tempenter);
    Serial.print(".");
    Serial.print(tempdecimal);
    Serial.println(" C");
     
    //escriptura LCD
    lcd.setCursor(0, 0);
    lcd.print("Temperatura");     
    lcd.setCursor(0,1);
    lcd.print("          ");
    lcd.setCursor(0,1);
    lcd.print(tempenter);
    lcd.print(".");
    lcd.print(tempdecimal);
    lcd.print(" C");
     
    //escriptura EEPROM
  
    w=word(sensorValue);
    //Serial.print(w);
    //Serial.print("\n");
    b1=byte(w);
    //Serial.print(b1);
    //Serial.print("\t");
    b2 = w >> 8;
    //Serial.print(b2);
    //Serial.print("\n");
  
    //EEPROM
    //escriptura de les dades
    i2c_eeprom_write_byte(0x50, addr, b1);
    delay(10);
    addr++;
    i2c_eeprom_write_byte(0x50, addr, b2);
    delay(10);
    addr++;
  
    delay(1000); //mode prova, escriu cada 2 segons
    //delay(180000); //espera 1 minut. en 24 h tindrem 1440 mostres

    temp = 0;


   }
 }

//Funcions per llegir i escriure a la EEPROM. Es troben a la wiki d'Arduino: http://www.arduino.cc/playground/Code/I2CEEPROM
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB
  Wire.send(rdata);
  Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddresspage >> 8)); // MSB
  Wire.send((int)(eeaddresspage & 0xFF)); // LSB
  byte c;
  for ( c = 0; c < length; c++)
    Wire.send(data[c]);
  Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.receive();
  return rdata;
}

// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
  Wire.beginTransmission(deviceaddress);
  Wire.send((int)(eeaddress >> 8)); // MSB
  Wire.send((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,length);
  int c = 0;
  for ( c = 0; c < length; c++ )
    if (Wire.available()) buffer[c] = Wire.receive();
}

video

guió

  • 1. capçalera
  • 2. introducció a Arduino
  • 3. LM35, LCD display, memòria EEPROM
  • 4. entorn de programació
  • 5. funcionament. Variació temperatura. Temperatura puja i baixa
  • 6. data logging d'un dia sencer. Veure en el serial print com es llegeixen les dades, i com es visualitza una gràfica del registre de tot un dia.
  • crèdits

transcripció video català

Vull ensenyar el funcionament bàsic de la placa Arduino. Aquesta petita meravella de la tecnologia consta d'un microcontrolador Atmel, nombroses entrades i sortides digitals, entrades i sortides analògiques, comunicació sèrie i bus I2C, connexió molt fàcil amb l'ordinador via USB, des d'on podem desenvolupar, compilar i carregar el firmware. Arduino segueix la filosofia de l'Open Source Hardware, en la mateixa línia que l'Open Source Software, i gràcies a això podem trobar plaques que complementen i augmenten les possibilitats de l'Arduino, com ara una placa Ethernet, connexió Bluetooth, connexió wireless, connexió amb memòries SD.

Per veure les possibilitats de l'Arduino farem un sensor de temperatura, mostrant la temperatura en un display LCD i grabant les dades a una memòria EEPROM externa.

El sensor de temperatura LM35 té una resposta molt linial i és fàcil de calibrar. Amb l'Arduino podem escriure fàcilment en el display LCD. La memòria EEPROM és de 512 kbits o 64 Kbytes. Com que necessitem 2 bytes per emmagatzemar cada mostra, podem emmagatzemar 32000 mostres. Si agafem una mostra cada 5 minuts són 160000 minuts, és a dir, unes 2600 h i 3 mesos d'autonomia. Si es necessita més memòria, es poden trobar altres solucions com ara encadenar vàries memòries EEPROM, o bé utilitzar una placa de memòria SD que complementa l'Arduino. En aquest cas no escrivim la temperatura, que té decimals, sinó les dades que obtenim del sensor.

Amb Arduino tenim un entorn de desenvolupament que ens facilita molt la feina. El SDK està programat en Java, però el llenguatge amb què programem el microcontrolador és C o C++. Allò bàsic és escollir el teu model d'Arduino, en aquest cas un Arduino Mega, escollir el port sèrie, en aquest cas és un port sèrie virtual que físicament representa la connexió USB, el botó de compilar, i el botó de fer upload del firmware al microcontrolador.

Com podem veure, el sensor segueix fidelment les variacions de temperatura. El sensor de temperatura LM35 està calibrat directament amb graus celsius, la qual cosa simplifica molt el circuit.

A mode d'exemple, he registrat dins l'EEPROM les dades de quatre dies. Fiquem el firmware en mode lectura, carreguem el codi al microcontrolador, i per la sortida sèrie puc veure les dades llegides directament de l'EEPROM. Aquestes dades les copio al teu full de càlcul preferit, i podem visualitzar un registre típic de variació diària de temperatura.

transcripció video castellà

Quiero enseñaros el funcionamiento básico de la placa Arduino. Esta pequeña maravilla de la tecnología consta de un microcontrolador Atmel, numerosas entradas y salidas digitales, entradas y salidas analógicas, comunicación serie y bus I2C, conexión muy fácil con el ordenador via USB, desde donde podemos desarrollar, compilar y cargar el firmware. Arduino sigue la filosofía del Open Source Hardware, en la misma línea que el Open Source Software, y gracias a esto podemos encontrar placas que complementan y aumentan las posibilidades de Arduino, como una placa Ethernet, conexión Bluetooth, conexión wireless, conexión con memorias SD. Para ver las posibilidades de Arduino haremos un sensor de temperatura, mostrando la temperatura en un display LCD y grabando los datos en una memoria EEPROM externa.

El sensor de temperatura LM35 tiene una respuesta muy lineal y es fácil de calibrar. Con Arduino podemos escribir fácilmente en el display LCD. La memoria EEPROM es de 512 kbits o 64 Kbytes. Com o necesitamos 2 bytes para almacenar cada muestra, podemos almacenar 32000 muestras. Si cogemos una muestra cada 5 minutos son 160000 muestras, es decir, unas 2600 h y 3 meses de autonomía. Si se necesita más memoria se pueden encontrar otras soluciones, como encadenar varias memorias EEPROM, o bien utilizar una placa de memoria SD que se puede acoblar al Arduino. En este caso no escribimos la temperatura, que tiene decimales, sino los datos que obtenemos del sensor.

Con Arduino tenemos un entorno de desarrollo que nos facilita las tareas. El SDK está programado con Java, pero el lenguage con que programamos el microcontrolador es C o C++. Lo básico es escoger tu modelo de Arduino, en este caso un Arduino Mega, escoger el puerto serie, en este caso es un puerto serie virtual que físicamente representa la conexión USB, el botón de compilar, y el botón para hacer upload y cargar el firmware en el microcontrolardor.

Como podemos ver, el sensor sigue fielmente las variaciones de temperatura. El sensor de temperatura LM35 está calibrado directamente en grados celsius, lo que simplifica mucho la circuitería.

A modo de ejemplo, hemos registrado en la EEPROM los datos de varios días. Ponemos el software en modo Lectura, lo cargamos al microcontrolador, y por la salida serie puedo ver los datos leídos directamente de la EEPROM. Estos datos se copian en tu hoja de cálculo preferida, y podemos visualizar un registro típico de variación diaria de temperatura.

transcripció video anglès

I want to show the basics of Arduino to develop an electronic project. This little technological wonder is composed by an Atmel microcontroller, lots of analogical and digital inputs and outputs, serial communication and bus I2C, an easy connection with the computer via USB, from where you can develop, compile and load the firmware. Arduino follows the philosophy of the Open Source Hardware, related with the Open Source Software, and thanks that we can found boards and shields that expand the possibilities of the Arduino itself, like an ethernet shield, a bluetooth shield, a wireless shield, or the possibility to connect SD memories.

To show the Arduino possibilities, we are going to build a temperature sensor, showing the outdoor temperature in a liquid crystal display, and storing the data samples in an external EEPROM memory.

The temperature sensor is an LM35, and has a very lineal response and is easy to calibrate. With Arduino is so easy to write in a Liquid Crystal Display. The EEPROM memory has 512 kbits, or 64 Kbytes. Because we need 2 bytes to store each sample, we can store 32000 samples. If we fetch one sample every five minutes, we can register 160000 minutes, it means about 2600 h or 3 months of autonomy. If you need more memory, you can chain several EEPROM memories or use the SD Arduiono shield. In this case we don't write the temperature, that has decimals, we write de data output from the sensor. We also have an LCD display, and is so easy from Arduino to write bytes in the display.

With Arduino we have a software developers kit that makes easy our job. This SDK is developed in Java, but de user programming language is C or C++ related. The basics are to choose the Arduino model, in this case an Arduino Mega, to choose the serial port, in this case is a virtual serial port that physically represents the USB connection, the compilation button and the uploading button, to upload the firmware to the microcontroller.

We can see how this sensor follow the temperature oscillations. The LM35 temperature sensor is calibrated directly in Celsius degrees, and this is the reason that the schematics is so simple in this project.

In this example, we have registered the outdoor temperature for four days into the EEPROM memory. We put the firmware in reading mode, we upload this code to the microcontroller, and in the serial data console we can see all the temperatures read directly from the EEPROM. I copy all this data in my prefered spreadsheet, and visualize a typical register of a daily temperature variation.

Detalls tècnics del vídeo

  • p1: portada
  • p2: introducció a Arduino
  • p3: LM35, LCD display, memòria EEPROM
  • p4: entorn de programació
  • p5: funcionament. Variació temperatura. Temperatura puja i baixa
  • p6: data logging d'un dia sencer. Veure en el serial print com es llegeixen les dades, i com es visualitza una gràfica del registre de tot un dia
  • p7: crèdits

NOTA POSTERIOR. Per què treballar amb 640x480? Hauria de treballar amb la resolució més alta possible (la pantalla ja em dóna prou resolució, i de la videocàmera treballar amb qualitat màxima. Aleshores treballar amb la mínima de les dues fins al final (mantenint la ratio 4:3 o 16:9, que la videocàmera també pot treballar amb les dues). I quan converteixo a format YouTube aleshores puc baixar la resolució o bé que sigui l'aplicatiu de YouTube el que m'ajusti la qualitat o la resolució. Però sens dubte, m'interessa tenir uns videos originals amb la màxima resolució possible

$ cd /home/joan/projectes/ELECT_22/video/

$ recordmydesktop --no-sound -delay 3 -fps 25 --overwrite -o p1.ogv
$ ffmpeg -i p1.ogv -cropleft 106 -cropright 106 -s 640x480 -aspect 4:3 -r 25 -sameq p1.avi -ss 00:00:00.000 -t 00:00:06.000

$ ffmpeg -i /home/joan/prova_video/p1.ogv -cropleft 106 -cropright 106 -s 640x480 -aspect 4:3 -r 25 -sameq /home/joan/prova_video/p1.avi
$ avisplit -i /home/joan/prova_video/p1.avi -c -o /home/joan/prova_video/p1.avi -t 00:00:00-00:00:06
$ recordmydesktop --no-sound -delay 3 -fps 25 --overwrite -o p2_1.ogv
$ ffmpeg -i p2_1.ogv -cropleft 106 -cropright 106 -s 640x480 -aspect 4:3 -r 25 -sameq p2_1.avi -ss 00:00:00.000 -t 00:00:09.000
$ ffmpeg -i p3_5.avi -s 640x480 -sameq p3.avi -ss 00:00:22.000 -t 00:00:38.000
$ recordmydesktop --no-sound -delay 6 -fps 25 --overwrite -o p4.ogv
$ ffmpeg -i p4.ogv -cropright 212 -s 640x480 -aspect 4:3 -r 25 -sameq p4.avi -ss 00:00:00.000 -t 00:01:12.000
$ ffmpeg -i p3_5.avi -s 640x480 -sameq p5.avi -ss 00:00:00.000 -t 00:00:15.000
$ recordmydesktop --no-sound -delay 6 -fps 25 --overwrite -o p6.ogv
$ ffmpeg -i p6.ogv -cropright 212 -s 640x480 -aspect 4:3 -r 25 -sameq p6.avi -ss 00:00:00.000 -t 00:01:55.000
$ recordmydesktop --no-sound -delay 3 -fps 25 --overwrite -o p7.ogv
$ ffmpeg -i p7.ogv -cropleft 106 -cropright 106 -s 640x480 -aspect 4:3 -r 25 -sameq p7.avi -ss 00:00:00.000 -t 00:00:06.000

Ara ajuntem tots els videos:

$ avimerge -o proj22_sense_veu.avi -i p1.avi p2_1.avi p2_2.avi p2_3.avi p2_4.avi p2_5.avi p5.avi p3.avi p4.avi p5.avi p6.avi p7.avi 

faig el so:

$ arecord -r 44100 -f cd -t wav -D plughw:0 ELECT_22_so.wav
o bé
$ arecord -r 44100 -f cd -t wav -Dplug:record_left ELECT_22_so.wav
$ aplay -D plughw:UA25EX ELECT_22_so.wav
$ aplay -D plughw:0 ELECT_22_so.wav

em preocupa la sortida, que tingui prou volum. Al final he hagut de parlar fort en el micro, doncs el resultat que obtenia era amb poc volum (mirar)

NOTA POSTERIOR: Una possible solució per al tema del micròfon és l'aplicatiu alsamixer. Mirar bé com estan tots els paràmetres i ajustar algun control relacionat amb el micròfon, fer proves... COMPROVAT, aquest era el problema. Ara ja tinc un nivell de so adequat.

i ajunto el so amb el video sense so:

$ ffmpeg -i ELECT_22_so.wav -i proj22_sense_veu.avi -y -sameq ELECT_22.avi

finalment, exporto al format de YouTube:

$ ffmpeg -i ELECT_22.avi -s 640x480 -pass 1 -passlogfile log-file -ar 44100 -sameq -y ELECT_22.flv

i pujo el video:

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/hq6r_xZwNeU&hl=es&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/hq6r_xZwNeU&hl=es&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>

MILLORES A REALITZAR

  • incorporar les notes posteriors que s'expliquen més amunt
  • popsar una música de fons, encara que sigui fluixeta, per tal de no deixar silencis llargs i veure que hi ha una continuïtat. Intentar que no hi hagi tants silencis
  • Fer zoom, un pla més curt, en les escenes que ho requereixin, com per exemple, es podria haver fet un zoom de la LCD
  • això del full de paper és molt cutre. Buscar una superfície plana més gran.
  • fer una transició (fade) del títol a escena, i de l'escena a crèdits, doncs al ser negre es fa necessari perquè si no sobta.
  • captura de pantalla: que es vegi més el detall. Treballar amb més resolució, i potser puc capturar una part de la pantalla, no tota. Crec que una solució seria: la videocàmera a la seva màxima resolució (format panoràmic), i el recordesktop, en comptes de capturar tota la pantalla, capturar una finestra equivalent. Una altra possibilitat és utilitzar allò que fan els cécs, de fer un zoom de la pantalla.

Per tal de capturar una finestra de la pantalla, recordmydesktop té l'opció -windowid.

Per saber la id d'una finestra (s'ha de marcar sobre la finestra, i ha d'estar visible):

xwininfo
o bé
xwininfo |grep "Window id:"|sed -e "s/xwininfo\:\ Window id:\ // ;s/\ .*//" 
0x24000cf
$ recordmydesktop -windowid 0x24000cf -o foo.ogv

creat per Joan Quintana Compte, novembre 2009