Kuivausrummun lämpötilansäätö

/*
 * PWRcontroller.cpp
 * SSR-releen tai nollapistekytkevän triacin tehon asetus
 * 
 * Created: 15.2.2016 11:53:03
 * Author : Kremmen
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 8000000L

uint16_t cmscounter;
volatile uint16_t mscounter;	// millisekuntilaskuri (laskee millisekunteja pwm-syklin alusta)
uint16_t tmpsetpoint, csetpoint;
volatile uint16_t setpoint;	// asetusarvo (0 - 1000)

uint16_t ADsum;					// AD-muunnoksen keskiarvoistuksen apumuuttujia
uint8_t ADindex;
#define  ADINDEXMAX 64			// oltava 2:n potenssi!
uint16_t ADvalue[ADINDEXMAX];

volatile bool cyclestart;
bool pwroutput, indicator;		// indicator on merkkivalon tilanohjaus. Kirkkaus seuraa tehon päälläoloa
uint8_t portvalue;


int main(void) {
uint8_t i;

 // Alustetaan GPIO - portti D
	PORTD = 0;
	DDRD = 0x03;
 
    // Alustetaan kello, timeri1 ja A/D-muunnin
	CLKPR = 1 << CLKPCE;			// enable prescaler
	CLKPR = 0;						// prescaler = 1 (8MHz kello)
	
	TCCR1A = 0;						// Compare outputit pois päältä WGM bitit 0 ja 1 = =
	TCCR1B = 1<<WGM12 | 1<<CS10;	// CTC moodi, prescaler = 1
	TIMSK1 = 1 << OCIE1A;			// Timer 1 keskeytys vertailurekisteristä A
	OCR1A = 0x1f40;					// vertailu = 8000  --> 1ms aikakeskeytykset
	
	ADMUX = 0x00;
	ADCSRA = 1 << ADEN | 1 << ADIE | 1 << ADPS0; // muunnin päälle, keskeytykset päälle, muuntimen kellojakaja /4

	// nollataan A/D-muuntimen bufferi
	for ( i=0; i<ADINDEXMAX; i++ ) {
		ADvalue[i] = 0;
	}
	ADindex = 0;
	ADsum = 0;
	
	sei();
	//pwm-looppi
    for ( ; ; ) {
		// uuden pwm-syklin alussa powerit päälle
		if (cyclestart) {
			cli();
			cyclestart = false;
			sei();
			pwroutput = true;
		}
		// tsekataan syklissä kulunut aika
		cli();
		cmscounter = mscounter;
		csetpoint = setpoint;
		sei();
		// jos päälläoloaika on kulunut niin powerit pois päältä
		if ( cmscounter >= csetpoint ) pwroutput = false;
		// siirretään lopputulos GPIO-pinniin
		portvalue = (PIND & 0xfc);
		portvalue |= ((pwroutput & 0x01 ) | (indicator & 0x01)) << 1;
		PORTD = portvalue;
    }
}

// Timer1 Compare A: 1 millisekunnin keskeytys
//	kasvatetaan millisekuntilaskuria
//	
ISR(TIMER1_COMPA_vect) {
	ADCSRA = ADCSRA |  1 << ADSC | 1 << ADIE;	// käynnistetään uusi A/D-muunnos
	if ( ++mscounter >= 1000) {
		mscounter = 0;
		cyclestart = true;
	}
	indicator = !indicator;
}

// A/D-muuntimen keskeytys
ISR(ADC_vect) {
	ADsum -= ADvalue[ADindex];
	ADvalue[ADindex] = ADC;
	ADsum += ADvalue[ADindex];
	ADindex++;
	if ( ADindex >= ADINDEXMAX) ADindex = 0;
	tmpsetpoint = ADsum >> 6;	// jako 64:llä. Synkattava ADINDEXMAX:in kanssa!
	
	// A/D-muunnos tuottaa lukeman 0 - 1024. Jaksonaika on 1000 ms joten
	// setpoint on 24 isompi kuin jakso. Käytetään ero hyväksi tekemällä hieman välystä molempiin päihin
	// Lukemat 0-12 tulkitaan nollaksi ja isommista vähennetään 12. Tällöin viimeiset 12 inkrementtiä vastaavat "täyttä kaasua"
	// Näin varmistetaan, että potikalla päästään ihan nollasta ihan täysille.
	
	if (tmpsetpoint < 12 ) setpoint = 0;
	else setpoint = tmpsetpoint - 12;
	
}