/* thermometer_NTC_C */
/* 3 digit unsigned "xx.x" temperature presentation */

// Arduino UNO R3
// AVR_ATmega328P
#define F_CPU 16000000UL
#include <avr/io.h>           // AVR register names/addresses and bit names/numbers
#include <avr/cpufunc.h>      // for the nop instruction 
#include <util/delay.h>

void _delay_ms ( double );
void _delay_us ( double );

void init_AD( void );
unsigned int get_AD( void);


/* --- Temperature calculation  --- */
float temperatureNTC( unsigned int ADvalue );



/* --- serial shift 3 digit 7-segment display  --- */

#define SEG7_DDR  DDRD
#define SEG7_PORT PORTD
#define SEG7_LOAD PIND2  // (D02)
#define SEG7_SCLK PIND3  // (D03)
#define SEG7_SDI  PIND4  // (D04)

void display_init( void );
void shiftByte( unsigned char );
void display_temperature( unsigned int );





/* *********************************** */
/*            MAIN PROGRAM             */
/* *********************************** */

int main(void)
{
  unsigned int ADvalue;
  float temp;
  unsigned int tempvalue;

  display_init( );
  init_AD( );


while(1)
  {

    // thermometer measurement
    ADvalue = get_AD( );
    temp = temperatureNTC( ADvalue ); 
    tempvalue = (unsigned int)(temp * 10.0);


    // 7-segment display
    display_temperature( tempvalue );

    _delay_ms(200);          
  }

}











/* *********************************** */
/*            FUNCTIONS                */
/* *********************************** */


/* ------------------------ */
/*  AD conversion           */
/* ------------------------ */

void init_AD( void )
{
   // Bits in ADCSRA register:  "ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0"
   
   // F_ADC = F_CPU/PRESCALE   sample rate (50kHz < F_ADC < 200kHz)
   // 16MHz/128 = 125KHz  so we set ADC prescaler to 128
      
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);  // "-----111" ADPS 128
   ADCSRA |= (1 << ADEN); // "1-------"    Enable AD converter
   
   // Bits in ADMUX register:  "REFS1 REFS0 ADLAR - MUX3 MUX2 MUX1 MUX0"
   
   // Select AD0  "----0000" is default, nothing has to be done 
   // Set 10 bit Right adjust "--0-----" is default, nothing has to be done

   // In main program to start AD 
   // ADCSRA |= (1 << ADSC);
   // In main program to wait for AD done
   // while(ADCSRA & (1<<ADSC)){}
}

unsigned int get_AD( void)
{
        unsigned int num;
        ADCSRA |= (1 << ADSC);             // Start AD (ADCSRA "-1------")      
        while( ADCSRA & (1 << ADSC) ) {}   // Wait for AD done 
        num = ADC; // result 10 bit right adjusted
        return num;
}

/* ------------------------ */
/*  Temperature conversion  */
/* ------------------------ */

float temperatureNTC( unsigned int ADvalue ) //  using Steinhart-Hart 
{
const float BETA = 3950; 
// should match the Beta Coefficient of the thermistor

float celsius = 1 / (log(1 / (1023. / ADvalue - 1)) / BETA + 1.0 / 298.15) - 273.15;
if(celsius < 0) celsius = 0;
return celsius;
}



/* ----------------------------- */
/*  Shiftregister 7-seg display  */
/* ----------------------------- */

void display_init( void )
{
       SEG7_PORT  &= (~( 1 << SEG7_LOAD ));  // Load = 0 
       SEG7_DDR  |= (1 << SEG7_LOAD);        // Output

       SEG7_PORT  &= (~( 1 << SEG7_SCLK ));  // SCLK = 0 
       SEG7_DDR  |= (1 << SEG7_SCLK);        // Output

       SEG7_PORT  &= (~( 1 << SEG7_SDI ));   // Load = 0 
       SEG7_DDR  |= (1 << SEG7_SDI);         // Output
  
}


void display_temperature( unsigned int temperature )
{
  unsigned char data;
  unsigned int temp;

  unsigned char NUMBERS[] = {
  // "0123465789 -" for active Low display
   0x03,  // 0000 0011  "0"
   0x9F,  // 1001 1111  "1"
   0x25,  // 0010 0101  "2"
   0x0D,  // 0000 1101  "3"
   0x99,  // 1001 1001  "4"
   0x49,  // 0100 1001  "5"
   0x41,  // 0100 0001  "6"
   0x1F,  // 0001 1111  "7"
   0x01,  // 0000 0001  "8"
   0x19,  // 0001 1001  "9"
   0xFF,  // 1111 1111  "Blank"
   0xFD   // 1111 1101  "Minus"
  };
  
  SEG7_PORT  &= (~( 1 << SEG7_LOAD ));  // Load = 0

  temp = temperature % 10;  // x--
  data = (unsigned char) temp;
  data = NUMBERS[data];
  // data &= 0xFE;  // insert decimal point x.--
  shiftByte( data );

  temperature = temperature / 10; 
  
  temp = temperature % 10;   // -x-
  data = (unsigned char) temp;
  data = NUMBERS[data];
  data &= 0xFE;  // insert decimal point -x.-
  shiftByte( data );


  temperature = temperature / 10;
  
  temp = temperature % 10;  // --x
  data = (unsigned char) temp;
  data = NUMBERS[data];
  // data &= 0xFE;  // insert decimal point --x.
  shiftByte(data );



   _delay_ms(1); 
               
  SEG7_PORT |= ( 1 << SEG7_LOAD );  /* "1" */ 
}


void shiftByte( unsigned char data)
{
  unsigned char i;
  SEG7_PORT &= ~( 1 << SEG7_SCLK ); /* "0" */  

    for( i = 0; i < 8; i++ )
      {
              if (data & 0x01) SEG7_PORT |=  ( 1 << SEG7_SDI );
              else  SEG7_PORT &= ~( 1 << SEG7_SDI ); 

              SEG7_PORT |= ( 1 << SEG7_SCLK );   /* "1" */
              _delay_ms(1);
              SEG7_PORT &= ~( 1 << SEG7_SCLK );  /* "0" */  

              data >>= 1;
              
      }
              _delay_ms(1);  
}





/* *********************************** */
/*            HARDWARE                 */
/* *********************************** */

/*                     Chip ATMega328                          Arduino Uno R3 stackable header
                                                                              _______
                                                              Digital:  _____/       \__  Analog:
               ______________  ______________                   txd ->-|D00 >RXD      A5|-
              |              \/              |                  rxd -<-|D01 <TXD      A4|-
        Res---|01 PC6/RES' ATM328  SCL/PC5 28|-(A5)-      SEG7_Load -<-|D02           A3|-
 txd ->-(D00)-|02 PD0/RXD          SDA/PC4 27|-(A4)-      SEG7_SCLK -<-|D03~          A2|-
 rxd -<-(D01)-|03 PD1/TXD              PC3 26|-(A3)-       SEG7_SDI -<-|D04           A1|-
   Load-(D02)-|04 PD2/INT0             PC2 25|-(A2)-                  -|D05~          A0|-<-NTC_OUT
   SCLK-(D03)-|05 PD3/INT1/PWM         PC1 24|-(A1)-                  -|D06~            | Power:      
    SDI-(D04)-|06 PD4                  PC0 23|-(A0)-<-NTC_OUT         -|D07          Vin|-
       +5V ---|07 VCC                  GND 22|--- Gnd                  |             GND|--- GND
       Gnd ---|08 GND                 AREF 21|--- Vin                 -|D08          GND|- 
    Xtal |X|--|09 PB6/OSC1            AVCC 20|--- +5V                 -|D09~         +5V|--- +5V
   16MHz |X|--|10 PB7/OSC2         SCK/PB5 19|-(D13)-                 -|D10~       +3.3V|-
       -(D05)-|11 PD5/PWM         MISO/PB4 18|-(D12)-                 -|D11~         Res|-
       -(D06)-|12 PD6/PWM     PWM/MOSI/PB3 17|-(D11)-                 -|D12        IOREF|-
       -(D07)-|13 PD7          PWM/SS'/PB2 16|-(D10)-                 -|D13 LED     --- |
       -(D08)-|14 PB0              PWM/PB1 15|-                       -|GND             | 
              |______________________________|                        -|AREF            |
                                                                      -|SCL             |
                                                                      -|SDA             |
                                                                       |________________|
*/


/*
  74HC595 Shiftregister for 3 digit 7-segment display       
         ______________________________________
        |  SEG7  Active low '0' LED on         |
 +5V ---|Vcc      /-a-\                     Vcc|---
 GND ---|Gnd      f   b                     Gnd|---
 D04 ->-|SDI      |-g-|   a.b.c.d.e.f.g.dp  SDO|---
 D03 ->-|SCLK     e   c   lsb first        SCLK|---
 D02 ->-|Load     \-d-/ dp                 Load|---
        |______________________________________|
*/

/*
            ________________
           | NTC Thermistor |
      OUT -| NTC 10k        |
      VCC -| R 10k          |
      GND -|                |
           |________________|

*/
74HC595
74HC595
74HC595