Translate

Showing posts with label RF. Show all posts
Showing posts with label RF. Show all posts

Friday 22 July 2016

Arduino GPS master clock with 433/315 MHz transmitter

I've got a few clock projects in the back of my mind, and this is a bit of an aside to them all. I also wish to upgrade the Astronomical clock project, as the DS1307 often drifts about, losing and gaining seconds as it feel like it...

The idea is to have a master clock, GPS locked with built in 433 MHz transmitter, which will send an accurate time signal to the other clocks to bring them into sync. The transmitter will be triggered randomly, at least once every 24 hours, or by a push button connected to pin 12.

I'll be re-using the code from the quick and dirty 7-segment GPS clock here, and some of the code for the transmit function from the dehumidifier project.

I've added a 4x20 LCD display, with I2C piggyback interface board, and the u-blox GPS module we've used in the GPS logger.

The GPS module will be configured by the sketch itself, to 200mS refresh rate.

There's two sketches, the GPS clock itself, and a simple test receiver sketch to check everything's working as it should.

The I2C display is a generic display, purchased from eBay, and uses the PCF8574 I2C receiver IC. I tried a couple of different libraries, but eventually settled with the library from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads which works well with my display.
Well also use the virtual wire library to handle our comms, https://www.pjrc.com/teensy/td_libs_VirtualWire.html and the most excellent TinyGPS++ http://arduiniana.org/libraries/tinygpsplus/

There's an LED connected to pin 9, which blinks on and off every time the seconds are updated.

Here's the schematic...




... and the hardware lashed up for testing.

The second arduino is acting as our test receiver. There's no RF module in there as yet.. It's coupled to the clock arduino, GND is coupled, and pin 10 on the clock is connected to pin 9 on the receiver board. It's also supplying 5V to the other board.







Here's the data being displayed. Date (in UK format DD/MM/YYYY) , UTC time, latitude, longitude, no of satellites in use, horizontal dilution of precision and the number of seconds until the next transmission.







Here's the output from our terminal window, connected to the receiver board, showing the time and date are being correctly received when A3 is pulled to ground.




So, the final build looks like this...

You can see the antenna is simply a straight piece of wire, 173mm long (for 433 MHz modules, other frequencies will need a different length)


And assembled. Managed to cut the right sized hole for the display for once!











Here's the GPS receiver, which I'm going to mount remotely on the roof, so it get's good reception. I've stuck it into of a water-proof IP rated box, and fitted a Buccaneer connector.









OK, so to the code....

This is the transmitter code:



and the test receiver code...



Now all that remains is to box it up, and create some clocks!

Wednesday 6 April 2016

Mobius HD Actioncam and RFI.

Now, being a gadget lover that I am, I decided to upgrade the rather old dashcam in my car to something a little more "HD". After doing a bit of research, and seeing the footage of a colleagues camera, I decided to get a Mobius 1080P Actioncam, purchased from a reputable source (beware the fakes). Good choice. Small unit, great pictures, sound is OK... except....

... it ruined my radio reception.





Now I have a newish car, and it's fitted with a DAB radio. After fitting the camera to my windscreen, I noticed DAB reception of my favourite station, Planet Rock, became patchy. Disconnecting the camera solved the issue.... hmmmm ... RFI ... Radio Frequency Interference.

So what was going on? I broke out my ancient spectrum analyser, and, equipped with a simple whip antenna, took some measurements....

Here's the DAB reception, centred on 220MHz, with the Mobius disconnected. The two humps are the two DAB Mux's (multiplexes) I can receive at home...










... and here's the same shot with the camera connected... yuck. I suspect the big peak to the right of the mux is effecting the AGC of the radio, and there's a lot of hash underneath it too, upsetting the signal to noise ratio... boo!








I tried a simple method of preventing RFI radiating from the cable of the device. I wrapped as many turns of the USB power lead round a random (ex-computer power supply) ferrite ring.









Brilliant....














... and after some field tests, reception restored!


Friday 12 February 2016

Video rack video modulator repair and warning! Model CCT811

Remember the video rack I built a while ago? It's details are here.

Well, it's developed a fault. The UHF modulator has been giving very poor pictures after a few minutes of operation. I decided to take it out, and repair it.

IF YOU HAVE ONE OF THESE UNITS, I WOULD HAVE SERIOUS RESERVATIONS ABOUT IT'S ELECTRICAL SAFETY. 

I purchased it ages ago from eBay, and it came fitted with an unfused euro plug, which I cut off, and fitted a standard UK Plug, and fused it at 1 amp. I'm glad I did... read on ...

It's a useful thing. Is stable (when working properly), is adjustable throughout European VHF allocations, as well as UHF, and has switchable FM sound between 5.5 MHz and 6 MHz sound sub-carriers....
Disassembling the unit reveals a few horrors....

Check the mains input to the diminutive switched-mode supply ..... No fuse is evident!

What you can't see by this picture is the bottom of the case, the black bit. It's metal. There's no earth, which would be fine if the thing met Double Insulated (Class II) standards, which I doubt it does. You can read about classes here.

There's also zero filtering on the mains input, so any noise from the switched mode makes it's merry way back down the mains lead and out onto our mains, spoiling our radio reception (and, ironically, our TV reception too!) if it radiates (which it will).

Grim. Glad I fitted a fused plug ....

Examination of the power supply shows it to be nothing more than a simple blocking oscillator.

There's a simple zener on the output attempting to provide a little regulation. You can see where the board is a little discoloured, as it's been running warm. There are two capacitors in the primary, the mains smoothing capacitor (4.7uF 400V) proved to be very low in capacity. I fitted a 10uF , as I had one to hand. I also changed the smaller cap (10uF 50v) whilst I was there.


 A quick check shows the unit to be working again.... but what to do about the safety issues?

Mounting it back in the rack, I've fitted an in line filter and fuse (100mA). I'm not so concerned about earthing the case, as the modulator is inaccessible when the rack is assembled, that doesn't mean you should be though!

Pity really ... "for a ha'p'orth of tar" an otherwise good unit is spoiled.... and possibly electrically unsafe and a fire risk. It carries a CE mark, which I've no doubt it doesn't deserve.


 This gives you some idea of the size of that supply transformer, that's a 1p piece!
The guilty parties. Caps. As usual!

Saturday 10 October 2015

Arduino Mains Monitor with SIM900A GSM messaging.

Picture the scene... You're away on holiday, sunning yourself in Spain (or if you're Spanish, enjoying the damp weather in the UK !) ... and thousands of miles away, some spurious minor electrical niggle in your house causes the RCD circuit breaker to open. You return 10 days later to find the contents of your freezer oozing their way across the kitchen floor. Not nice... You reset the breaker, and the power comes back on, showing no faults.

It happens from time to time in my house. I've tested each circuit, and every appliance to try and find the cause of the random tripping. The fault is not visible on any of my insulation readings, but, nevertheless it does happen. Sometimes not for years.... frustrating!

So what can we do about it? Fix the fault would be the easiest thing to do, but it's eluding me. How about monitoring the mains, and sending me a message, so if it does trip, I can reset the power without issue? Good plan...

Now the disclaimer:

WARNING. Do NOT try this at home. This project deals with mains voltages. A shock from the mains will hurt and can easily be fatal. Work safely. Use an RCD. Disconnect from the mains before making any adjustments. 
RESPECT IT'S AUTHORITY

I will not, under any circumstances, accept any liability if you decide to re-create this project for yourself.


Now that's got that out of the way...

So, we have a plan. Measure the mains voltage (and why not frequency at the same time?), and act conditionally on it's failure. We also need to get it to send us a message. We're going to need some form of uninterruptable power supply, so when the mains does go off, our micro will still be running, and we've got power enough to send the message. Here's the circuit:


I'll go through it step by step...

Power comes in via a fuse to two transformers. TR1, is a mains to 15V transformer, and is used as our power supply. It feeds a bridge rectifier, B1 and C1 and C2 are used to smooth and decouple the resultant DC. The DC is fed via D2 to a 7805 regulator, which provides the 5V for the Arduino and the SIM900  module. So that's fairly straightforward. The 7805 in this instance is a 2A part, as the SIM900A does require a fair amount of current to function.

(You could, and it would be safer to do so, build this unit using two wall warts, one, with, say at 15VDC, 3A output to replace TR1 & B1, and a second, with AC output in place of TR2. That way, all the tricky and potentially dangerous stuff with the mains is eliminated)

The rectified DC from B1 is also fed to two LM317 voltage regulators in series. The first, IC1, is configured as a 100mA constant current source, this is then used to feed the second regulator, IC2, which is configured as a conventional voltage regulator, in this case, R3 is adjusted to provide around 14V. This forms a 100mA constant current charger, with maximum voltage of 14V, which we can use to charge G1, which is an old 12V NiMH battery I happened to have kicking about. It's got plenty of capacity left, so will do nicely as our back up battery. S3 is a battery diconnect switch. Useful for resetting. (Why didn't I use an LM200, as it is capable of both current and voltage regulation in one package, instead of two LM317's? Because I didn't have one!)

So, when the mains is present, our battery is being charged. In the event of mains failure, D2 will stop conducting, and the supply will be seamlessly taken over by the battery, supplying current to the 7805 via D1. D3 prevents current flowing back into the charging circuit. The battery voltage is also sampled at the mid-point of the potential divider, R11 and R12, and fed to the Arduino A1 pin. T2, between the reference pin of IC2 and ground, is used to switch off the charging circuit momentarily, so we can measure the battery voltage, and not just the output of the charger. It's controlled by the Arduino A2 pin, configured as a digital output.

OK, so that's power and back up power sorted, so what about measuring the mains? TR2 is a small (3VA) 18V mains transformer. This feeds another bridge rectifier, B2, and a small smoothing network, formed by C7. The voltage developed across C7 is fed to a potential divider formed by R5 and R4, and the resultant voltage fed to Arduino A0. This voltage will be directly proportional to the mains input voltage on the primary of T2.... or will it? Whilst I was experimenting, I noticed the measurement wasn't linear. Adding a bit of loading, in the form of R15 to the secondary helped matters no end, although it was accurate enough over the range required for this to be left out, if required.

Also coupled to the secondary is our frequency measuring network. The AC is fed via coupling capacitor C8 to the base of a BC547, T1. This provides a 5 volt 50 Hz signal to the input of IC4A (a Schmitt trigger hex interter), this will square our pulses up. The output of IC4a is fed via a low pass filter, formed by R8 and C9 to the input of IC4B, the output of which is connected to the Arduino pin D8. We'll use this to measure the frequency of the mains. Tie all of the unused inputs of IC4 to ground.

On to the micro side of things...

The LCD is wired to the Arduino in the time-honoured fashion, except for the cathode of the backlight, which isn't connected straight to ground, but to the collector of T3. This allows us to control the backlight, using A4 of the Arduino configured as a digital output. There's a momentary switch coupled to A3, which is used as a "push to transmit" function, and a toggle switch, S2, connected to pin A5, which is used to stop the SIM900 sending messages. R9 is the LCD's contrast control.

The SIMR pin on the SIM900 module is connected to the Arduino's hardware serial Tx pin, and the SIMT pin is connected to the Rx pin.

The software.....

We're going to need something to measure our frequency. I did initially use PulseIn , but it's not that accurate, so I switched to using the most excellent FreqMeasure library, available from https://www.pjrc.com/teensy/td_libs_FreqMeasure.html . Now this has a drawback. It uses Int 1, and this is in conflict with the software serial library, which is why the SIM900 is connected to the hardware serial port of the Arduino. The issue here is the hardware port is also where the inbuilt USB interface sends/receives data, so you'll need to disconnect the SIM900 from the arduino whilst uploading the sketch, or doing any serial debugging. You can use SoftwareSerial during development, but be prepared for some unusual responses from FreqMeasure!

Ok, so the sketch.

There's a rake of variables set at the start. The variables to watch are the mains tolerances, these will need to be set for your local mains (They're currently set for UK mains spec.)

  float MainsMinV = 216.2; // This sets the lower limit for the mains voltage. Change this to suit your local voltage limit
  float MainsMaxV= 253; // Maximum voltage limit
  float BatteryMin=11.2; // Battery low limit
  float MainsMinF=49.5; // Minimum allowable mains frequency limit, change to suit local power
  float MainsMaxF=50.5; // Maximum allowable mains frequency limit.

You will also need to change line 260 :
      Serial.println("AT + CMGS = \"+44xxxxxxxxxx\"");// recipient's mobile number, in international format
If your mains is not ~240v, you will also need to change the scaling factor in the software , line 286, so the voltage reads correctly. Currently the mains voltage is scaled so 250V is equal to 5V at our micro. If, say, you're on 120V mains, and want the voltage to top out at , say 130V, then the scaling will be 130/5 = 26. It's currently set to 51, so 5V on our analogue port reads as 255V :
  ACVoltage = (sensorValue * (5.0 / 1023.0))*51;

Adjust R4 to get the mains calibration correct.

So, here's the complete sketch:


If you're using a SIM900A module outside of Asia, you may run into difficulties, as I did. There's some brief notes I made here : http://andydoz.blogspot.co.uk/2015/10/sim900-and-sim900a-module-signal.html and a link to a website which contains detailed instructions on sorting out the firmware to make the unit work.
Here's some pictures of my unit:



BTW. Sainsbury's is my service provider!









Electrical Safety is paramount. Here is the incoming mains earth (ground) securely tied to the chassis of my metal case. 

Friday 2 October 2015

SIM900 (and SIM900A) module signal strength.




I've been working on a mains monitor project for a while, and I've wanted to interface it to a mobile phone module, so it will send me data. I'll publish the finished thing up soon, but , in the meantime, reading forums etc, people seem to have a couple of problems.








1) Getting the oh-so-very-cheap SIM900A module to work.

2) Getting a signal strength report from the thing.




The first problem appears to be that the SIM900A module, which I purchased for less than a tenner from eBay, doesn't work outside Asia. Yep. It certainly doesn't work here in the UK. But, never fear, there's a website with all the info to help us out. http://amichalec.net/2014/08/sim900a-fixed-for-europe/ which, after a little fiddling about, had provided a firmware cure. Now I have used my little FTDI module to flash the firmware on my unit at 57,600 Baud. The website claims you need to set the baudrate of your device to 460800 baud, which mine won't support. It worked fine at 57,600, however. I did have to wait a little while (about 20 mins) for the process to complete though.
The second problem seems to bug a lot of users. I searched in vain for a ready-to-go library to solve all my woes, but couldn't find one, so here's a little routine to get the signal strength out of the unit, so you can do with it what you will...
#include <SoftwareSerial.h>
SoftwareSerial SIM900 (6,7); // SIM900 connected to pins 6 & 7 (pin 6 to SIMT and pin 7 to SIMR)
char Reply[200]; // Serial buffer length
int number = 43; // msg length
int Signal; // Signal strength as reported
int temp1; // 4 temporary integers, used to extract the data from the incoming serial.
int temp2;
int temp3;
int temp4;
int BER; // Bit error rate
int SignaldBm; //Signal in dBm
void setup() { SIM900.
{
SIM900.begin(9600); // Start serial comms with module
Serial.begin(57600); // Start serial comms with PC
}
void GetStatus() { SIM900.
SIM900.write("AT+CMGF=1\r"); //set GSM to text mode
delay (150); SIM900.
SIM900.write("AT+CSQ\r"); //Send command for signal report
delay (200);
while(SIM900.available() >0 ) { //wait for responce
for(int i=0; i<44; i++) //read character into array from serial port
Reply[i] = SIM900.read(); } Reply[199] =
}
Reply[199] = '/0'; temp1=Reply[31]-


temp1=Reply[31]-'0'; //convert relevant characters from array into integers
temp2=Reply[32]-'0'; temp3=Reply[33]-
temp3=Reply[33]-'0'; temp4=Reply[34]-
temp4=Reply[34]-'0';

if (temp1 == -48) { //if temp1 is -48 then do it again as the data is not valid (yet)
GetStatus();
}

if (temp3 == -4) { // use temp3 to determine where in the array the relevent integers are (-4 is a ",")
Signal= temp2+ temp1*10; // calculate signal if the first digit is a multiple of 10
BER = temp4;
}

else{ Signal= temp1;
Signal= temp1; //calculate signal if the first digit is not a multiple of 10
BER = temp3;
}

if ( Signal == 99) { // if our signal is 99, IE no signal condition , the return a signal of -1
Signal = -1;
}


SignaldBm = Signal*2 -113; // calculate dBm for geeks like me.
Serial.print ("Signal: "); //output stats to serial interface.
Serial.println (Signal);
Serial.print (SignaldBm);
Serial.println ("dBm");
Serial.print ("BER: ");
Serial.println (BER); }

}
void loop() { GetStatus (); }
{
GetStatus ();
}
There , I hope that eases the pain for a few users! Have fun, and check back soon for the mains monitor!







Sunday 10 August 2014

Dehumidifer datalogging...

<Deep voice over> Just when you thought it was safe to go into the attic</Deep voice over>

 Just when you thought the project was over (and it is really!) someone comes along and puts an idea in your head... "Hey, Andy, Why don't you log the data, and make some nice graphs" ... and, in reality, why would I want to .... because

a) I'm erring on the side of geeky

and

b) Because I can...

So, what's needed...

A scrappy old Windows box ... yes, this is just the ticket , 500 MB of RAM, 900MHz processor, 100MB HDD ... more than enough for the job.

A copy of Gobetwino, available here http://mikmo.dk/gobetwino.html

Another arduino board, another receiver and some code. (I suppose you could use your exisiting display, and just add the Serial.print bits to that code if you wished. Mine's all nicely boxed up, so it had to be stand alone)

// Receiver Sketch for Dehumidifier controller project
// Written by A.G.Doswell 08 Aug 2014
// Receiver connected to pin 9


#include <VirtualWire.h>
#include <VirtualWire_Config.h>

int TX_ID =10;
int Temp;
int Humidity;
int Dew;
boolean Output;
char buffer[5];
int led = 13;


void setup() {
              pinMode(led, OUTPUT);   
              //Comms set up
              Serial.begin(9600);
              // Virtualwire setup
              vw_set_tx_pin(10); // Even though it's not used, we'll define it so the default doesn't interfere with the LCD library.
              vw_set_rx_pin(9); // RX pin set to pin 9
              vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second, nice and slow! 
              vw_rx_start();     
              }  
void loop()
{
typedef struct rxRemoteData //Defines the received data, this is the same as the TX struct
{
int    TX_ID; 
int    Temp;   
int    Humidity;
int    Dew;
boolean Output;

};

struct rxRemoteData receivedData;
uint8_t rcvdSize = sizeof(receivedData);

if (vw_get_message((uint8_t *)&receivedData, &rcvdSize)) 
{
  if (receivedData.TX_ID == 10)     { //Only if the TX_ID=10 do we process the data.
    int TX_ID = receivedData.TX_ID;
    int Temp = receivedData.Temp;
    int Humidity = receivedData.Humidity;
    int Dew = receivedData.Dew;
    boolean Output = receivedData.Output;
    digitalWrite(led, HIGH);
        
      // writes the received data to the serial interface
      
      Serial.print("#S|DATA|[");
      Serial.print(itoa((Humidity), buffer, 10));
      Serial.print(";");
      Serial.print(itoa((Temp), buffer, 10));
      Serial.print(";");
      Serial.print(itoa((Dew), buffer, 10));
      Serial.println("]#");
      digitalWrite(led, LOW);
 
      } 

  }
}

// End of file


So there it is. Load that into your favorite arduino, and connect a receiver to pin 9.
Now we need to tell Gobetwino what to do when it sees data from the com port. Firstly, quit the Arduino IDE. The two can't be running at the same time, or Gobetwino can't access the serial port the arduino is chatting on.

Firstly click on Commands.


Then click the New Command button. Using the drop down box , select LGFIL (Log data to file). Give it the Command name DATA (must be in capitals to match our Arduino data). Now create a blank data.txt file somewhere, using Windows explorer, just right click on a directory, click new and Text document. Name it data.txt. I chose the root of C: here for ease, but it can be anywhere....



Now back to Gobetwino. Click on the browse button, and point it to our freshly created data.txt file.


Check the Time stamp box. 

Click on save, and click on settings. Now click the serial port tab, and select the serial port our Arduino is communicating on. This is the same port the Arduino IDE was using.

Now every time the Arduino receives data from our transmitter, it will blink it's LED breifly, and send the data to Gobetwino, which will add a time stamp, and save it dutifully to the data.txt file.

You should end up (after a while) with a txt file looking a bit like this....

08/08/2014 16:13:15;28;36;14
08/08/2014 16:13:36;29;38;16
08/08/2014 16:13:58;29;38;16
08/08/2014 16:14:19;28;36;14
08/08/2014 16:14:40;28;36;14
08/08/2014 16:15:01;29;38;16
08/08/2014 16:15:22;28;36;14
08/08/2014 16:15:43;29;38;16
08/08/2014 16:16:04;29;38;16
08/08/2014 16:16:26;29;38;16
08/08/2014 16:16:47;29;38;16
08/08/2014 16:17:08;29;38;16
08/08/2014 16:17:29;29;38;16
08/08/2014 16:17:50;29;38;16
08/08/2014 16:18:11;28;36;14
08/08/2014 16:18:33;29;38;16
08/08/2014 16:18:54;29;38;16
08/08/2014 16:19:15;29;38;16
08/08/2014 16:19:36;29;38;16
08/08/2014 16:19:57;29;38;16
08/08/2014 16:20:18;29;38;16
08/08/2014 16:20:39;29;38;16
08/08/2014 16:21:01;28;36;14
08/08/2014 16:21:22;28;36;14
08/08/2014 16:21:43;28;36;14
08/08/2014 16:22:04;29;37;15


Now if we make a copy of the file, and change the extension to .csv (if windows worries about this making our file unusable, just carry on regardless!) It will then open in the spreadsheet programme of your choice (I choose OpenOffice), and with a little charting, we can create our graph...


Yes well, that's all very nice 'an 'all.... but wouldn't it be nice if the data was sent to me?

I'm not going to go into this in detail... as it took me hours to get it to work, and I'm still not really sure how I got it all to work... but there's a very useful piece of software called Sendemail available here: http://caspian.dotconf.net/menu/Software/SendEmail/ that I configured using the usual Windows task scheduler to copy the file, email me the copy, and then install a new blank in it's place... and it works a treat!

That's it for this project. It REALLY is... 



Friday 30 May 2014

Wireless Dehumidifier Controller Completion.

The new transmitter and receiver pair duly arrived, fitted and tested. Great range now. I haven't fully tested it's range, but it works beautifully from my attic to my workshop on the ground floor. During testing I became aware of other transmitters sending data on the same channel every now and again (remember my doorbell and weather station?) Perhaps sending data at such a slow datarate every 2 seconds is a bit anti-social, likely to clutter up the band a bit, and is unnecessary, so I've altered the sketch to send the data every 18 seconds.


Finished receiver in a Hammond clear blue case. Posh eh?

Powered from a redundant mobile phone charger (see note below).








Display on the receiver.











A note on aerials. The aerial (or antenna if you must) is simply 173mm of copper wire. Keep it as straight as possible and vertical. 

For the revised transmission rate, only the transmitter sketch changes. The receiver remains the same.

// 
// FILE:  wireless_dehumid.pde
// Written by Andy Doswell 24th May 2014
// PURPOSE: DHT11 sensor with LCD Display and output for controlling dehumidifier.
// Data send via virtualwire and 433MHZ link to remote display
// Dehumidifier is controlled by a relay attached to pin 7, defined in rlyPin.
// DHT11 sensor is connected to 8, as defined in #define
// LCD is a Hitachi HD44780 or compatible, attached thus:
// LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2
// RW to GND
// V0 Held high (this may or may not work with your LCD, usual practice is to connect this to a 10K pot between +5 and GND)
// TX connected to pin 10
// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
 double a = 17.271;
 double b = 237.7;
 double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
 double Td = (b * temp) / (a - temp);
 return Td;
}

#include <VirtualWire.h>
#include <VirtualWire_Config.h>

#include <dht.h>

dht DHT;

#define DHT11_PIN 8

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// define constants & global variables
const int rlyPin = 7; //defines pin the relay is connected to. relay is active low
const int TimerLength = 1800;// number of seconds in an hour / 2 - this sets the minimum time the dehumidifier will remain on for.
int Timer = 0; //timer is off to start
boolean DewFlag = false; // This is the dew flag. Off as default.
boolean OutputStatus = false; //Output status is off as default
int chk;
int Temp;
int Dew;
int Humidity;
int DewTrip;


// Data structure set up for Transmission

struct TXData
{
  int TX_ID;
  int Temp;
  int Humidity;
  int Dew;
  boolean Output;
};
  

void setup()
{
  lcd.begin(16, 2); // defines the LCD as a 16 x 2
  pinMode (rlyPin, OUTPUT); // sets our relay pin
  digitalWrite (rlyPin, HIGH); // sets the relay off for default condition.
  
  // Virtualwire setup
  vw_set_tx_pin(10); // TX pin set to 10
  vw_set_rx_pin(9); // RX pin set to a spare pin, even though we don't use it. If left as default it interferes with LCD operation.
  vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second
  

}

void loop()
{
  for(int i = 0; i < 10 ; i++) { //transmit only every 9 loops (18 seconds)
    chk = DHT.read11(DHT11_PIN); // these 4 lines get data from the sensor
    Dew = dewPointFast(DHT.temperature, DHT.humidity);
    Temp = (DHT.temperature);
    Humidity = (DHT.humidity);
    DewTrip= Dew + 5; // Brings the dehumidifier on 5 deg C before the dew point. 
  
    // writes information about the system to the LCD
    lcd.clear ();
    lcd.print("Humidity:");
    lcd.print(Humidity);
    lcd.print("%");
    lcd.setCursor(0, 1);
    lcd.print(Temp);
    lcd.print((char)0xDF);
    lcd.print("C");
    lcd.setCursor(6, 1);
    lcd.print("Dew:");
    lcd.print(Dew);
    lcd.print((char)0xDF);
    lcd.print("C");
   
  // Dew detect loop. If the dewTrip point is reached, start the timer running and set the Dew flag
    if ( Temp <= DewTrip ) {
      DewFlag = true;
      Timer = 1;       
    } 
    else {
      DewFlag = false;
    }

  
    if (Timer >= TimerLength and DewFlag == false) { // If the timer has expired and there's no dew, switch the dehumidifier off.
      Timer = 0;
      digitalWrite (rlyPin, HIGH);
   
    }

    if (Timer !=0) {                // If the timer is running, switch the dehumidifier on , and write On to the lcd.
      digitalWrite (rlyPin, LOW);
      lcd.setCursor (13,0);
      lcd.print (" On");
      OutputStatus = true;
      Timer++;
    }
  
    else {
      lcd.setCursor (13,0);
      lcd.print ("off");
      OutputStatus = false;
    }
  
 delay (2000);
  }
  
struct TXData payload; //Loads the Data struct with the payload data
  
payload.TX_ID=10;
payload.Temp = Temp;
payload.Humidity = Humidity;
payload.Dew = Dew;
payload.Output = OutputStatus;
vw_send((uint8_t *)&payload, sizeof(payload)); //Transmits the struct
vw_wait_tx(); //waits for the TX to complete

}  
  
//
// END OF FILE
//


The receiver is powered from a redundant mobile phone charger, rated at 5V at 800mA. I was quite surprised to find it's off load voltage to be just under 7 volts. I expected it to be regulated. I fitted a 7805 voltage regulator inside the case. I was worried if the 7805 had enough headroom, but it seems to function well enough.

Saturday 24 May 2014

Arduino dehumidifier controller project - Wireless update!

Some spare time over the weekend means I can finally crack on with this!

After experimenting with a number of methods of sending and receiving data, I came across the virtualwire library here: http://www.airspayce.com/mikem/arduino/VirtualWire/

Now, there's a few things to note. Whilst surfing the various boards, there's talk of virtualwire only being able to send characters, which makes sending an integer a bit of a bind. There's people doing itoa's and atoi's back again. What happens if you need to send multiple values like we do? Temperature, humidity etc? We'll have to sync the transmitter and receiver for the first time... then what happens if a packet is dropped? It was all a bit much really, and sending integers as character arrays was all a bit wasteful of bandwidth. 

Now virtualwire is great, it takes care of manchester coding your data, and provides a bit of pre-amble so your simple receiver can sort out it's agc before outputing data. It's data is defined as uint_8 .... hang on ... that's a byte isn't it? So why can't I send an integer? It's just data ... 

So, pencil and pad at the ready, and a bit of a read about struct in by big book of C and we can create a custom message, with a unique identifier (just in case someone rings my wireless doorbell or my wireless weather station happens to transmit at the same time and corrupts our message, or indeed preventing our receiver attempting to decode such a message!)

For testing purposes, the two arduinos (arduini?) were linked by a bit of wire instead of the RF link. (Connect your output pin to the input, and link the grounds.)

Data rate during testing was 2000 bits per second.
Once the RF link was added I reduced this to 300 bits per second to make the link a little more robust.

Even reducing the data rate to 300 bits left me with woeful range, so I investigated. Output from the transmitter seemed good on the spectrum analyser, on frequency and plenty of output. 
Output from the receiver was noisy and it appeared the receiver was particularly "deaf". 
I used a frequency source to sweep the receiver, to see if it was tuned in accurately, my thinking being there's a nice big coil on the top to tweak! Sweeping the tuner found it tuned to 315MHz! Great. A 433 TX and a 315 RX. It was amazing it worked at all on the bench! Thankfully the supplier has agreed to send me out a new set, so hopefully It'll be wireless soon enough! 

Here's the transmitter code:-



// 
// FILE:  wireless_dehumid.pde
// Written by Andy Doswell 24th May 2014
// PURPOSE: DHT11 sensor with LCD Display and output for controlling dehumidifier.
// Data send via virtualwire and 433MHZ link to remote display
// Dehumidifier is controlled by a relay attached to pin 7, defined in rlyPin.
// DHT11 sensor is connected to 8, as defined in #define
// LCD is a Hitachi HD44780 or compatible, attached thus:
// LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2
// RW to GND
// V0 Held high (this may or may not work with your LCD, usual practice is to connect this to a 10K pot between +5 and GND)
// TX connected to pin 10
// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
 double a = 17.271;
 double b = 237.7;
 double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
 double Td = (b * temp) / (a - temp);
 return Td;
}

#include <VirtualWire.h>
#include <VirtualWire_Config.h>

#include <dht.h>

dht DHT;

#define DHT11_PIN 8

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// define constants & global variables
const int rlyPin = 7; //defines pin the relay is connected to. relay is active low
const int TimerLength = 1800;// number of seconds in an hour / 2 - this sets the minimum time the dehumidifier will remain on for.
int Timer = 0; //timer is off to start
boolean DewFlag = false; // This is the dew flag. Off as default.
boolean OutputStatus = false; //Output status is off as default

// Data structure set up for Transmission

struct TXData
{
  int TX_ID;
  int Temp;
  int Humidity;
  int Dew;
  boolean Output;
};
  

void setup()
{
  lcd.begin(16, 2); // defines the LCD as a 16 x 2
  pinMode (rlyPin, OUTPUT); // sets our relay pin
  digitalWrite (rlyPin, HIGH); // sets the relay off for default condition.
  
  // Virtualwire setup
  vw_set_tx_pin(10); // TX pin set to 10
  vw_set_rx_pin(9); // RX pin set to a spare pin, even though we don't use it. If left as default it interferes with LCD operation.
  vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second
  

}

void loop()
{
  int chk = DHT.read11(DHT11_PIN); // these 4 lines get data from the sensor
  int Dew = dewPointFast(DHT.temperature, DHT.humidity);
  int Temp = (DHT.temperature);
  int Humidity = (DHT.humidity);
  int DewTrip= Dew + 5; // Brings the dehumidifier on 5 deg C before the dew point. 
  
// writes information about the system to the LCD
  lcd.clear ();
  lcd.print("Humidity:");
  lcd.print(Humidity);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print(Temp);
  lcd.print((char)0xDF);
  lcd.print("C");
  lcd.setCursor(6, 1);
  lcd.print("Dew:");
  lcd.print(Dew);
  lcd.print((char)0xDF);
  lcd.print("C");
  
  struct TXData payload; //Loads the Data struct with the payload data
  
  payload.TX_ID=10;
  payload.Temp = Temp;
  payload.Humidity = Humidity;
  payload.Dew = Dew;
  payload.Output = OutputStatus;
  
  vw_send((uint8_t *)&payload, sizeof(payload)); //Transmits the struct
  vw_wait_tx(); //waits for the TX to complete
  
// Dew detect loop. If the dewTrip point is reached, start the timer running and set the Dew flag
  if ( Temp <= DewTrip ) {
    DewFlag = true;
    Timer = 1;       
  } 
  else {
    DewFlag = false;
}

  
  if (Timer >= TimerLength and DewFlag == false) { // If the timer has expired and there's no dew, switch the dehumidifier off.
    Timer = 0;
    digitalWrite (rlyPin, HIGH);
   
  }

  if (Timer !=0) {                // If the timer is running, switch the dehumidifier on , and write On to the lcd.
    digitalWrite (rlyPin, LOW);
    lcd.setCursor (13,0);
    lcd.print (" On");
    OutputStatus = true;
    Timer++;
  }
  
 else {
   lcd.setCursor (13,0);
    lcd.print ("off");
    OutputStatus = false;
 }
  
 delay (2000);

}
//
// END OF FILE
//





and the receiver code:-




// Receiver Sketch for Dehumidifier controller project
// Written by A.G.Doswell 23 May 2014
// LCD is a Hitachi HD44780 or compatible, attached thus:
// LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2
// RW to GND
// V0 Held high (this may or may not work with your LCD, usual practice is to connect this to a 10K pot between +5 and GND)
// Receiver connected to pin 9


#include <VirtualWire.h>
#include <VirtualWire_Config.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int TX_ID =10;
int Temp;
int Humidity;
int Dew;
boolean Output;



void setup() {
              lcd.begin (16, 2);
              // Virtualwire setup
              vw_set_tx_pin(10); // Even though it's not used, we'll define it so the default doesn't interfere with the LCD library.
              vw_set_rx_pin(9); // RX pin set to pin 9
              vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second, nice and slow! 
              vw_rx_start();     
              }  
void loop()
{
typedef struct rxRemoteData //Defines the received data, this is the same as the TX struct
{
int    TX_ID; 
int    Temp;   
int    Humidity;
int    Dew;
boolean Output;
};

struct rxRemoteData receivedData;
uint8_t rcvdSize = sizeof(receivedData);

if (vw_get_message((uint8_t *)&receivedData, &rcvdSize)) 
{
  if (receivedData.TX_ID == 10)     { //Only if the TX_ID=10 do we process the data.
    lcd.setCursor(13,0);
    lcd.print (" Rx");
    delay (100);
    int TX_ID = receivedData.TX_ID;
    int Temp = receivedData.Temp;
    int Humidity = receivedData.Humidity;
    int Dew = receivedData.Dew;
    boolean Output = receivedData.Output;
    
        
      // writes the received data to the LCD
  lcd.clear ();
  lcd.print("Humidity:");
  lcd.print(Humidity);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print(Temp);
  lcd.print((char)0xDF);
  lcd.print("C");
  lcd.setCursor(6, 1);
  lcd.print("Dew:");
  lcd.print(Dew);
  lcd.print((char)0xDF);
  lcd.print("C");
  
  if (Output == true) {
      lcd.setCursor (13,0);
      lcd.print (" On");
    
  }
     else {
       lcd.setCursor (13,0);
       lcd.print ("off");

           }
  
      } 

  }
}

// End of file

Let me know if this has been of any use...  but for now I have a nice dry loft!