Raspberry pi pico
Programación C
Sensores:
LDR - DHT22 (AM2302) - BMP180 - 18B20
OLED DS1302
Anteriormente había
realizado un visualizador
de sensores con el ESP32.Programación C
Sensores:
LDR - DHT22 (AM2302) - BMP180 - 18B20
OLED DS1302
Algún tiempo después lo hice en la Raspberry pi pico programándolo en microPython - PICO4
En este artículo lo realizo con la Raspberry pi pico y programando en C.
El final del montaje queda de la siguiente forma:
sen_p1 y sen_p2
El primer paso es colocar un led a modo de piloto de alimentación, y hacer parpadear el led que viene en la placa.
#include
<stdio.h> #include <pico/stdlib.h> #define OUTPUT 1 #define INPUT 0 #define HIGH 1 #define LOW 0 void pinMode(unsigned int port, char modo); void digitalWrite(unsigned int port, char val); void delay(long t); #define MILED 25 int main() { stdio_init_all(); delay(1000); printf("-----------------------\n"); printf("----Hola SENSORES------\n"); pinMode(MILED, OUTPUT); while(1) { printf("Estado %d\n",0); digitalWrite(MILED, LOW); delay(1000); printf("Estado %d\n",1); digitalWrite(MILED, HIGH); delay(2000); } } //---------------I/O---------------- void pinMode(unsigned int port, char modo) { gpio_init(port); if(modo==OUTPUT) gpio_set_dir(port, GPIO_OUT); else gpio_set_dir(port, GPIO_IN); } void digitalWrite(unsigned int port, char val) { gpio_put(port, val); } void delay(long t) { sleep_ms(t); } |
A partir de ahora, las funciones se meterán en un fichero ardu.h donde se incluirán las funciones.
sen_p3
En este paso colocamos un sensor de temperatura y humedad
El sensor es el DHT22 o su equivalente AM2302.
#include
<stdio.h> #include <pico/stdlib.h> #include "ardu.h" #define MILED 25 //----DHT----------- #define PIN_DHT 15 unsigned int humedad,temperatura,control; unsigned char dataSensor[5]; unsigned int ck; void leerDHT(void); int main() { stdio_init_all(); delay(1000); printf("----Hola SENSORES------\n"); pinMode(MILED, OUTPUT); while(1) { leerDHT(); printf("AM2302_H=%.1f%% T=%.1f ºC Control=%d\n",(float)humedad/10,(float)temperatura/10,control); digitalWrite(MILED, LOW); delay(1000); digitalWrite(MILED, HIGH); delay(2000); printf("-----------------------\n"); } } //----------DHT-------------------- void leerDHT(void) { unsigned char n,z,x; unsigned char contador1,contador0; unsigned char datos[45]; control=temperatura=humedad=0; pinMode(PIN_DHT,OUTPUT); digitalWrite(PIN_DHT,LOW); delay(2); digitalWrite(PIN_DHT,HIGH); pinMode(PIN_DHT,INPUT); for(n=0;n<42;n++) { contador0=contador1=0; while(1==digitalRead(PIN_DHT)) { delayMicroseconds(5); contador1++; if(contador1>250)goto salir; } while(0==digitalRead(PIN_DHT)) { delayMicroseconds(5); contador0++; if(contador1>250)goto salir; } datos[n]=contador1; } z=0; x=0; for(n=2;n<42;n++) { dataSensor[z]<<=1; if(datos[n]>=contador0) { (dataSensor[z])|=1;} x++; if(x==8) { x=0; z++; } } humedad=dataSensor[0]; humedad<<=8; humedad|=dataSensor[1]; temperatura=dataSensor[2]; temperatura<<=8; temperatura|=dataSensor[3]; control=dataSensor[4]; salir: ; } //--------------------------------- |
Primero la hice sobre arduino y luego trasladé el código a la Raspberry pi pico.
El paso de una placa a otra fue fácil, no tuve que hacer ningún cambio.
El protocolo 1-wire, es bastante sencillo de programar.
----Hola SENSORES------
AM2302_H=39.4% T=22.5 ºC Control=108
-----------------------
AM2302_H=40.7% T=22.5 ºC Control=121
sen_p4
En este paso ponemos un sensor de luz tipo LDR, y leemos el valor mediante un conversor ADC.
... #include "hardware/gpio.h" #include "hardware/adc.h" ... //---Voltios LDR--- uint16_t result; ... main() { ... //INIT --ADC-- adc_init(); adc_gpio_init(28); // Select ADC input 0 (GPIO26) adc_select_input(2); const float conversion_factor = 3.3f / 4096; ... while(1) { .... result = adc_read(); printf("LDR-> RAW=%d, voltaje=%f V\n", result, result * conversion_factor); ... } } |
Este código no tiene demasiado explicación, configuración pin 28, y lectura del valor.
----Hola SENSORES------
AM2302_H=38.8% T=23.5 ºC Control=112
LDR-> RAW=402, voltaje=0.323877 V
-----------------------
AM2302_H=40.1% T=23.5 ºC Control=125
LDR-> RAW=403, voltaje=0.324683 V
-----------------------
sen_p5
En este paso colocamos un sensor de presión que además dispone de un sensor de temperatura.
El sensor viene en un módulo BMP180, los datos se mandan mediante el bus I2C.
... #include "pico/binary_info.h" #include "hardware/i2c.h" #include <math.h> ... //----I2C------- i2c_inst_t *XXi2c = i2c0; //i2c1 para 26-27 12c0 para 0-1 ... #define SDA_PIN 0 #define SCL_PIN 1 #define BMP180_ADDR 0x77 // 7-bit address #define BMP180_WRITE_MODE _u(0xFE) #define BMP180_READ_MODE _u(0xFF) #define BMP180_REG_CONTROL 0xF4 #define BMP180_REG_RESULT 0xF6 #define BMP180_COMMAND_TEMPERATURE 0x2E void bmpGetData(void); void bmpComand(uint8_t cmd); int bmpInput(char address); void getVarBMP(void); void scanI2C(void); long Temperatura, Presion, PresionBase; ... main() { ... //INIT --I2C-- printf("SDA=%d SDL=%d \n", SDA_PIN, SCL_PIN); i2c_init(i2c_default, 100000); gpio_set_function( SDA_PIN, GPIO_FUNC_I2C); gpio_set_function( SCL_PIN, GPIO_FUNC_I2C); gpio_pull_up( SDA_PIN); gpio_pull_up( SCL_PIN); bi_decl(bi_2pins_with_func( SDA_PIN, SCL_PIN, GPIO_FUNC_I2C)); scanI2C(); getVarBMP(); delay(50); bmpGetData(); //Calcula la presión base...... PresionBase=Presion; ... while(1) { .... bmpGetData(); printf("BMP_TempGRADOS=%0.2f ºC\n",(float)Temperatura/100); printf("BMP_Presion=%0.2f bares\n",(float)Presion/100); ... } } |
Solo muestro el código correspondiente a la comunicación I2C y al cálculo de la presión.
En este caso el código del arduino es totalmente diferente al de la Raspberry.
Me costó mucho tiempo y trabajo el descubrir la diferencia entre los tipos de enteros.
En arduino el tamaño de int es de 16bit, en la raspberry es de 32bit.
Y se me ocurrió utilizar el tipo sort, y resulto erroneo su tamaño, por lo que lo mejor es utilizar int16_t o uint16_t.
Hay que tener en presente que existen varios I2C en la raspberry y debemos especificar el que usamos.
Por ejemplo: i2c1 para 26-27 e 12c0 para 0-1 .........
Aunque la librería es mia, he utilizado algún código de otros, en bibliografía pongo las fuentes.
-----------------------
AM2302_H=41.0% T=23.7 ºC Control=136
LDR-> RAW=915, voltaje=0.737183 V
BMP_TempGRADOS=22.21 ºC
BMP_Presion=934.37 bares
-----------------------
Señales del bus I2C cuando lee datos, funcion void bmpGetData(void)
sen_p6
En este paso colocamos un sensor de temperatura 18B20.
Este chip se comunica mediante una sola línea de datos, y si se quiere se puede utilizar solo dos lineas para hacer funcionar el sensor.
Además se pueden colocar varios chip en paralelo, que se podrán leer sus temperaturas independientemente.
//----DS18B20------ #define ONE_WIRE_PIN 22 void onewire_reset(); void onewire_write(unsigned char data); int onewire_read(); int ds1820_read(); float temp18B; ... main() { while(1) { .... temp18B=ds1820_read(); printf("DS18b20_Temp=%0.2f ºC\n",temp18B/10); ... } } //-------------ONEWIRE------------- void onewire_reset() { pinMode(ONE_WIRE_PIN,OUTPUT); digitalWrite(ONE_WIRE_PIN,LOW); delayMicroseconds(500); digitalWrite(ONE_WIRE_PIN,HIGH); pinMode(ONE_WIRE_PIN,INPUT); delayMicroseconds(500); digitalWrite(ONE_WIRE_PIN,HIGH); pinMode(ONE_WIRE_PIN,INPUT); } void onewire_write(unsigned char data) { unsigned char count; for(count = 0; count < 8; ++count) { pinMode(ONE_WIRE_PIN,OUTPUT); digitalWrite(ONE_WIRE_PIN,LOW); delayMicroseconds(2); if(data & 1) { digitalWrite(ONE_WIRE_PIN,HIGH); } else { digitalWrite(ONE_WIRE_PIN,LOW); } data>>=1; delayMicroseconds(60); digitalWrite(ONE_WIRE_PIN,HIGH); pinMode(ONE_WIRE_PIN,INPUT); delayMicroseconds(2); // for more than 1us minimum. } } int onewire_read() { unsigned char count; unsigned char data; for(count = 0; count < 8; ++count) { data>>=1; pinMode(ONE_WIRE_PIN,OUTPUT); digitalWrite(ONE_WIRE_PIN,LOW); delayMicroseconds(2); pinMode(ONE_WIRE_PIN,INPUT); delayMicroseconds(10); if(digitalRead(ONE_WIRE_PIN)&1 ) { data|=128; } delayMicroseconds(50); } delayMicroseconds(100); return data; } int ds1820_read() { unsigned char busy=0, tempL, tempH; long temp; onewire_reset(); onewire_write(0xCC); onewire_write(0x44); delay(10); onewire_reset(); onewire_write(0xCC); onewire_write(0xBE); tempL = onewire_read(); tempH = onewire_read(); temp=tempH; temp<<=8; temp|=tempL; //Serial.print(" HEX ");Serial.print(temp,HEX); temp=(temp*625)/1000; return(temp); } |
Está basado en un bus, un maestro y varios esclavos de una sola línea de datos en la que se alimentan.
En este protocolo se pueden colocar varios 18B20 en paralelo, por lo cual debería colocar una función de detección de elementos.
Otra forma es saber la identificación en ROM de cada elemento.
En mi caso uno de los 18B20 tiene la siguiente dirección: byte addr[8]={0x28,0xDC,0x5C,0x16,0xA8,1,0x3C,0x28};
Esto me hubiese costado mucho, además solo voy a colocar un 18B20, por lo que utilizo un modo de lectura diferente.
SKIP ROM [CCh] Este comando puede ahorrar tiempo en un sistema de bus de caída única al permitir que el bus maestro acceda al funciones de memoria sin proporcionar el código ROM de 64 bits. Si hay más de un esclavo presente en el bus y se emite un comando de lectura después del comando Saltar ROM, se producirá una colisión de datos en el bus como múltiples esclavos transmiten simultáneamente (los pulldowns de drenaje abierto producirán un resultado AND cableado). www.dalsemi.com
-----------------------
AM2302_H=42.3% T=24.7 ºC Control=159
LDR-> RAW=236, voltaje=0.190137 V
BMP_TempGRADOS=23.30 ºC
BMP_Presion=933.90 bares
-----------------------
sen_p7
Por último colocamos un visualizardor tipo OLED , el modelo SSD1306.
Lo bueno de colocar este modelo es que se conecta en el bus I2C, lo que resulta muy práctico y sencillo.
... #include "ole.h" char miBuffer[40]; ... main() { ... while(1) { ... xclearDisplay(); StringAT(0,0,"--SETA43--"); sprintf(miBuffer,"LDR=%d %0.3fV",result,result * conversion_factor); StringAT(0,1,miBuffer); sprintf(miBuffer,"DHT_Hum. %.1f %c",(float)humedad/10,37); StringAT(0,2,miBuffer); sprintf(miBuffer,"DHT_Temp. %.1f %cC",(float)temperatura/10,127); StringAT(0,3,miBuffer); sprintf(miBuffer,"DS18b20_=%0.2f %cC",temp18B/10,127); StringAT(0,4,miBuffer); sprintf(miBuffer,"BMP_Pres.=%0.1f b ",(float)Presion/100); StringAT(0,5,miBuffer); sprintf(miBuffer,"BMP_Temp.=%0.1f %cC",(float)Temperatura/100,127); StringAT(0,6,miBuffer); ... } } |
Es simple de utilizar, solo hay que añadir el fichero ole.h , no tiene muchas funciones, pero hace su trabajo.
Cuando empecé a programar la raspberry pi pico, pensé que la transición sería más fácil, pero no fue así.
La cantidad de bibliotecas que existe en arduino no existen en raspberry.
El paso de programas entre arduino y rasberry no es inmediata, y muchos de los programas y biblitecas no funcionan,
Debemos pensar que los int en arduino son de 16bit, y en raspberry es de 32bit, esto genera muchos problemas.
Si queremos utilizar enteror de 16bit en raspberry, se debe utilizar int16_t o uint16_t.
PROGRAMAS
Espero que este montaje os haya parecido interesante.
Saludos.
Juan Galaz
Bibliografía:
https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf
https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf
https://www.puntoflotante.net/termometro.htm
espgrs.html
28/02/2016 - Arduino - Predicción del tiempo. GY-68 - BMP-180. Predicción
21/02/2016 - Arduino power low - Termómetro máximos y mínimos con gráfica - DS18B20 LCD Nokia PCD8544. Tempe
09/02/2016 - Arduino -Barómetro - Termómetro. GY-68 - BMP-180. Parte 2 (librería propia). ArduBer
03/02/2016 - Arduino -Barómetro - Termómetro. GY-68 - BMP-180. Parte 1. ArduBar
No hay comentarios:
Publicar un comentario