Pages

Monday, January 14, 2019

An inexpensive, low power wireless sensor using attiny13a, ds18b20, ldr, rf433


Here is a simple project based on Attiny13a ( which is limited with 1kb flash and 64bytes of SRAM). In this project a simple sensor node is made out of this and collects data from a digital temperature sensor (ds18b20)  and the ambient light with an ldr and converted by the ADC(analogue to digital converter) inside the attiny13a.

Wireless sensor in a transparent  tic -tac box to measure light/temperature. It takes 10 micro amps when idle and around 7 milli amps when transmitting. It transmits data in every 16 minutes intervals

All collected data is send to the receiver via wireless link based on 433mhz OOK modules which needs a protocol to send the data (unlike the dedicated wireless chips with built in protocols and error corrections)

The wireless data is captured in a clock with seven segment led display and a serial connector to send the data to a raspberry pi for further processing.

Example data received from the sensor
data received from the wireless sensor. Top plot is outside temperature and the bottom one is the light intensity 


Attiny13 based wireless sensor prototype


Currently at the receive end an atmega328p is used and the result is displayed via serial terminal. But this can be converted in to an oled display/lcd display.  More on this and uploading the data to a cloud service  and doing analysis on a next post.

The idea of this project is to build from scratch (as far as possible) and use minimalist devices to achieve maximum outcome. I didn't choose assembler, but did the firmware in C and takes exactly 1024 bytes.(This can be the next exercise to free up more space). Within this 1024 bytes , the firmware handles the one wire protocol, reading the ADC,  power saving routines and a watchdog timer, and a wireless protocol (borrowed from virtual wire with CRC checksum). The code can be further improved to add some more extras. A small pcb is made which can be used for pro-typing alternate projects such as rolling code remote, wireless water tank overflow detection/pump control etc)

Hardware

The prototype is built on a 2 X 3cm pcb , home etched (details below) and has an sop (attiny13) some connectors and ldr, ds18b20, some pull-up resistors.

Schematic for the transmitter prototype. The diagram is missing a 10k pull up resistor for the data pin for the one wire thermometer (ds18b20)

The rf module used is shown below with a simple wire antenna


Firmware

The software  and the source can be downloaded from the github here. It needs avr-gcc to compile and use avrdude to upload to the chips using an isp programmer. you may use an arduino uno as an isp programmer. There is a make file and all you need to do is type in


make flash 


Building from scratch

1) PCB - can be made using a presensitised board (e.g Bungard) or toner transfer.

A simple one side PCB for the prototype board


All cad files can be downloaded from the project page on github.

A few pictures from my prototype is shown below

step 1) making a layout

PCB layout (step 1)

Step 2) uv exposure (home made with uv led)



3) Developing (bungard)

4) Etched board (ferric chloride)


5) Applying solder mask
6) Assembling



Firmware (main routine in tx)


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include "virtualwire.h"
#include <avr/sleep.h>
#include <avr/wdt.h>
#define DS18B20_PIN PB4
#define BUTTON_PIN PB2
// CHANGE IN TX LIBRARY FILE IF CHANGED
#define LDRPIN PB3
#define LEDPIN PB1

typedef struct messagedata
{
 unsigned char RX_ID;
 unsigned int temperature;
 unsigned int light;
 unsigned char button; 
} messagedata;
messagedata txdata={.RX_ID='A',.temperature=25,.light='L',.button='L'};

// watchdog interrupt
ISR(WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }

static  void myWatchdogEnable() 
{ 
  cli();  
  MCUSR = 0;                          // reset various flags
  //set timer to 1 sec
  //WDTCR |= (0<<WDP3) | (1<<WDP2) | (1<<WDP1) | (0<<WDP0);
  //set timer to 8 sec
  WDTCR |= (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
  WDTCR |= (1<<WDTIE);
  WDTCR |= (0<<WDE);
  sei();
  wdt_reset(); //call to this reset the timer
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
} 


int main(void)
{
 DDRB &=~(1<<LDRPIN); //ADC0 is input PB5
    uint16_t nticks=37; // number of prescaled ticks needed TRY 150
    uint8_t prescaler=2;; // Bit values for CS0[2:0] TRY 1
    TCCR0A = 0;
    TCCR0A = _BV(WGM01); // Turn on CTC mode / Output Compare pins disconnected
    TCCR0B = 0;
    TCCR0B = prescaler; // set CS00, CS01, CS02 (other bits not needed)
 OCR0A = (uint8_t)(nticks);
 TIMSK0 |= _BV(OCIE0A);
 vw_ddr |= (1<<vw_tx_pin);
 vw_port &= ~(1<<vw_tx_pin);
 uint16_t t;
    uint8_t rcvdSize = sizeof(txdata);
 // Set the ADC input to PB3 or ADC3
    ADMUX |= (1 << MUX0);
 ADMUX |= (1 << MUX1);
    ADMUX |= (1 << ADLAR); 
    ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
    sei();
        
    while (1)
    {
  t=DS18B20_read();
  txdata.temperature=t;
  //t = adc_read();
  ADCSRA |= (1 << ADSC);//start conversion
  while (ADCSRA & (1 << ADSC)); 
  txdata.light=ADC;
  uint8_t counter=9;
  while(counter)
  {   
   vw_send((uint8_t *)&txdata, rcvdSize);
   vw_wait_tx();
   _delay_ms(500);
   counter--;
  }
  ADCSRA &= ~(1<<ADEN);     //turn off ADC
        ACSR |= _BV(ACD);         // disable analog comparator
  counter=120;
  while(counter)
  {   
   myWatchdogEnable ();  // 8 seconds
   counter--;
  }
  ADCSRA |= (1<<ADEN);    //turn on ADC
    }
}

No comments:

Post a Comment