/* Netzgerät Operating System v.06 (2003-12-13)
Power supply unit operating system v.06 (2003-12-13)
(c) 2003 by Malte Marwedel, www.marwedels.de/malte, m.marwedel@onlinehome.de
Diese Datei darf frei kopiert und compiliert werden.
It's allowed to copy and compile this file freely.
Änderungen an der Datei sind erlaubt, solange kenntlich gemacht wird,
dass es sich dann nicht mehr um die original Datei handelt.
It's allowed to modify this file as long it is mentioned that it isn't the original
file any longer.
Es muss immer erkennbar sein, dass die original Datei von mir stammt
It must always be recognizable that the original file is written by me
Die Benutzung des Programmes erfolgt auf eigene Gefahr, ich hafte nicht für Schäden jeglicher art, falls dieses Programm welche verursachen sollte.
The use of this program it at your own risk, I'm not responsible for damage of any kind, if this program should cause which.
Sie sollten das programm nur benutzen, wenn sie es auch verstehen.
You should only use the program, if you understand it.
Programm für gcc, MCU: AT90S4433, 8MHZ Quarz
Program for gcc, MCU AT90S4433 with a frequency of 8MHZ
Zum Kompilieren hab ich winavr20030913 verwendet
I've used winavr20030913 for compiling
Es ist nötig, mit Optimierung zu kompilieren, z.b Compiler Anweisung -O2, so benötigt das Programm c.a 3,8 KB. Ohne Optimierung wären es 5,1 KB, was nicht in den AT4433 passen würde
It is necessary to compile with optimization, for example compiler directive -O2, so the program need around 3,8 KB. Without optimization it would be around 5,1 KB which is too much for an AT4433

Messgenauigkeit der Anzeige (im vergleich mit einem normalem Multimeter):
Measuring resolution of the Display (compared to a normal Multimeter):
Voltage (Output: 2..17V) : +-0,15V
Ampere (Output: 0..0,5A) : +-30mA

Änderungen seit Version os_ver03.c auf os_ver04.c:
Modifications since version os_ver03.c to os_ver04.c:
Dies ist eine erweiterte Version von os_ver03.c. Sie ist speziell an die Eigenheiten meines Neztteils mit zwei wählbaren Eingansspannungen angepasst.
Nach dem Einschalten erkennt der MCU, welche maximale Spannung möglich ist (12 oder 24 V am Eingang) und setzt entsprechend den maximal erlaubten Strom
This is an advanced version of os_ver03.c. This version is optimized for the special type of my power supply with two input sources.
After switching on, the MCU recognizes which maximum voltage is possible (12 or 24 V at the input) and sets the right maximum current.

Änderungen seit Version os_ver04.c auf os_ver05.c:
Modifications since version os_ver04.c to os_ver05.c:
Es gibt einen neuen Menüpunkt (Taste 6) bei dem sich die erlabten Spannungsabweichungen wählen lassen.
There is a new Menupoint (Key 6) were the allowed voltage difference is selectable
Modus 1: +2%, -2% erlaubte Abweichung (allowed difference),                   +1%,   -1% Regelgenauigkeit (regulation accuracy)
Modus 2: +5%, -10% erlabute Abweichung, default (allowed difference, default) +2,5%, -5% Regelgenauigkeit (regulation accuracy)
Modus 3: +10%, -20% erlabute Abweichung (allowed difference)                  +5%,  -10% Regelgenauigkeit (regulation accuracy)
Modus 4: +50%, -255% erlaubte Abweichung (allowed difference)                 +25%, -25% Regelgenauigkeit (regulation accuracy)
Modus 5: +50%, -255% erlabute Abweichung (allowed difference), +25%, -25% Regelgenauigkeit (regulation accuracy), langsames hochdrehen der Spannung für Motoren (slow power up for engines)
seit os_ver06.c (since os_ver06.c):
Modus 6: +50%, -255% erlabute Abweichung (allowed difference), +10%, -20% Regelgenauigkeit (regulation accuracy), langsames hochdrehen der Spannung für Motoren (slow power up for engines)

Änderungen seit Version os_ver05.c auf os_ver06.c:
Modifications since version os_ver05.c to os_ver06.c:
PinC0 gibt ein High Signal aus, wenn die Leistungsabgabe des Steuertransistors 15W überschreitet. Dies ermöglicht den Anschluss eines geregelten Lüfters
PinC0 is a high signal, if the power transistor produces more than 15W heat. This can be used for drive a regulated fan

BEKANNTE PROBLEME:
Da die Ausgangsspannung des Spannungsreglers leider etwas lastabhängig ist, versucht der MCU einen Spannungsabfall zu
kompensieren, indem er die Ausgangsspannung (PWM) nach oben regelt. Fällt der Stromverbrauch am Ausgang dann schlagartig, so
kann an dem Ausgang EINE WESENTLICH ZU HOHE SPANNUNG ANLIEGEN !!!!. Zwar wird der MCU beim feststellen einer solchen den
Ausgang deaktivieren, jedoch mit einer gewissen Verzögerung (Abfallzeit des Relais, AD Wandlungszeit u.s.w.). In dieser Zeit
KANN EINE AM AUSGANG ANGESCHLOSSENE SCHALTUNG SCHANDEN NEHMEN.
KNOWN PROBLEMS:
Unfortunately the output voltage depend a little bit on the needed current. So the MCU trys to compensate this by increasing the output
voltage (PWM). If then the needed current decreases abruptly, the output voltage will rise.
BY THIS WAY THERE COULD BE A MUCH TOO HIGH OUTPUT VOLTAGE. When the MCU recognizes this he will switch off the output, but this
need some time (conversion time of the AD converter, declivity time of the Relay and so on).THIS TIME COULD BE LONG ENOUGH
THAT AT A CIRCUIT CONNECTED AT THE OUTPUT COULD BECOME DAMAGED.

Mögliche Verbesserrungen:
Beim Wechseln von diffmode = 5 zu einem anderem Diffmode, dauert das Regeln der Spannung recht lange, dies wäre verbesserungsfähig.
Im Interresse von mehr Sicherheit, könnte der Watchdog des MCU so programmiert werden, dass der MCU bei einem Hängen der Schleife einen
Neustart durchführt
Einen Modus, bei dem ein konstanter Strom anstelle einer konstanten Spannung geregelt wird
Ein schnelleres Regeln der Spannung, insbesondere bei einem Spannungsabfall durch eine hohe Last am Ausgang
Abspeichern der Einstellungen im EEpromdes MCU
Kalibrieren der Spannung/Strom Anzeige
Meine Rechtschreibung ;-)
Possible improvements:
Changing from diffmode =5 to an other diffmode, it takes much time to adjust the voltage
For more safety, the watchdog of the MCU could be used so that the MCU will restart when the main loop hangs
A mode were the MCU generates a constant current instead of a constant voltage
saving the settings in the EEprom of the MCU
calibrating of the voltage/current measurement
My orthography ;-)

PortD Pin 0: output, Segment c
PortD Pin 1: output, Segment e
PortD Pin 2: output, Segment d, Status LED 4, rot (red)
PortD Pin 3: output, Segment g, Status LED 3, gelb (yellow)
PortD Pin 4: output, Segment f, Status LED 2, grün (green)
PortD Pin 5: output, Segment a, Status LED 1, grün (green)
PortD Pin 6: output, Segment b
PortD Pin 7: output, Ziffer 4 (Number 4)
PortB Pin 0: output, Ziffer 3 (Number 3)
PortB Pin 1: output, Relai Ein/Aus (Relay on/off)
PortB Pin 2: output, Ziffer 2 (Number 2)
PortB Pin 3: output, Ziffer 1 (Number 1), Status LEDs
PortB Pin 4: output, 390 Ohm Widerstand (Resistor)
PortB Pin 5: output, 52 Ohm Widerstand (Resistor)
PortB Pin 6: nicht nach außen geführt (not available)
PortB Pin 7: nicht nach außen geführt (not available)
PortC Pin 0: output, Lüfter Ausgang (fan output)
PortC Pin 1: input, Strom Messung analog (Current measurement)
PortC Pin 2: input, Messen der Spannung analog (Voltage measurement)
PortC Pin 3: unbenutzt (not used)
PortC Pin 4: unbenutzt (not used)
PortC Pin 5: input, analoge Zifferntastatur (Number Keyboard)
PortC Pin 6: nicht nach außen geführt (not available)
PortC Pin 7: nicht nach außen geführt (not available)
PortA 0-7  : auf AT90S4433 nicht vorhanden (at AT90S4433 not available)
Messung der Ausgangsspannung : zwischen Ausgang und ADC2 befindet sich ein 560 Ohm Widerstand. Zwischen ADC2 und Masse ein 100 Ohm Widerstand.
  Beide wirken so als Spannungsteiler. Direkt vor ADC2 befindet sich jedoch noch ein 10KOhm Schutzwiderstand, der direkt keinen Einfluss auf den Spannungsteiler hat.
  Änderung um eine Digitalstelle am Analogeingang ist also: (5V/1024)*(560Ohm/100Ohm)= 0,027 Volt -> +- 0,027V Messgenauigkeit
Measurement of the output Voltage :Between the output and ADC2 is a 560 Ohm Resistor. Between ADC2 and Ground is a 100 Ohm Resistor,
  Both Resistors work as voltage divider. Directly before ADC2 is a 10KOhm Resistor for Protection, which has no effect of the voltage divider.
  The result of the digital measurement can be calculated as follow: (5V/1024)*(560Ohm/100Ohm)= 0,027 Volt -> +- 0,027V measuring accuracy
*/

#include <io.h> //Befehle mit Beschreibung der io.h (commands with a description of io.h): http://users.rcn.com/rneswold/avr/x1540.html
#include <inttypes.h>
#include <interrupt.h>
#include <sig-avr.h>

typedef unsigned char u08;
typedef unsigned short u16;
typedef short s16;
typedef char s08;

u08 res52, res390, resun;/*Variablen für die PWM Erzeugung (Variables for PWM production)
ist res52 größer Null, so ist res390 für die Feineinstellung nur zwischen 248 and 255 sinnvoll
is res52 larger than Zero, at res390 only a range between 248 and 255 is useful for fine adjustment
*/
u08 res52old, res390old; //um nach dem abschalten die ursprünglichen Werte wieder herzustellen (restore the primary values after deactivating the output)
u08 dispmode, ziffer; //Variablen für die Anzeige (Variables for the display)
/* display mode, Variable dispmode:
0: Initialisierung (initialize)
1: Spannung anzeigen (show voltage)
2: Strom anzeigen (show current)
3: Soll Spannung anzeigen (show ideal voltage)
4: Max Strom anzeigen (show maximum allowed current)
5: Fehlercode anzeigen (show error code)
Variable ziffer: welche Ziffer gerade beschrieben werden soll
Variable ziffer: told the program which number is currently written
*/
u08 disptemp01; //nur kurzzeitig benötigte Variable (temporary needed variable)
u16 disptemp02; //nur kurzzeitig benötigte Variable (temporary needed variable)
u16 voltist, voltsoll, ampereist, amperemax;//die bezeichnungen Sprechen wohl für sich (current voltage, ideal voltage, current ampere, maximum ampere)
u16 ampereabsolutemax; //Amperzahl, die der Trafo maximal liefern kann und die maximal eingestellt werden darf (absolute maximum available current from the transformer)
u08 ecode; //Variable, mit Fehlercode, eigentlich reicht auch u08 was c.a 90 Byte sparen würde, jedoch für testzwecke wird u16 benötigt
           //Variable with the error code, normally u08 would be possible also it would save around 90 Byte, but for testing purpose u16 is needed
/* Fehlercode bedeutung (wird nach dem Start auf LED Anzeige angezeigt, im Betrieb durch drücken der Taste 5 anzeigbar):
meaning for the error code (after the system start it will be displayed at the LED display, in normal mode, it can be displayed by pressing key 5)
E02 : Es wurde versucht den Ausgang bei einer fehlerhaft eingestellten Spannung zu aktivieren (there has been a try to activate the output with a wrong voltage)
E03 : Spannung überschreitet im Betrieb die erlaubte Abweichung (the output voltage was too high)
E04 : Spannung unterschreitet im Betrieb die erlabute Abweichung (the output voltage was too low)
E05 : Maximal zulässiger Strom wurde überschritten (there was more then the allowed output current)
E06 : Spannung überschreitet Soll-wert kurzzeitig um mehr das doppelte der erlaubten Abweichung. (the output voltage was for a short moment more than twice as high as the allowed difference)
E07 : Strom überschreitet kurzzeitig den vom Trafo lieferbaren Strom (the output current was for a short moment higher than the available current)
E08 : Strom überschreitet kurzzeitig den erlaubten Strom um das Doppelte (the output current was for a short moment two times higher than the allowed current)
100 : Spannung erfolgreich auf den gewünschten Wert geregelt (Voltage has the right value)
101 : Ausgang erfolgreich aktiviert, Relai zieht an (Output is activated, Relay is on)
(200 : MCU erfolgreich initialisiert (MCU successfully initialized)), nur in os_ver03.c (only in os_ver03.c)
201 : MCU erfolgreich initialisiert, 12 V gewählt (MCU successfully initialized, 12 V selected)
202 : MCU erfolgreich initialisiert, 24 V gewählt (MCU successfully initialized, 24 V selected)
*/
u16 temp01; //Temponäre Variable (temporary variable)
u08 temp02; //Temponäre Variable (temporary variable)
s16 temp03; //Temponäre Variable (temporary variable)
u16 ctast, cvolt, campere;//Variablen für die AD Durchschnittsberechnung (variables for the AD cut through calculation)
u08 sdurch; //variable, die sagt, wann der durchschnitt berechnet werden soll (variable which says then the cut through could be calculated)
u08 rdurch; //variable, die dafür sorgt, dass nicht so schnell nachgeregelt wird und ein zuweites regeln verhindern soll (variable for slower and better voltage regulation)
u08 lasttast,taststep;//lasttast letzter empfangener tasten AD wert, taststep zum erkennen von tastendrücken (variables for recognize the number keyboard inputs)
u08 progmode; //0 = aus 1 = ausgang aktiv 2 = werte werden durch tasten eingegeben 3 = spannung wird eingestellt (0 = off 1 = output is active 2 = values are entered by the keyboard 3 = regulating the output voltage)
u16 allowedvoltdiffmin,allowedvoltdiffmax; //erlaubte abweichung vom sollvolt, soll 2 % der Spannung betragen (allowed difference from the entered voltage, should be 2 %)
u16 allowedvoltdiffminr,allowedvoltdiffmaxr;//auf diese Werte soll geregeld werden (die hälfte von der erlaubten Abweichung
u08 diffmode;//siehe oben, neu seit os_ver05.c (see above, new since os_ver05.c)
u08 inputvoltage; //neu seit os_ver06.c (new since os_ver06.c)

SIGNAL(SIG_OVERFLOW0) { //toggel der Ausgänge PB4 und PB5 (toggle the outputs PB4 and PB4)
resun++; //wird alle 256 Takte erhöht, beginnt also alle 65536 Takte von vorn (will be increased every 256 Cycles, starts every 65536 at the beginning)
if (resun < res52) {  //je größer res52, desto öfter wird durchgesteuert und je kleiner ist die Spannung, Grobsteuerung (as higher res52 as lower is the output voltage, primary control)
sbi(PORTB,PINB5);
}
else {
cbi(PORTB,PINB5);
}
if (resun < res390) { //je größer res390, desto öfter wird durchgesteuert und je kleiner ist die Spannung, Feinsteuerung (as higher res390 as lower is the output, fine tuning)
sbi (PORTB,PINB4);
}
else {
cbi (PORTB,PINB4);
}
//ecode = res52;
outp(0,   TCNT0);
}


void setdiffvolt(void) { //setzt die Spannungsabweichungen (sets the allowed voltage difference)
if (diffmode == 1) {
allowedvoltdiffmin = voltsoll / 50; //2%
allowedvoltdiffmax = allowedvoltdiffmin; //2%
}
if (diffmode == 2) {
allowedvoltdiffmin = voltsoll / 10; //10%
allowedvoltdiffmax = voltsoll / 20; //5%
}
if (diffmode == 3) {
allowedvoltdiffmin = voltsoll / 5; //20%
allowedvoltdiffmax = voltsoll / 10; //10%
}
allowedvoltdiffminr = allowedvoltdiffmin / 2;
if ((diffmode > 3) && (diffmode < 7)) {
allowedvoltdiffmin = voltsoll; //beliebig
allowedvoltdiffminr = allowedvoltdiffmin / 4; //25 % Regelgenauigkeit (regulation resolution)
allowedvoltdiffmax = voltsoll / 2; //50%
}
allowedvoltdiffmaxr = allowedvoltdiffmax / 2;
if (diffmode == 6) {
allowedvoltdiffmaxr = allowedvoltdiffmax / 10;
allowedvoltdiffminr = allowedvoltdiffmin / 5;
}
}

void nachregeln(void) { //Regelt den Ausgang im Betrieb nach (regulate the output slowly when the output is activate to optimize the output voltage)
if (progmode < 2) {
if (voltist < voltsoll-allowedvoltdiffminr){ //Spannung zu niedrig (voltage is too low)
if ((res390 > 0) && (res52 == 0)) {
res390--;
}else
if (res52 > 0) {
if (res390 > 248) {
res390--;
}else{
res390 = 255;
res52--;
}
}//ende res52 größer 0 (end res52 is higher than zero)
}//ende Spannung zu niedrig (end voltage is to low)
if (voltist  > voltsoll+allowedvoltdiffmaxr) { //Spannung zu hoch (voltage is too high)
if (res390 < 255) {
res390++;
} else {
if (res52 < 255){
res52++;
res390 = 248;
}
}
}//ende Spannung zu hoch (end voltage is too high)
}//ende spannung im Betrieb leicht nachregeln (end voltage fine regulating)
if ((progmode == 0) && ((diffmode == 5)||(diffmode == 6))) { //slow power up mode
res52 = 198; //setzt die Ausgangsspannung auf 2V (sets the output voltage to 2V)
res390 = 200;
}
}


void ausgangaus(void) {
cbi(PORTB,PINB1); //Ausgang aus (output deactivate)
dispmode = 5;
progmode = 0;
res52 = res52old;
res390 = res390old;
}

void anzeige(void) {//Zeigt die Daten am LED Display an (show the data on the led display)
const u16 teiler[5]={1,1000,100,10,1};
const u08 segcode[10]={0x77,0x41,0x6e,0x6d,0x59,0x3d,0x3f,0x61,0x7f,0x7d};
switch(dispmode) //je nachdem, was angezeigt werden soll (based on what should be shown in the display)
{
case 0x00 : disptemp02 = 0; break;
case 0x01 : disptemp02 = voltist; break;
case 0x02 : disptemp02 = ampereist; break;
case 0x03 : disptemp02 = voltsoll; break;
case 0x04 : disptemp02 = amperemax; break;
case 0x05 : disptemp02 = ecode; break;
case 0x06 : disptemp02 = diffmode; break;
}
//Extrahieren der Ziffer (extracting number)
disptemp01 = (disptemp02 / teiler[ziffer]) % 10;
disptemp01 = segcode[disptemp01];
//Setzte Status LEDs, wenn Ziffer 1 (set status LEDs if Number is 1)
if (ziffer == 1) {
if (disptemp01 != 0x41) {
disptemp01 = 0;
}
/* bei (at)
dispmode = 1: LED 1 setzen (set LED 1)
dispmode = 2: LED 2 setzern (set LED 2)
dispmode = 3: LED 1 und LED 3 setzen (set LED 1 and LED 3)
dispmode = 4: LED 2 und LED 3 setzen (set LED 2 and LED 3)
dispmode = 5: LED 4 setzen (set LED 4)
dispmode = 3 + progmode = 2 : LED 1 setzen, LED 3 setzen und LED 4 Setzen (set LED 1,3,4)
dispmide = 4 + progmode = 2 : LED 2 setzen, LED 3 setzen und LED 4 Setzen (set LED 2,3,4)
*/
if ((dispmode == 1) || (dispmode == 3))
sbi(disptemp01,5); //grüne LED 1 (green Led 1)
if ((dispmode == 2) || (dispmode == 4))
sbi(disptemp01,4); //grüne LED 2 (green Led 2)
if ((dispmode == 3) || (dispmode == 4) || (dispmode == 6))
sbi(disptemp01,3); //gelbe LED (yellow LED)
if ((dispmode == 5) || (progmode == 2) || (progmode == 3))
sbi(disptemp01,2); //
if ((progmode == 1) && (sdurch < 32)) //sorgt dafür, dass das Minus bz. Plus Zeichen bei aktivem Ausgang blinkt (if output is activated the - or + symbol is blinking)
sbi(disptemp01,1);

}
//E. für Error bei spezieller Bedingung anzeigen, sollte Speichermangel auftreten, kann der Teil auch wieder entfernt werden
//shows E. for error in the display, if you have trouble with the avariable flash memory, you can remove it)
if ((ziffer == 2) && (dispmode == 5) && (ecode < 100)) //die zwei Zeilen benötigen insgesamt 30 Byte Flash ROM (these to lines need 30 Byte of flash ROM)
disptemp01 = 0x3e;
//Reseten der Pins für die Ziffer aktivierung (reset of the number Pins for activating a new number)
cbi(PORTB,PINB0);
cbi(PORTB,PINB2);
cbi(PORTB,PINB3);
outp(disptemp01,PORTD); //schreibt die Ziffer auf die Ausgänge (writes the number on the output)
switch(ziffer) { //Setzt den richtigen Ausgang für die aktive Ziffer (sets the new number pin)
case 0x01: sbi(PORTB,PINB3); break;
case 0x02: sbi(PORTB,PINB2); break;
case 0x03: sbi(PORTB,PINB0); break;
case 0x04: sbi(PORTD,PIND7); break;
}
ziffer++;
if (ziffer > 4) {
ziffer = 1;
}
}

void adwandlung(u08 kanal) { //führt eine AD Wandlung auf dem übergebendem Pin durch (proceeds an AD conversion)
outp(kanal, ADMUX); //Kanal wählen (select AD channel)
outp(inp(ADCSR) | BV(ADSC), ADCSR); //setzt das ADSC Bit, aus (set the ADSC Bit, from): www.mikrocontroller.net/forum/read-1-2718.html#2761
while (inp(ADCSR) & BV(ADSC));      //wartet, bis die Wandlung komplett ist (waits until the conversion is complete)
temp01 = ADCW;     //das Ergebnis der Wandlung wird in temp01 geschrieben (the result of the conversion is written into temp01)
}

void tastdecode(void) {//Erkennt die Tasten und bearbeitet dessen Aktionen (recognize which key is pressed and do the right action based on the pressed key)
//ecode = 110;
ctast = 12; //12 hat keine Funktion (12 doesn't has a function)
switch(lasttast) {
case 17 : ctast = 0; break;
case 34 : ctast = 1; break;
case 50 : ctast = 2; break;
case 67 : ctast = 3; break;
case 83 : ctast = 4; break;
case 99 : ctast = 5; break;
case 114 : ctast = 6; break;
case 115 : ctast = 6; break;
case 116 : ctast = 6; break;
case 130 : ctast = 7; break;
case 131 : ctast = 7; break;
case 132 : ctast = 7; break;
case 147 : ctast = 8; break;
case 148 : ctast = 8; break;
case 149 : ctast = 8; break;
case 164 : ctast = 9; break;
case 165 : ctast = 9; break;
case 166 : ctast = 9; break;
case 181 : ctast = 10; break; //R Taste (R key)
case 182 : ctast = 10; break; //R Taste (R key)
case 183 : ctast = 10; break; //R Taste (R key)
case 199 : ctast = 11; break; //Ausgang ein Taste (activate output key)
case 200 : ctast = 11; break; //Ausgang ein Taste (activate output key)
case 201 : ctast = 11; break; //Ausgang ein Taste (activate output key)
}
if ((progmode < 2) && (ctast > 0) && (ctast < 7)) {//Modus setzen (set mode)
dispmode = ctast;
//ecode = 111;
}
if ((progmode == 0) && (ctast == 10)&& (((dispmode < 5)&& (dispmode > 2))||(dispmode == 6))) { //Konfigurationsmodus (modus of configuration)
//ecode = 112 ;
if (dispmode == 3) { //Spannung einstellen (set voltage)
//ecode = 103;
progmode = 2;
ctast = 12;
voltsoll = 0;
res52 = 255;
res390 = 255;
}
if (dispmode == 4) { //max Strom einstellen (set maximum current)
//ecode = 104;
progmode = 2;
ctast = 12;
amperemax = 0;
}
if (dispmode == 6) {
progmode = 2;
ctast = 12;
diffmode = 0;
}
}
if ((progmode == 2)&& (ctast < 10)) { //eine Ziffer wurde einegeben (a number was entered)
//ecode = 105;
if (dispmode == 3){ //Volt setzen (set voltage)
voltsoll = (voltsoll + ctast)*10;
if (voltsoll > 199) {
progmode = 3;//3 = Spannung einstellen (3 = set voltage)
dispmode = 1;
res390 = 255;
if (voltsoll > 219) //damit die Spannungsanpassung schneller geht einige voreingestellte Werte (for a faster voltage regulation some pre defined values)
res52 = 200;
if (voltsoll > 239)
res52 = 160;
if (voltsoll > 299)
res52 = 96;
if (voltsoll > 599)
res52 = 32;
setdiffvolt();
}
}
if (dispmode == 4) { //erlaubten Strom setzen (set maximum current)
amperemax = amperemax*10 +ctast;
if (amperemax >= ampereabsolutemax ) {
progmode = 0;
}
}
if ((dispmode == 6) && (ctast > 0) && (ctast <7)) {//volt Abweichungen einstellen (set voltage differences)
diffmode = ctast;
setdiffvolt();
progmode = 0;
}
}
if ((progmode == 2) && (ctast == 10) && (dispmode == 4) && (amperemax > 0)) //manueelles eingabe ende bei ampere, bei volt ist dies immer eindeutig, daher nicht benötigt (manual stop of maximum current key input, not needed at voltage)
progmode = 0;
if (amperemax > ampereabsolutemax)
amperemax = ampereabsolutemax;
if ((progmode == 1) && (ctast > 6) && (ctast < 11)) {//Relai abfallen lassen (deactivate output)
cbi(PORTB,PINB1);
progmode = 0;
ecode = 100;
}
if ((progmode == 0 ) && (ctast == 11)) //Teilberechtigung zum schließen des Relais, Spannungsprüfung folgt später (activate output key was pressed, first step for activating)
progmode = 1;
ctast = 0;
}



int main( void ) {
//setzen die i/o Ports als Ein oder Ausgang (define i/o ports as in- or outputs)
outp(0xff,DDRB);
outp(0x01,DDRC);
outp(0xff,DDRD);
//initialisierung der Pulsweitenmodulation für die Spannung (starting of pwm for the voltage)
outp((1<<TOIE0), TIMSK);
outp(0,   TCNT0); //setzt den Timer auf null (reset timer)
outp(1,   TCCR0); //startet den Timer (start timer)
res52 = 0;  //setzt die Ausgangsspannung auf Maximum (sets the output voltage to maximum)
res390 = 0;
sei();          //aktiviert die interrupts (activate the interrupts)
//initialisierung des AD Wandlers: ADEN: aktiviert den Wandler, ADSC: startet eine Wandlung ADPS0-ADPS2: ADC Frequenzteiler = 128, alle andere Register Funktionen: siehe AT90S4433 Datenblatt
//starting of the AD converter: ADEN: activate the converter, DSCS: starts a conversion, ADS0-ADS2 : AD Frequency divider = 128, all other registers: see AT90S4433 datasheet
outp(BV(ADEN) | BV(ADSC) | BV(ADPS0) | BV(ADPS1) | BV(ADPS2), ADCSR);
while (inp(ADCSR) & BV(ADSC));//wartet, bis der erste Konvertierung komplett ist (wait until the first conversion is done)
dispmode = 5;   //Standartwerte setzen, Display zeigt nach Starten eventuelle Fehlercodes an (set default values, show error code after startup)
progmode = 0;   //Standartwerte setzen, Ausgang ist nach Starten aus (Relai) (set default values, output is deactivated after startup)
voltsoll = 200; //Standartwerte setzen, Ausgang ist nach Starten auf 2 Volt eingestellt (Spannungsregler) (set default values, output voltage is 2 Volt)
amperemax = 10; //Standartwerte setzen, maximal zulässiger Ausgangsstrom ist nach dem Starten auf 100mA eingestellt ((set default values, maximum current is 100mA)
diffmode = 2; //standartwerte setzen, neu seit os_ver05.c (set default values, new since os_ver05.c)
setdiffvolt();  //Standartwerte setzen, erlaubte Spannungsabweichung beträgt nach Starten +5%, -10% (set default values, allowed volt difference is +5%, -10%)
for (temp02 = 0; temp02< 100 ; temp02++) {//warteschleife, damit sich die spannung erstmal bis zum maximum aufbauen kann (loop for waiting so that the voltage has time to increase to the maximum)
adwandlung(2);  //Messung der maximalen Ausgangsspannung (measurement of maximum output voltage)
if (temp01 > 290) { //24V input voltage, temp01 ist bei 24 V 309 und bei 12 V 266. Die Zahlen wurden ermittelt, indem für testzwecke ecode = temp01 geschrieben wurde
                   //24V input voltage, by 24 V temp01 is 309 and by 12 V temp01 is 266. This numbers were generated by writing ecode = temp01 for testing
ampereabsolutemax = 30; //Maximal darf 0,30 Ampere eingestellt werden, bitte dem verwendeten Transformator anpassen
                        //maximum allowed current which is available form the power supply unit is set to 0.3 Ampere, please modify based on your used power supply unit
inputvoltage = 24;
ecode = 202;    //Standartwerte setzen, Fehlercode ist 202, bedeuten Initialisierung erfolgreich mit 24 V Eingangsspannung(set default value, ecode = 200 means that the startup was successful with 24V input voltage)
}else{ // 12V Eingangsspannung ( 12V input voltage)
ampereabsolutemax = 780; //Maximal darf 7,80 Ampere eingestellt werden, bitte dem verwendeten Transformator anpassen
                         //maximum allowed current which is available form the power supply unit is set to 7,8 Ampere, please modify based on your used power supply unit
inputvoltage = 12;
ecode = 201;    //Standartwerte setzen, Fehlercode ist 201, bedeuten Initialisierung erfolgreich mit 12 V Eingangsspannung (set default value, ecode = 200 means that the startup was successful with 12V input voltage)
}
}
//ecode = temp01; //nur für testzwecke aktivieren, siehe 12 Zeilen drüber (for testing purpose only, see 11 lines above)
res52 = 198; //setzt die Ausgangsspannung auf 2V (sets the output voltage to 2V)
res390 = 200;
for (;;) {//endlosschleife (endless loop)
sdurch++;
adwandlung(5);//Tastatur überprüfen (check the keyboard)
if ((temp01 > 510) && (temp01 < 700) && (progmode == 1)) {//Taste gedrückt, schnell abschalten (key pressed, fast deactivating of the output)
cbi(PORTB,PINB1); //Ausgang aus (output off)
progmode = 0;
ecode = 100;
res52 = res52old;
res390 = res390old;
}
if (temp01 > 48)
ctast = ctast +temp01;
adwandlung(2); //Spannung überprüfen (check voltage)
if ((temp01*16 / 5 -7 > voltsoll + allowedvoltdiffmax*2) && (progmode == 1)) { //Sicherheitsspannungsabschaltung (safety disconnection)
ausgangaus();
ecode = 6;
}
cvolt = cvolt +temp01;
adwandlung(1); //Strom überprüfen (check current)
if (progmode == 1) { //das Überprüfen des Stromes bringt ja nur was, wenn der Ausgang auch aktiv ist
                     //the testing of the current is only useful, when the output is activated
if ((temp01*32 / 33 > ampereabsolutemax)) { //Sicherheitsstromabschaltung (safety disconnection)
ausgangaus();
ecode = 7;
}
if (temp01 > amperemax*2) { //Sicherheitsstromabschaltung (safety disconnection because of too high current)
ausgangaus();
ecode = 8;
}
}
campere = campere +temp01;
//lüfter Ausgang regeln (regulate fan output)
temp02 = (inputvoltage-(voltist/100))*(ampereist /100);
if ((temp02 > 24) || ((temp02 > 9) && (sdurch % 2 == 0))) { //wenn mehr als 9 Watt abfallen: niedrige Drehzahl, wenn mehr als 24W: hohe Lüfter Drehzahl
sbi(PORTC,PINC0); //lüfter an (fan on)                      //more than 9W: slow fan, more than 24W: fan has maximum speed
}else{
cbi (PORTC,PINC0); //lüfter aus (fan off)
}


if (sdurch == 64) { //Jetzt die realen Werte berechnen (now calculate the real values)
rdurch++;
//Bearbeitung des Tastendrucks (work on key is pressed )
ctast = ctast / 256;
/* in unterer If Verzweigung: (in lower if case:)
if (taststep == 3 )
verwenden, damit auf eine Tastatureingabe reagiert wird soblad eine Taste gedrückt wurde (use instead to let the keyboard react by pressing down a key)
if ((ctast+1) < lasttast) && (taststep > 3))
verwenden, damit auf den Tastendruck erst nach dem Loslassen einer Taste reagiert wird (nicht mit os_ver05.c getestet). (use instead to let the keyboard react by pressing up a key (not tested with os_ver05.c))
*/
if (taststep == 3) //Tastendruck als solchen erkennen (recognize a pressed key)
tastdecode(); //Subroutine zur Behandlung des Tastendrucks (subroutine for action based on the pressed key)
temp02 = abs(ctast - lasttast);
if ((temp02 < 3) && (ctast > 16)) //gleiche Taste erkannt (same key pressed)
{taststep++;}
else
{taststep = 0;}
lasttast = ctast;
ctast = 0;
//ecode = lasttast;
//ende Bearbeiten des Tastendrucks (end of key pressing procedure)
//Spannung berechnen (calculate the voltage)
voltist = cvolt / 20 - 7; //Ideal wäre cvolt / 23,406  - bei mir war die gemessene Spannung mit (cvolt / 20)-7 jedoch deutlich genauer
                          //best would be cvolt / 23,406 - but at my circuit the measurement of the voltage was better with (cvolt /20) -7
//Strom berechnen, 1 digitalstelle ist 0,009766A, es werden 64 Messungen durchgeführt
//calculate the current, one digitalplace is 0,009766A, there will be 64 measurements
ampereist = campere / 66; //ideal wäre 65,979 (best would be 65,979)
sdurch = 0;
cvolt = 0;
campere = 0;
//angleichen der Spannung nach Eingabe einer neuen(optimizing the voltage after entering a new one)
if (progmode == 3) { //Spannung regeln (regulating of the voltage)
temp02 = rdurch % 2;
if ((voltist < 600) || (temp02 == 0)) {
if (voltsoll > voltist) //Spannung zu niedrig (voltage too low)
res52--;
temp01 = abs(voltist - voltsoll);
if ((temp01 < allowedvoltdiffmin) || (res52 == 0) || (voltsoll < voltist)){//res52 = 0 bedeutet Spannung nicht einstellbar, also abbruch des Einstellungsversuches
progmode = 0;                                                           //res52 = 0 means that the voltage isn't possible, break of regulation
ecode = 100;
}
/*if (res52 == 0) {  //Stört bei der Regelungstechnik von os_ver05.c blos, war in os_ver01.c sinnvoll (needless in os_ver05.c was useful in os_ver01.c)
ecode = 1;
dispmode = 5;
}
*/
}
}
//Spannung im Betrieb eventuell nachregeln (slowly regulating the voltage during deactivate and activate output)
temp02 = rdurch % 2;
temp03 = voltist - voltsoll; //negativ, wenn spannung zu gering (negative if voltage is too low)
if ((temp03 > 100) || (temp03 < 100) || (temp02 == 0)) //wenn differenz größer 1 Volt oder jeden zweiten prog durchlauf, dann regeln
nachregeln();                                          //if difference is higher than 1 volt or every second run, then regulate
if ((temp03 > 200) || (temp03 < 200) || (voltist < 300)) //wenn Differenz größer 2 Volt oder Spannung kleiner 3 V, dann ein zweites mal Regeln (damit die Regelung schneller geht)
nachregeln();                                            //if difference is higher than 2 volt or the voltage is lower than 3 volt, then regulate again so that it is faster
if ((temp03 > 400) || (temp03 < 400) || (voltist < 200)) //wenn Differenz größer 4 Volt oder Spannung kleiner 2 V, dann ein drittes mal Regeln (damit die Regelung schneller geht)
nachregeln();                                            //if difference is higher than 3 volt or voltage is lower than 2 volt, then regulate a third time so that the wished voltage can be reached very vast
}//ende sdurch = 64 (end sdurch = 64)
//überprüfen der Ausgangsspannung (check the output voltage)
temp01 = abs(voltist - voltsoll);
if ((progmode == 1) && (voltist < voltsoll+allowedvoltdiffmax)&&(voltist > voltsoll - allowedvoltdiffmin)) {
res52old = res52;
res390old = res390;
sbi(PORTB,PINB1); //Ausgang an (output on)
ecode = 101;
}
if ((progmode == 1) && (voltist > voltsoll+allowedvoltdiffmax) && (voltist < voltsoll - allowedvoltdiffmin) && (bit_is_clear(PORTB, PINB1) )){ //nicht innerhalb der erlaubten spannung, relai darf garnicht erst aktiviert werden
ecode = 2;                                                                            //voltage not within the allowed 2 % difference, so it's not allowed to activate the output
progmode = 0;
dispmode = 5;
}
if ((progmode == 1) && (voltist > allowedvoltdiffmax + voltsoll)) {//zu hohe Spannung
ausgangaus();                                                     //too high voltage
ecode = 3;
}
if ((progmode == 1) && (voltist < voltsoll - allowedvoltdiffmin)) {//zu niedrige Spannung
ausgangaus();                                                      //too low voltage
ecode = 4;
}
if ((progmode == 1) && (ampereist > amperemax)) {//zu großer Strom (too high current)
ausgangaus();
ecode = 5;
}

anzeige();

}//ende der Endlosschleife (end of endless loop)
}//ende der Funktion Main (end of function main)
//ende der Datei (end of file)
