Thursday, November 22, 2012

water meter counter atmega8 C++ source code


This code is from project: Water meter counter

adc.h

#ifndef _H_ADC_
#define _H_ADC_

#include "main.h"


class Adc {

   public:
      Adc();
      unsigned char get(unsigned char);

};


#endif

adc.cpp

#include "adc.h"
#include <avr/io.h>

Adc::Adc() {
   
  
   // Set reference voltage
   // REFS[0..1] = low -> AREF
   L(ADMUX, REFS0);
   L(ADMUX, REFS1);

   // prescaler set
   // ADPS[0..2] =  / 128
   H(ADCSRA, ADPS0);
   H(ADCSRA, ADPS1);
   H(ADCSRA, ADPS2);

   
   // watch only 8bits from ADCH
   H(ADMUX, ADLAR);

   // enable ADC
   H(ADCSRA, ADEN);
}

unsigned char Adc::get(unsigned char pin) {

   // Clear register
   ADCH=0x00;

   // clear pin register
   ADMUX&=~0x07;

   //  set pin from 0 to 7 (function parameter);
   ADMUX|=pin;

   // start processing
   H(ADCSRA, ADSC);   

   // wait for processing ends
   while(IS(ADCSRA, ADSC)); 

   // return 8-bit data
   return ADCH;
}

delay.h

#ifndef _H_DELAY_
#define _H_DELAY_

#include "main.h"
#include <util/delay.h>
#define nop()  __asm__ __volatile__("nop")

void delay_ms(unsigned short ms);
void delay_us(unsigned short us);

#endif

delay.cpp

#include "delay.h"

void delay_ms(unsigned short ms) {
    while ( ms ) {
      ms--;
      _delay_ms(1);
   }
}

void delay_us(unsigned short us) {
    while ( us ) {
      us--;
      _delay_us(1);
   }
}

led_nums.h

#ifndef _H_LED_NUMS_
#define _H_LED_NUMS_

#define Dec2Bcd(dec) (((dec / 10) << 4) + (dec % 10))

#define RED    0
#define BLUE   4

class LedNums {
   
   private:   
     char nums[8];
     
   
   public:
      LedNums();
      ~LedNums();
      
      void init(void);
      void drive(void);
     
      void set(unsigned char, unsigned short); 

};



#endif

led_nums.cpp

#include "led_nums.h"
#include "main.h"
#include "delay.h"

#include <avr/io.h>


LedNums::LedNums() {
   
}


LedNums::~LedNums() {

}


/****************************************************************************/
/* This function get a short number and puts it to 'nums' array which is    */
/* used to display numbers on 2 led displays                                */
/****************************************************************************/
 void LedNums::set(unsigned char offset, unsigned short n) {
    
   // 4 digit
   nums[0 + offset] = (n / 1000);
         
   n-= (nums[0 + offset] * 1000);
   
   // 3 digit
   nums[1 + offset] = (n / 100);
   
   n-= (nums[1 + offset] * 100);
   
   // 2 digit
   nums[2 + offset] = (n / 10);
   
   // 1 digit
   n-= (nums[2 + offset] * 10);
   
   nums[3 + offset] = n;
   
   // add + 48 (0 in ascii)
   nums[0 + offset]+=48;
   nums[1 + offset]+=48;
   nums[2 + offset]+=48;
   nums[3 + offset]+=48;  
 }


/****************************************************************************/
/* Init ports                                                               */
/****************************************************************************/
void LedNums::init(void) {
   
   // set PORTB as output
   DDRB = 0xFF;
   
   // set part of PORTC as output
   DDRC = 0x0F;
   
   // initial values
   PORTC = 0x0F;
   PORTB = 0x00;
}


/****************************************************************************/
/* Drive leds                                                               */
/****************************************************************************/
void LedNums::drive(void) {
   unsigned char i = 0;
   unsigned char n = 0;
   
   
   // go throught all 8 digits
   for(i=0; i<8;i++) {
      
      // substract 48 (ascii 0)        
      n = nums[7-i] - 48;
      
      // send BCD value to port C (connected to DM7447)
      PORTC = Dec2Bcd(n); 
      
      // enable one digit
      PORTB = (1 << i);  
      
      // red one is darker than blue, so we add here a bigger delay
      if(i>3) {
         // bigger delay -> brighter
         delay_us(24);
      }
      else {
         // smaller delay, power attached for a short time -> darker
         delay_us(4);
      }
      
      // turn of digit
      PORTB = 0;   
   }
}

main.h

#ifndef _H_MAIN_
#define _H_MAIN_

#define  F_CPU 1000000L

#define H(a,b) a |=(1<<(b))
#define L(a,b) a &=~(1<<(b))
#define IS(a,b) bit_is_set(a,b)
#define BS(a,b) (a & (1<<(b)))

#endif


#ifndef F_CPU
   #error CPU speed unknown
#endif


main.cpp

#include "main.h"
#include "operators.h"
#include "delay.h"
#include "led_nums.h"
#include "adc.h"

#include <avr/interrupt.h>
#include <avr/wdt.h>          // WATCHDOG

#include <stdlib.h>


/****************************************************************************/
/* Object pointers                                                          */
/****************************************************************************/
LedNums        *ln;
Adc            *adc;


/****************************************************************************/
/* main function                                                            */
/****************************************************************************/
int main()
{
   ln    = new LedNums;
   adc   = new Adc;

   
   ln->init();   

   ln->set(RED, 1234);
   ln->set(BLUE, 1231);


   unsigned char hot = 0;
   unsigned char cold = 0;
   
   unsigned char old_hot = 0;
   unsigned char old_cold = 0;
   
   unsigned char hot_diff  = 1;
   unsigned char cold_diff = 1;
      
   unsigned short count          = 0;
   unsigned short counter_hot    = 0;
   unsigned short counter_cold   = 0;
   
   
   while(1) {
      count++;
      
      // do this very often
      if(count % 3 == 0) {
         
         // get value from ADC, pin 4 and 5
         hot   = adc->get(4);
         cold  = adc->get(5);
      
      
         // this code is very dirty and it was written only to check
         // if this device have a chance to work, so don't be mad
         // I will fix this :)
                  
         // back spot on water meter gives number 120 from CNY70,
         // so we wait for in, and then increment liter counter         
         if(hot == 120 && old_hot < 120) {
            counter_hot++;
            
            // very ugly hack -> we ignore fluctuations here
            delay_ms(1000);
         }
                  
         if(cold == 120 && old_cold < 120) {
            counter_cold++;
            
            // very ugly hack -> we ignore fluctuations here
            delay_ms(1000);
         }
            
         old_cold = cold;
         old_hot = hot;         
      }
      

      // now we can set variables in LedNums class
      if(count > 30) {
                  
         ln->set(RED, counter_hot);
         ln->set(BLUE, counter_cold);
         
         count = 0;
      }
      
      // put power to 8 digits
      ln->drive();
   }

   return 0;
}

operators.h

#ifndef _H_OPERATORS_
#define _H_OPERATORS_

#include <stdlib.h>

void * operator new(size_t size); 

#endif

operators.cpp

#include "operators.h"

void * operator new(size_t size)
{
   return malloc(size);
} 


Makefile

CPU=atmega8

GCC=avr-g++
CFLAGS= -Os -mmcu=$(CPU) -Wall -fpack-struct -fshort-enums -funsigned-bitfields -Wl,--relax -fno-move-loop-invariants -funsigned-char -fno-inline-small-functions -fdata-sections -fno-tree-loop-optimize -lprintf_min 

INCLUDES=
LIBS=

OBJCPY=avr-objcopy
OBJECTS=main.o operators.o delay.o led_nums.o adc.o

PROJECT_NAME=mega8
HEX_FILE=$(PROJECT_NAME).hex
HEX_FILE_DUMP=$(PROJECT_NAME)_dump.hex

PROG=uisp
PROG_FLAGS=-dprog=dapa 

all: cls $(PROJECT_NAME) obj size #upload

$(PROJECT_NAME): $(OBJECTS)
  $(GCC) -o $(PROJECT_NAME) $(OBJECTS) $(CFLAGS) $(LIBS) $(INCLUDES)

main.o: main.cpp main.h templates.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c main.cpp

operators.o: operators.cpp operators.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c operators.cpp

delay.o: delay.cpp delay.h
  $(GCC) $(CFLAGS) $(INCLUDES) -c delay.cpp
  
led_nums.o: led_nums.cpp
  $(GCC) $(CFLAGS) $(INCLUDES) -c led_nums.cpp
  
adc.o: adc.cpp
  $(GCC) $(CFLAGS) $(INCLUDES) -c adc.cpp

obj: $(OBJECTS)
  $(OBJCPY) -O ihex $(PROJECT_NAME) $(HEX_FILE)

clean:
  rm -f $(PROJECT_NAME) $(OBJECTS) $(HEX_FILE)

cls:
  clear

size:
  du -b $(HEX_FILE) 

upload: all $(HEX_FILE)
  $(PROG) $(PROG_FLAGS) --erase --upload if=$(HEX_FILE)

download:
  $(PROG) $(PROG_FLAGS) --download of=$(HEX_FILE_DUMP)

No comments:

Post a Comment