extern "C"{
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
}
/****************************************************************
* Symmetrisches Labornetzgerät, Spannungs- und Stromanzeige *
* auf Flüssigkristallanzeige 16 x 2 Zeichen *
* heha, 100930 *
****************************************************************/
/* Angeschlossene Hardware
P6.0 A0 59 Sollspannung, 0 .. 2,5 V (vom Potenziometer)
P6.1 A1 60 Sollstrom, 0 .. 2,5 V (vom Potenziometer)
P6.2 A2 61 neg. Istspannung, 0V=-16V, ca. Uref=0V
P6.3 A3 2 neg. Iststrom, 0 .. 2,5 V (von INA128P)
P6.6 A6 5 pos. Iststrom, 0 .. 2,5 V (von INA128P)
P6.7 A7 6 pos. Istspannung, 0 .. 2,5 V
P3.5 - 33 RS (0=Befehl / 1=Daten)
P3.6 - 34 R/W (0=Schreiben / 1=Lesen)
P3.7 - 35 E (Freigabe, Taktleitung, high-aktiv)
P4.0..P4.7 36..43 Datenbus (8 bit), standardmäßig auf EINGABE
*/
/*====================*
*= Routinen für LCD =*
*====================*/
static __attribute__ ((naked)) void delay(int n) {
//Zeit = (1/MCLK)*(8+(3*n))
asm("lcdloop: dec %0\n jnz lcdloop\n ret" :: "r" (n));
}
#define lcdDelay(ms) delay(1000*(ms));
// 1 Byte lesen (rs=0x40: Statusregister, rs=0x60: Datenbyte)
static char lcdRead(char rs) {
P3OUT = rs;
P3OUT |= 0x80; // E high
nop();
char ret = P4IN; // Datenbyte lesen
P3OUT &=~0x80; // E low
return ret;
}
static void lcdBusyWait() {
while (lcdRead(0x40)&0x80);
}
//static char LcdRead(char rs) {
// lcdBusyWait();
// return lcdRead(rs);
//}
static inline unsigned swpb(unsigned x) {return x>>8|x<<8;}
// 1 Byte schreiben (HIBYTE: 0x00: Befehl, 0x20: Datenbyte)
static void lcdWrite(unsigned c) {
P4OUT = c; // Byte ausgeben
P4DIR = 0xFF;
lcdRead(swpb(c)); // gleiches Signalspiel, gelesenes Byte verwerfen
P4DIR = 0;
}
static void LcdWrite(unsigned c) {
lcdBusyWait();
lcdWrite(c);
}
static char charmap[]={
0x00,0x00,0x0F,0x11,0x11,0x0F,0x01,0x0E, // g mit Unterlänge
0x00,0x00,0x1E,0x11,0x11,0x1E,0x10,0x10, // p mit Unterlänge
};
static void LcdInit() {
lcdDelay(30); //wait more than 30ms
lcdWrite(0x30); //set 8 bit interface
lcdDelay(1);
lcdWrite(0x30);
lcdDelay(1);
lcdWrite(0x30);
lcdDelay(1);
LcdWrite(0x38); // 2-zeilige Anzeige
LcdWrite(0x01); // Anzeige löschen
LcdWrite(0x06); // Auto-Adressinkrement
LcdWrite(0x0C); // Display EIN, Cursor AUS
LcdWrite(0x40); // Zeichengenerator-RAM-Adresse setzen
for (size_t i=0; i<sizeof(charmap); i++) LcdWrite((unsigned char)charmap[i]|0x2000);
}
// String ausgeben
static void LcdWrite(const char*s) {
for(;;) {
char c=*s++;
if (!c) break;
LcdWrite((unsigned char)c|0x2000);
}
}
// String ab Speicherposition ausgeben
static void LcdWrite(unsigned at, const char*s) {
LcdWrite(at);
LcdWrite(s);
}
/*=============================*
*= Formatierte Zahlenausgabe =*
*=============================*/
// Dezimalzahl mit Zwangs-Vorzeichen formatieren
// linksbündig, mit Leerzeichen aufgefüllt
// mit Komma bei <Nachkommastelle> wenn !=0
static int Dezimal(int v, char*s, int len, int nk) {
char*a=s; // String-Anfang
// 1. Zahl (Platz muss reichen!)
s+=sprintf(s,"%+0*d",nk+2,v);
// 2. Vorzeichen korrigieren wenn Null
if (v==0) *a=' ';
// 3. Komma einbasteln
if (nk) {
char*e=s+1;
do{
char*d=s;
*d=*--s;
}while(--nk);
*s=',';
s=e; // auf das Ende
}
// 4. Leerzeichen auffüllen
while (s-a<len) *s++=' ';
// 5. terminieren
*s=0;
return s-a;
}
// Spannung (in mV, -16000 .. +16000) formatieren
static int Spannung(int v, char*s) {
if (abs(v)>=10000) return Dezimal(v/10,s,6,2); // 10-mV-Schritte
else return Dezimal(v,s,6,3); // 1-mV-Schritte
}
// Strom (in 0,1 mA, -12000 .. +12000) formatieren
static int Strom(int v, char*s) {
if (abs(v)>=1000) return Dezimal(v/10,s,5,0); // ganze mA
else return Dezimal(v,s,5,1); // 100-µA-Schritte
}
// Messwert skalieren (mit Faktor <f>/4096) und verschieben (mit Offset <o>)
static int Scale(int v, int f, int o) {
return int((long)v*f>>12)+o;
}
static char dispstate;
static char dispdelay;
static void ShowState0() {
LcdWrite(0x80,"+ ??? V - ??? V");
LcdWrite(0xC0,"+ ?? mA - ?? mA"); // zweite Zeile (0,1)
}
static void ShowState1() {
LcdWrite(0x80," S\011annun\010sbe\010r.:");
LcdWrite(0xC0," ca. ?? V ");
}
static void ShowState2() {
LcdWrite(0x80,"Strombe\010renzun\010:");
LcdWrite(0xC0," ca. ?? mA ");
}
static void ShowState3() {
LcdWrite(0x80," Tem\011eratur ");
LcdWrite(0xC0," ca. + ?? \337C ");
}
static void setstate(char state) {
dispdelay=10;
if (dispstate==state) return;
dispstate=state;
switch (state) {
case 0: ShowState0(); break;
case 1: ShowState1(); break;
case 2: ShowState2(); break;
case 3: ShowState3(); break;
}
}
// Sind zwei Abtastwerte nahe beieinander?
// Bei großer zulässiger Differenz auch die Absolutwerte einkalkulieren
static int near(int v1, int v2, int diff=50) {
if (diff>50) diff+=(v1+v2)>>6;
return abs(v1-v2)<diff;
}
int main(void) {
WDTCTL = WDTPW|WDTHOLD; // Watchdog beruhigen
SVSCTL = 0x18; // Bei Unterschreiten der Betriebsspannung unter 3 V Reset auslösen lassen
P1OUT = 0; P1DIR = 0xFF; // Unbeschaltete Pins festnageln
P2OUT = 0; P2DIR = 0xFF;
P3OUT = 0; P3DIR = 0xFF;
P4OUT = 0; P4DIR = 0xFF;
P5OUT = 0; P5DIR = 0xFF;
P6OUT = 0; P6SEL = 0xFF; // Port 6 rein analog
ADC12CTL0 = 0x44F0; // 2,5 V Referenzspannung
ADC12CTL1 = 0x02F6; // langsam arbeiten
ADC12MCTL0 = 0x10; // Usoll
ADC12MCTL1 = 0x17; // +Uist
ADC12MCTL2 = 0x12; // -Uist
ADC12MCTL3 = 0x11; // Isoll
ADC12MCTL4 = 0x16; // +Iist
ADC12MCTL5 = 0x13; // -Iist
ADC12MCTL6 = 0x9A; // Chiptemperatur
LcdInit();
setstate(3);
static char s[12];
static int Usoll,UistP,UistN,Isoll,IistP,IistN,Temp;
static int Usoll_, Isoll_; // vergangene Werte
// Spannungen in mV, Ströme in 0,1 mA, Temperatur in 0,1 °C
ADC12CTL0|=3; // ADU freigeben und starten
for(;;) {
while (!(ADC12IFG&1<<5)); // warten bis fertig
// Werte auslesen und skalieren (Werte experimentell gefunden)
Usoll=Scale(ADC12MEM0,18600,0);
UistP=Scale(ADC12MEM1,16113,-3);
UistN=Scale(ADC12MEM2,18599,-16060);
Isoll=Scale(ADC12MEM3,13000,0);
IistP=Scale(ADC12MEM4,13013,0);
IistN=Scale(ADC12MEM5,-14508,Scale(UistN,-54,0));
Temp =Scale(ADC12MEM6,2380,-800);
// Übertemperatur detektieren und Anzeige umschalten,
// bei permanenter Übertemperatur wechselt die Anzeige zwischen 0 und 3
if (Temp>600 && !dispdelay) setstate(3);
// Wertänderungen an Usoll detektieren und Anzeige umschalten
if (!near(Usoll,Usoll_) // am U-Knopf gedreht?
&& near(Isoll,IistP,100) // UND Strombegrenzung an Ausgang+?
&& near(Isoll,-IistN,100) // UND Strombegrenzung an Ausgang-?
&& dispstate!=3) setstate(1); // Anzeige umschalten
Usoll_=Usoll;
// Wertänderungen an Isoll detektieren und Anzeige umschalten
if (!near(Isoll,Isoll_) // am I-Knopf gedreht?
&& !near(Isoll,IistP,100) // UND keine Strombegrenzung an Ausgang+?
&& !near(Isoll,-IistN,100) // UND keine Strombegrenzung an Ausgang-?
&& dispstate!=3) setstate(2); // Anzeige umschalten
Isoll_=Isoll;
// Veränderliche Positionen aktualisieren
switch (dispstate) {
case 0: {
Spannung(UistP,s); LcdWrite(0x80,s); // Cursor nach (0,0)
Spannung(UistN,s); LcdWrite(0x89,s); // Cursor nach (9,0)
Strom(IistP,s); LcdWrite(0xC0,s); // Cursor nach (0,1)
Strom(IistN,s); LcdWrite(0xC9,s); // Cursor nach (9,1)
}break;
case 1: {
Spannung(Usoll,s); LcdWrite(0xC7,s+1); // ohne Vorzeichen ausgeben
}break;
case 2: {
Strom(Isoll,s); LcdWrite(0xC7,s+1); // ohne Vorzeichen ausgeben
}break;
case 3: {
Dezimal(Temp,s,6,1); LcdWrite(0xC6,s);
}break;
}
delay(0); // maximal warten
if (dispdelay && !(--dispdelay) && dispstate) setstate(0);
}
}
Detected encoding: UTF-8 | 0
|