// ************************************************************************************************ 
//    Absolute Beginner Projekt 06
//
//	Analog eingang lesen, PWM Ausgabe von Port D6, Textanzeige auf einem LCD
// ************************************************************************************************ 
// Copyright keins
// Version 
/*
* Chip type           : ATMEGA 88
* Clock frequency     : Internal clock 1 Mhz (The device is shipped with this option selected.)
* Fuse Bits einfach auf Auslieferungszustand lassen!

Ein- und Ausgänge
PORT B 0 (14) = Anschluss 11 am LCD = DB4 
PORT B 1 (15) = Anschluss 12 am LCD = DB5 
PORT B 2 (16) = Anschluss 13 am LCD = DB6
PORT B 3 (17) = Anschluss 14 am LCD = DB7
PORT B 4 (18) = Anschluss  4 am LCD = RS
PORT B 5 (19) = Anschluss  6 am LCD = E Enable
PORT B 6 ( 9) = 
PORT B 7 (10) = 

PORT C 0 (23) = Mittelabgriff 1KOhm Poti, die anderen Enden hängen an VCC und GND
PORT C 1 (24) = 
PORT C 2 (25) = 
PORT C 3 (26) = 
PORT C 4 (27) = 	
PORT C 5 (28) = 

PORT D 0 ( 2) = 
PORT D 1 ( 3) = 
PORT D 2 ( 4) =  
PORT D 3 ( 5) =  
PORT D 4 ( 6) = 
PORT D 5 (11) = 
PORT D 6 (12) = PWM Ausgabe, LED gegen Masse
PORT D 7 (13) = 
*/


// 
// 

// ************************************************************************************************ 
// Include Dateien laden
// ************************************************************************************************ 
#include	<avr\io.h>	//AVR Register und Konstantendefinitionen
#include	<avr\interrupt.h> //AVR Interrupt Vektoren
#include	<stdlib.h>
#include	<inttypes.h>
#include "lcd-routines.h"


              
// ************************************************************************************************ 
//                       Initialisierung          
// ************************************************************************************************ 
void initial(void)
{    
// **** Einrichten von Ein- und Ausgängen ******************************************************* 
DDRD = 0xff;      	// PortD Ausgänge 
DDRC = 0x00;      	// PortC Eingänge 

// **** Einrichten von PWM Betrieb *************************************************************** 
// Der Timer 0 wird im Fast PWM Modus betrieben

TCCR0A  = ((1 <<WGM01)|(1<<WGM00)) ;// waveform generation mode auf "Fast PWM" setzen
						// WGM02 in TCCR0B bleibt auf 0 (default)
TCCR0A |=(1<<COM0A1 ) ; 		// set compare output mode to non inverting mode)
						//  COM0A0, COM0B1 and COM0B0 bleiben auf 0 (default)
//TCCR0B =(1<<CS01|1<<CS00);// set clk prescaler to 64 (macht 122,1Hz PWM Frequenz)
TCCR0B =(1<<CS02 ) ; 	// set clk prescaler to 256 (macht 15,3Hz PWM Frequenz)
 				// WGM02, FOC0A and FOC0B bleiben auf 0 (default)
OCR0A=0; 			// set initial value of OCR0A (0x00 erzeugt einen spike am output)
TCNT0 = 0 ; 		// reset timer / counterregister

sei() ;

}
// ************************************************************************************************ 



// *ADC initialisieren*****************************************************************************
// in "ADMUX" muss die Referenzspannung zum Verleich mit der zu messenden Spannung
// eingestellt werden. Hier eingestellt ist AVCC als  Referenzspannung.
// Wenn AVCC auf VCC liegt, ist diese Spannung nicht übermäßig 
// präzise, aber man hat einen größeren Eingangsspannungsbereich von 0-5V
// In der Regel ist das völlig ausreichend.
// in "ADCSRA" wird mit ADPS2 bis ADPS0 die Wandlungfrequenz eingestellt.
// Diese soll lt. Datenblatt zwischen 50 KHz und 200KHz liegen. Hier ist 125KHz eingestellt.
// ************************************************************************************************ 
 
void ADC_Init(void) {
 
  uint16_t result;
 
  ADMUX = (1<<REFS0);      			// AVCC als  Referenzspannung nutzen
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     	// Frequenzvorteiler 8 ==> 1.000.000/8 = 125.000Hz
  ADCSRA |= (1<<ADEN);                  	// ADC aktivieren
 
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
 
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
  while (ADCSRA & (1<<ADSC) );          // auf Abschluss der Konvertierung warten
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
     Wandlung nicht übernommen. */
  result = ADCW;
}
// ************************************************************************************************ 


// *ADC Einzelmessung ****************************************************************************** 
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) )     // auf Abschluss der Konvertierung warten
    ;
  return ADCW;                    // ADC auslesen und zurückgeben
}
// ********************************************************************************** 


// ********************************************************************************** 
//  Display integer 0-9999 
//  Durch geschicktes multiplizieren und dividieren wird die Integer-Zahl
//  in ihre einzelnen Stellen zerlegt und diese dann am LCD ausgegeben.
//  Es wird nicht abgefragt, ob die Zahl größer als 9999 ist!
//  Währe dies der Fall, wird ein falsches Zeichen am LCD angezeigt.
// ********************************************************************************** 
void print4(unsigned int x)
{
  unsigned int y;
    y=x/1000;lcd_data(y+0x30);x-=(y*1000);
    y=x/100;lcd_data(y+0x30);x-=(y*100);
    y=x/10;lcd_data(y+0x30);x-=(y*10);
    lcd_data(x+0x30);
}


// ********************************************************************************** 
// Hauptprogramm
// ********************************************************************************** 

int main(void)
{

int variable = 0;  
char pwm_sollwert = 0;  

 // ******** Initialisierung ********************************************************

initial();	// Initialisierung Ports etc.
ADC_Init(); // Initialisierung Analogeingang
lcd_init(); // Initialisierung des LCD

// ******** Hauptschleife ***********************************************************	
    
  while(1)
  {

// *Analogwerte einlesen *********************************************************** 

variable = ADC_Read(0); // einlesen vom Analogeingang 0 und speichern in "variable"

// *LCD Anzeige ******************************************************************** 

  lcd_data( 'A' );	// Ausgabe einzelner Zeichen am LCD
  lcd_data( 'D' );
  lcd_data( 'C' );
  lcd_data( '0' );
  lcd_data( '=' );
  print4(variable);	// Ausgabe einer vierstelligen Integer-Zahl am LCD
  lcd_setcursor( 0, 1 );// den Curser am LCD wieder auf Anfang für den nächsten Programmdurchlauf

// ************************************************************************************************ 

// *PWM Sollwert setzen ******************************************************************** 

pwm_sollwert = variable/4;  // hätte man auch direkt nach OCR0A speichern können
OCR0A=(pwm_sollwert);

// ************************************************************************************************ 
  } // Ende while(1)Endlosschleife
  return 0;
}// Ende Hauptprogramm
