So, hier die versprochenen Code-Schnippsel.
Das ganze ist eher als Anregung gedacht und eigentlich nur Pseudo-Code, weil nicht alle Haeder dabei sind. Es sind nur die relevanten stellen, die für ne C-Messung gebraucht wurden. Der Code ist recht antik, undokumentiert und war auch nicht für's breite Publikum gedacht...
Das ganze drumrum hab ich weggelassen wie Taster abfragen, VFD-Routinen, etc
Laufen tut das auf einem AT90S2313 mit 8MHz Keramik.
Hier wird nur der C geladen und die Zeit in Ticks gemessen.
Code:
#include "capacity.h"
//#include "morse.h"
extern void ioinit();
extern void wait_10ms (const byte);
// Multiplikator:
// k = (ny * R * ln 2)^{-1}
// mit ny = 8MHz und R = 10k:
// k = 18pF / Inkrement
word measure_time (byte loadTime)
{
// Load capacity via AIN+ push-pull
SET (PORT_AIN_POS); MAKE_OUT (PORT_AIN_POS);
wait_10ms (loadTime);
// disable all interrupts
cli();
// stop timer1
TCCR1B = 0;
// enable AC (ACD = 0)
// AC Input Capture on -> connect to Input Capture of Timer/Counter1
// AC Interrupt on Falling Output Edge
ACSR = _BV(ACIC) | _BV (ACIS1);
// disconnect timer1 from output pin OC, no PWM
TCCR1A = 0;
// reset timer1 to 0
TCNT1 = 0;
// clear Timer1 Overflow and InputCapture Flags
TIFR = _BV (TOV1) | _BV (ICF1);
// start timer 1 at full speed
// no clear on compare match
// no noise cancel
// input capture edge = falling
TCCR1B = _BV (CS10);
// here we go!
// start discharging via external resistor
// AIN+ to high Z
MAKE_IN (PORT_AIN_POS); CLR (PORT_AIN_POS);
byte flag;
do
{
flag = TIFR & (_BV (TOV1) | _BV (ICF1));
} while (flag == 0);
if (flag & _BV (TOV1))
return 0xffff;
return ICR1;
// restore status of machine
// ioinit();
// morse (_O_);
// if (flag & _BV (ICF1))
// morse_dec (capture-4);
// morse (_FRAGE_);
}
Und hier etwas von dem Geklimper drumrum: Umrechnen in Kapazität, Messbereich auswählen, Kalibrierung, etc
Code:
#include "ports.h"
#include "main.h"
#include "util.h"
#include "taster.h"
#include "timer.h"
#include "vfd.h"
#include "capacity.h"
extern void ioinit();
static unsigned long mul_ww (word, word);
static void measureC (byte doCallibrate);
static void put_decimal (byte pos, word val, byte dot);
static word callibra[3] = {3, 3, 3};
enum
{
OHM_1M = 0,
OHM_47K = 1,
OHM_1K5 = 2
};
#define CONST_1M 687995. /* 0M993 */
#define CONST_47K 32140. /* 46K8 */
#define CONST_1K5 759.5 /* 1K49 */
// doCallibrate == 0: C bestimmen und anzeigen
// doCallibrate != 0: C bestimmen und callibrate[] damit besetzen
void measureC (byte doCallibrate)
{
word capval;
char dim;
char toobig;
byte ohm;
word const_R;
byte loadTime;
byte dot;
ioinit();
#if VFD
vfd_reset (1);
#endif
vfd_clear();
vfd.bright = 0;
vfd.cursor_on = 0;
vfd.cursor_blink = 0;
vfd_init ();
for (ohm = OHM_1M; ohm <= OHM_1K5; ohm++)
{
switch (ohm)
{
default:
case OHM_1M:
MAKE_IN (PORT_RELAIS1); CLR (PORT_RELAIS1);
MAKE_IN (PORT_RELAIS2); CLR (PORT_RELAIS2);
const_R = (word) (1.01*1e12*65536./(XTAL_PHI * CONST_1M)); // 1pF
loadTime = 20;
dot = 0;
dim = 'p';
break;
case OHM_47K:
MAKE_OUT (PORT_RELAIS1); SET (PORT_RELAIS1);
MAKE_IN (PORT_RELAIS2); CLR (PORT_RELAIS2);
const_R = (word) (1.01*1e10*65536./(XTAL_PHI * CONST_47K)); // 100pF
loadTime = 40;
dot = 1;
dim = 'n';
break;
case OHM_1K5:
MAKE_OUT (PORT_RELAIS1); SET (PORT_RELAIS1);
MAKE_OUT (PORT_RELAIS2); SET (PORT_RELAIS2);
const_R = (word) (1.17*1e9*65536./(XTAL_PHI * CONST_1K5)); // 1nF
loadTime = 150;
dot = 0;
dim = 'n';
break;
}
wait_10ms (10);
capval = measure_time (loadTime);
toobig = (0xffff == capval);
if (doCallibrate)
{
if (toobig)
break;
callibra[ohm] = capval-3;
}
else
{
if (!toobig)
{
capval -= callibra[ohm];
capval = (word) (mul_ww (const_R, capval) >> 16);
break;
}
}
ioinit();
}
ioinit();
vfd.bright = 4;
vfd_init ();
if (toobig)
{
static const prog_char STR_C_ZU_GROSS[] = "C zu groß";
if (doCallibrate)
{
vfd_pos_string_P (0x03, STR_C_ZU_GROSS);
vfd_pos_string_P (0x40, PSTR("zum kalibrieren"));
}
else
vfd_pos_string_P (0x43, STR_C_ZU_GROSS);
return;
}
if (doCallibrate)
{
vfd_pos_string_P (0x03, PSTR("Kalibriert"));
return;
}
if (ohm == OHM_1K5)
{
if (capval > 1000)
{
capval = (word) (mul_ww (capval, (word) (65536./10.)) >> 16);
dim = 0xe4; // my
dot = 2;
}
}
if (ohm == OHM_1M)
{
if (capval > 1000)
{
dim = 'n';
dot = 3;
}
}
vfd_pos_char (0x40, '0'+ohm);
put_decimal (0x48, capval, dot);
vfd_pos_char (0x4a, dim);
vfd_pos_char (0x4b, 'F');
}
void put_decimal (byte pos, word val, byte dot)
{
byte i = 0;
do
{
word r,d;
divmod10 (d, r, val);
vfd_pos_char (pos--, '0' + (byte) r);
val = d;
i++;
if (i == dot)
vfd_pos_char (pos--, '.');
} while (val);
}
#if 1
// return (a*b) >> 16
unsigned long mul_ww (word _a, word b)
{
unsigned long ab = 0;
unsigned long a = _a;
while (1)
{
if (b & 1)
ab += a;
b >>= 1;
if (b==0)
return ab;
a <<= 1;
}
}
#endif
Lesezeichen