Jump to content

NLCbanner2024.jpg.2478be509670e60c2d6efd04834b8b47.jpg

Observatory Environment Instrumentation


Gina

Recommended Posts

Been doing some outside work towards the job.  Dug a trench for the new route of the water pipe containing the CAT5 cable, dug up the pipe, relaid the pipe in the new trench and fed it under the scope room floor roughly towards the pump.  Then replaced the waterlogged sods to fill the holes and trampled them in.  Sorry, no photos - too cold to mess about and just wanted to get the job done before freezing to death  :grin:  May take one or two tomorrow, weather permitting.

Link to comment
Share on other sites

  • Replies 77
  • Created
  • Last Reply

Hi Gina,

I'm sure you know this already but just to say that Pin Change interrupts are available on all the Arduino Nano I/O pins. They are a bit less capable than the 'External Interrupts' on pins 2 and 3 as there is only one interupt vector for each port - 3 ports on the Nano - and you can't trigger on a rising or falling edge, only on a logical inversion. But - gives you a lot more flexibility.

The code below is for a Nano using both PinChange and External Interrupts. It is part of my ongoing (v. slowly) obsy automation project. 

Regards, Hugh

/*          
AB3         
Version AB3_0113    
ROTATION MONITORING AND POSITION          
   
Uses Wire.h http://www.gammon.com.au/i2c          
This sketch is used on an Arduino Nano to count the motor pulses from ABoard1 and the Rotary Encoder ticks          
          
INPUT: I2C          
The 'proper' controller is ABoard 2, an Arduino Mega. AB2 controls Aboard3 using I2C via the Wire.h library.          
The ABoard3 I2C bus connections are:          
      Pin A4    Serial Data (SDA)         
      Pin A5    Serial Clock SCL)         
          
INPUT: Rotary Encoder         
The rotary encoder is a Bourns ENA1J-B28 L00064L 1139M MEX 64 cycle per turn optical encoder.         
Aboard3 Pins D11 and D12 connect to Channel A and Channel B respectively.          
          
INPUT: Dome Motor Pulses          
The pulses sent to the MA542 stepper driver are also sent to Aboard 3 Pin D2. This pin is           
the External Interrupt pin, vector INT0  
          
INPUT: Home Position Sensor         
The home position sensor is an Omron EESX671 Optical Sensor.          
The sensor output is connected to ABoard3 Pin D5. 
         
INPUT: Motor Direction        
Motor direction is input to ABoard3 from ABoard2. The ABoard2 pin, pnVmInRotMotor            
(AB2:A0{54}) is connected to  Velleman pins DI4 and DO2 and also to AB3:D3.           
AB3:D3 is an External Interrupt pin, vector INT1.           
Note that the Motor Direction signal is also sent to AB2:A3{57} as signal pnVmOutCWCCW            
and that the Vellema pins DI4 and DO2 are wired together.           
The direction is CW when pnVmInRotMotor is HIGH.            
COMMANDS VIA I2C          
//I2C Commands for Aboard 3 - POSITION COMMANDS
const byte sendPulseCount = 31;
const byte sendRETickCount = 32;
const byte sendAzimuthAngle = 33;
const byte sendLastPosition = 34;
const byte sendAnyInt = 35;
const byte startDataLog = 36;
const byte stopDataLog = 37; 
          
MESSAGES SENT VIA I2C         
Aboard3 sends these messages as I2C Master          
const byte domeIsJammed = 131;          
          
DATA REQUESTED FROM ABOARD3         
Aboard3 deals with the following requests for data from Aboard2         
azimuthAngle, 4 byte float of calculated angle        
pulseCount, 4 byte long motor pulse count       
reTickCount, 4 byte long rotary encoder tick count        
          
OUTPUTS         
All outputs from ABoard3 are sent via the I2C bus.          
*/          
          
#include <Wire.h>                       
#include "streaming.h"                        
#include "I2C_AnythingHEG.h"                       
                        
//CONSTANTS                       
//I2C Addresses                       
const byte ABoard1 = 8;                         
const byte ABoard2 = 9;                         
const byte ABoard3 = 10;                        
const byte ABoard4 = 11;                        
                        
//I2C Commands for Aboard 3 - POSITION COMMANDS
const byte sendPulseCount = 31;
const byte sendRETickCount = 32;
const byte sendAzimuthAngle = 33;
const byte sendlastPosition = 34;
const byte sendAnyInt = 35;
const byte startDataLog = 36;
const byte stopDataLog = 37;
              
//I2C Messages sent to ABoard2                        
const byte domeIsJammed = 131;                  
//PIN ASSIGNMENTS For ABOARD3
const byte pnMotorPulse = 2;      //Port PD2, INT0, ISR(INT0_vect){}
const byte pnMotorDirection = 3;  //Port PD3, INT1, ISR(INT1_vect){}
const byte pnDomeAtHome = 5;      //Port PD5, PCINT21,ISR(PCINT2_vect){}
const byte pnREChanA = 11;        //Port PB3, PCINT3, ISR(PCINT0_vect){}
const byte pnREChanB = 12;        //Port PB4, PCINT4, ISR(PCINT0_vect){}
                        
//*******************COMMAND SWITCHING VARIABLES********************************                        
volatile byte myCommand = 0; //Value is obtained in receiveEvent ISR                        
uint8_t oldCommand = 0;                        
uint8_t oldSREG; //Used for restoring interrupt state                       
uint8_t myMessage = 0; //Used to report status changes back to ABoard2                       
                        
//*****************EXPERIMENTAL STUFF FOR I2C_Anything and wire.Request****************                       
float azimuthAngle = 123.456; //Trial value                     
long pulseCount = 123456789L; //Trial value                     
float batteryVoltage = 23.1234; //Trial value           
long reTickCount = 356L;  //Trial value                        
int myInt = 12345;  //Trial value  
long lastPosition = 54321654; //Trial value   
//*****************EXPERIMENTAL STUFF FOR PULSE COUNTING*******************************                  
//************************************Temporary testing********************************
int volatile myTest = 0;
long volatile ratioCount = 0L;
long volatile totalCount = 0L;
long volatile tickCount = 0L;
long volatile addPulse = 0L;
                    
                        
void setup()                        
{                       
//**********************************SERIAL FOR DEBUG ONLY************************                     
  Serial.begin(115200);                     
                        
//**********************************SET UP FOR I2C COMMS************************                      
  Wire.begin(ABoard3);                      
  Wire.onReceive (receiveEvent);  // interrupt handler for incoming messages                
  Wire.onRequest (requestEvent);  // interrupt handler for when data is wanted
//*************************INPUT PIN MODE SETUP**********************************
//NOTE Set all PCINT0:5 pins (D8, D9, D10, D11, D12 & D13) to INPUT_PULLUP
  pinMode(pnDomeAtHome, INPUT); //D5
  pinMode(pnMotorDirection, INPUT); //D3
  pinMode(pnMotorPulse, INPUT); //D2
  pinMode(pnREChanA, INPUT); //D11
  pinMode(pnREChanB, INPUT); //D12
  
//**************************SET UP PIN CHANGE INTERRUPTS**************************
//Set the Pin Change Interrupt Masks
//Clear all bits to start with
  PCMSK0 &= 0b00000000; //Clear all bits  
  PCMSK1 &= 0b00000000; //Clear all bits  
  PCMSK2 &= 0b00000000; //Clear all bits  
  
//Mask for PCINTs 0 through 7 is PCMSK0
//Need to allow interrupts on PCINT3 and PCINT4, so set bits 3 and 4
//Use a compound bitwise OR to set the bits
//DEBUG - Try counting RE ticks using only Channel A, PB3
  PCMSK0 |= 0b00001000; //Interrupt on pins 11 and 12, RE Ticks
//Mask for PCINTs 16through 23 is PCMSK2
//Need to allow interrupts on PCINT21 so set bit 5
  PCMSK2 |= 0b00100000; //Interrupt on pin 5, Home Position Sensor activates
  
//Now enable the interrupts (TURN THEM ON) by setting bits in PCICR
//PCICR is Pin Change Interupt Control Register.Set bit 0 (PCIE0)  
//to enable interrupts PCINT0:7 This catches PCINT3 and 4 - RE Ticks
//Set bit 2 (PCIE2) to enable interrupts PCINT16:23. Catches PCINT21 - Home Position Sensor activated
  PCICR &= 0b00000000; //Clear PCICR register 
  PCICR |= 0b00000001; //Set bit 0 - Catches PCINT3 & PCINT4 - RE Ticks
  PCICR |= 0b00000100; //Set bit 2 - Catch PCINT21 - Home Position Sensor activated
  
//**************************SET UP 'EXTERNAL INTERRUPTS'**************************
//Interupts on External Interrupt Pins 2 (INT0) and 3 (INT1).
//INT0 occurs when a Stepper Motor drive pulse is received from ABoard1
//INT1 occurs when the ABoard2 pin, pnVmInRotMotor toggles 
//indicating a motor direction change.
//To use the 'External Interrupts' the following registers need to be set-up:         
          
//EICRA External Interrupt Control Register A       
//Need to set Interrupt Sense Control bits ISC11 .. ISC00 (bits 3:0)          
//First clear all bits, then set as follows:          
//bit 3 ISC11 0     
//bit 2 ISC10 1 This combination = Any logical change causes interrupt    
//bit 1 ISC01 0     
//bit 0 ISC00 1 This combination = Any logical change causes interrupt    
          
//So, code is
    EICRA &= 0b00000000; //Clear EICRA register     
    EICRA |= 0b00000101; // Set bits 0 and 2 in EICRA register      
          
//EIMSK External Interrupt Mask Register        
//Need to set External Interrupt Request Enables INT1 & INT0  (bits 1:0)          
//First clear both bits, then set as follows: 
        
//bit 1  INT1  1 External interrupt pin (D3) enabled   
//bit 0  INT0  1 External interrupt pin (D2) enabled   
          
//So, code is
    EIMSK &= 0b00000000; //Clear EIMSK register     
    EIMSK |= 0b00000011; // Set bits 0 and 1 in EIMSK register      
          
//NOTE: Setting EIMSK TURNS ON THE EXTERNAL INTERRUPTS          
    myCommand = 0;  
    myTest = 0;
    tickCount = 0L;
}  //END of Set-Up             
              
                        
void loop()                                             
{                                               
//******************************COMMAND ACTIONS******************************  
if (myTest == 3)   //RE tick
  {
    Serial << "Tick Count = " << tickCount << "  totalCount = " << totalCount << "\n"; 
    myTest = 0; 
  }
}                                             
                        
//*************************FUNCTIONS / ISRs FROM HEREON*************************                        
              
//I2C SEND MESSAGE BYTE FUNCTION                        
void sendMessage(byte myTarget, byte What)                        
{                       
  Wire.beginTransmission(myTarget);                       
  Wire.write(What);                       
  Wire.endTransmission();                       
}                       
 //I2C RECEIVE EVENT ISR FUNCTION              
void receiveEvent(int howMany)
{
/*
Generic ABoard Receive Event ISR          
Receives single bytes from ABoard2.         
Single bytes FROM ABoard2 are always commands.    
*/
  
  while (Wire.available() > 0)
    {
      myCommand = Wire.read();
    }
}
              
void requestEvent ()              
  { 
  /*
  Slave:  The ABoard2 requestFrom call triggers the slave's requestEventISR       
    The ISR uses switch case on the previously received command, stored as        
    myCommand and then uses I2C_Anything to write the appropriate data.       
    e.g.  switch (myCommand)      
      {     
        case 31: //sendPulseCount   
          I2C_singleWriteAnythingHEG(motorPulseCount);  
          break;  
  Commands        
  const byte sendPulseCount = 31;
  const byte sendRETickCount = 32;
  const byte sendAzimuthAngle = 33;
  const byte sendlastPosition = 34;
  const byte sendAnyInt = 35;
  
  Data Examples
  float azimuthAngle = 123.4567; //Trial value                     
  long pulseCount = 123456789L; //Trial value                     
  float batteryVoltage = 23.1234;             
  long reTickCount = 356L;                        
  int myInt = 12345;              
  */  
  switch (myCommand) //Command received earlier via receiveEvent             
     {              
     case 31: I2C_singleWriteAnythingHEG(pulseCount); break;   // send the data             
     case 32: I2C_singleWriteAnythingHEG(reTickCount); break;   // send the data    
     case 33: I2C_singleWriteAnythingHEG(azimuthAngle); break;   // send the data    
     case 34: I2C_singleWriteAnythingHEG(lastPosition); break;   // send the data    
     case 35: I2C_singleWriteAnythingHEG(myInt); break;   // send the data    
default:            
        Serial << "We definitely shouldn't be here in requestEvent, line 165" << "\n";         
     break;   
                  
     }  // end of switch              
  }  // end of requestEvent 
ISR(INT0_vect) //Triggered by stepper motor drive pulse from ABoard1
{
    //myTest = 1;
    ratioCount++;
    totalCount = totalCount + addPulse;
}    
ISR(INT1_vect) //Triggered by a change in motor direction
{
    //myTest = 2;
    if( digitalRead(pnMotorDirection))
      {
        addPulse = 1L;
      }
    else
      {
        addPulse = -1L;
      } 
}
ISR(PCINT0_vect) //Triggered by a ROTARY ENCODER TICK
{
    myTest = 3;
    tickCount++;
}
ISR(PCINT2_vect) //Triggered by activation of Home Position Sensor
{
    //myTest = 4;
}
Link to comment
Share on other sites

Thank you Hugh :)  I didn't know that although I had thought any data pin could be used as an interrupt, maybe that was at the back of my mind.  I'm not altogether sure it really needs interrupts anyway - it could be that polling is all that's required.  I have used both interrupts and polling for data transfer in the past.  Interrupts have certain niceties :)

Actually, for this job the Arduino has very little to do and polling could work.  I have yet to design the sketch - I'll post it when I have it, of course :D

Link to comment
Share on other sites

Hi Gina,

I like using interrupts rather than polling - more elegant and often simpler control structures, not to mention a very fast response. But - an absolute pig to debug when things don't work! As 'not working' is the normal operating state of my code, I tend to get a lot of debugging practice.

In fact I have only just recovered from a long dark night of the soul over Christmas and the New Year when I felt like giving up entirely. I couldn't for the life of me find out why my code wasn't working. I suspected hardware problems and replaced everything, one bit at a time. I actually found two hardware faults, a Chinese clone Nano with a duff 5V regulator and a vero board mistake. But after correcting these, still nothing. Finally I tracked it down to a bit of hurried cut and paste coding I did in my sketch just before Christmas. Phew!!!

I still do have problems but these are just a result of my poor design - I didn't provide any shielding around the stepper motor driver wiring and I am getting false triggering of interrupts. However, I am just about to stick everything stepper in a metal enclosure with a decent filter on the incoming DC supply and use shielded cables for the I2C lines. That should sort out the interference problems.

Regards, Hugh

Link to comment
Share on other sites

I'll start accumulating code :D

DHT22  boolean function returning true or false depending on good readings or error.  This needs changing a bit and duplicating for aall DHT22s.  I don't think the dewpoint calculation want to go here - it can go in the main weather station Arduino.

#include <dht.h>dht DHT;#define DHT22_1_PIN 10#define DHT22_2_PIN 11#define DHT22_3_PIN 12int indoorTemp, indoorHumidity, indoorDewPoint, outdoorTemp, outdoorHumidity, outdoorDewPoint;  // values in tenths (10 x real)
//==============================================================================================================================//boolean readDHT22(){  double celsius, hum, a, b, temp, Td;  int chk = DHT.read22(DHT22_1_PIN);  switch (chk)  {  case DHTLIB_OK:    celsius = DHT.temperature;     hum = DHT.humidity;    a = 17.271;    b = 237.7;    temp = (a * celsius) / (b + celsius) + log(hum/100);    Td = (b * temp) / (a - temp);    indoorTemp = celsius * 10;    indoorHumidity = hum * 10;    indoorDewPoint = Td * 10;    return true;    break;  case DHTLIB_ERROR_CHECKSUM:     Serial.println(" ***** DHT22 Checksum Error *****");    return false;    break;  case DHTLIB_ERROR_TIMEOUT:     Serial.println("  ***** DHT22 Timeout Error *****");     return false;    break;  default:     Serial.println("  ***** DHT22 Error *****");     return false;    break;  }}//

Water level measuring part.  Needs changing to change value to BCD and store mybbles and remove analogue PWM output.

                  /* File name :- HC-SR04_Ping_distance_sensor_DS2438_01 -- saved 2016-01-10 1115 Gina mods to use DS2438 1-wire device.  Serial Monitor code retained for testing. HC-SR04 Ping distance sensor: VCC to arduino 5v  GND to arduino GND Echo to Arduino pin 7  Trig to Arduino pin 8  This sketch originates from Virtualmix: http://goo.gl/kJ8Gl Has been modified by Winkle ink here: http://winkleink.blogspot.com.au/2012/05/arduino-hc-sr04-ultrasonic-distance.html And modified further by ScottC here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html on 10 Nov 2012. Adopted and modified to use DS2438 1-wire device for remote display of water level. 10 Jan 2016. */#define echoPin 7 // Echo Pin#define trigPin 8 // Trigger Pin#define LEDPin 13 // Onboard LED#define outPin 3  // Ouput Pinint maximumRange = 300; // Maximum range neededint minimumRange = 0; // Minimum range neededlong duration, distance; // Duration used to calculate distancevoid setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(LEDPin, OUTPUT); // Use LED indicator (if required) pinMode(outPin, OUTPUT); // PWM Output to DS2438}void loop() {/* The following trigPin/echoPin cycle is used to determine the distance of the nearest object by bouncing soundwaves off of it. */  digitalWrite(trigPin, LOW);  delayMicroseconds(2);  digitalWrite(trigPin, HIGH); delayMicroseconds(10);   digitalWrite(trigPin, LOW); duration = pulseIn(echoPin, HIGH);  //Calculate the distance (in cm) based on the speed of sound. distance = (duration/4.55) - 256.0;  // Gina mod for DS2438  if (distance >= maximumRange || distance <= minimumRange){ /* Send a negative number to computer and Turn LED ON  to indicate "out of range" */ Serial.println("-1"); digitalWrite(LEDPin, HIGH);  } else { /* Send the distance to the computer using Serial protocol, and turn LED OFF to indicate successful reading. */ Serial.println(distance); digitalWrite(LEDPin, LOW); analogWrite(outPin, distance);  }  //Delay 50ms before next reading. delay(50);}
Link to comment
Share on other sites

I have removed the dewpoint calculation from the DHT22 code but this is still using the Serial Monitor to display errors which isn't available in this unit - there is no USB connection.  It doesn't really make any difference which error occurs, only that there is an error and the data is invalid.  This condition can be saved for each DHT22 in the data to be transmitted by the 1-wire bus.  Also, we need to arrange this function to return values from all 3 DHT22s.  The standard practice is to store the return values in parameters and use a single procedure or function, called for each sensor.

Here is the modified DHT22 read function returning true or false plus temperature and humidity multiplied by 10 in the integers temp and hum :-

boolean readDHT22(int which, int temp, int hum){  int chk;  switch (which)  {    case 1: chk = DHT.read22(DHT22_1_PIN);    case 2: chk = DHT.read22(DHT22_2_PIN);    case 3: chk = DHT.read22(DHT22_3_PIN);  }  switch (chk)  {  case DHTLIB_OK:    temp = DHT.temperature * 10.0;    hum = DHT.humidity * 10.0;    return true;    break;  default:      return false;    break;  }}

This function will be called three times, once for each DHT22.

Link to comment
Share on other sites

I've been thinking about the data struture of the array for transmission by 1-wire.  Since the data values from the sensors are going to be converted to a string of three BCD values it makes sence to hold the array as a string and index it to read the characters sequentially.  This simplifies the DHT22 part of the sketch to :-

#include <dht.h>dht DHT;#define DHT22_1_PIN 10#define DHT22_2_PIN 11#define DHT22_3_PIN 12String dataString:////==============================================================================================================================//String readDHT22(int which){  int chk, temp, hum;  switch (which)  {    case 1: chk = DHT.read22(DHT22_1_PIN);    case 2: chk = DHT.read22(DHT22_2_PIN);    case 3: chk = DHT.read22(DHT22_3_PIN);  }  switch (chk)  {  case DHTLIB_OK:    temp = DHT.temperature * 10.0 + 300;  //  Add 30°C to allow for temperatures below freezing    hum = DHT.humidity * 10.0;    return String(temp, DEC) + String(hum, DEC);  // Convert temperature and humidity into BCD strings    break;  default: return "000000";  //  Error return 6 zeros to indicate error    break;  }}//void loop{  dataString = readDHT22(1) + readDHT22(2) + readDHT22(3);

The water level can have higher resolution now as the limit has been raised from 0-255 to 0-999 - by changing the divisor.  Like the DHT22 this can be converted to a three character string and added to outString.

Link to comment
Share on other sites

Seen a problem with the above code.  Numerical values of 0-9 will be converted to a one character string and values from 10-99 to a two character string.  These will need padding with zeros.  Easy enough to do but would cause chaos if not implemented.

Link to comment
Share on other sites

Here is one way of catering for data values <10 and between 20 and 99.

#include <dht.h>dht DHT;#define DHT22_1_PIN 10#define DHT22_2_PIN 11#define DHT22_3_PIN 12String dataString;////==============================================================================================================================//String readDHT22(int which){  int chk, temp, hum;  String tempString, humString;  switch (which)  {    case 1: chk = DHT.read22(DHT22_1_PIN);    case 2: chk = DHT.read22(DHT22_2_PIN);    case 3: chk = DHT.read22(DHT22_3_PIN);  }  switch (chk)  {  case DHTLIB_OK:    temp = DHT.temperature * 10.0 + 300;  //  Add 30°C to allow for temperatures below freezing    hum = DHT.humidity * 10.0;    tempString = String(temp, DEC); // Convert temperature a BCD string    if (temp < 100) { tempString = "0" + tempString; }    if (temp < 10) { tempString = "0" + tempString; }    humString = String(hum, DEC); // Convert humidity into a BCD string      if (temp < 100) { humString = "0" + humString; }    if (temp < 10) { humString = "0" + humString; }    return tempString + humString ;    break;  default: return "000000";  //  Error return 6 zeros to indicate error    break;  }}//void setup (){}void loop(){  dataString = readDHT22(1) + readDHT22(2) + readDHT22(3);}

However, the situation can be avoided for the temperature by applying a suitable offset.  I have already applied an offset to avoid negative data values.  We are very unlikely to see temperatures above 50°C or below -30°C these correspond to data values of 500 and -300.  We could let the max value go up to 999.  Suppose we add 400 to the data.  Max value becomes 900 and min value 100 so no need to add in any zeros.  QED :D  Unfortunately this doesn't apply to humidity which can be from 0 to 99.9, though unlikely to go below 1%.

Code becomes :-

#include <dht.h>dht DHT;#define DHT22_1_PIN 10#define DHT22_2_PIN 11#define DHT22_3_PIN 12String dataString;////==============================================================================================================================//String readDHT22(int which){  int chk, temp, hum;  String humString;  switch (which)  {    case 1: chk = DHT.read22(DHT22_1_PIN);    case 2: chk = DHT.read22(DHT22_2_PIN);    case 3: chk = DHT.read22(DHT22_3_PIN);  }  switch (chk)  {  case DHTLIB_OK:    temp = DHT.temperature * 10.0 + 400;  //  Add 40°C to allow for temperatures below freezing and avoid data values below 100    hum = DHT.humidity * 10.0;    humString = String(hum, DEC);    // Convert humidity into BCD string    if (hum < 100) { humString = "0" + humString; }    if (hum < 10) { humString = "0" + humString; }    return String(temp, DEC) + humString;  // Convert temperature into BCD string and add humidity string    break;  default: return "000000";  //  Error return 6 zeros to indicate error    break;  }}//void setup (){}void loop(){  dataString = readDHT22(1) + readDHT22(2) + readDHT22(3);}

And now I'm off outside to finish off the cable run.

Link to comment
Share on other sites

Cleaned up the area where I rerouted the cable feed a bit but it's too wet to do much with.  Then looked under scope room floor through access hole and fished coiled cable out and up through access hole in floor.

post-13131-0-97155700-1452785868_thumb.jpost-13131-0-06902800-1452785873_thumb.jpost-13131-0-72713600-1452785874_thumb.jpost-13131-0-73568300-1452785876_thumb.j

Link to comment
Share on other sites

AFAICT the CAT5 cable is in good condition but it will need electrical testing to be sure.  I have one end in the scope room and the other in the back porch.  I just need to drill a hole through the house wall to bring the cable into the living room - have to look for a masonry drill :D

Link to comment
Share on other sites

Here is a test sketch for the water level sensor - sends string to Serial Monitor for testing.  Used this sketch to test the real final unit with Arduino Nano as shown in photos above.  And it works fine :)

Range 100-500 in mm (non-inclusive) - displayed as "101" to "499" with "000" indicating error (out of range).  This three character string will be added to the DHT22 strings to form the whole data string.  No separate error codes are needed as errors are sent as "000" (water level) or "000000" (DHT22) in the data strings.

/* File name :- HC-SR04_Ping_distance_sensor_mm_for_2408_01  2016-01-14 1655 Test sketch sending output string to Serial Monitor.  Range 100-500 with 000 indicating error (out of range) HC-SR04 Ping distance sensor: VCC to arduino 5v  GND to arduino GND Trig to Arduino pin 8 Echo to Arduino pin 9   This sketch originates from Virtualmix: http://goo.gl/kJ8Gl Has been modified by Winkle ink here: http://winkleink.blogspot.com.au/2012/05/arduino-hc-sr04-ultrasonic-distance.html And modified further by ScottC here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html on 10 Nov 2012. Adopted and modified by Gina January 2016. */#define trigPin 8 // Trigger Pin#define echoPin 9 // Echo Pin#define LEDPin 13 // Onboard LEDint maximumRange = 500; // Maximum range neededint minimumRange = 100; // Minimum range neededlong duration, distance; // Duration used to calculate distancevoid setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)}void loop() {/* The following trigPin/echoPin cycle is used to determine the distance of the nearest object by bouncing soundwaves off of it. */  digitalWrite(trigPin, LOW);  delayMicroseconds(2);  digitalWrite(trigPin, HIGH); delayMicroseconds(10);   digitalWrite(trigPin, LOW); duration = pulseIn(echoPin, HIGH);  //Calculate the distance (in mm) based on the speed of sound. distance = duration/5.82;  if (distance >= maximumRange || distance <= minimumRange){ /* Send a negative number to computer and Turn LED ON  to indicate "out of range" */ Serial.println("000"); digitalWrite(LEDPin, HIGH);  } else { /* Send the distance to the computer using Serial protocol, and turn LED OFF to indicate successful reading. */ Serial.println(String(distance, DEC)); digitalWrite(LEDPin, LOW);  }  //Delay 50ms before next reading. delay(50);}

This sketch reads the distance every 50ms sending single values to the Serial Monitor for this test sketch.  Since the DS2408 method of sending water level data indoors doesn't have any smoothing, I shall add this into the water level measurement code.

Link to comment
Share on other sites

Added code to accumulate the duration over a number of cycles (set to 100 in this sketch giving a reading every 5s).  Tested and working.  Still showing a variation of several mm but accurate enough for purpose.

/* File name :- HC-SR04_Ping_distance_sensor_mm_for_2408_01  2016-01-14 1655 Test sketch sending output string to Serial Monitor.  Range 100-500 with 000 indicating error (out of range) HC-SR04 Ping distance sensor: VCC to arduino 5v  GND to arduino GND Trig to Arduino pin 8 Echo to Arduino pin 9   This sketch originates from Virtualmix: http://goo.gl/kJ8Gl Has been modified by Winkle ink here: http://winkleink.blogspot.com.au/2012/05/arduino-hc-sr04-ultrasonic-distance.html And modified further by ScottC here: http://arduinobasics.blogspot.com.au/2012/11/arduinobasics-hc-sr04-ultrasonic-sensor.html on 10 Nov 2012. Adopted and modified by Gina January 2016. */#define trigPin 8 // Trigger Pin#define echoPin 9 // Echo Pin#define LEDPin 13 // Onboard LEDint maximumRange = 500; // Maximum range neededint minimumRange = 100; // Minimum range neededlong duration, distance; // Duration used to calculate distanceint cycles = 100; // Number of cycles of ping to accumulate average durationvoid setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)}//void accumulateDuration() {/* The following trigPin/echoPin cycle is used to determine the distance of the nearest object by bouncing soundwaves off of it. */  digitalWrite(trigPin, LOW);  delayMicroseconds(2);  digitalWrite(trigPin, HIGH); delayMicroseconds(10);  digitalWrite(trigPin, LOW); duration = duration + pulseIn(echoPin, HIGH); //Delay 50ms before next reading. delay(50);}void loop() {  duration = 0; for (int c = 0; c < cycles; c++) { accumulateDuration(); } duration = duration / cycles; //Calculate the distance (in mm) based on the speed of sound. distance = duration/5.82; if (distance >= maximumRange || distance <= minimumRange){ /* Send a negative number to computer and Turn LED ON  to indicate "out of range" */ Serial.println("000"); digitalWrite(LEDPin, HIGH);  } else { /* Send the distance to the computer using Serial protocol, and turn LED OFF to indicate successful reading. */ Serial.println(String(distance, DEC)); digitalWrite(LEDPin, LOW);  } }
Link to comment
Share on other sites

Pretty well everything is remote controlled already but I've yet to finish automating or even remote controlling the roof :D  I don't think it'll take too long once I get back onto it :D

I think I've pretty much fixed the observatory against the weather when the roof is closed and everything is bolted shut and clamped down so I may start moving the gear back out in the next few days.  We're starting to get some clear hours of night sky and I'm itching to make use of them.  If we get some decent weather I might well get back to the roof motorisation and remote control "real soon now" as they say "across the pond".  I'm already moving towards the remote control side with the 1-wire remote Arduino control.

Link to comment
Share on other sites

Code-wise there are several sections to this project.

  1. Water level measurement
  2. Temperature and humidity measurements
  3. Responding to DS2408 requests for data
  4. Programming the 1-wire DS2408 on the master Arduino
  5. Data processing on the master
  6. Code to drive the various dials

1. and 2. are written and just want combining. 

3. shouldn't be a problem - I have ideas of how to do it. 

4. I've been Googling like mad trying to find code examples for controlling the DS2408 without much success so far.  So if anyone has used a DS2408 from Arduino I would love to hear from you :) 

5. is pretty much done already in the weather staion project. 

6. control of dials will want adding.

Link to comment
Share on other sites

In addition to measuring how high the water rises in the hole underneath my observatory, I also want to display and record such things as temperature and humidity both in the scope room and outside plus sky condition and if it's raining.  May be nice to know how the warm room is faring too.  Also, highly relevant to observatory wellbeing is wind and rainfall.  This means a weather station effectively but it's more than the usual weather station reads and records/displays.  Most weather stations measure wind speed and direction, outside temperature and humidity, indoor temperature and humidity plus rainfall and atmospheric pressure.  I want more thermometers and humidity sensors and other things.

All these sensors are in or around the observatory and the data needs transmitting to the house where a wall display will show current conditions and a computer with data processing software to accumulate data and send it to a weather website over the internet.  The only other data weather sites show is the atmospheric pressure and trends in this can give some idea of weather to come (very roughly).  This can be measured anywhere and indoors is as good a place as anywhere.

I have decided to transmit water level data using the 1-wire bus which not only has a range of up to 100m but also allows multiple sensor devices on the one bus.  Connection is by CAT5 ethernet cable using just one twisted pair out of the four.  The Arduino has the 1-wire bus master built in using the 1-wire library and appropriate libraries for the various devices.  Hence, it makes sense if I can also use 1-wire for all the other sensors.

The wind instruments will be on a 6m mast to the side of the observatory and I already have a 1-wire design for these.  The outdoor sensors will be in a mini Stevenson Screen attached to the north side of the building.

Here is a list of data measurements I would like :-

  1. Wind speed
  2. Wind direction
  3. Outside temperature
  4. Outside humidity
  5. Scope room temperature
  6. Scope room humidity
  7. Warm room temperature
  8. Warm room humidity
  9. Rainfall
  10. Water level under building
  11. Rain sensor
  12. Sky sensor
  13. Outside light level
  14. Atmospheric pressure but this can be measured indoors and doesn't need transmitting from the observatory.

My 'professional' Oregon Weather Station broke in under 12 months. Bearing failure in the anemometer and wind direction vane......

Link to comment
Share on other sites

I had much the same trouble with a couple of Fine Offset stations I bought from Maplin.  That and several other problems :(  One problem with the bearing was inadequate protection from the weather the other was inferior bearings.  With good design and good quality bearings this problem can be avoided.  But good design means either paying more or making your own.

Link to comment
Share on other sites

Here is a photo of the anemometer parts.  Printed parts should be pretty effective in keeping wet out and stopping it getting to the bearing.  The vane bearing will also be similarly protected from wind blown rain.

post-13131-0-56092700-1452965675_thumb.j

Here is the top parts assembled, underside view.

post-13131-0-63230900-1452965721_thumb.j

As above with ring to keep the wet out.

post-13131-0-07832100-1452965725_thumb.j

This photo includies the pillar and bearing post (printed in pink ABS) which is a tight fit in the support pillar

post-13131-0-57223300-1452965727_thumb.j

Finally, here is the complete anemometer perched on my anglepoist type light/magnifier ready to be mounted on top of the wind vane housing.

post-13131-0-83514100-1452966283_thumb.j

Link to comment
Share on other sites

Since I have +5v available at the masthead I'm now planning to replace the reed switch with a hall effect device - as used in the top-end Davis weather stations nowadays.  I will change from one to three magnets on the anemometer rotor giving 3 pulses per revolution rather than the 2 given by one magnet and reed switch.  To make the change I shall redesign and 3D print two new parts - the rotor for 3 magnets and the (pink) reed switch holder and bearing post part which will now take the hall effect device instead of reed switch.

Link to comment
Share on other sites

I printed a new rotor but reused the stator for the hall effect chip by just drilling a hole for the wires.  Rigged up a test circuit with resistor and LED.

post-13131-0-43776800-1452986634_thumb.j

Some photos.

Hall effect device fitted to stator.

post-13131-0-24193100-1452986660_thumb.j

Rotor with magnets.  These are tiny rare earth "supermagnets" just 3mm cube.

post-13131-0-32331100-1452986663_thumb.j

Test rig with rotor nounted on ball bearing to check everything worked before further assembling the anemometer.  Used some spare multiwire flat cable to connect to hall effect device and to test LED circuit.  Colour code : black - Gnd, white - Vcc, grey - Out (open collector NPN transistor).

post-13131-0-66028500-1452986665_thumb.j

Cups fitted to rotor.

post-13131-0-88070200-1452986667_thumb.j

Anemometer fully assembled and under test with light breeze from room fan.  Responded to just a "light air" with one pulse every two seconds - roughly equivalent to 0.5mph.  1 rev/s was reckoned to represent about 3mph so with 3 magnets, 1mph = 1 pulse per second.

post-13131-0-17740900-1452986670_thumb.j

Link to comment
Share on other sites

The weather forecast is decidedly grotty for the next few days with plenty of heavy rain so I'm concentrating on projects I can do indoors.  In view of the rain I think I'll get back to experiments with 1-wire interfacing to Arduino with the DS2408.  I have a second DS2408 soldered to an adapter PCB and I'll connect that to an Arduino UNO and Nano and play with the DS2408 code on the UNO.  OR I might just connect the PIO lines on the DS2408 to LEDs and switches first and get that working.

Link to comment
Share on other sites

Here is the circuit diagram of the test rig.

post-13131-0-08495900-1453032469_thumb.j

First test is with the DS2408 device detection and address display.

#include <WProgram.h>#include <DS2408.h>#include <OneWire.h>#include <string.h>#include <stdio.h>#define ONE_WIRE_BUS_PORT 8DS2408  ds(ONE_WIRE_BUS_PORT);Devices devices;uint8_t device_count;void setup(void) {           // **********  This line is highlighted by the compiler with errors **********    Serial.begin(9600);    device_count = ds.find(&devices);    print_devices(&devices, device_count);}void loop(void) {     delay(10000);}/* --------------- PRINT HELPERS --------------- */void print_byte(uint8_t data) {    for(int index=0; index<8; index++) {        Serial.print(data & 1, BIN);        data = data >> 1;    }}void print_address(byte* address) {    Serial.print("[");    for(int index = 0; index < sizeof(Device); index++) {        Serial.print(address[index], HEX);        if(index < sizeof(Device)-1)            Serial.print(" ");    }    Serial.print("] ");}void print_devices(Devices* devices, uint8_t device_count) {    Serial.print("Found ");    Serial.print(device_count , HEX);    Serial.println(" devices.");    for(int index=0; index < device_count; index++) {        Serial.print(index+1, HEX);        Serial.print(". ");        print_address((*devices)[index]);        Serial.println();    }}

I have installed the DS2408 Arduino Library and already have the rest.  Trying to compile this I get errors :-

sketch_jan17a:13: error: variable or field 'print_devices' declared void
sketch_jan17a:13: error: 'Devices' was not declared in this scope
sketch_jan17a:13: error: 'devices' was not declared in this scope
sketch_jan17a:13: error: expected primary-expression before 'device_count'
sketch_jan17a:8: error: 'DS2408' does not name a type
sketch_jan17a:10: error: 'Devices' does not name a type
sketch_jan17a.ino: In function 'void setup()':
sketch_jan17a:16: error: 'ds' was not declared in this scope
sketch_jan17a:16: error: 'devices' was not declared in this scope
sketch_jan17a:17: error: 'print_devices' was not declared in this scope
sketch_jan17a.ino: In function 'void print_address(byte*)':
sketch_jan17a:33: error: 'Device' was not declared in this scope
sketch_jan17a.ino: At global scope:
sketch_jan17a:41: error: variable or field 'print_devices' declared void
sketch_jan17a:41: error: 'Devices' was not declared in this scope
sketch_jan17a:41: error: 'devices' was not declared in this scope
sketch_jan17a:41: error: expected primary-expression before 'device_count'
 

The sketch was taken from here :- Expand Arduino IO with 1wire DS2408

Link to comment
Share on other sites

The example sketch from the DS2408 library also fails to compile :(  Here is the error list :-

led_strobe:11: error: 'DS2408' does not name a type
led_strobe:13: error: 'Device' does not name a type
led_strobe:14: error: 'Device' does not name a type
led_strobe:17: error: 'Devices' does not name a type
led_strobe:37: error: variable or field 'print_devices' declared void
led_strobe:37: error: 'Devices' was not declared in this scope
led_strobe:37: error: 'devices' was not declared in this scope
led_strobe:37: error: expected primary-expression before 'device_count'
led_strobe:38: error: variable or field 'setup_devices' declared void
led_strobe:38: error: 'Devices' was not declared in this scope
led_strobe:38: error: 'devices' was not declared in this scope
led_strobe:38: error: expected primary-expression before 'device_count'
led_strobe:39: error: variable or field 'display_mode' declared void
led_strobe:39: error: 'Device' was not declared in this scope
led_strobe:40: error: variable or field 'display_activity' declared void
led_strobe:40: error: 'Device' was not declared in this scope
led_strobe:41: error: variable or field 'display_state' declared void
led_strobe:41: error: 'Device' was not declared in this scope
led_strobe.pde: In function 'void setup()':
led_strobe:49: error: 'ds' was not declared in this scope
led_strobe:49: error: 'devices' was not declared in this scope
led_strobe:50: error: 'print_devices' was not declared in this scope
led_strobe:51: error: 'setup_devices' was not declared in this scope
led_strobe.pde: In function 'void loop()':
led_strobe:59: error: 'devices' was not declared in this scope
led_strobe:62: error: 'ds' was not declared in this scope
led_strobe:75: error: 'display_mode' was not declared in this scope
led_strobe:76: error: 'display_activity' was not declared in this scope
led_strobe:77: error: 'display_state' was not declared in this scope
led_strobe.pde: At global scope:
led_strobe:82: error: variable or field 'setup_devices' declared void
led_strobe:82: error: 'Devices' was not declared in this scope
led_strobe:82: error: 'devices' was not declared in this scope
led_strobe:82: error: expected primary-expression before 'device_count'
 

This is the sketch :-

#include <WProgram.h>#include <DS2408.h>#include <OneWire.h>#include <string.h>#include <stdio.h>#define DEVICE_BUS_PORT 9DS2408  ds(DEVICE_BUS_PORT);Device led_device    = {0x29, 0xF5, 0x22, 0x7, 0x00, 0x00, 0x00, 0xBD};Device reader_device = {0x29, 0xF5, 0x22, 0x7, 0x00, 0x00, 0x00, 0x47};Devices devices;uint8_t device_count;static FILE uartout = {0} ;static int uart_putchar (char c, FILE *stream) {    Serial.write(c) ;    return 0 ;}void setup_stdout() {    fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);    stdout = &uartout ;}#ifdef CXA_PURE_VIRTUAL_FIXextern "C" void __cxa_pure_virtual(void);void __cxa_pure_virtual(void) { while(1); }#endifvoid print_byte(uint8_t data);void print_address(byte* address);void print_devices(Devices* devices, uint8_t device_count);void setup_devices(Devices* devices, uint8_t device_count);void display_mode(Device device);void display_activity(Device device);void display_state(Device device);void setup(void) {    Serial.begin(9600);    setup_stdout();    Serial.println("Welcome2");    device_count = ds.find(&devices);    print_devices(&devices, device_count);    setup_devices(&devices, device_count);}void loop(void) {    uint8_t state = 0;    bool left = 1;    for(int index=0; index<device_count; index++) {        print_address(devices[index]);                if(devices[index][7] == 0xBD) {            ds.set_state(devices[index], state);            for(int index1=0; index1<100; index1++) {                if(state == 0xFF || state == 0)                    left = !left;                if(left)                    state = (state<<1)+1;                else                    state = state>>1;                ds.set_state(state, true);                delay(100);            }        }                display_mode(devices[index]);        display_activity(devices[index]);        display_state(devices[index]);        Serial.println();    }}void setup_devices(Devices* devices, uint8_t device_count) {    for(int index=0; index < device_count; index++) {        ds.set_mode((*devices)[index], RESET_PIN_MODE(STROBE_MODE));    }}void display_mode(Device device) {    Serial.print(" MODE=");    print_byte(ds.get_mode(device));}void display_activity(Device device) {    Serial.print(" ACTIVTY=");    print_byte(ds.get_activity(device));}void display_state(Device device) {    Serial.print(" STATE=");    print_byte(ds.get_state(device));}void print_byte(uint8_t data) {    for(int index=0; index<8; index++) {        Serial.print(data & 1, BIN);        data = data >> 1;    }}void print_address(byte* address) {    Serial.print("[");    for(int index = 0; index < sizeof(Device); index++) {        Serial.print(address[index], HEX);        if(index < sizeof(Device)-1)            Serial.print(" ");    }    Serial.print("] ");}void print_devices(Devices* devices, uint8_t device_count) {    Serial.print("Found ");    Serial.print(device_count , HEX);    Serial.println(" devices.");    for(int index=0; index < device_count; index++) {        Serial.print(index+1, HEX);        Serial.print(". ");        print_address((*devices)[index]);        Serial.println();    }}
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.