/*
* 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;
}