Page 2 sur 2

Re: [RESOLU] Programmation d'un node pour un capteur BMP180

Publié : 04 sept. 2016, 02:39
par jackyhi
Bonsoir à tous
je viens de tester un sketch MySensors 2.0 pour BMP180 et avec un afficheur LCD nokia5110 qui a l'air de bien fonctionner!.

je me suis inspiré du skecth pressure.ino de mysensor dans la bibliothèque MySensorsArduinoExamples-master et d'autres sketch pour piloter le nokia5110 en ne consommant pas trop de ressources programme et mémoire. Difficulté de faire tourner deux périphérique utilisant la fonction SPI.

Ma cible un arduino Pro min Atmega328 3v3 8Mhz une sonde BMP180 un Bouton poussoir pour les leds backpan un écran LCD monochrome 48 lignes x 84 colonnes Nokia 5110 un module NRF24L01 le tout câblé sur une plaque à trous et alimenter par une batterie lithium lion 3,7v 3000mAh. Le bouton poussoir sert à amener à la masse la ligne Light de l'afficheur pour allumer les leds du backpan lorsqu'on veut lire l'afficheur dans le noir.

Mon environnement de travail Domoticz sur PC tournant sous Unbutu

Développement PC sous Windows 10 avec IDE 1.6.10
Gateway version Mysensors 2.0

Voici mon code:

Code : Tout sélectionner

/*
This Code has extra features 
including a XY positioning function on Display
and a Line Draw function on Nokia 3310 LCD 
It is modded from the original 
http://playground.arduino.cc/Code/PCD8544
*/
// Enable debug prints to serial monitor
//#define MY_DEBUG 
//

// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
//Definition niveau de puissance d'émission pour le NRF24L01  MIN,LOW,HIGH,MAX 
//Attention au débit nécessaire sur l'alimentation 3.3v lors de puissance MAX
#define MY_RF24_PA_LEVEL RF24_PA_MAX
#include <SPI.h>
#include <MySensors.h>  
#include <Wire.h>
#include <Adafruit_BMP085.h>

#define PIN_SCE   4  // LCD CS  .... Pin 2
#define PIN_RESET 8  // LCD RST .... Pin 1
#define PIN_DC    5  // LCD Dat/Com. Pin 3
#define PIN_SDIN  6  // LCD SPIDat . Pin 4
#define PIN_SCLK  7  // LCD SPIClk . Pin 5
                     // LCD Gnd .... Pin 7
                     // LCD Vcc .... Pin 6 to 3v3!!!
const int blPin = 3;    // PWM commande LED - Backlight LED, pin 8 on LCD.

#define LCD_C     LOW
#define LCD_D     HIGH

#define LCD_X     84
#define LCD_Y     48
#define LCD_CMD   0

#define BARO_CHILD 0
#define TEMP_CHILD 1


static const char ASCII[] PROGMEM = {
   0x00, 0x00, 0x00, 0x00, 0x00 // 20  
  ,0x00, 0x00, 0x5f, 0x00, 0x00 // 21 !
  ,0x00, 0x07, 0x00, 0x07, 0x00 // 22 "
  ,0x14, 0x7f, 0x14, 0x7f, 0x14 // 23 #
  ,0x24, 0x2a, 0x7f, 0x2a, 0x12 // 24 $
  ,0x23, 0x13, 0x08, 0x64, 0x62 // 25 %
  ,0x36, 0x49, 0x55, 0x22, 0x50 // 26 &
  ,0x00, 0x05, 0x03, 0x00, 0x00 // 27 '
  ,0x00, 0x1c, 0x22, 0x41, 0x00 // 28 (
  ,0x00, 0x41, 0x22, 0x1c, 0x00 // 29 )
  ,0x14, 0x08, 0x3e, 0x08, 0x14 // 2a *
  ,0x08, 0x08, 0x3e, 0x08, 0x08 // 2b +
  ,0x00, 0x50, 0x30, 0x00, 0x00 // 2c ,
  ,0x08, 0x08, 0x08, 0x08, 0x08 // 2d -
  ,0x00, 0x60, 0x60, 0x00, 0x00 // 2e .
  ,0x20, 0x10, 0x08, 0x04, 0x02 // 2f /
  ,0x3e, 0x51, 0x49, 0x45, 0x3e // 30 0
  ,0x00, 0x42, 0x7f, 0x40, 0x00 // 31 1
  ,0x42, 0x61, 0x51, 0x49, 0x46 // 32 2
  ,0x21, 0x41, 0x45, 0x4b, 0x31 // 33 3
  ,0x18, 0x14, 0x12, 0x7f, 0x10 // 34 4
  ,0x27, 0x45, 0x45, 0x45, 0x39 // 35 5
  ,0x3c, 0x4a, 0x49, 0x49, 0x30 // 36 6
  ,0x01, 0x71, 0x09, 0x05, 0x03 // 37 7
  ,0x36, 0x49, 0x49, 0x49, 0x36 // 38 8
  ,0x06, 0x49, 0x49, 0x29, 0x1e // 39 9
  ,0x00, 0x36, 0x36, 0x00, 0x00 // 3a :
  ,0x00, 0x56, 0x36, 0x00, 0x00 // 3b ;
  ,0x08, 0x14, 0x22, 0x41, 0x00 // 3c <
  ,0x14, 0x14, 0x14, 0x14, 0x14 // 3d =
  ,0x00, 0x41, 0x22, 0x14, 0x08 // 3e >
  ,0x02, 0x01, 0x51, 0x09, 0x06 // 3f ?
  ,0x32, 0x49, 0x79, 0x41, 0x3e // 40 @
  ,0x7e, 0x11, 0x11, 0x11, 0x7e // 41 A
  ,0x7f, 0x49, 0x49, 0x49, 0x36 // 42 B
  ,0x3e, 0x41, 0x41, 0x41, 0x22 // 43 C
  ,0x7f, 0x41, 0x41, 0x22, 0x1c // 44 D
  ,0x7f, 0x49, 0x49, 0x49, 0x41 // 45 E
  ,0x7f, 0x09, 0x09, 0x09, 0x01 // 46 F
  ,0x3e, 0x41, 0x49, 0x49, 0x7a // 47 G
  ,0x7f, 0x08, 0x08, 0x08, 0x7f // 48 H
  ,0x00, 0x41, 0x7f, 0x41, 0x00 // 49 I
  ,0x20, 0x40, 0x41, 0x3f, 0x01 // 4a J
  ,0x7f, 0x08, 0x14, 0x22, 0x41 // 4b K
  ,0x7f, 0x40, 0x40, 0x40, 0x40 // 4c L
  ,0x7f, 0x02, 0x0c, 0x02, 0x7f // 4d M
  ,0x7f, 0x04, 0x08, 0x10, 0x7f // 4e N
  ,0x3e, 0x41, 0x41, 0x41, 0x3e // 4f O
  ,0x7f, 0x09, 0x09, 0x09, 0x06 // 50 P
  ,0x3e, 0x41, 0x51, 0x21, 0x5e // 51 Q
  ,0x7f, 0x09, 0x19, 0x29, 0x46 // 52 R
  ,0x46, 0x49, 0x49, 0x49, 0x31 // 53 S
  ,0x01, 0x01, 0x7f, 0x01, 0x01 // 54 T
  ,0x3f, 0x40, 0x40, 0x40, 0x3f // 55 U
  ,0x1f, 0x20, 0x40, 0x20, 0x1f // 56 V
  ,0x3f, 0x40, 0x38, 0x40, 0x3f // 57 W
  ,0x63, 0x14, 0x08, 0x14, 0x63 // 58 X
  ,0x07, 0x08, 0x70, 0x08, 0x07 // 59 Y
  ,0x61, 0x51, 0x49, 0x45, 0x43 // 5a Z
  ,0x00, 0x7f, 0x41, 0x41, 0x00 // 5b [
  ,0x02, 0x04, 0x08, 0x10, 0x20 // 5c backslash
  ,0x00, 0x41, 0x41, 0x7f, 0x00 // 5d ]
  ,0x04, 0x02, 0x01, 0x02, 0x04 // 5e ^
  ,0x40, 0x40, 0x40, 0x40, 0x40 // 5f _
  ,0x00, 0x01, 0x02, 0x04, 0x00 // 60 `
  ,0x20, 0x54, 0x54, 0x54, 0x78 // 61 a
  ,0x7f, 0x48, 0x44, 0x44, 0x38 // 62 b
  ,0x38, 0x44, 0x44, 0x44, 0x20 // 63 c
  ,0x38, 0x44, 0x44, 0x48, 0x7f // 64 d
  ,0x38, 0x54, 0x54, 0x54, 0x18 // 65 e
  ,0x08, 0x7e, 0x09, 0x01, 0x02 // 66 f
  ,0x0c, 0x52, 0x52, 0x52, 0x3e // 67 g
  ,0x7f, 0x08, 0x04, 0x04, 0x78 // 68 h
  ,0x00, 0x44, 0x7d, 0x40, 0x00 // 69 i
  ,0x20, 0x40, 0x44, 0x3d, 0x00 // 6a j 
  ,0x7f, 0x10, 0x28, 0x44, 0x00 // 6b k
  ,0x00, 0x41, 0x7f, 0x40, 0x00 // 6c l
  ,0x7c, 0x04, 0x18, 0x04, 0x78 // 6d m
  ,0x7c, 0x08, 0x04, 0x04, 0x78 // 6e n
  ,0x38, 0x44, 0x44, 0x44, 0x38 // 6f o
  ,0x7c, 0x14, 0x14, 0x14, 0x08 // 70 p
  ,0x08, 0x14, 0x14, 0x18, 0x7c // 71 q
  ,0x7c, 0x08, 0x04, 0x04, 0x08 // 72 r
  ,0x48, 0x54, 0x54, 0x54, 0x20 // 73 s
  ,0x04, 0x3f, 0x44, 0x40, 0x20 // 74 t
  ,0x3c, 0x40, 0x40, 0x20, 0x7c // 75 u
  ,0x1c, 0x20, 0x40, 0x20, 0x1c // 76 v
  ,0x3c, 0x40, 0x30, 0x40, 0x3c // 77 w
  ,0x44, 0x28, 0x10, 0x28, 0x44 // 78 x
  ,0x0c, 0x50, 0x50, 0x50, 0x3c // 79 y
  ,0x44, 0x64, 0x54, 0x4c, 0x44 // 7a z
  ,0x00, 0x08, 0x36, 0x41, 0x00 // 7b {
  ,0x00, 0x00, 0x7f, 0x00, 0x00 // 7c |
  ,0x00, 0x41, 0x36, 0x08, 0x00 // 7d }
  ,0x10, 0x08, 0x08, 0x10, 0x08 // 7e ~
  ,0x78, 0x46, 0x41, 0x46, 0x78 // 7f DEL
};

const float A = 210;  //688; // <-- adapt this value to your own location's altitude  MANCE 210m
char strV[8];
//char strA[8];
//char strP[8];
char Str[13];
String strMsg;
// Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute.
const unsigned long SLEEP_TIME = 60000; 

const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
enum FORECAST
{
  STABLE = 0,     // "Stable Weather Pattern"
  SUNNY = 1,      // "Slowly rising Good Weather", "Clear/Sunny "
  CLOUDY = 2,     // "Slowly falling L-Pressure ", "Cloudy/Rain "
  UNSTABLE = 3,   // "Quickly rising H-Press",     "Not Stable"
  THUNDERSTORM = 4, // "Quickly falling L-Press",    "Thunderstorm"
  UNKNOWN = 5     // "Unknown (More Time needed)
};

Adafruit_BMP085 bmp = Adafruit_BMP085();      // Digital Pressure Sensor 

float lastPressure = -1;
float lastTemp = -1;
int lastForecast = -1;

const int LAST_SAMPLES_COUNT = 5;
float lastPressureSamples[LAST_SAMPLES_COUNT];

// this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
// get kPa/h be dividing hPa by 10 
#define CONVERSION_FACTOR (1.0/10.0)

int minuteCount = 0;
bool firstRound = true;
// average value is used in forecast algorithm.
float pressureAvg;
// average after 2 hours is used as reference value for the next iteration.
float pressureAvg2;

float dP_dt;
bool metric;

MyMessage tempMsg(TEMP_CHILD, V_TEMP);
MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
MyMessage forecastMsg(BARO_CHILD, V_FORECAST);




void LcdCharacter(char character)
{
  LcdWrite(LCD_D, 0x00);// Colonne vide de pagination
  unsigned int val = (character - 0x20) * 5;
  LcdWrite(LCD_D, pgm_read_byte_near(ASCII + val));
  LcdWrite(LCD_D, pgm_read_byte_near(ASCII + val+1));
  LcdWrite(LCD_D, pgm_read_byte_near(ASCII + val+2));
  LcdWrite(LCD_D, pgm_read_byte_near(ASCII + val+3));  
  LcdWrite(LCD_D, pgm_read_byte_near(ASCII + val+4));  
  LcdWrite(LCD_D, 0x00);// Colonne vide de pagination
}

void LcdClear(void)
{
  for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
  {
    LcdWrite(LCD_D, 0x00);
  }
}

void LcdInitialise(void)
{
  pinMode(PIN_SCE,   OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC,    OUTPUT);
  pinMode(PIN_SDIN,  OUTPUT);
  pinMode(PIN_SCLK,  OUTPUT);

  digitalWrite(PIN_RESET, LOW);
 // delay(1);
  digitalWrite(PIN_RESET, HIGH);

  LcdWrite( LCD_CMD, 0x21 );  // LCD Extended Commands.
  LcdWrite( LCD_CMD, 0xB7 );  // Set LCD Vop (Contrast). //B1
  LcdWrite( LCD_CMD, 0x04 );  // Set Temp coefficent. //0x04
  LcdWrite( LCD_CMD, 0x14 );  // LCD bias mode 1:48. //0x13
  LcdWrite( LCD_CMD, 0x0C );  // LCD in normal mode. 0x0d for inverse
  LcdWrite(LCD_C, 0x20);
  LcdWrite(LCD_C, 0x0C);
}

void LcdString(char *characters)
{
  while (*characters)
  {
    LcdCharacter(*characters++);
  }
}

void LcdWrite(byte dc, byte data)
{
  digitalWrite(PIN_DC, dc);
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
  digitalWrite(PIN_SCE, HIGH);
}

// gotoXY routine to position cursor 
// x - range: 0 to 84
// y - range: 0 to 5

void gotoXY(int x, int y)
{
  LcdWrite( 0, 0x80 | x);  // Column.
  LcdWrite( 0, 0x40 | y);  // Row.  

}

void setup()
{
 Serial.begin(115200);
 pinMode(blPin, OUTPUT);
 LcdInitialise();
  LcdClear();
analogWrite(blPin, 127); // blPin is ocnnected to retro LEDS 
if (!bmp.begin()) 
  {
    Serial.println("Could not find a valid BMP085 sensor, check wiring!");
    while (1) {}
  }
   metric = getConfig().isMetric;
  
}

void presentation()  {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("Pressure Sensor", "1.1");

  // Register sensors to gw (they will be created as child devices)
  present(BARO_CHILD, S_BARO);
  present(TEMP_CHILD, S_TEMP);
}  
 
 

void loop()
{
  float P = bmp.readSealevelPressure(A) / 100.0; //pressure
  float T = bmp.readTemperature(); //temperature

  if (!metric) 
  {
    // Convert to fahrenheit
    T = T * 9.0 / 5.0 + 32.0;
  }

int forecast = sample(P);


 // temp
  memset(strV, 0 ,sizeof(strV));
  //Reinitialise le tableau Str[11]
  memset(Str, 0, sizeof(Str));
  dtostrf(T, 3, 2, strV);
  strMsg = "T= ";
  strMsg += strV;
  strMsg += " C";
//  Serial.println(strV);
//  Serial.println(strMsg);
  gotoXY(0,0);
  strMsg.toCharArray(Str,strMsg.length()+1);
  LcdString ( Str);
  double TF = (T + 32)*5.0/9.0;
  memset(strV, 0 ,sizeof(strV));  
  dtostrf(TF, 3, 2, strV);
  memset(Str, 0, sizeof(Str));
  strMsg = "   ";
  strMsg += strV;
  strMsg += " F";
//  Serial.println(strV);
//  Serial.println(strMsg);  
  gotoXY(0,1);
  strMsg.toCharArray(Str,strMsg.length()+1);
  LcdString ( Str);
 
  // altitude
  memset(Str, 0, sizeof(Str));
  memset(strV, 0 ,sizeof(strV));
  dtostrf(A, 5, 2, strV);
  strMsg = "A= ";
  strMsg += strV;
  strMsg += " m";
//  Serial.println(strV);
//  Serial.println(strMsg);  
  gotoXY(0,2);
  strMsg.toCharArray(Str,strMsg.length()+1);
  LcdString ( Str);
  memset(Str, 0, sizeof(Str));
  memset(strV, 0 ,sizeof(strV));  
  double AF = 3.28*A;
  dtostrf(AF, 5, 2, strV);
  strMsg = "   ";
  strMsg += strV;
  strMsg += " ft";
//  Serial.println(strV);
//  Serial.println(strMsg);  
  gotoXY(0,3);
  strMsg.toCharArray(Str,strMsg.length()+1);
  LcdString ( Str); 
  // pressure
  memset(Str, 0, sizeof(Str));
  memset(strV, 0 ,sizeof(strV));
  dtostrf(P, 5, 1, strV);
  strMsg = "P= ";
  strMsg += strV;
  strMsg += "hPA";
//  Serial.println(strV);
//  Serial.println(strMsg);  
  //dtostrf(0.75*P, 5, 2, strP);  
  gotoXY(0,4);
  strMsg.toCharArray(Str,strMsg.length()+1);
  LcdString ( Str); 
  Serial.print("Temperature = ");
  Serial.println(T);
  Serial.print("Pressure = ");
  Serial.print(P);
  Serial.println(" hPa");
  Serial.print("Forecast = ");
  Serial.println(weather[forecast]);
  
  if (T != lastTemp) 
  {
    send(tempMsg.set(T, 1));
    lastTemp = T;
  }

  if (P != lastPressure) 
  {
    send(pressureMsg.set(P, 0));
    lastPressure = P;
  }

  if (forecast != lastForecast)
  {
    send(forecastMsg.set(weather[forecast]));
    lastForecast = forecast;
  }

  sleep(SLEEP_TIME);
}

float getLastPressureSamplesAverage()
{
  float lastPressureSamplesAverage = 0;
  for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
  {
    lastPressureSamplesAverage += lastPressureSamples[i];
  }
  lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;

  return lastPressureSamplesAverage;
}

// Algorithm found here
// http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
// Pressure in hPa -->  forecast done by calculating kPa/h
int sample(float P)
{
  // Calculate the average of the last n minutes.
  int index = minuteCount % LAST_SAMPLES_COUNT;
  lastPressureSamples[index] = P;

  minuteCount++;
  if (minuteCount > 185)
  {
    minuteCount = 6;
  }

  if (minuteCount == 5)
  {
    pressureAvg = getLastPressureSamplesAverage();
  }
  else if (minuteCount == 35)
  {
    float lastPressureAvg = getLastPressureSamplesAverage();
    float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    if (firstRound) // first time initial 3 hour
    {
      dP_dt = change * 2; // note this is for t = 0.5hour
    }
    else
    {
      dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
    }
  }
  else if (minuteCount == 65)
  {
    float lastPressureAvg = getLastPressureSamplesAverage();
    float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    if (firstRound) //first time initial 3 hour
    {
      dP_dt = change; //note this is for t = 1 hour
    }
    else
    {
      dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
    }
  }
  else if (minuteCount == 95)
  {
    float lastPressureAvg = getLastPressureSamplesAverage();
    float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    if (firstRound) // first time initial 3 hour
    {
      dP_dt = change / 1.5; // note this is for t = 1.5 hour
    }
    else
    {
      dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
    }
  }
  else if (minuteCount == 125)
  {
    float lastPressureAvg = getLastPressureSamplesAverage();
    pressureAvg2 = lastPressureAvg; // store for later use.
    float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    if (firstRound) // first time initial 3 hour
    {
      dP_dt = change / 2; // note this is for t = 2 hour
    }
    else
    {
      dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
    }
  }
  else if (minuteCount == 155)
  {
    float lastPressureAvg = getLastPressureSamplesAverage();
    float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    if (firstRound) // first time initial 3 hour
    {
      dP_dt = change / 2.5; // note this is for t = 2.5 hour
    }
    else
    {
      dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
    }
  }
  else if (minuteCount == 185)
  {
    float lastPressureAvg = getLastPressureSamplesAverage();
    float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
    if (firstRound) // first time initial 3 hour
    {
      dP_dt = change / 3; // note this is for t = 3 hour
    }
    else
    {
      dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
    }
    pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
    firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
  }

  int forecast = UNKNOWN;
  if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
  {
    forecast = UNKNOWN;
  }
  else if (dP_dt < (-0.25))
  {
    forecast = THUNDERSTORM;
  }
  else if (dP_dt > 0.25)
  {
    forecast = UNSTABLE;
  }
  else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
  {
    forecast = CLOUDY;
  }
  else if ((dP_dt > 0.05) && (dP_dt < 0.25))
  {
    forecast = SUNNY;
  }
  else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
  {
    forecast = STABLE;
  }
  else
  {
    forecast = UNKNOWN;
  }

  // uncomment when debugging
 // Serial.print(F("Forecast at minute "));
 // Serial.print(minuteCount);
 // Serial.print(F(" dP/dt = "));
 // Serial.print(dP_dt);
 // Serial.print(F("kPa/h --> "));
 // Serial.println(weather[forecast]);

  return forecast;
}
Photo 1 du capteur mysensor  Temp Pression
Photo 1 du capteur mysensor Temp Pression
SensorTempPression2.jpg (289.99 Kio) Consulté 3275 fois
Photo 2 du capteur mysensor  Temp Pression
Photo 2 du capteur mysensor Temp Pression
SensorTempPression1.jpg (437.02 Kio) Consulté 3275 fois