Dit heb je nodig om je programma in de Unit te zetten:
1) Arduino IDE gratis
2) Klein printje maken om geschikt te maken om op de print te steken. €1,-
3) STK-500 bij Ali... voor € 11,-
4) Programma- gratis
Programma:
/*
* Project: Alusta Ventilatierooster Aansturing (ATmega32L)
* Geoptimaliseerd voor 4.9152 MHz Kristal met verbeterde IR-respons
* Functie: Handmatige override (4 uur) toegevoegd om CO2 te negeren bij wind/tocht
* Fix: IR-timing finetuning om foutieve waarden (122/58) bij code 61 te voorkomen
* ppm staat op 750 met een hysteresis van 60 en is te wijzigen naar behoefte in het programma
* Hardware: ATmega32L (TQFP-44)
* Topcase001 mag gebruikt worden, maar dit moet blijven staan
*/
#include <Arduino.h>
#include <util/delay.h>
#include <avr/interrupt.h>
// --- Exacte Klok Instellingen ---
#ifndef F_CPU
#define F_CPU 4915200L
#endif
#define BAUDRATE 19200
#define BAUD_PRESCALLER 15
// --- IR Timing (Timer 1 met Prescaler

---
// 4.9152 MHz / 8 = 614.4 ticks per ms.
// RC5 bit = 1.778ms -> 1092.4 ticks.
#define RC5_BIT_TICKS 1090
#define RC5_HALF_BIT 545
// --- Instellingen voor stabiliteit ---
const int MOTOR_MARGIN = 20;
const int CO2_TARGET = 750;
const int CO2_HYSTERESIS = 60;
const int CH_CO2 = 0;
const int CH_POT = 1;
// --- Override Instellingen ---
const unsigned long OVERRIDE_DURATION = 14400000; // 4 uur in milliseconden
// --- Globale Variabelen ---
unsigned int thresholdO = 0;
unsigned int thresholdD = 0;
int co2_value = 0;
char buffer[50];
bool isKalibrerend = false;
unsigned long overrideEndTime = 0; // Tijdstip waarop handmatige modus afloopt
// --- USART Init ---
void USART_init(void) {
UBRRH = 0;
UBRRL = BAUD_PRESCALLER;
UCSRB = (1 << RXEN) | (1 << TXEN);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
}
void USART_putstring(const char* StringPtr) {
while (*StringPtr != 0x00) {
while (!(UCSRA & (1 << UDRE)));
UDR = *StringPtr;
StringPtr++;
}
}
// --- Robuuste RC5 Decoder ---
int decodeRC5() {
// Check of PD3 laag is (startbit)
if (PIND & (1 << PIND3)) return -1;
unsigned int packet = 0;
TCCR1A = 0;
TCCR1B = (1 << CS11); // Prescaler 8
TCNT1 = 0;
// Stap 1: Wacht tot midden van de eerste bit-helft (ca. 400-444us)
// Iets korter gezet (250 ticks) om zeker vóór de eerste flankwissel te zijn
while (TCNT1 < 250) {
if (TCNT1 > 800) { TCCR1B = 0; return -1; }
}
TCNT1 = 0;
for (int i = 0; i < 14; i++) {
// Wacht tot midden van de volgende bit (1.778ms verder)
while (TCNT1 < RC5_BIT_TICKS) {
if (TCNT1 > 1800) { TCCR1B = 0; return -1; }
}
TCNT1 = 0;
packet <<= 1;
// Sample: Bij RC5 is een IR-puls (pin laag) een logische '1'
if (!(PIND & (1 << PIND3))) {
packet |= 1;
}
}
TCCR1B = 0;
if (packet == 0 || packet == 0x3FFF) return -1;
// RC5 packet: [S1][S2][T][A4][A3][A2][A1][A0][C5][C4][C3][C2][C1][C0]
// Commando zijn de laatste 6 bits (C5-C0)
int command = packet & 0x3F;
// S2 bit (bit 12) wordt gebruikt als 7e commandobit (inverted)
if (!(packet & (1 << 12))) {
command |= 0x40;
}
return command;
}
// --- Kalibratie Methode ---
void kalibreerRooster() {
isKalibrerend = true;
unsigned int adc_v;
unsigned int vorige_adc = 0;
USART_putstring("\r\n--- Start Kalibratie ---\r\n");
USART_putstring("Stap 1: Openen...\r\n");
PORTA = 0b00101000;
_delay_ms(2000);
for (int t = 0; t < 200; t++) {
adc_v = analogRead(CH_POT);
if (t > 0 && abs((int)adc_v - (int)vorige_adc) < 2) break;
vorige_adc = adc_v;
_delay_ms(800);
}
thresholdO = adc_v;
PORTA = 0b11000011;
_delay_ms(2000);
USART_putstring("Stap 2: Sluiten...\r\n");
vorige_adc = 0;
PORTA = 0b00010100;
_delay_ms(2000);
for (int t = 0; t < 200; t++) {
adc_v = analogRead(CH_POT);
if (t > 0 && abs((int)adc_v - (int)vorige_adc) < 2) break;
vorige_adc = adc_v;
_delay_ms(800);
}
thresholdD = adc_v;
PORTA = 0b11000011;
USART_putstring("Kalibratie Voltooid.\r\n");
_delay_ms(1500);
isKalibrerend = false;
}
void setup() {
DDRD |= 0b10000000; // Power LED (PD7)
DDRC |= 0b00110000;
DDRA |= 0b00111100;
USART_init();
pinMode(11, INPUT_PULLUP); // PD3 (IR)
PORTC |= 0b00110000;
sei();
kalibreerRooster();
}
void loop() {
PORTC |= 0b00110000;
unsigned long currentMillis = millis();
// 1. IR CODE VERWERKING
int code = decodeRC5();
if (code != -1) {
// Alleen loggen als de code in de buurt van onze commando's komt of foutief verschoven is
if (code == 60 || code == 61 || code == 62 || code == 63 || code == 122 || code == 58) {
USART_putstring("IR Ontvangen: ");
itoa(code, buffer, 10); USART_putstring(buffer); USART_putstring("\r\n");
}
// Vang ook de verschoven waarden op als '61'
if (code == 61 || code == 122 || code == 58) {
USART_putstring("Commando: AUTO (Gecorrigeerd)\r\n");
overrideEndTime = 0;
isKalibrerend = true;
int c_co2 = (int)(analogRead(CH_CO2) * 3.8);
int c_pot = analogRead(CH_POT);
if (c_co2 >= CO2_TARGET) {
PORTA = 0b00101000;
while (analogRead(CH_POT) < (thresholdO - 40)) { _delay_ms(5); }
} else if (c_co2 < (CO2_TARGET - CO2_HYSTERESIS)) {
PORTA = 0b00010100;
while (analogRead(CH_POT) > (thresholdD + MOTOR_MARGIN + 10)) { _delay_ms(5); }
}
PORTA = 0b11000011;
_delay_ms(400);
isKalibrerend = false;
}
else if (code == 60 || code == 62 || code == 63) {
isKalibrerend = true;
switch (code) {
case 62: // Open
USART_putstring("Commando: OPEN (4 uur override)\r\n");
overrideEndTime = currentMillis + OVERRIDE_DURATION;
PORTA = 0b00101000;
while (analogRead(CH_POT) < (thresholdO - MOTOR_MARGIN)) { _delay_ms(5); }
PORTA = 0b11000011;
PORTA = 0b00001000;
break;
case 60: // Dicht
USART_putstring("Commando: DICHT (4 uur override)\r\n");
overrideEndTime = currentMillis + OVERRIDE_DURATION;
PORTA = 0b00010100;
while (analogRead(CH_POT) > (thresholdD + MOTOR_MARGIN)) { _delay_ms(5); }
PORTA = 0b11000011;
PORTA = 0b00000100;
break;
case 63: // Kalibratie
kalibreerRooster();
break;
}
_delay_ms(400);
isKalibrerend = false;
}
}
// 2. AUTOMATISCHE CO2 CONTROLE
if (!isKalibrerend) {
static unsigned long lastSnuffel = 0;
if (currentMillis - lastSnuffel > 2000) {
int adc_co2 = analogRead(CH_CO2);
co2_value = (int)(adc_co2 * 3.8);
int pot_v = analogRead(CH_POT);
USART_putstring("CO2: "); itoa(co2_value, buffer, 10); USART_putstring(buffer);
if (overrideEndTime != 0 && currentMillis < overrideEndTime) {
USART_putstring(" | Modus: HANDMATIG\r\n");
} else {
overrideEndTime = 0;
USART_putstring(" | Modus: AUTO\r\n");
if (co2_value >= CO2_TARGET) {
if (pot_v < (thresholdO - 40)) PORTA = 0b00101000;
else PORTA = 0b11000011;
}
else if (co2_value < (CO2_TARGET - CO2_HYSTERESIS)) {
if (pot_v > (thresholdD + MOTOR_MARGIN + 10)) PORTA = 0b00010100;
else PORTA = 0b11000011;
}
else {
PORTA = 0b11000011;
}
}
lastSnuffel = currentMillis;
}
}
}