Commit d41368b8 authored by Julien Leduc's avatar Julien Leduc

Initial GPLv3 code base for the DCES project

parent 0017a3d0
--------------------
dces-dtrhf-ser1ch-v1
--------------------
Here is what the name stands for:
Data Center Environmental Sensor sensing Dust, Temperature, Relative Humidity and Fan speed sending results on SERial 1 CHannel - version 1.
This is a long name, but it precisely defines what is implemented in the project.
Compiling and flashing the firmware
-----------------------------------
Some prerequites, to compile this firmware, you need to install the ``arduino-core`` package, the full IDE is not needed, because it is simple an faster to build from the commandline:
::
$ yum instal arduino-core
Before going any further you need to adapt the configuration file to your setup: edit ``dces-dtrhf-ser1ch-v1.conf`` in ``dces-dtrhf-ser1ch-v1/arduino/``.
Then to build and flash the arduino board, simply run ``build.sh`` from command line:
::
$ cd dces-dtrhf-ser1ch-v1/arduino
$ ./build.sh
It is only going to build ``dces-dtrhf-ser1ch-v1/arduino/final/final.ino`` using ``dces-dtrhf-ser1ch-v1/arduino/final/Makefile``.
To clean the project, just ``make clean`` from ``dces-dtrhf-ser1ch-v1/arduino/final`` directory.
If ``UPLOAD=true`` in ``dces-dtrhf-ser1ch-v1.conf``, the firmware is going to be flashed on the arduino board.
Configuring the firmware
------------------------
Firmware configuration is done from the arduino serial port using ``SerialCommand`` library.
When the firmware starts it displays measured data by default:
::
$ picocom /dev/ttyACM0
port is : /dev/ttyACM0
flowcontrol : none
baudrate is : 9600
parity is : none
databits are : 8
escape is : C-a
local echo is : no
noinit is : no
noreset is : no
nolock is : no
send_cmd is : sz -vv
receive_cmd is : rz -vv
imap is :
omap is :
emap is : crcrlf,delbs,
Terminal ready
8471, 8384, 446, 26.69, 31.37, 196, 0, 960
8419, 8448, 163, 26.69, 31.44, 196, 0, 960
...
#!/bin/bash
##############################################################################
#
# This file is part of the DCES project.
# See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
#
# Copyright (C) 2016 CERN
# All rights not expressly granted are reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# @author DCES Dev team, dces-dev@cern.ch
#############################################################################
. ./dces-dtrhf-ser1ch-v1.conf 2>/dev/null
cd final
if [[ $UPLOAD = "true" ]]
then
echo "Compiling and upgrading arduino firmware"
make BOARD=$BOARD SERIALDEV=$DEVICE upload
else
echo "Compiling only"
make BOARD=$BOARD SERIALDEV=$DEVICE
fi
###
# Example configuration file for dust sensor firmware update
###
###
# Configuration section for firmware compilation/upgrade
###
[MAKE_SECTION]
# UPLOAD="true" automatically build and upload firmware upon rpm installation
UPLOAD="false"
# Arduino board type for dust sensor as specified in /usr/share/arduino/hardware/arduino/boards.txt
BOARD="mega2560"
# TTY device for serial communications
DEVICE="/dev/ttyACM0"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
I2C.h - I2C library
Copyright (c) 2011-2012 Wayne Truchsess. All right reserved.
Rev 5.0 - January 24th, 2012
- Removed the use of interrupts completely from the library
so TWI state changes are now polled.
- Added calls to lockup() function in most functions
to combat arbitration problems
- Fixed scan() procedure which left timeouts enabled
and set to 80msec after exiting procedure
- Changed scan() address range back to 0 - 0x7F
- Removed all Wire legacy functions from library
- A big thanks to Richard Baldwin for all the testing
and feedback with debugging bus lockups!
Rev 4.0 - January 14th, 2012
- Updated to make compatible with 8MHz clock frequency
Rev 3.0 - January 9th, 2012
- Modified library to be compatible with Arduino 1.0
- Changed argument type from boolean to uint8_t in pullUp(),
setSpeed() and receiveByte() functions for 1.0 compatability
- Modified return values for timeout feature to report
back where in the transmission the timeout occured.
- added function scan() to perform a bus scan to find devices
attached to the I2C bus. Similar to work done by Todbot
and Nick Gammon
Rev 2.0 - September 19th, 2011
- Added support for timeout function to prevent
and recover from bus lockup (thanks to PaulS
and CrossRoads on the Arduino forum)
- Changed return type for stop() from void to
uint8_t to handle timeOut function
Rev 1.0 - August 8th, 2011
This is a modified version of the Arduino Wire/TWI
library. Functions were rewritten to provide more functionality
and also the use of Repeated Start. Some I2C devices will not
function correctly without the use of a Repeated Start. The
initial version of this library only supports the Master.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if(ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
#ifndef I2C_h
#define I2C_h
#define START 0x08
#define REPEATED_START 0x10
#define MT_SLA_ACK 0x18
#define MT_SLA_NACK 0x20
#define MT_DATA_ACK 0x28
#define MT_DATA_NACK 0x30
#define MR_SLA_ACK 0x40
#define MR_SLA_NACK 0x48
#define MR_DATA_ACK 0x50
#define MR_DATA_NACK 0x58
#define LOST_ARBTRTN 0x38
#define TWI_STATUS (TWSR & 0xF8)
#define SLA_W(address) (address << 1)
#define SLA_R(address) ((address << 1) + 0x01)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define MAX_BUFFER_SIZE 32
class I2C
{
public:
I2C();
void begin();
void end();
void timeOut(uint16_t);
void setSpeed(uint8_t);
void pullup(uint8_t);
void scan();
uint8_t available();
uint8_t receive();
uint8_t write(uint8_t, uint8_t);
uint8_t write(int, int);
uint8_t write(uint8_t, uint8_t, uint8_t);
uint8_t write(int, int, int);
uint8_t write(uint8_t, uint8_t, char*);
uint8_t write(uint8_t, uint8_t, uint8_t*, uint8_t);
uint8_t read(uint8_t, uint8_t);
uint8_t read(int, int);
uint8_t read(uint8_t, uint8_t, uint8_t);
uint8_t read(int, int, int);
uint8_t read(uint8_t, uint8_t, uint8_t*);
uint8_t read(uint8_t, uint8_t, uint8_t, uint8_t*);
private:
uint8_t start();
uint8_t sendAddress(uint8_t);
uint8_t sendByte(uint8_t);
uint8_t receiveByte(uint8_t);
uint8_t stop();
void lockUp();
uint8_t returnStatus;
uint8_t nack;
uint8_t data[MAX_BUFFER_SIZE];
static uint8_t bytesAvailable;
static uint8_t bufferIndex;
static uint8_t totalBytes;
static uint16_t timeOutDelay;
};
extern I2C I2c;
#endif
#######################################
# Syntax Coloring Map For I2C
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
I2C KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
timeOut KEYWORD2
setSpeed KEYWORD2
pullup KEYWORD2
scan KEYWORD2
write KEYWORD2
read KEYWORD2
available KEYWORD2
receive KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
I2c KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
\ No newline at end of file
/*******************************************************************************
SerialCommand - An Arduino library to tokenize and parse commands received over
a serial port.
Copyright (C) 2011-2013 Steven Cogswell <steven.cogswell@gmail.com>
http://awtfy.com
See SerialCommand.h for version history.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "SerialCommand.h"
#include <string.h>
#ifndef SERIALCOMMAND_HARDWAREONLY
#include <SoftwareSerial.h>
#endif
// Constructor makes sure some things are set.
SerialCommand::SerialCommand()
{
usingSoftwareSerial=0;
strncpy(delim," ",MAXDELIMETER); // strtok_r needs a null-terminated string
term='\r'; // return character, default terminator for commands
numCommand=0; // Number of callback handlers installed
clearBuffer();
}
#ifndef SERIALCOMMAND_HARDWAREONLY
// Constructor to use a SoftwareSerial object
SerialCommand::SerialCommand(SoftwareSerial &_SoftSer)
{
usingSoftwareSerial=1;
SoftSerial = &_SoftSer;
strncpy(delim," ",MAXDELIMETER); // strtok_r needs a null-terminated string
term='\r'; // return character, default terminator for commands
numCommand=0; // Number of callback handlers installed
clearBuffer();
}
#endif
//
// Initialize the command buffer being processed to all null characters
//
void SerialCommand::clearBuffer()
{
for (int i=0; i<SERIALCOMMANDBUFFER; i++)
{
buffer[i]='\0';
}
bufPos=0;
}
// Retrieve the next token ("word" or "argument") from the Command buffer.
// returns a NULL if no more tokens exist.
char *SerialCommand::next()
{
char *nextToken;
nextToken = strtok_r(NULL, delim, &last);
return nextToken;
}
// This checks the Serial stream for characters, and assembles them into a buffer.
// When the terminator character (default '\r') is seen, it starts parsing the
// buffer for a prefix command, and calls handlers setup by addCommand() member
void SerialCommand::readSerial()
{
// If we're using the Hardware port, check it. Otherwise check the user-created SoftwareSerial Port
#ifdef SERIALCOMMAND_HARDWAREONLY
while (Serial.available() > 0)
#else
while ((usingSoftwareSerial==0 && Serial.available() > 0) || (usingSoftwareSerial==1 && SoftSerial->available() > 0) )
#endif
{
int i;
boolean matched;
if (usingSoftwareSerial==0) {
// Hardware serial port
inChar=Serial.read(); // Read single available character, there may be more waiting
} else {
#ifndef SERIALCOMMAND_HARDWAREONLY
// SoftwareSerial port
inChar = SoftSerial->read(); // Read single available character, there may be more waiting
#endif
}
#ifdef SERIALCOMMANDDEBUG
Serial.print(inChar); // Echo back to serial stream
#endif
if (inChar==term) { // Check for the terminator (default '\r') meaning end of command
#ifdef SERIALCOMMANDDEBUG
Serial.print("Received: ");
Serial.println(buffer);
#endif
bufPos=0; // Reset to start of buffer
token = strtok_r(buffer,delim,&last); // Search for command at start of buffer
if (token == NULL) return;
matched=false;
for (i=0; i<numCommand; i++) {
#ifdef SERIALCOMMANDDEBUG
Serial.print("Comparing [");
Serial.print(token);
Serial.print("] to [");
Serial.print(CommandList[i].command);
Serial.println("]");
#endif
// Compare the found command against the list of known commands for a match
if (strncmp(token,CommandList[i].command,SERIALCOMMANDBUFFER) == 0)
{
#ifdef SERIALCOMMANDDEBUG
Serial.print("Matched Command: ");
Serial.println(token);
#endif
// Execute the stored handler function for the command
(*CommandList[i].function)();
clearBuffer();
matched=true;
break;
}
}
if (matched==false) {
(*defaultHandler)();
clearBuffer();
}
}
if (isprint(inChar)) // Only printable characters into the buffer
{
buffer[bufPos++]=inChar; // Put character into buffer
buffer[bufPos]='\0'; // Null terminate
if (bufPos > SERIALCOMMANDBUFFER-1) bufPos=0; // wrap buffer around if full
}
}
}
// Adds a "command" and a handler function to the list of available commands.
// This is used for matching a found token in the buffer, and gives the pointer
// to the handler function to deal with it.
void SerialCommand::addCommand(const char *command, void (*function)())
{
if (numCommand < 30) {
#ifdef SERIALCOMMANDDEBUG
Serial.print(numCommand);
Serial.print("-");
Serial.print("Adding command for ");
Serial.println(command);
#endif
strncpy(CommandList[numCommand].command,command,SERIALCOMMANDBUFFER);
CommandList[numCommand].function = function;
numCommand++;
} else {
// In this case, you tried to push more commands into the buffer than it is compiled to hold.
// Not much we can do since there is no real visible error assertion, we just ignore adding
// the command
#ifdef SERIALCOMMANDDEBUG
Serial.println("Too many handlers - recompile changing MAXSERIALCOMMANDS");
#endif
}
}
// This sets up a handler to be called in the event that the receveived command string
// isn't in the list of things with handlers.
void SerialCommand::addDefaultHandler(void (*function)())
{
defaultHandler = function;
}
/*******************************************************************************
SerialCommand - An Arduino library to tokenize and parse commands received over
a serial port.
Copyright (C) 2011-2013 Steven Cogswell <steven.cogswell@gmail.com>
http://awtfy.com
Version 20131021A.
Version History:
May 11 2011 - Initial version
May 13 2011 - Prevent overwriting bounds of SerialCommandCallback[] array in addCommand()
defaultHandler() for non-matching commands
Mar 2012 - Some const char * changes to make compiler happier about deprecated warnings.
Arduino 1.0 compatibility (Arduino.h header)
Oct 2013 - SerialCommand object can be created using a SoftwareSerial object, for SoftwareSerial
support. Requires #include <SoftwareSerial.h> in your sketch even if you don't use
a SoftwareSerial port in the project. sigh. See Example Sketch for usage.
Oct 2013 - Conditional compilation for the SoftwareSerial support, in case you really, really
hate it and want it removed.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/
#ifndef SerialCommand_h
#define SerialCommand_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// If you want to use SerialCommand with the hardware serial port only, and want to disable
// SoftwareSerial support, and thus don't have to use "#include <SoftwareSerial.h>" in your
// sketches, then uncomment this define for SERIALCOMMAND_HARDWAREONLY, and comment out the
// corresponding #undef line.
//
// You don't have to use SoftwareSerial features if this is not defined, you can still only use
// the Hardware serial port, just that this way lets you get out of having to include
// the SoftwareSerial.h header.
//#define SERIALCOMMAND_HARDWAREONLY 1
#undef SERIALCOMMAND_HARDWAREONLY
#ifdef SERIALCOMMAND_HARDWAREONLY
#warning "Warning: Building SerialCommand without SoftwareSerial Support"
#endif
#ifndef SERIALCOMMAND_HARDWAREONLY
#include <SoftwareSerial.h>
#endif
#include <string.h>
#define SERIALCOMMANDBUFFER 16
#define MAXSERIALCOMMANDS 30
#define MAXDELIMETER 2
#define SERIALCOMMANDDEBUG 1
#undef SERIALCOMMANDDEBUG // Comment this out to run the library in debug mode (verbose messages)
class SerialCommand
{
public:
SerialCommand(); // Constructor
#ifndef SERIALCOMMAND_HARDWAREONLY
SerialCommand(SoftwareSerial &SoftSer); // Constructor for using SoftwareSerial objects
#endif
void clearBuffer(); // Sets the command buffer to all '\0' (nulls)
char *next(); // returns pointer to next token found in command buffer (for getting arguments to commands)
void readSerial(); // Main entry point.
void addCommand(const char *, void(*)()); // Add commands to processing dictionary
void addDefaultHandler(void (*function)()); // A handler to call when no valid command received.
private:
char inChar; // A character read from the serial stream
char buffer[SERIALCOMMANDBUFFER]; // Buffer of stored characters while waiting for terminator character
int bufPos; // Current position in the buffer
char delim[MAXDELIMETER]; // null-terminated list of character to be used as delimeters for tokenizing (default " ")
char term; // Character that signals end of command (default '\r')
char *token; // Returned token from the command buffer as returned by strtok_r
char *last; // State variable used by strtok_r during processing
typedef struct _callback {
char command[SERIALCOMMANDBUFFER];
void (*function)();
} SerialCommandCallback; // Data structure to hold Command/Handler function key-value pairs
int numCommand;
SerialCommandCallback CommandList[MAXSERIALCOMMANDS]; // Actual definition for command/handler array
void (*defaultHandler)(); // Pointer to the default handler function
int usingSoftwareSerial; // Used as boolean to see if we're using SoftwareSerial object or not
#ifndef SERIALCOMMAND_HARDWAREONLY
SoftwareSerial *SoftSerial; // Pointer to a user-created SoftwareSerial object
#endif
};
#endif //SerialCommand_h
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
// Dust measurement example:
// You need to include lib_dust.h
#include <lib_dust.h>
float dust=0;
float avgDust, medDust, stdevDust;
void setup(){
Serial.begin(9600);
initDust(); // Don't forget to call initDust() to set A0 pin as input pin
}
void loop(){
float myAvgDust, myMedDust, myStdevDust; // my own calirated values
dust = measureDust(avgDust, medDust, stdevDust); // Then, you just have to call measureDust() whenever you want, and get the dust level
Serial.print("Dust value averaged by the dust library: ");
Serial.println(dust);
// finer custom made calibration for the sensor
myAvgDust = ((avgDust*0.0049)-0.0256)*120000-38000;
myMedDust = ((medDust*0.0049)-0.0256)*120000-38000;
myStdevDust = stdevDust*588;
Serial.println("My own calibrated values: ");
Serial.println(myAvgDust);
Serial.println(myMedDust);
Serial.println(myStdevDust);
delay(2000);
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <lib_dust.h>
// GLOBALS
unsigned int dustPin=0;
unsigned int ledPower=2;
unsigned int delayTime=280;
unsigned int delayTime2=40;
float offTime=9680; // so that delayTime + delayTime2 + offTime = 10ms
unsigned int skip_measurements=50; // skip the first 50 mesurements of a series
unsigned int dustVal=0;
float voltage = 0;
float dustdensity = 0;
float ppmpercf = 0;
unsigned int dustValues[NB_MEAS]; // array storing all the measured values (10 bit)
// since we'll be doing an average over several values, we can increase the precision of each measurement to more bits
// with a simple bit shift without fearing an overflow
unsigned long sum; // to store the sum of measured dust values (4 bytes): NB_MEAS < 4194303 to avoid overflow => OK
// INITIALIZE DUST PIN
void initDust(void){
pinMode(ledPower,OUTPUT);
}
// MEASURE DUST
float measureDust(float &avgRetDust, float &medRetDust, float &stdevRetDust){
unsigned int i,j; // loop indexes
unsigned int temp; // temporary dust value
float medianDust, varDust, stdevDust, avgDust; // some statistical values
// skip initial measurements see dust_calib
for (i=0; i<skip_measurements; i++) {
digitalWrite(ledPower,LOW); // power on the LED
delayMicroseconds(delayTime);
delayMicroseconds(delayTime2);
digitalWrite(ledPower,HIGH); // turn the LED off
delayMicroseconds(offTime);
}
// Let s do the real measurements
for (i=0; i<NB_MEAS; i++) {
digitalWrite(ledPower,LOW); // power on the LED
delayMicroseconds(delayTime);
dustValues[i]=analogRead(dustPin) << 6; // read the dust value and shift the 10bit ADC value by 6 bits
delayMicroseconds(delayTime2);
digitalWrite(ledPower,HIGH); // turn the LED off
delayMicroseconds(offTime);
}
#ifdef DEBUG
// display values in measurement order first
// because later the array is going to be sorted to find the median
Serial.println("all values:");
for (i=0; i<NB_MEAS; i++) {
Serial.print(i);
Serial.print(" ");
Serial.println(dustValues[i]);
}
#endif
// compute median values
for (i=0; i<NB_MEAS-1; i++) { // careful: stopping 1 index before the end
for(j=i+1; j<NB_MEAS; j++) {
if(dustValues[j] < dustValues[i]) {
// swap elements
temp = dustValues[i];
dustValues[i] = dustValues[j];
dustValues[j] = temp;
}
}
}
// compute avg
sum = 0;
for (i=0; i<NB_MEAS; i++) {
sum += dustValues[i];
}
avgDust = sum/NB_MEAS;
// compute variance
for (i=0; i<NB_MEAS; i++) {
varDust = (dustValues[i]-avgDust)*(dustValues[i]-avgDust);
}
varDust = varDust/NB_MEAS;
stdevDust = sqrt(varDust);
// now dustValues is sorted
if(NB_MEAS%2==0) {
// if there is an even number of elements, return mean of the two elements in the middle
medianDust = (dustValues[NB_MEAS/2] + dustValues[NB_MEAS/2 - 1]) / 2.0;
} else {
// else return the element in the middle
medianDust = dustValues[NB_MEAS/2];
}
#ifdef DEBUG
Serial.print("medianDust: ");
Serial.println(medianDust, 3);
Serial.print("stdevDust: ");
Serial.println(stdevDust,3);
Serial.print("avgDust: ");
Serial.println(avgDust,3);
#endif
// copy those in the results with no scaling
avgRetDust = avgDust;
medRetDust = medianDust;
stdevRetDust = stdevDust;
// default scaling for compatibility reasons...
voltage = avgDust*0.0049;
dustdensity = 0.17*voltage-0.1;
ppmpercf = (voltage-0.0256)*120000;
if (ppmpercf < 0)
ppmpercf = 0;
if (dustdensity < 0 )
dustdensity = 0;
if (dustdensity > 0.5)
dustdensity = 0.5;
return ppmpercf;
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <Arduino.h>
#define NB_MEAS 100 // Number of measurements to do: 1 every 10ms for 1 secs
void initDust(void); // Call this function to initialize the pin (A0) used to measure dust
float measureDust(float &avgRetDust, float &medRetDust, float &stdevRetDust); // Call this function will measure dust and return the value(s)
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
// Fan control and RPM measurement example:
// You need to include lib_fan.h
#include <lib_fan.h>
unsigned int duty_cycle = 0;
unsigned int speed = 0;
bool bSpeed = false;
void setup(){
Serial.begin(9600);
initFan(); // Don't forget to call initFan() to set PWM/Tachometer pins
}
void loop(){
setRPM(duty_cycle); // Call setRPM(value) to set the speed of the fan (value in percent)
delay(2000);
speed = getRPM(); // Call getRPM will return the instant RPM of the fan (or 0 if timeout)
Serial.println(speed);
if(duty_cycle<100 && bSpeed==false){
duty_cycle += 5;
}
else if(duty_cycle==100 && bSpeed==false){
bSpeed = true;
}
else if(duty_cycle>0 && bSpeed==true){
duty_cycle -= 5;
}
else if(duty_cycle==0 && bSpeed==true){
bSpeed = false;
}
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <lib_fan.h>
// GLOBALS
unsigned int RPM_Measure_Timeout = RPM_TIMEOUT; // Used to set a measure timeout
unsigned int i_Cnt; // Used to count interrupts (2 per revolution)
unsigned long s_Time, e_Time, d_Time; // Used to measure time per revolution: start, end, delta
bool b_Cnt = false; // Used to know whether the measure is finished
// INIT FAN PWM AND TACHOMETER
void initFan(void){
DDRB |= (1 << DDB6); // Set PB6 as an output (PWM output, pin 12)
DDRD &= ~(1 << DDD2); // Set PD2 as an input (Tachometer input, pin 19)
TCCR1A |= (1 << COM1B1); // Configures the Timer/Counter 1 for fast PWM
TCCR1A |= (1 << WGM11);
TCCR1A |= (1 << WGM10);
TCCR1B |= (1 << WGM13);
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS10);
OCR1A = 639; // Set the top value of PWM register to set frequency at 25kHz
OCR1B = 639/100*FAN_SPEED; // Set the default duty-cycle depending on #define FAN_SPEED (in %)
noInterrupts(); // Configures interruption for tachometer
EICRA |= (1 << ISC21); // Here, on falling edge
interrupts();
}
// GET THE RPM OF THE FAN
unsigned int getRPM(void){
unsigned int RPM_Measure = 0; // Will contain the value of instant RPMs
unsigned int i_Bcl = 0; // Used to measure the timeout
noInterrupts(); // Enable interruptions for tachometer
EIMSK |= (1 << INT2);
interrupts();
for(i_Bcl=0; i_Bcl<=RPM_Measure_Timeout; i_Bcl++){ // Watch dog for RPM measure Timeout
delay(1);
if(b_Cnt==true){ // If the measure is finished
d_Time = (e_Time-s_Time); // Then, compute the results to get duration of one revolution
RPM_Measure = (1000000/d_Time)*60; // Compute the duration to get instant RPMs
b_Cnt = false;
break;
}
}
if(i_Bcl>=RPM_Measure_Timeout){ // If there is a real timeout on the RPM measure (fan blocked)
noInterrupts(); // Disable interruptions
EIMSK &= ~(1 << INT2);
interrupts();
i_Cnt = 0; // Reset counting variable
RPM_Measure = 0; // Set RPMs to 0 (Timeout...)
}
return RPM_Measure;
}
// SET PWM DUTY CYCLE IN %
void setRPM(unsigned int pct){
unsigned int duty_cycle=0; // Temp variable
if(pct>=0 && pct<=100){ // If the value is between 0 and 100
duty_cycle = pct*639/100; // Convert the percentage to the corresponding value on 639
}
else{
duty_cycle =(639*FAN_SPEED)/100; // If the value isn't in the interval, set the default value
}
OCR1B = duty_cycle; // Affect the value on 639 to the compare register
}
// INTERRUPTION SUBROUTINE (used to count interrupts generated by the fan -> 2 per revolution)
ISR(INT2_vect, ISR_BLOCK){
i_Cnt++;
if(i_Cnt==2 && b_Cnt==false){ // If we are at the begginning of the revolution
s_Time = micros(); // Get the time
}
if(i_Cnt==4 && b_Cnt==false){ // If we are at the end of the revolution
e_Time = micros(); // Get the time
noInterrupts();
EIMSK &= ~(1 << INT2); // Stop interruptions
interrupts();
b_Cnt = true; // Set b_Cnt to true to tell the measure is finished
i_Cnt = 0; // Reset the counting variable
}
}
// SET A DIFFERENT TIMEOUT FOR RPM MEASURE (in ms)
void setRPMTimeout(unsigned int timeout){
if(timeout>=1 && timeout<=1000){
RPM_Measure_Timeout = timeout;
}
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <Arduino.h>
#define FAN_SPEED 25 // Duty-cycle of PWM in %
#define RPM_TIMEOUT 200 // RPM Measure Timeout in milliseconds
#define RPMMIN 700
#define RPMMAX 10000
void initFan(void); // Used to initialize PWM and Tachometer
unsigned int getRPM(void); // Used to get instant RPMs (returns the value)
void setRPM(unsigned int pct); // Used to set the fan speed (in percent)
void setRPMTimeout(unsigned int timeout); // Used to set an other RPM measure timeout
../I2C/I2C.cpp
\ No newline at end of file
../I2C/I2C.h
\ No newline at end of file
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
// Temperature/Humidity measurement with HIH-6120 example:
// You need to include lib_hih6120.h
#include <lib_hih6120.h>
float fT;
float fH;
unsigned long measTime=0;
int hih_state;
void setup(){
Serial.begin(9600);
initI2C(); // Don't forget to call initI2C() to be able to communicate with HIH-6120
}
void loop(){
updateTH(); // Call updateTH() when you want the HIH-6120 to perform measures
delay(50);
hih_state = getTH(&measTime); // Call getTH(unsigned int* pTime) to download HIH-6120 values in a buffer
// getTH() takes an unsigned int address (pointer) that will filled with the
// duration of the data transfert (in us) and returns the validity of the measure:
// 0: This is an unread value, 1: The value has already been read
// To be sure that the value is unread, let at least 40 ms between updateTH()
// and getTH()
fT = getTemp(); // Call getTemp() will return the value of the temperature (in *C) from the buffer
fH = getHumi(); // Call getHumi() will return the value of the humidity (in %) from the buffer
Serial.print("Temperature: ");
Serial.print(fT);
Serial.println("*C");
Serial.print("Humidity: ");
Serial.print(fH);
Serial.println("%");
Serial.print("Measure duration: ");
Serial.print(measTime);
Serial.println("us");
Serial.print("Measure validity: ");
Serial.println(hih_state);
Serial.println("");
delay(2000);
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <lib_hih6120.h>
uint8_t high_Temp, low_Temp, high_Humi, low_Humi; // 4 bytes for I2C readings
uint16_t tmp_Temp, tmp_Humi; // 2 bytes temporary variables
// INITIALIZE I2C COMMUNICATIONS FOR HIH-6120
void initI2C(void){
I2c.begin(); // Join i2c bus (address optional for master)
I2c.timeOut(200); // Set an I2C timeout of 100 ms
I2c.setSpeed(1); // Set high I2C speed (400 kHz)
I2c.pullup(0); // Disable internal pullup resistors
}
// MAKE HIH-6120 UPDATE TEMPERATURE/HUMIDITY
void updateTH(void){
I2c.write(0x27, 0x00, 0); // Make HIH-6120 updates its values.
}
// GET TEMPERATURE
float getTemp(void){
float temp = (((float)tmp_Temp/16382)*165)-40; // Calculating the value of temperature in celsius degrees
return temp;
}
// GET HUMIDITY
float getHumi(void){
float humi = ((float)tmp_Humi/16382)*100; // Calculating the value of humidity in percent
return humi;
}
// START TIMER
void startTimer(unsigned long* pTime){
*pTime = micros();
}
// END TIMER
unsigned long endTimer(unsigned long* pTime){
unsigned long end = micros();
unsigned long delta=0;
delta = end - *pTime; // calculate the time spent while acquiring data
return delta;
}
// GET TEMPERATURE/HUMIDITY
int getTH(unsigned long* pTime){
int HIH_state=1;
startTimer(pTime); // Fill pTime with the time in us
I2c.read(0x27, 4); // Request 4 bytes from HIH-6120 @ 0x27
if(I2c.available()==4){ // Get the 4 bytes containing:
high_Humi = I2c.receive(); // Humidity (on 14 bits) for the 2 first bytes
low_Humi = I2c.receive();
high_Temp = I2c.receive(); // Temperature (on 14 bits) for the 2 last bytes
low_Temp = I2c.receive();
}
*pTime = endTimer(pTime); // Returns the time difference between pTime value and now
HIH_state = (int)((high_Humi & 0xC0) >> 6); // Get the 2 status bits (00 -> Ok, 01 -> Stale values)
// Compute the values (humidity/temperature)
tmp_Temp = ((((uint16_t) high_Temp) << 8) | low_Temp) >> 2; // Assembly of 2 bytes of the temperature
tmp_Humi = (((uint16_t) (high_Humi & 0x3f)) << 8) | low_Humi; // Assembly of 2 bytes of the humidity
return HIH_state;
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <Arduino.h>
#include <stdlib.h>
#include "I2C.h"
// PROTOTYPES
void initI2C(void); // Initialize I2C communications with HIH-6120 (@0x27)
void updateTH(void); // Make HIH-6120 updates its values
float getTemp(void); // Get temperature
float getHumi(void); // Get humidity
void startTimer(unsigned long* pTime); // Fill pTime with micros()
unsigned long endTimer(unsigned long* pTime); // Returns delta time between *pTime and now
int getTH(unsigned long* pTime); // Updates temp/humi vars in the program
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <lib_leds.h>
void initLEDs(void){
DDRK |= (1 << DDK7);
DDRK |= (1 << DDK6);
PORTK &= ~(1 << DDK7);
PORTK &= ~(1 << DDK6);
}
void controlLED15(bool on){
if(on){
PORTK |= (1 << DDK7);
}
else{
PORTK &= ~(1 << DDK7);
}
}
void controlLED14(bool on){
if(on){
PORTK |= (1 << DDK6);
}
else{
PORTK &= ~(1 << DDK6);
}
}
void toggleLED15(bool tog){
bool b=((PINK & 0b10000000)>>7);
if(b && tog){
PORTK &= ~(1 << DDK7);
}
else if(~b && tog){
PORTK |= (1 << DDK7);
}
if(!tog){
PORTK &= ~(1 << DDK7);
}
}
void toggleLED14(bool tog){
bool b=((PINK & 0b01000000)>>6);
if(b && tog){
PORTK &= ~(1 << DDK6);
}
else if(~b && tog){
PORTK |= (1 << DDK6);
}
if(!tog){
PORTK &= ~(1 << DDK6);
}
}
/******************************************************************************
*
* This file is part of the DCES project.
* See http://www.ohwr.org/projects/dces-dtrhf-ser1ch-v1
*
* Copyright (C) 2016 CERN
* All rights not expressly granted are reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @author DCES Dev team, dces-dev@cern.ch
*****************************************************************************/
#include <Arduino.h>
void initLEDs(void);
void controlLED14(bool on);
void controlLED15(bool on);
void toggleLED14(bool tog);
void toggleLED15(bool tog);
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment