Monday, December 21, 2015

Arduino radio controlled clock

In order to build a radio controlled clock with the arduino, you need a DCF reciever. In this post the receiver board from conrad is being used (Nr. 641138). For the display the Seven-Segment-LED-Backpack from Adafruit is utilized. - You can of course replace it with any display you like (an LCD for example). The circuit:


DCF + Arduino + Seven-Segment-Display

The pullup-resistor and the filtercap are necessary for the reciever board to work. They aren't needed for the 7-seg-display.

Circuit on breadboard

In order for the DCF-code to work you'll need to add three Arduino-libraries to the IDE (Sketch->Include Library-> Add .ZIP Library): DCF77, Time and Timezone.
I had trouble with compiling the examples included in the DCF77-library. Updating the Time-library resolved that problem (link).

In order to run the 7-seg-display you'll need the library from adafruit: github-link

The code:

/*
 * Arduino-clock with DCF77-reciever and 7-seg-display
 */

#include "Wire.h"
#include "DCF77.h"
#include "Time.h"
#include "Timezone.h="
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include "Arduino.h"

#define DCF_PIN 2           // Connection pin to DCF 77 device
#define DCF_INTERRUPT 0    // Interrupt number associated with pin

//Australia Eastern Time Zone (Sydney, Melbourne)
TimeChangeRule aEDT = {"AEDT", First, Sun, Oct, 2, 660};    //UTC + 11 hours
TimeChangeRule aEST = {"AEST", First, Sun, Apr, 3, 600};    //UTC + 10 hours
Timezone ausET(aEDT, aEST);

//Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};     //Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};       //Central European Standard Time
Timezone CE(CEST, CET);

//United Kingdom (London, Belfast)
TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60};        //British Summer Time
TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0};         //Standard Time
Timezone UK(BST, GMT);

//US Eastern Time Zone (New York, Detroit)
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240};  //Eastern Daylight Time = UTC - 4 hours
TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -300};   //Eastern Standard Time = UTC - 5 hours
Timezone usET(usEDT, usEST);

//US Central Time Zone (Chicago, Houston)
TimeChangeRule usCDT = {"CDT", Second, dowSunday, Mar, 2, -300};
TimeChangeRule usCST = {"CST", First, dowSunday, Nov, 2, -360};
Timezone usCT(usCDT, usCST);

//US Mountain Time Zone (Denver, Salt Lake City)
TimeChangeRule usMDT = {"MDT", Second, dowSunday, Mar, 2, -360};
TimeChangeRule usMST = {"MST", First, dowSunday, Nov, 2, -420};
Timezone usMT(usMDT, usMST);

//Arizona is US Mountain Time Zone but does not use DST
Timezone usAZ(usMST, usMST);

//US Pacific Time Zone (Las Vegas, Los Angeles)
TimeChangeRule usPDT = {"PDT", Second, dowSunday, Mar, 2, -420};
TimeChangeRule usPST = {"PST", First, dowSunday, Nov, 2, -480};
Timezone usPT(usPDT, usPST);

//Eastern European Time (Finland, Greece, etc)
TimeChangeRule rEST = {"EST", Last, Sun, Mar, 1, 180};      //Eastern European Time
TimeChangeRule rEET = {"EET", Last, Sun, Oct, 1, 120};      //Eastern European Summer Time
Timezone EET(rEST, rEET);

time_t time;
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);
Adafruit_7segment matrix = Adafruit_7segment();
bool on;


void setup() 
{
  
  Serial.begin(9600); 
  DCF.Start();
  setSyncInterval(30);
  setSyncProvider(getDCFTime);
  Serial.println("Waiting for DCF77 time ... ");
  Serial.println("It will take at least 2 minutes until a first update can be processed.");
  on=false;
  
  while(timeStatus()== timeNotSet) 
  { 
     // wait until the time is set by the sync provider     
     digitalClockDisplay();
     delay(1000);
  }
  Serial.println("Setup done.");
  matrix.begin(0x70);
}

void loop() 
{
  delay(1000);
  time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
  if (DCFtime!=0)
  {
    Serial.println("Time is updated");
    setTime(DCFtime);
  } 
  on = !on;
  boolean drawDots = false;
  int ho = hour();
  int minu = minute();
  matrix.writeDigitNum(0, ho/10 , drawDots);
  matrix.writeDigitNum(1, ho%10, drawDots);
  matrix.drawColon(on);
  matrix.writeDigitNum(3, minu/10, drawDots);
  matrix.writeDigitNum(4, minu%10, drawDots);
  matrix.writeDisplay();
  digitalClockDisplay(); 
  
}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
  
}

void printDigits(int digits)
{
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

unsigned long getDCFTime()
{ 
  time_t DCFtime = DCF.getUTCTime(); // Convert from UTC
  
  if (DCFtime!=0) {
    Serial.print("X");    // Indicator that a time check is done
    time_t LocalTime = CE.toLocal(DCFtime);//UK.toLocal(DCFtime);
    return LocalTime;
  }
  return 0;
}

Above code is set for the central european timezone. If you live somewhere else, in the UK for example, change the value of "LocalTime" in the fifth to last line to "UK.toLocal(DCFtime)". The same goes for other timezones (they get declared / are listed at the beginning of the code).

It takes around two minutes for the clock to get the current time. You can follow the process by opening the Serial Monitor of the Arduino IDE.

Saturday, May 16, 2015

Arduino Ethernet and Weathershield

A combination of the weathershield from sparkfun and the Ethernet-Arduino:

Ethernet-Arduino and the Weathershield
What the webpage looks like:

type the IP-adress directly into the url-bar of your browser

The code:
#include 
#include 
#include  //I2C needed for sensors
#include "MPL3115A2.h" //Pressure sensor
#include "HTU21D.h" //Humidity sensor

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 0, 12);

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String HTTP_req;          // stores the HTTP request

MPL3115A2 myPressure; //Create an instance of the pressure sensor
HTU21D myHumidity; //Create an instance of the humidity sensor

// analog I/O pins
const byte REFERENCE_3V3 = A3;
const byte LIGHT = A1;
const byte BATT = A2;
const byte WDIR = A0;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

//Global Variables

//These are all the weather values that wunderground expects:
float humidity = 0; // [%]
float tempf = 0; // [temperature F]
//float baromin = 30.03;// [barom in] - It's hard to calculate baromin locally, do this in the agent
float pressure = 0;
//float dewptf; // [dewpoint F] - It's hard to calculate dewpoint locally, do this in the agent

float light_lvl = 455; //[analog value from 0 to 1023]

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) 
  {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  
  pinMode(REFERENCE_3V3, INPUT);
  pinMode(LIGHT, INPUT);

  //Configure the pressure sensor
  myPressure.begin(); // Get sensor online
  myPressure.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
  myPressure.setOversampleRate(7); // Set Oversample to the recommended 128
  myPressure.enableEventFlags(); // Enable all three pressure and temp event flags 

  //Configure the humidity sensor
  myHumidity.begin();


  // turn on interrupts
  interrupts();

  //Serial.println("Weather Shield online!");

}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) 
  {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) 
    {
      if (client.available()) 
      {
        char c = client.read();
        HTTP_req += c;  // save the HTTP request 1 char at a time
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          
          calcWeather();
                              
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("");
          client.println("");
          
          client.println("");
          client.println("Weathershield ");          
          client.println("");
          
          client.println("");
          
          client.println("

Wheatershield

"); client.println("Humidity: "); client.println(humidity); client.println("% "); client.println("Temperature: "); client.println(tempf); client.println("°C "); client.println("Pressure: "); client.println(pressure); client.println(" bar "); client.println("Light level: "); client.println(light_lvl); client.println(" lux "); client.println(""); client.println(""); HTTP_req = ""; // finished with request, empty string break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); Serial.println("client disconnected"); } } //Calculates each of the variables that wunderground is expecting void calcWeather() { //Calc humidity humidity = myHumidity.readHumidity(); //float temp_h = myHumidity.readTemperature(); //Serial.print(" TempH:"); //Serial.print(temp_h, 2); //Calc tempf from pressure sensor tempf = myPressure.readTempF(); //conversion into Celsius tempf = (tempf-32)/1.8; //Serial.print(" TempP:"); //Serial.print(tempf, 2); //Calc pressure pressure = myPressure.readPressure(); //convert to bar pressure = pressure/100000; //Calc light level light_lvl = get_light_level(); } //Returns the voltage of the light sensor based on the 3.3V rail //This allows us to ignore what VCC might be (an Arduino plugged into USB has VCC of 4.5 to 5.2V) float get_light_level() { float operatingVoltage = analogRead(REFERENCE_3V3); float lightSensor = analogRead(LIGHT); operatingVoltage = 3.3 / operatingVoltage; //The reference voltage is 3.3V lightSensor = operatingVoltage * lightSensor; return(lightSensor); }

Wednesday, February 18, 2015

Minimalistic Arduino

In order to build a minimalistic Arduino, you need:
  • one 10kOhm resistor
  • two 22pF capacitors
  • one 100nF capacitor
  • one 16.000Mhz quartz oscillator
  • the ATMEGA 328P-chip (best with preinstalled bootloader)
  • a 5V Voltage-supply and some wiring
  • something for programming the chip (existing Arduino-Board or a USB-FTDI-Serial converter)
optional:
  • one LED and a 150 Ohm resistor (two of both if you want one for the voltage supply as well)
  • switch (Reset switch)
  • USB-FTDI-Serialchip / Arduinoboard
the basic schematic:
minimalistic Ardunio schematic (with optional reset-switch)
If you like the default LED on PIN 13 on the original Arduinoboard, connect first the LED to Pin 19  (right after AVCC), then the 150 Ohm resistor to the LED and the other end to ground.

If you want to supply your project with for example 9V from a battery you can build a simple voltageregulator like this (not suited for AC-Input!):

simple DC-Voltageregulator
all you need is a LM7805 and two 10uF capacitors. If you want, you can connect a LED with resistor to the 5V output (in order to see if the Atmega is under power).

If you are using a USB-FTDI-Serialchip (UFSC) connect the DTR/RST-PIN to the RESET-Pin of the Atmega via a 100nF capacitor. RX of the UFSC goes to the TX of the Atmega and the TX of the UFSC goes to the RX-Pin of the Atmega.

Sunday, February 8, 2015

Arduino & EasyDriver & Steppermotor

If you'd like to run a steppermotor with your Arduino, you're going to need a EasyDriver. This chip allows you to connect a variety of different steppermotors and supply them with their needed voltage (in most cases 12 V). Most common steppermotors will have four wires comming out of them which connect as follows:

Wiring of the EasyDriver, the Arduino and the steppermotor (LED is optional)

If you have a motor with six wires comming out of it, try connecting the two outer and the two inner wires to the chip.

The following Arduinocode has been modified so that you can connect up to three EasyDriver-chips. If you like you can connect three LEDs to Pins 11, 12 and 13 in order to see which motor is supposed to be running (don't forget to use appropriate resistors).

//////////////////////////////////////////////////////////////////
//©2011 bildr
//Released under the MIT License - Please reuse change and share
//Using the easy stepper with your arduino
//use rotate and/or rotateDeg to controll stepper motor
//speed is any number from .01 -> 1 with 1 being fastest - 
//Slower Speed == Stronger movement
//code-change (2015): run up to three motors:
//motor 1: connected to PIN 2 and 3
//motor 2: connected to PIN 4 and 5
//motor 3: connected to PIN 6 and 7
//connect LEDs to PIN 11,12 and 13 to see which motor is supposed to be running
/////////////////////////////////////////////////////////////////

#define DIR_PIN 2
#define STEP_PIN 3
#define DIR_PINt 4
#define STEP_PINt 5
#define DIR_PINth 6
#define STEP_PINth 7

void setup() 
{
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PINt, OUTPUT);
  pinMode(STEP_PINt, OUTPUT);
  pinMode(DIR_PINth, OUTPUT);
  pinMode(STEP_PINth, OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(11,OUTPUT);
} 

void loop()
{ 

  int dir = (steps > 0)? HIGH:LOW;
  steps = abs(steps);

  switch(motor){
    case 1:
    digitalWrite(DIR_PIN,dir); 
    break;
    case 2:
    digitalWrite(DIR_PINt,dir); 
    break;
    case 3:
    digitalWrite(DIR_PINth,dir); 
    break;
    default:
    break;
  }
  
  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++)
  {
    switch(motor){
      case 1:
      digitalWrite(STEP_PIN, HIGH);
      digitalWrite(13,HIGH);
      delayMicroseconds(usDelay);
      digitalWrite(STEP_PIN, LOW);
      digitalWrite(13,LOW);
      break;
      case 2:
      digitalWrite(STEP_PINt, HIGH);
      digitalWrite(12,HIGH);
      delayMicroseconds(usDelay); 
      digitalWrite(12,LOW);
      digitalWrite(STEP_PINt, LOW);      
      break;
      case 3:
      digitalWrite(STEP_PINth, HIGH);
      digitalWrite(11,HIGH);
      delayMicroseconds(usDelay); 
      digitalWrite(11,LOW);
      digitalWrite(STEP_PINth, LOW);
      break;
      default:
      break;
    }

    delayMicroseconds(usDelay);
  }
} 

void rotateDeg(float deg, float speed, int motor)
{
  //rotate a specific number of degrees (negitive for reverse movement)
  //speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger
  //motor specifies which motor to turn (number between 1 and 3)
  int dir = (deg > 0)? HIGH:LOW;
  switch(motor){
    case 1:
    digitalWrite(DIR_PIN,dir); 
    break;
    case 2:
    digitalWrite(DIR_PINt,dir);
    break;
    case 3:
    digitalWrite(DIR_PINth,dir);
    break;
    default:
    break;
  }
 
  int steps = abs(deg)*(1/0.225);
  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++){
    switch(motor){
      case 1:
      digitalWrite(13,HIGH);
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(usDelay); 
      digitalWrite(13,LOW);
      digitalWrite(STEP_PIN, LOW);
      break;
      case 2:
      digitalWrite(STEP_PINt, HIGH);
      digitalWrite(12,HIGH);
      delayMicroseconds(usDelay); 
      digitalWrite(12,LOW);
      digitalWrite(STEP_PINt, LOW);
      break;
      case 3:
      digitalWrite(STEP_PINth, HIGH);
      digitalWrite(11,HIGH);
      delayMicroseconds(usDelay); 
      digitalWrite(11,LOW);
      digitalWrite(STEP_PINth, LOW);
      break;
      default:
      break;
    }
    delayMicroseconds(usDelay);
  }
}

The EasyDriver has a few more connectors you can use:
 
EasyDriver-chip

Most important are ENABLE and SLP (Sleep). You can connect each of them to a seperate Arduino PIN and use the digitalWrite(PIN, HIGH) command to activate them. The difference between these two:
  • ENABLE set to HIGH will stop the powersupply to the steppermotor (you will be able to turn the motor shaft by hand), the IC is still under power.
  • SLP set to LOW will stop the powersupply of the motor and will put the IC into a hibernate-mode. Waking the IC up again can take some time (a few ms)

Monday, September 22, 2014

Arduino, QC1602A and HC-SR04

There are two ways to connect a LCD-Display and an Arduino: Via I2C or by connecting them as follows:

Wiring of the Arduino, HC-SR04 and the LCD-Display


The Arduino-Code:
#include <LiquidCrystal.h>
/*
LCD-Connection:
VSS to GND
VDD to +5V
VO to potentiometer to GND
RS to 12
RW to 11
E to 10
D4 to 5
D5 to 4
D6 to 3
D7 to 2
A to 13 
K to GND

HC-SR04-Connection:
VCC to +5V
Trig to 8
Echo to 7
GND to GND

LED-Connection:
(GND-Resistor-LED)
green LED to 6
red LED to 9
*/


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
int backLight = 13; //pin 13 for Background-light


#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define erPin 9 //Pin for reed LED
#define goPin 6 //Pin for green LED

int maximumRange = 2000; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance

void setup()
{
  pinMode(echoPin, INPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(erPin, OUTPUT);
  pinMode(goPin,OUTPUT);
  
  pinMode(backLight, OUTPUT);
  digitalWrite(backLight, HIGH); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
  
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
    
}


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" */
 // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.clear();
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print("-1");
  digitalWrite(erPin, HIGH);
  digitalWrite(goPin, LOW);
  

 }
 else {
 /* Send the distance to the computer using Serial protocol, and
 turn LED OFF to indicate successful reading. */
 // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.clear();
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(distance);
  digitalWrite(erPin,LOW);
  digitalWrite(goPin, HIGH);
 

 }
 
 //Delay 50ms before next reading.
 delay(100);
}