Professional Documents
Culture Documents
Tester Code v1.1.08
Tester Code v1.1.08
Tester Code v1.1.08
h>
#include <util/delay.h>
#include <avr/sleep.h>
#include <stdlib.h>
#include <string.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <math.h>
#include <stdint.h>
#include <avr/power.h>
#include <Wire.h>
//#include <LiquidCrystal.h>
//LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // RS,E,D4,D5,D6,D7
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3E, 16, 2);
// ******** config options for your Semiconductor tester
// Every changing of this Makefile will result in new compiling the whole
// programs, if you call make or make upload.
// The LCD_DOGM option must be set for support of the DOG-M type of LCD modules
with ST7036 controller.
// For this LCD type the contrast must be set with software command.
//#define LCD_DOGM
// The WITH_UART option enables the software UART (TTL level output at Pin PC3,
26).
// If the option is deselected, PC3 can be used as external voltage input with a
// 10:1 resistor divider.
//#define WITH_UART
// The CAP_EMPTY_LEVEL defines the empty voltage level for capacitors in mV.
// Choose a higher value, if your Tester reports "Cell!" by unloading capacitors.
#define CAP_EMPTY_LEVEL 4
// The AUTOSCALE_ADC option enables the autoscale ADC (ADC use VCC and Bandgap
Ref).
#define AUTOSCALE_ADC
#define REF_R_KORR 3
// The ESR_ZERO value define the zero value of ESR measurement (units = 0.01 Ohm).
//#define ESR_ZERO 29
#define ESR_ZERO 20
// NO_AREF_CAP tells your Software, that you have no Capacitor installed at pin
AREF (21).
// This enables a shorter wait-time for AUTOSCALE_ADC function.
// A capacitor with 1nF can be used with the option NO_AREF_CAP set.
#define NO_AREF_CAP
// The OP_MHZ option tells the software the Operating Frequency of your ATmega.
// OP_MHZ 16
// Restart from sleep mode will be delayed for 16384 clock tics with crystal mode.
// Operation with the internal RC-Generator or external clock will delay the
restart by only 6 clock tics.
// You must specify this with "#define RESTART_DELAY_TICS=6", if you don't use the
crystal mode.
//#define RESTART_DELAY_TICS 6
// The USE_EEPROM option specify where you wish to locate fix text and tables.
// If USE_EEPROM is unset, program memory (flash) is taken for fix text and tables.
//#define USE_EEPROM
// Setting EBC_STYPE will select the old style to present the order of Transistor
connection (EBC=...).
// Omitting the option will select the 123=... style. Every point is replaced by a
character identifying
// type of connected transistor pin (B=Base, E=Emitter, C=Collector, G=Gate,
S=Source, D=Drain).
// If you select EBC_STYLE=321 , the style will be 321=... , the inverted order to
the 123=... style.
//#define EBC_STYLE
//#define EBC_STYLE 321
// Setting of NO_NANO avoids the use of n as prefix for Farad (nF), the mikro
prefix is used insted (uF).
//#define NO_NANO
// The ANZ_MESS option specifies, how often an ADC value is read and accumulated.
// Possible values of ANZ_MESS are 5 to 200.
#define ANZ_MESS 25
// The POWER_OFF option enables the power off function, otherwise loop measurements
infinitely
// until power is disconnected with a ON/OFF switch (#define POWER_OFF).
// If you have the tester without the power off transistors, you can deselect
POWER_OFF .
// If you have NOT selected the POWER_OFF option with the transistors installed,
// you can stop measuring by holding the key several seconds after a result is
// displayed. After releasing the key, the tester will be shut off by timeout.
// Otherwise you can also specify, after how many measurements without found part
// the tester will shut down (#define POWER_OFF=5).
// The tester will also shut down with found part,
// but successfull measurements are allowed double of the specified number.
// You can specify up to 255 empty measurements (#define POWER_OFF=255).
//#define POWER_OFF 5
//#define POWER_OFF
// Option BAT_CHECK enables the Battery Voltage Check, otherwise the SW Version is
displayed instead of Bat.
// BAT_CHECK should be set for battery powered tester version.
//#define BAT_CHECK
// The BAT_OUT option enables Battery Voltage Output on LCD (if BAT_CHECK is
selected).
// If your 9V supply has a diode installed, use the BAT_OUT=600 form to specify the
// threshold voltage of your diode to adjust the output value.
// This threshold level is added to LCD-output and does not affect the voltage
checking levels.
//#define BAT_OUT 150
// The sleep mode of the ATmega168 or ATmega328 is normally used by the software to
save current.
// You can inhibit this with the option INHIBIT_SLEEP_MODE .
//#define INHIBIT_SLEEP_MODE
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
// ######## Configuration
#ifndef ADC_PORT
//#define DebugOut 3 // if set, output of voltages of resistor measurements in
row 2,3,4
//#define DebugOut 4 // if set, output of voltages of Diode measurement in row
3+4
//#define DebugOut 5 // if set, output of Transistor checks in row 2+3
//#define DebugOut 10 // if set, output of capacity measurements (ReadCapacity)
in row 3+4
/*
Port, that is directly connected to the probes.
This Port must have an ADC-Input (ATmega8: PORTC).
The lower pins of this Port must be used for measurements.
Please don't change the definitions of TP1, TP2 and TP3!
The TPREF pin can be connected with a 2.5V precision voltage reference
The TPext can be used with a 10:1 resistor divider as external voltage probe up
to 50V
*/
/*
exact values of used resistors (Ohm).
The standard value for R_L is 680 Ohm, for R_H 470kOhm.
To calibrate your tester the resistor-values can be adjusted:
*/
#define R_L_VAL 6800 // standard value 680 Ohm, multiplied by 10 for 0.1
Ohm resolution
//#define R_L_VAL 6690 // this will be define a 669 Ohm
#define R_H_VAL 47000 // standard value 470000 Ohm, multiplied by 10,
divided by 100
//#define R_H_VAL 47900 // this will be define a 479000 Ohm, divided by 100
/*
Port for the Test resistors
The Resistors must be connected to the lower 6 Pins of the Port in following
sequence:
RLx = 680R-resistor for Test-Pin x
RHx = 470k-resistor for Test-Pin x
RL1 an Pin 0
RH1 an Pin 1
RL2 an Pin 2
RH2 an Pin 3
RL3 an Pin 4
RH3 an Pin 5
*/
#ifdef STRIP_GRID_BOARD
// Strip Grid board version
#define RST_PIN 0 // Pin, is switched to low, if push button is
pressed
#else
// normal layout version
#define RST_PIN 17 // Pin, is switched to low, if push button is
pressed
#endif
#ifdef STRIP_GRID_BOARD
// special Layout for strip grid board
#define HW_LCD_EN_PORT PORTD
#define HW_LCD_EN_PIN 5
// With the option NO_CAP_HOLD_TIME you specify, that capacitor loaded with 680 Ohm
resistor will not
// be tested to hold the voltage same time as load time.
// Otherwise (without this option) the voltage drop during load time is compensated
to avoid displaying
// too much capacity for capacitors with internal parallel resistance.
// #define NO_CAP_HOLD_TIME
// U_SCALE can be set to 4 for better resolution of ReadADC function for resistor
measurement
#define U_SCALE 4
// Watchdog
//#define WDT_enabled
/*
If you remove the "#define WDT_enabled" , the Watchdog will not be activated.
This is only for Test or debugging usefull.
For normal operation please activate the Watchdog !
*/
// the following definitions specify where to load external data from: EEprom or
flash
#ifdef USE_EEPROM
#define MEM_TEXT EEMEM
#else
#define MEM_TEXT PROGMEM
#define MEM2_TEXT PROGMEM
#define MEM_read_word(a) pgm_read_word(a)
#define MEM_read_byte(a) pgm_read_byte(a)
#define MEM2_read_byte(a) pgm_read_byte(a)
#define MEM2_read_word(a) pgm_read_word(a)
#define lcd_fix2_string(a) lcd_pgm_string(a)
#define use_lcd_pgm
#endif
// CABLE_CAP defines the capacity (pF) of 12cm cable with clip at the terminal pins
#define CABLE_CAP 3
//------------------=========----------
#if PROCESSOR_TYP == 168
//------------------=========----------
#define MCU_STATUS_REG MCUCR
#define ADC_COMP_CONTROL ADCSRB
#define TI1_INT_FLAGS TIFR1
#define DEFAULT_BAND_GAP 1070
#define DEFAULT_RH_FAKT 884 // mega328 1070 mV
// LONG_HFE activates computation of current amplification factor with long
variables
#define LONG_HFE
// COMMON_COLLECTOR activates measurement of current amplification factor in
common collector circuit (Emitter follower)
#define COMMON_COLLECTOR
#define MEGA168A 17
#define MEGA168PA 18
//------------------=========----------
#elif PROCESSOR_TYP == 328
//------------------=========----------
#define MCU_STATUS_REG MCUCR
#define ADC_COMP_CONTROL ADCSRB
#define TI1_INT_FLAGS TIFR1
#define DEFAULT_BAND_GAP 1070
#define DEFAULT_RH_FAKT 884 // mega328 1070 mV
// LONG_HFE activates computation of current amplification factor with long
variables
#define LONG_HFE
// COMMON_COLLECTOR activates measurement of current amplification factor in
common collector circuit (Emitter follower)
#define COMMON_COLLECTOR
//------------------=========----------
#elif PROCESSOR_TYP == 1280
//------------------=========----------
#define MCU_STATUS_REG MCUCR
#define ADC_COMP_CONTROL ADCSRB
#define TI1_INT_FLAGS TIFR1
#define DEFAULT_BAND_GAP 1070
#define DEFAULT_RH_FAKT 884 // mega328 1070 mV
// LONG_HFE activates computation of current amplification factor with long
variables
#define LONG_HFE
// COMMON_COLLECTOR activates measurement of current amplification factor in
common collector circuit (Emitter follower)
#define COMMON_COLLECTOR
//------------------=========----------
#else
// ATmega8
//------------------=========----------
#define MCU_STATUS_REG MCUCSR
#define ADC_COMP_CONTROL SFIOR
#define TI1_INT_FLAGS TIFR
#define DEFAULT_BAND_GAP 1298 //mega8 1298 mV
#define DEFAULT_RH_FAKT 740 // mega8 1250 mV
// LONG_HFE activates computation of current amplification factor with long
variables
#define LONG_HFE
// COMMON_COLLECTOR activates measurement of current amplification factor in
common collector circuit (Emitter follower)
#define COMMON_COLLECTOR
#ifndef INHIBIT_SLEEP_MODE
#define INHIBIT_SLEEP_MODE /* do not use the sleep mode of ATmega */
#endif
#endif
#if PROCESSOR_TYP == 8
// 2.54V reference voltage + correction (fix for ATmega8)
#ifdef AUTO_CAL
#define ADC_internal_reference (2560 + (int8_t)eeprom_read_byte((uint8_t
*)&RefDiff))
#else
#define ADC_internal_reference (2560 + REF_R_KORR)
#endif
#else
// all other processors use a 1.1V reference
#ifdef AUTO_CAL
#define ADC_internal_reference (ref_mv + (int8_t)eeprom_read_byte((uint8_t
*)&RefDiff))
#else
#define ADC_internal_reference (ref_mv + REF_R_KORR)
#endif
#endif
#ifndef REF_R_KORR
#define REF_R_KORR 0
#endif
#ifndef REF_C_KORR
#define REF_C_KORR 0
#endif
#ifdef POWER_OFF
// if POWER OFF function is selected, wait 14s
// if POWER_OFF with parameter > 2, wait only 5s before repeating
#if (POWER_OFF+0) > 2
#define OFF_WAIT_TIME SHORT_WAIT_TIME
#else
#define OFF_WAIT_TIME LONG_WAIT_TIME
#endif
#else
// if POWER OFF function is not selected, wait 14s before repeat measurement
#define OFF_WAIT_TIME LONG_WAIT_TIME
#endif
//**********************************************************
// defines for the selection of a correctly ADC-Clock
// will match for 1MHz, 2MHz, 4MHz, 8MHz and 16MHz
// ADC-Clock can be 125000 or 250000
// 250 kHz is out of the full accuracy specification!
// clock divider is 4, when CPU_Clock==1MHz and ADC_Clock==250kHz
// clock divider is 128, when CPU_Clock==16MHz and ADC_Clock==125kHz
#define F_ADC 125000
//#define F_ADC 250000
#if F_CPU/F_ADC == 2
#define AUTO_CLOCK_DIV (1<<ADPS0)
#endif
#if F_CPU/F_ADC == 4
#define AUTO_CLOCK_DIV (1<<ADPS1)
#endif
#if F_CPU/F_ADC == 8
#define AUTO_CLOCK_DIV (1<<ADPS1) | (1<<ADPS0)
#endif
#if F_CPU/F_ADC == 16
#define AUTO_CLOCK_DIV (1<<ADPS2)
#endif
#if F_CPU/F_ADC == 32
#define AUTO_CLOCK_DIV (1<<ADPS2) | (1<<ADPS0)
#endif
#if F_CPU/F_ADC == 64
#define AUTO_CLOCK_DIV (1<<ADPS2) | (1<<ADPS1)
#endif
#if F_CPU/F_ADC == 128
#define AUTO_CLOCK_DIV (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
#endif
//**********************************************************
#define F_ADC_F 500000
#if F_CPU/F_ADC_F == 2
#define FAST_CLOCK_DIV (1<<ADPS0)
#endif
#if F_CPU/F_ADC_F == 4
#define FAST_CLOCK_DIV (1<<ADPS1)
#endif
#if F_CPU/F_ADC_F == 8
#define FAST_CLOCK_DIV (1<<ADPS1) | (1<<ADPS0)
#endif
#if F_CPU/F_ADC_F == 16
#define FAST_CLOCK_DIV (1<<ADPS2)
#endif
#if F_CPU/F_ADC_F == 32
#define FAST_CLOCK_DIV (1<<ADPS2) | (1<<ADPS0)
#endif
#if F_CPU/F_ADC_F == 64
#define FAST_CLOCK_DIV (1<<ADPS2) | (1<<ADPS1)
#endif
#if F_CPU/F_ADC_F == 128
#define FAST_CLOCK_DIV (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
#endif
#ifndef PIN_RP
#define PIN_RP 220 // estimated internal resistance PORT to VCC
// will only be used, if not set before in config.h
#endif
#ifndef PIN_RM
#define PIN_RM 190 // estimated internal resistance PORT to GND
// will only be used, if not set before in config.h
#endif
//**********************************************************
#ifdef SWUART_INVERT
#define TXD_VAL 0
#else
#define TXD_VAL TXD_MSK
#endif
#ifdef INHIBIT_SLEEP_MODE
// save memory, do not use the sleep mode
#define wait_about5ms() wait5ms()
#define wait_about10ms() wait10ms()
#define wait_about20ms() wait20ms()
#define wait_about30ms() wait30ms()
#define wait_about50ms() wait50ms()
#define wait_about100ms() wait100ms()
#define wait_about200ms() wait200ms()
#define wait_about300ms() wait300ms()
#define wait_about400ms() wait400ms()
#define wait_about500ms() wait500ms()
#define wait_about1s() wait1s()
#define wait_about2s() wait2s()
#define wait_about3s() wait3s()
#define wait_about4s() wait4s()
#else
// use sleep mode to save current for user interface
#define wait_about5ms() sleep_5ms(1)
#define wait_about10ms() sleep_5ms(2)
#define wait_about20ms() sleep_5ms(4)
#define wait_about30ms() sleep_5ms(6)
#define wait_about50ms() sleep_5ms(10)
#define wait_about100ms() sleep_5ms(20)
#define wait_about200ms() sleep_5ms(40)
#define wait_about300ms() sleep_5ms(60)
#define wait_about400ms() sleep_5ms(80)
#define wait_about500ms() sleep_5ms(100)
#define wait_about1s() sleep_5ms(200)
#define wait_about2s() sleep_5ms(400)
#define wait_about3s() sleep_5ms(600)
#define wait_about4s() sleep_5ms(800)
#endif
#undef AUTO_RH
#ifdef WITH_AUTO_REF
#define AUTO_RH
#else
#ifdef AUTO_CAL
#define AUTO_RH
#endif
#endif
#undef CHECK_CALL
#ifdef WITH_SELFTEST
// AutoCheck Function is needed
#define CHECK_CALL
#endif
#ifdef AUTO_CAL
// AutoCheck Function is needed
#define CHECK_CALL
#define RR680PL resis680pl
#define RR680MI resis680mi
#define RRpinPL pin_rpl
#define RRpinMI pin_rmi
#else
#define RR680PL (R_L_VAL + PIN_RP)
#define RR680MI (R_L_VAL + PIN_RM)
#define RRpinPL (PIN_RP)
#define RRpinMI (PIN_RM)
#endif
#ifndef ESR_ZERO
// define a default zero value for ESR measurement (0.01 Ohm units)
#define ESR_ZERO 20
#endif
#ifndef RESTART_DELAY_TICS
// define the processor restart delay for crystal oscillator 16K
// only set, if no preset (Makefile) exists.
#define RESTART_DELAY_TICS 16384
// for ceramic oscillator 258 or 1024 Clock tics can be selected with fuses
// for external oscillator or RC-oscillator is only a delay of 6 clock tics.
#endif
// with EBC_STYLE you can select the Pin-description in EBC= style instead of
123=??? style
//#define EBC_STYLE
#if EBC_STYLE == 123
// unset the option for the 123 selection, since this style is default.
#undef EBC_STYLE
#endif
#ifdef LCD_CYRILLIC
#define LCD_CHAR_OMEGA 4 // Omega-character
#define LCD_CHAR_U 5 // micro-character
#else
#define LCD_CHAR_OMEGA 244 // Omega-character
#define LCD_CHAR_U 228 // micro-character
#endif
#ifdef LCD_DOGM
#undef LCD_CHAR_OMEGA
#define LCD_CHAR_OMEGA 0x1e // Omega-character for DOGM module
#undef LCD_CHAR_U
#define LCD_CHAR_U 5 // micro-character for DOGM module loadable
#endif
// the hFE (B) can be determined with common collector and common emitter circuit
// with more than 16K both methodes are possible
#ifdef COMMON_COLLECTOR
#if FLASHEND > 0x3fff
#define COMMON_EMITTER
#endif
#else
#define COMMON_EMITTER
#endif
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
#define MAIN_C
// Big Capacities (>50uF) are measured with up to 500 load-pulses with the 680 Ohm
resistor.
// Each of this load-puls has an length of 10ms. After every load-pulse the
voltage of the
// capacitor is measured. If the voltage is more than 300mV, the capacity is
computed by
// interpolating the corresponding values of the table RLtab and multiply that with
the number
// of load pulses (*10).
// Widerstand 680 Ohm 300 325 350 375 400 425 450 475
500 525 550 575 600 625 650 675 700 725 750 775 800 825
850 875 900 925 950 975 1000 1025 1050 1075 1100 1125 1150 1175
1200 1225 1250 1275 1300 1325 1350 1375 1400 mV
const uint16_t RLtab[] MEM_TEXT =
{22447,20665,19138,17815,16657,15635,14727,13914,13182,12520,11918,11369,10865,1040
1, 9973, 9577, 9209, 8866, 8546, 8247, 7966, 7702, 7454, 7220, 6999, 6789, 6591,
6403, 6224, 6054, 5892, 5738, 5590, 5449, 5314, 5185, 5061, 4942, 4828, 4718, 4613,
4511, 4413, 4319, 4228};
#ifdef AUTO_RH
// resistor 470000 Ohm 1000 1050 1100 1150 1200 1250 1300 1350 1400 mV
const uint16_t RHtab[] PROGMEM = { 954, 903, 856, 814, 775, 740, 707, 676, 648};
#endif
#ifdef WITH_SELFTEST
const unsigned char SELFTEST[] MEM_TEXT = "Selftest mode..";
const unsigned char RELPROBE[] MEM_TEXT = "isolate Probe!";
const unsigned char ATE[] MEM_TEXT = "Test End";
#endif
#endif
#ifndef WITH_UART
//#define WITH_VEXT
#endif
#else
#ifndef BAT_CHECK
#ifndef WITH_UART
//#define WITH_VEXT
#endif
#endif
#endif
#ifdef WITH_VEXT
const unsigned char Vext_str[] MEM_TEXT = "Vext=";
#define LCD_CLEAR
#endif
#ifdef WITH_SELFTEST
const unsigned char URefT[] MEM2_TEXT = "Ref=";
const unsigned char RHfakt[] MEM2_TEXT = "RHf=";
const unsigned char RH1L[] MEM_TEXT = "RH-";
const unsigned char RH1H[] MEM_TEXT = "RH+";
const unsigned char RLRL[] MEM_TEXT = "+RL- 12 13 23";
const unsigned char RHRH[] MEM_TEXT = "+RH- 12 13 23";
const unsigned char RHRL[] MEM_TEXT = "RH/RL";
const unsigned char R0_str[] MEM2_TEXT = "R0=";
#define LCD_CLEAR
#endif
#ifdef CHECK_CALL
const unsigned char RIHI[] MEM_TEXT = "Ri_Hi=";
const unsigned char RILO[] MEM_TEXT = "Ri_Lo=";
const unsigned char C0_str[] MEM_TEXT = "C0 ";
const unsigned char T50HZ[] MEM_TEXT = " 50Hz";
#endif
#ifdef AUTO_CAL
const unsigned char MinCap_str[] MEM2_TEXT = " >100nF";
const unsigned char REF_C_str[] MEM2_TEXT = "REF_C=";
const unsigned char REF_R_str[] MEM2_TEXT = "REF_R=";
#endif
#ifdef DebugOut
#define LCD_CLEAR
#endif
const unsigned char DiodeIcon1[] MEM_TEXT = { 0x11, 0x19, 0x1d, 0x1f, 0x1d, 0x19,
0x11, 0x00 }; // Diode-Icon Anode left
const unsigned char DiodeIcon2[] MEM_TEXT = { 0x11, 0x13, 0x17, 0x1f, 0x17, 0x13,
0x11, 0x00 }; // Diode-Icon Anode right
const unsigned char CapIcon[] MEM_TEXT = { 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
0x1b, 0x00 }; // Capacitor Icon
const unsigned char ResIcon1[] MEM_TEXT = { 0x00, 0x0f, 0x08, 0x18, 0x08, 0x0f,
0x00, 0x00 }; // Resistor Icon1 left
const unsigned char ResIcon2[] MEM_TEXT = { 0x00, 0x1e, 0x02, 0x03, 0x02, 0x1e,
0x00, 0x00 }; // Resistor Icon2 right
const unsigned char OmegaIcon[] MEM_TEXT = { 0x00, 0x00, 0x0e, 0x11, 0x11, 0x0a,
0x1b, 0x00 }; // Omega Icon
const unsigned char MicroIcon[] MEM_TEXT = { 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0e,
0x09, 0x10 }; // Micro Icon
/*
// generate Omega- and u-character as Custom-character, if these characters has a
number of loadable type
#if LCD_CHAR_OMEGA < 8
const unsigned char CyrillicOmegaIcon[] MEM_TEXT = {0,0,14,17,17,10,27,0}; //
Omega
#endif
#if LCD_CHAR_U < 8
const unsigned char CyrillicMuIcon[] MEM_TEXT = {0,17,17,17,19,29,16,16}; //
micro
#endif
*/
#ifdef AUTO_CAL
//const uint16_t R680pl EEMEM = R_L_VAL+PIN_RP; // total resistor to VCC
//const uint16_t R680mi EEMEM = R_L_VAL+PIN_RM; // total resistor to GND
const int8_t RefDiff EEMEM = REF_R_KORR; // correction of internal Reference
Voltage
#endif
#ifdef AUTO_CAL
//const uint16_t cap_null EEMEM = C_NULL; // Zero offset of capacity measurement
const int16_t ref_offset EEMEM = REF_C_KORR; // default correction of internal
reference voltage for capacity measurement
// LoPin:HiPin 2:1 3:1 1:2 :
3:2 1:3 2:3
const uint8_t c_zero_tab[] EEMEM =
{ C_NULL,C_NULL,C_NULL+TP2_CAP_OFFSET,C_NULL,C_NULL+TP2_CAP_OFFSET,C_NULL,C_NULL };
// table of zero offsets
#endif
// End of EEPROM-Strings
#else
// no MAIN_C
#define COMMON extern
#ifdef WITH_SELFTEST
extern const unsigned char SELFTEST[] MEM_TEXT;
extern const unsigned char RELPROBE[] MEM_TEXT;
extern const unsigned char ATE[] MEM_TEXT;
#endif
#ifdef AUTO_CAL
//extern uint16_t R680pl;
//extern uint16_t R680mi;
extern int8_t RefDiff;
extern uint16_t ref_offset;
extern uint8_t c_zero_tab[];
#endif
#ifdef AUTO_RH
extern const uint16_t RHtab[];
#endif
#endif // MAIN_C
struct Diode_t {
uint8_t Anode;
uint8_t Cathode;
unsigned int Voltage;
};
COMMON struct {
unsigned long hfe[2]; // current amplification factor
unsigned int uBE[2]; // B-E-voltage of the Transistor
uint8_t b,c,e; // pins of the Transistor
}trans;
#ifndef INHIBIT_SLEEP_MODE
// with sleep mode we need a global ovcnt16
COMMON volatile uint16_t ovcnt16;
COMMON volatile uint8_t unfinished;
#endif
#ifdef AUTO_CAL
COMMON uint8_t pin_combination; // coded Pin-combination
2:1,3:1,1:2,x:x,3:2,1:3,2:3
COMMON uint16_t resis680pl; // port output resistance + 680
COMMON uint16_t resis680mi; // port output resistance + 680
COMMON uint16_t pin_rmi; // port output resistance to GND side, 0.1 Ohm units
COMMON uint16_t pin_rpl; // port output resistance to VCC side, 0.1 Ohm units
#endif
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
// definitions of parts
#define PART_NONE 0
#define PART_DIODE 1
#define PART_TRANSISTOR 2
#define PART_FET 3
#define PART_TRIAC 4
#define PART_THYRISTOR 5
#define PART_RESISTOR 6
#define PART_CAPACITOR 7
#define PART_CELL 8
// Bipolar
#define PART_MODE_NPN 1
#define PART_MODE_PNP 2
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
// wait functions
#define wait5s() delay(5000)
#define wait4s() delay(4000)
#define wait3s() delay(3000)
#define wait2s() delay(2000)
#define wait1s() delay(1000)
#define wait500ms() delay(500)
#define wait400ms() delay(400)
#define wait300ms() delay(300)
#define wait200ms() delay(200)
#define wait100ms() delay(100)
#define wait50ms() delay(50)
#define wait40ms() delay(40)
#define wait30ms() delay(30)
#define wait20ms() delay(20)
#define wait10ms() delay(10)
#define wait5ms() delay(5)
#define wait4ms() delay(4)
#define wait3ms() delay(3)
#define wait2ms() delay(2)
#define wait1ms() delay(1)
#define wait500us() delayMicroseconds(500)
#define wait400us() delayMicroseconds(400)
#define wait300us() delayMicroseconds(300)
#define wait200us() delayMicroseconds(200)
#define wait100us() delayMicroseconds(100)
#define wait50us() delayMicroseconds(50)
#define wait40us() delayMicroseconds(40)
#define wait30us() delayMicroseconds(30)
#define wait20us() delayMicroseconds(20)
#define wait10us() delayMicroseconds(10)
#define wait5us() delayMicroseconds(5)
#define wait4us() delayMicroseconds(4)
#define wait3us() delayMicroseconds(3)
#define wait2us() delayMicroseconds(2)
#define wait1us() delayMicroseconds(1)
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
// LCD-commands
#define CMD_ClearDisplay 0x01
#define CMD_ReturnHome 0x02
#define CMD_SetEntryMode 0x04
#define CMD_SetDisplayAndCursor 0x08
#define CMD_SetIFOptions 0x20
#define CMD_SetCGRAMAddress 0x40 // for Custom character
#define CMD_SetDDRAMAddress 0x80 // set Cursor
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
#ifndef INHIBIT_SLEEP_MODE
// prepare sleep mode
EMPTY_INTERRUPT(TIMER2_COMPA_vect);
EMPTY_INTERRUPT(ADC_vect);
#endif
uint8_t tmp = 0;
//unsigned int PRR;
byte TestKey;
byte TestKeyPin = 17; // A3
pinMode(TestKeyPin, INPUT);
lcd.init();
//lcd.begin(16,2);
lcd.backlight();
//lcd_init(); // initialize LCD
//ON_DDR = 0;
//ON_PORT = 0;
/*
// switch on
ON_DDR = (1<<ON_PIN); // switch to output
#ifdef PULLUP_DISABLE
ON_PORT = (1<<ON_PIN); // switch power on
#else
ON_PORT = (1<<ON_PIN)|(1<<RST_PIN); // switch power on , enable internal
Pullup for Start-Pin
#endif
*/
// ADC-Init
ADCSRA = (1<<ADEN) | AUTO_CLOCK_DIV; // prescaler=8 or 64 (if 8Mhz clock)
#ifdef __AVR_ATmega8__
//#define WDRF_HOME MCU_STATUS_REG
#define WDRF_HOME MCUCSR
#else
#define WDRF_HOME MCUSR
#endif
/*
tmp = (WDRF_HOME & (1<<WDRF)); // save Watch Dog Flag
WDRF_HOME &= ~(1<<WDRF); // reset Watch Dog flag
wdt_disable(); // disable Watch Dog
*/
/*
#ifndef INHIBIT_SLEEP_MODE
// switch off unused Parts
PRR = (1<<PRTWI) | (1<<PRTIM0) | (1<<PRSPI) | (1<<PRUSART0);
DIDR0 = (1<<ADC5D) | (1<<ADC4D) | (1<<ADC3D);
TCCR2A = (0<<WGM21) | (0<<WGM20); // Counter 2 normal mode
#if F_CPU <= 1000000UL
TCCR2B = (1<<CS22) | (0<<CS21) | (1<<CS20); // prescaler 128, 128us @ 1MHz
#define T2_PERIOD 128
#endif
#if F_CPU == 2000000UL
TCCR2B = (1<<CS22) | (1<<CS21) | (0<<CS20); // prescaler 256, 128us @ 2MHz
#define T2_PERIOD 128
#endif
#if F_CPU == 4000000UL
TCCR2B = (1<<CS22) | (1<<CS21) | (0<<CS20); // prescaler 256, 64us @ 2MHz
#define T2_PERIOD 64
#endif
#if F_CPU >= 8000000UL
TCCR2B = (1<<CS22) | (1<<CS21) | (1<<CS20); // prescaler 1024, 128us @ 8MHz,
64us @ 16MHz
#define T2_PERIOD (1024 / (F_CPU / 1000000UL)); // set to 128 or 64 us
#endif
sei(); // enable interrupts
#endif
*/
//ADC_PORT = TXD_VAL;
//ADC_DDR = TXD_MSK;
if(tmp) {
// check if Watchdog-Event
// this happens, if the Watchdog is not reset for 2s
// can happen, if any loop in the Program doen't finish.
lcd_line1();
lcd_fix_string(TestTimedOut); // Output Timeout
wait_about3s(); // wait for 3 s
//ON_PORT = 0; // shut off!
//ON_DDR = (1<<ON_PIN); // switch to GND
//return;
}
#ifdef PULLUP_DISABLE
#ifdef __AVR_ATmega8__
SFIOR = (1<<PUD); // disable Pull-Up Resistors mega8
#else
MCUCR = (1<<PUD); // disable Pull-Up Resistors mega168 family
#endif
#endif
/*
#if POWER_OFF+0 > 1
// tester display time selection
display_time = OFF_WAIT_TIME; // LONG_WAIT_TIME for single mode, else
SHORT_WAIT_TIME
if (!(ON_PIN_REG & (1<<RST_PIN))) {
// if power button is pressed ...
wait_about300ms(); // wait to catch a long key press
if (!(ON_PIN_REG & (1<<RST_PIN))) {
// check if power button is still pressed
display_time = LONG_WAIT_TIME; // ... set long time display anyway
}
}
#else
#define display_time OFF_WAIT_TIME
#endif
*/
empty_count = 0;
mess_count = 0;
}
void loop()
{
// Entry: if start key is pressed before shut down
start:
TestKey = 1;
while(TestKey) {
TestKey = digitalRead(TestKeyPin);
delay(100);
}
while(!TestKey) {
TestKey = digitalRead(TestKeyPin);
delay(100);
}
lcd_clear();
delay(100);
#ifdef WITH_UART
uart_newline(); // start of new measurement
#endif
ADCconfig.RefFlag = 0;
Calibrate_UR(); // get Ref Voltages and Pin resistance
lcd_line1(); // 1 row
#ifdef BAT_CHECK
// Battery check is selected
ReadADC(TPBAT); // Dummy-Readout
trans.uBE[0] = W5msReadADC(TPBAT); // with 5V reference
lcd_fix_string(Bat_str); // output: "Bat. "
#ifdef BAT_OUT
// display Battery voltage
// The divisor to get the voltage in 0.01V units is ((10*33)/133) witch is
about 2.4812
// A good result can be get with multiply by 4 and divide by 10 (about
0.75%).
//cap.cval = (trans.uBE[0]*4)/10+((BAT_OUT+5)/10); // usually output only 2
digits
//DisplayValue(cap.cval,-2,'V',2); // Display 2 Digits of this 10mV units
cap.cval = (trans.uBE[0]*4)+BAT_OUT; // usually output only 2 digits
DisplayValue(cap.cval,-3,'V',2); // Display 2 Digits of this 10mV units
lcd_space();
#endif
#else
lcd_fix2_string(VERSION_str); // if no Battery check, Version .. in row 1
#endif
#ifdef WDT_enabled
//wdt_enable(WDTO_2S); // Watchdog on
#endif
// begin tests
#ifdef AUTO_RH
RefVoltage(); // compute RHmultip = f(reference voltage)
#endif
#ifdef WITH_VEXT
// show the external voltage
while (!(ON_PIN_REG & (1<<RST_PIN))) {
lcd_line2();
lcd_clear_line();
lcd_line2();
lcd_fix_string(Vext_str); // Vext=
ADC_DDR = 0; // deactivate Software-UART
trans.uBE[1] = W5msReadADC(TPext); // read external voltage
ADC_DDR = TXD_MSK; // activate Software-UART
#ifdef WITH_UART
uart_newline(); // start of new measurement
#endif
#ifndef DebugOut
lcd_line2(); // LCD position row 2, column 1
#endif
if(PartFound == PART_CELL) {
lcd_clear();
lcd_fix_string(Cell_str); // display "Cell!"
goto end2;
}
#ifdef CHECK_CALL
AutoCheck(); // check, if selftest should be done
#endif
if(PartFound == PART_DIODE) {
if(NumOfDiodes == 1) { // single Diode
//lcd_fix_string(Diode); // "Diode: "
#else
// too less memory to sort the pins
lcd_testpin(diodes[0].Anode);
lcd_fix_string(AnKat); // "->|-"
lcd_testpin(diodes[0].Cathode);
#endif
UfOutput(0x70);
// load current of capacity is (5V-1.1V)/(470000 Ohm) = 8298nA
lcd_fix_string(GateCap_str); // "C="
ReadCapacity(diodes[0].Cathode,diodes[0].Anode); // Capacity opposite flow
direction
DisplayValue(cap.cval,cap.cpre,'F',3);
goto end;
} else if(NumOfDiodes == 3) {
// Serial of 2 Diodes; was detected as 3 Diodes
trans.b = 3;
trans.c = 3;
if(diodes[0].Cathode == diodes[1].Anode) {
trans.b = 0;
trans.c = 1;
}
if(diodes[0].Anode == diodes[1].Cathode) {
trans.b = 1;
trans.c = 0;
}
if(diodes[0].Cathode == diodes[2].Anode) {
trans.b = 0;
trans.c = 2;
}
if(diodes[0].Anode == diodes[2].Cathode) {
trans.b = 2;
trans.c = 0;
}
if(diodes[1].Cathode == diodes[2].Anode) {
trans.b = 1;
trans.c = 2;
}
if(diodes[1].Anode == diodes[2].Cathode) {
trans.b = 2;
trans.c = 1;
}
#if DebugOut == 4
lcd_line3();
lcd_testpin(diodes[0].Anode);
lcd_data(':');
lcd_testpin(diodes[0].Cathode);
lcd_space();
lcd_string(utoa(diodes[0].Voltage, outval, 10));
lcd_space();
lcd_testpin(diodes[1].Anode);
lcd_data(':');
lcd_testpin(diodes[1].Cathode);
lcd_space();
lcd_string(utoa(diodes[1].Voltage, outval, 10));
lcd_line4();
lcd_testpin(diodes[2].Anode);
lcd_data(':');
lcd_testpin(diodes[2].Cathode);
lcd_space();
lcd_string(utoa(diodes[2].Voltage, outval, 10));
lcd_line1();
#endif
if(PartMode == PART_MODE_NPN) {
lcd_fix_string(NPN_str); // "NPN "
} else {
lcd_fix_string(PNP_str); // "PNP "
}
#ifdef EBC_STYLE
#if EBC_STYLE == 321
// Layout with 321= style
if (((PartMode == PART_MODE_NPN) && (trans.c < trans.e)) || ((PartMode !=
PART_MODE_NPN) && (trans.c > trans.e)))
#else
// Layout with EBC= style
if(PartMode == PART_MODE_NPN)
#endif
#else
// Layout with 123= style
if (((PartMode == PART_MODE_NPN) && (trans.c > trans.e)) || ((PartMode !=
PART_MODE_NPN) && (trans.c < trans.e)))
#endif
{
lcd_fix_string(AnKat); // "->|-"
} else {
lcd_fix_string(KatAn); // "-|<-"
}
}
lcd_fix_string(Uf_str); // "Uf="
DisplayValue(trans.uBE[0],-3,'V',3);
goto end;
if(PartMode&1) {
lcd_data('P'); // P-channel
} else {
lcd_data('N'); // N-channel
}
lcd_data('-');
tmp = PartMode/2;
if (tmp == (PART_MODE_N_D_MOS/2)) {
lcd_data('D'); // N-D
}
if (tmp == (PART_MODE_N_E_MOS/2)) {
lcd_data('E'); // N-E
}
if (tmp == (PART_MODE_N_JFET/2)) {
lcd_fix_string(jfet_str); // "JFET"
} else {
lcd_fix_string(mosfet_str); // "-MOS "
}
#ifdef EBC_STYLE
#if EBC_STYLE == 321
// layout with 321= style
if (((PartMode&1) && (trans.c > trans.e)) || ((!(PartMode&1)) && (trans.c
< trans.e)))
#else
// Layout with SGD= style
if (PartMode&1) // N or P MOS
#endif
#else
// layout with 123= style
if (((PartMode&1) && (trans.c < trans.e)) || ((!(PartMode&1)) && (trans.c >
trans.e)))
#endif
{
lcd_data(LCD_CHAR_DIODE1); // show Diode symbol >|
} else {
lcd_data(LCD_CHAR_DIODE2); // show Diode symbol |<
}
}
lcd_line2(); // 2 row
// Gate-threshold voltage
DisplayValue(gthvoltage,-3,'V',2);
goto end;
if (ResistorsFound == 2) {
ii = 2;
} else {
if (resis[2].rx > resis[ii].rx)
ii = 2;
}
char x = '1';
char y = '3';
char z = '2';
if (ii == 1) {
//x = '1';
y = '2';
z = '3';
}
if (ii == 2) {
x = '2';
y = '1';
z = '3';
}
lcd_data(x);
lcd_fix_string(Resistor_str); // "-[=]-"
lcd_data(y);
lcd_fix_string(Resistor_str); // "-[=]-"
lcd_data(z);
}
lcd_line2(); // 2 row
if (ResistorsFound == 1) {
RvalOut(0);
} else {
// output resistor values in right order
if (ii == 0) {
RvalOut(1);
RvalOut(2);
}
if (ii == 1) {
RvalOut(0);
RvalOut(2);
}
if (ii == 2) {
RvalOut(0);
RvalOut(1);
}
}
goto end;
lcd_line2(); // 2 row
DisplayValue(cap.cval_max,cap.cpre_max,'F',4);
goto end;
}
empty_count++;
mess_count = 0;
goto end2;
gakOutput:
lcd_line2(); // 2 row
PinLayout(Cathode_char,'G','A'); // CGA= or 123=...
//- - - - - - - - - - - - - - - - - - - - - - - - - - - -
end:
empty_count = 0; // reset counter, if part is found
mess_count++; // count measurements
end2:
//ADC_DDR = (1<<TPREF) | TXD_MSK; // switch pin with reference to GND, release
relay
ADC_DDR = TXD_MSK; // switch pin with reference to GND, release
relay
goto start;
for(gthvoltage = 0;gthvoltage<display_time;gthvoltage+=10) {
if(!(ON_PIN_REG & (1<<RST_PIN))) {
// If the key is pressed again...
// goto start of measurement
goto start;
}
wdt_reset();
wait_about10ms();
}
#ifdef POWER_OFF
#if POWER_OFF > 127
#define POWER2_OFF 255
#else
#define POWER2_OFF POWER_OFF*2
#endif
#else
goto start; // POWER_OFF not selected, repeat measurement
#endif
return;
} // end main
//******************************************************************
// output of flux voltage for 1-2 diodes in row 2
// bcdnum = Numbers of both Diodes:
// higher 4 Bit number of first Diode
// lower 4 Bit number of second Diode (Structure diodes[nn])
// if number >= 3 no output is done
void UfOutput(uint8_t bcdnum) {
lcd_line2(); // 2 row
lcd_fix_string(Uf_str); // "Uf="
mVOutput(bcdnum >> 4);
mVOutput(bcdnum & 0x0f);
}
lcd_space();
}
//******************************************************************
if(ChargeDirection&1) {
R_PORT |= PinToCharge; // R_PORT to 1 (VCC)
} else {
R_PORT &= ~PinToCharge; // or 0 (GND)
}
R_DDR |= PinToCharge; // switch Pin to output, across R to GND or VCC
wait_about10ms(); // wait about 10ms
// switch back Input, no current
R_DDR &= ~PinToCharge; // switch back to input
R_PORT &= ~PinToCharge; // no Pull up
}
for(lop_cnt=0;lop_cnt<10;lop_cnt++) {
adc_gnd = TXD_MSK; // put all ADC to Input
ADC_DDR = adc_gnd;
ADC_PORT = TXD_VAL; // ADC-outputs auf 0
R_PORT = 0; // R-outputs auf 0
R_DDR = (2<<(TP3*2)) | (2<<(TP2*2)) | (2<<(TP1*2)); // R_H for all Pins to GND
// all Pins with voltage lower than 1V can be connected directly to GND (ADC-
Port)
if (adcmv[0] < 1000) {
adc_gnd |= (1<<TP1); // Pin 1 directly to GND
}
if (adcmv[1] < 1000) {
adc_gnd |= (1<<TP2); // Pin 2 directly to GND
}
if (adcmv[2] < 1000) {
adc_gnd |= (1<<TP3); // Pin 3 directly to GND
}
ADC_DDR = adc_gnd; // switch all selected ADC-Ports at the same time
for(clr_cnt=0;clr_cnt<MAX_ENTLADE_ZEIT;clr_cnt++) {
wdt_reset();
adcmv[0] = W20msReadADC(TP1); // which voltage has Pin 1?
adcmv[1] = ReadADC(TP2); // which voltage has Pin 2?
adcmv[2] = ReadADC(TP3); // which voltage has Pin 3?
if (clr_cnt == MAX_ENTLADE_ZEIT) {
PartFound = PART_CELL; // mark as Battery
// there is charge on capacitor, warn later!
}
for(adcmv[0]=0;adcmv[0]<clr_cnt;adcmv[0]++) {
// for safety, discharge 5% of discharge time
wait1ms();
}
} // end for lop_cnt
}
#ifdef AUTO_RH
void RefVoltage(void) {
// RefVoltage interpolates table RHtab corresponding to voltage ref_mv .
// RHtab contain the factors to get capacity from load time with 470k for
// different Band gab reference voltages.
// for remember:
// resistor 470000 Ohm 1000 1050 1100 1150 1200 1250 1300 1350 1400 mV
// uint16_t RHTAB[] MEM_TEXT = { 954, 903, 856, 814, 775, 740, 707, 676, 648};
#ifdef AUTO_CAL
referenz = ref_mv + (int16_t)eeprom_read_word((uint16_t *)(&ref_offset));
#else
referenz = ref_mv + REF_C_KORR;
#endif
if (tabind > 7) {
tabind = 7; // limit to end of table
}
#ifdef LCD_CLEAR
void lcd_clear_line(void) {
// writes 20 spaces to LCD-Display, Cursor must be positioned to first column
unsigned char ll;
for (ll=0;ll<20;ll++) {
lcd_space();
}
}
#endif
/* ************************************************************************
* display of values and units
* ************************************************************************ */
/*
* display value and unit
* - max. 4 digits excluding "." and unit
*
* requires:
* - value
* - exponent of factor related to base unit (value * 10^x)
* e.g: p = 10^-12 -> -12
* - unit character (0 = none)
* digits = 2, 3 or 4
*/
void DisplayValue(unsigned long Value, int8_t Exponent, unsigned char Unit,
unsigned char digits)
{
char OutBuffer[15];
unsigned int Limit;
unsigned char Prefix; // prefix character
uint8_t Offset; // exponent of offset to next 10^3 step
uint8_t Index; // index ID
uint8_t Length; // string length
// determine prefix
if (Offset > 0)
{
Index++; // adjust index for exponent offset, take next prefix
Offset = 3 - Offset; // reverse value (1 or 2)
}
#ifdef NO_NANO
if (Index == 1)
{ // use no nano
Index++; // use mikro instead of nano
Offset += 3; // can be 3,4 or 5
}
#endif
// display value
// position of dot
Exponent = Length - Offset; // calculate position
#ifdef NO_NANO
while (Exponent < 0)
{
lcd_data('0'); // extra 0 for factor 10
Exponent++;
}
#else
if (Exponent < 0) lcd_data('0'); // extra 0 for factor 100
#endif
}
#ifndef INHIBIT_SLEEP_MODE
// set the processor to sleep state
// wake up will be done with compare match interrupt of counter 2
void sleep_5ms(uint16_t pause){
// pause is the delay in 5ms units
uint8_t t2_offset;
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
//set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
// wake up after output compare match interrupt
#else
// restart delay ist too long, use normal delay of 5ms
wait5ms();
#endif
wdt_reset();
}
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
void AutoCheck(void) {
#ifdef WITH_SELFTEST
#ifdef AUTO_CAL
uint8_t cap_found; // counter for found capacitor
#ifdef AUTOSCALE_ADC
int8_t udiff; // difference between ADC Voltage with VCC or Bandgap
reference
int8_t udiff2;
#endif
#endif
ADC_PORT = TXD_VAL;
ADC_DDR = TXD_MSK;
#define RequireShortedProbes
if (AllProbesShorted() != 3) return;
lcd_clear();
lcd_fix_string(SELFTEST); // "Selftest mode.."
lcd_line2();
lcd_fix2_string(R0_str); // "R0="
DisplayValue(adcmv[0],-2,' ',3);
DisplayValue(adcmv[1],-2,' ',3);
DisplayValue(adcmv[2],-2,LCD_CHAR_OMEGA,3);
if (tt == 5) { // can we switch the ADC pins to GND across R_H resistor?
R_PORT = 0;
R_DDR = 2<<(TP1*2); // Pin 1 over R_H to GND
adcmv[0] = W20msReadADC(TP1);
if (tt == 6) { // can we switch the ADC pins to VCC across the R_H resistor?
R_DDR = 2<<(TP1*2); // Pin 1 over R_H to VCC
R_PORT = 2<<(TP1*2);
adcmv[0] = W20msReadADC(TP1) - ADCconfig.U_AVCC;
R_DDR = 2<<(TP2*2); // Pin 2 over R_H to VCC
R_PORT = 2<<(TP2*2);
adcmv[1] = W20msReadADC(TP2) - ADCconfig.U_AVCC;
R_DDR = 2<<(TP3*2); // Pin 3 over R_H to VCC
R_PORT = 2<<(TP3*2);
adcmv[2] = W20msReadADC(TP3) - ADCconfig.U_AVCC;
lcd_fix_string(RH1H); // "RH_Hi="
}
if (tt == 7) { // can we switch the ADC pins to VCC across the R_H resistor?
u680 = ((long)ADCconfig.U_AVCC * (PIN_RM + R_L_VAL) / (PIN_RM + R_L_VAL +
R_H_VAL*100));
R_PORT = 2<<(TP1*2); // RH1 to VCC
R_DDR = (2<<(TP1*2)) | (1<<(TP1*2)); // RH1 to +, RL1 to -
adcmv[0] = W20msReadADC(TP1);
adcmv[0] -= u680;
R_PORT = 2<<(TP2*2); // RH2 to VCC
R_DDR = (2<<(TP2*2)) | (1<<(TP2*2)); // RH2 to +, RL2 to -
adcmv[1] = W20msReadADC(TP2);
adcmv[1] -= u680;
R_PORT = 2<<(TP3*2); // RH3 to VCC
R_DDR = (2<<(TP3*2)) | (1<<(TP3*2)); // RH3 to +, RL3 to -
adcmv[2] = W20msReadADC(TP3);
adcmv[2] -= u680;
lcd_fix_string(RHRL); // "RH/RL"
}
} // end for ww
wait_about1s();
} // end for tt
lcd_clear();
lcd_fix_string(RIHI); // "RiHi="
DisplayValue(RRpinPL,-1,LCD_CHAR_OMEGA,3);
lcd_line2();
lcd_fix_string(RILO); // "RiLo="
DisplayValue(RRpinMI,-1,LCD_CHAR_OMEGA,3);
wait_about2s();
lcd_clear();
lcd_fix_string(C0_str); // output "C0 "
DisplayValue(adcmv[5],0,' ',3); // output cap0 1:3
DisplayValue(adcmv[6],0,' ',3); // output cap0 2:3
DisplayValue(adcmv[2],-12,'F',3); // output cap0 1:2
#ifdef AUTO_CAL
for (ww=0;ww<7;ww++) {
if (adcmv[ww] > 70) goto no_c0save;
}
for (ww=0;ww<7;ww++) {
// write all zero offsets to the EEprom
(void) eeprom_write_byte((uint8_t *)(&c_zero_tab[ww]),adcmv[ww]+(COMP_SLEW1 /
(CC0 + CABLE_CAP + COMP_SLEW2)));
}
lcd_line2();
lcd_fix_string(OK_str); // output "OK"
no_c0save:
#endif
wait_about2s();
#ifdef AUTO_CAL
// Message C > 100nF
cap_found = 0;
for (ww=0; ww<64; ww++) {
lcd_clear();
lcd_data('1');
lcd_fix_string(CapZeich); // "-||-"
lcd_data('3');
lcd_fix2_string(MinCap_str); // " >100nF!"
PartFound = PART_NONE;
// measure offset Voltage of analog Comparator for Capacity measurement
ReadCapacity(TP3, TP1); // look for capacitor > 100nF
if ((cap.cpre == -9) && (cap.cval > 95) && (cap.cval < 22000)) {
cap_found++;
} else {
cap_found = 0; // wait for stable connection
}
if (cap_found > 1) {
// value of capacitor is correct
(void) eeprom_write_word((uint16_t *)(&ref_offset), load_diff); // hold
zero offset + slew rate dependend offset
lcd_clear();
lcd_fix2_string(REF_C_str); // "REF_C="
lcd_string(itoa(load_diff, outval, 10)); // output REF_C_KORR
#if 0
// Test for switching level of the digital input of port TP3
for (ii=0;ii<8;ii++) {
ADC_PORT = TXD_VAL; // ADC-Port 1 to GND
ADC_DDR = 1<<TP1 | TXD_MSK; // ADC-Pin 1 to output 0V
R_PORT = 2<<(TP3*2); // Pin 3 over R_H to VCC
R_DDR = 2<<(TP3*2); // Pin 3 over R_H to VCC
while (1) {
wdt_reset();
if ((ADC_PIN&(1<<TP3)) == (1<<TP3)) break;
}
while (1) {
wdt_reset();
if ((ADC_PIN&(1<<TP3)) != (1<<TP3)) break;
}
#ifdef AUTOSCALE_ADC
ADC_PORT = TXD_VAL; // ADC-Port 1 to GND
ADC_DDR = 1<<TP1 | TXD_MSK; // ADC-Pin 1 to output 0V
R_DDR = 2<<(TP3*2); // Pin 3 over R_H to GND
do {
adcmv[0] = ReadADC(TP3);
} while (adcmv[0] > 980);
lcd_line2();
lcd_fix2_string(REF_R_str); // "REF_R="
wait_about4s();
break;
}
lcd_line2();
DisplayValue(cap.cval,cap.cpre,'F',4);
wait_about200ms(); // wait additional time
} // end for ww
#endif
lcd_clear();
lcd_line2();
lcd_fix2_string(VERSION_str); // "Version ..."
lcd_line1();
lcd_fix_string(ATE); // "Selftest End"
#ifdef FREQUENCY_50HZ
//#define TEST_SLEEP_MODE // only select for checking the sleep delay
lcd_fix_string(T50HZ); // " 50Hz"
ADC_PORT = TXD_VAL;
ADC_DDR = 1<<TP1 | TXD_MSK; // Pin 1 to GND
R_DDR = (1<<(TP3*2)) | (1<<(TP2*2));
#ifdef TEST_SLEEP_MODE
sleep_5ms(2); // test of timing of sleep mode call
#else
wait10ms(); // normal delay
#endif
R_PORT = (1<<(TP3*2)); // Pin 3 over R_L to VCC, Pin 2 over R_L to GND
#ifdef TEST_SLEEP_MODE
sleep_5ms(2); // test of timing of sleep mode call
#else
wait10ms(); // normal delay
#endif
wdt_reset();
}
PartFound = PART_NONE;
wait_about1s();
#endif
}
#ifdef RequireShortedProbes
/*
* check for a short circuit between two probes
* from Markus R.
*
* requires:
* - ID of first probe (0-2)
* - ID of second probe (0-2)
*
* returns:
* - 0 if not shorted
* - 1 if shorted
*/
R_PORT = pgm_read_byte(&PinRLtab[Probe1]);
R_DDR = pgm_read_byte(&PinRLtab[Probe1]) | pgm_read_byte(&PinRLtab[Probe2]);
// read voltages
U1 = ReadADC(Probe1);
U2 = ReadADC(Probe2);
URH = ADCconfig.U_AVCC / 2;
if ((U1 > URH - 20) && (U1 < URH + 20))
{
if ((U2 > URH - 20) && (U2 < URH + 20))
{
Flag1 = 1;
}
}
// reset port
R_DDR = 0;
return Flag1;
}
/*
* check for a short circuit between all probes
* from Markus R.
*
* returns:
* - 0 if no probes are short-circuited
* - number of probe pairs short-circuited (3 = all)
*/
uint8_t AllProbesShorted(void)
{
uint8_t Flag2; // return value
// check all possible combinations
Flag2 = ShortedProbes(TP1, TP2);
Flag2 += ShortedProbes(TP1, TP3);
Flag2 += ShortedProbes(TP2, TP3);
return Flag2;
}
#endif
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
//******************************************************************
void CheckPins(uint8_t HighPin, uint8_t LowPin, uint8_t TristatePin) {
/*
Function for checking the characteristic of a component with the following pin
assignment
parameters:
HighPin: Pin, which will be switched to VCC at the beginning
LowPin: Pin, which will be switch to GND at the beginning
TristatePin: Pin, which will be undefined at the beginning
TristatePin will be switched to GND and VCC also .
*/
struct {
unsigned int lp_otr;
unsigned int hp1;
unsigned int hp2;
unsigned int hp3;
unsigned int lp1;
unsigned int lp2;
unsigned int tp1;
unsigned int tp2;
} adc;
uint8_t LoPinRL; // mask to switch the LowPin with R_L
uint8_t LoPinRH; // mask to switch the LowPin with R_H
uint8_t TriPinRL; // mask to switch the TristatePin with R_L
uint8_t TriPinRH; // mask to switch the TristatePin with R_H
uint8_t HiPinRL; // mask to switch the HighPin with RL
uint8_t HiPinRH; // mask to switch the HighPin with R_H
uint8_t HiADCp; // mask to switch the ADC port High-Pin
uint8_t LoADCp; // mask to switch the ADC port Low-Pin
uint8_t HiADCm; // mask to switch the ADC DDR port High-Pin
uint8_t LoADCm; // mask to switch the ADC DDR port Low-Pin
uint8_t PinMSK;
uint8_t ii; // temporary variable
#ifdef COMMON_EMITTER
unsigned int tmp16; // temporary variable
#else
#warning "without common emitter hFE"
#endif
#ifdef COMMON_COLLECTOR
unsigned long c_hfe; // amplification factor for common Collector (Emitter
follower)
#endif
/*
switch HighPin directls to VCC
switch R_L port for LowPin to GND
TristatePin remains switched to input , no action required
*/
wdt_reset();
//#ifdef AUTO_CAL
// uint16_t resis680pl;
// uint16_t resis680mi;
// resis680pl = eeprom_read_word(&R680pl);
// resis680mi = eeprom_read_word(&R680mi);
// #define RR680PL resis680pl
// #define RR680MI resis680mi
//#else
// #define RR680PL (R_L_VAL + PIN_RP)
// #define RR680MI (R_L_VAL + PIN_RM)
//#endif
// setting of Pins
R_PORT = 0; // resistor-Port outputs to 0
R_DDR = LoPinRL; // Low-Pin to output and across R_L to GND
ADC_DDR = HiADCm; // High-Pin to output
ADC_PORT = HiADCp; // High-Pin fix to Vcc
#if DebugOut == 5
lcd_line2();
lcd_clear_line();
lcd_line2();
#endif
if (adc.lp2>3911) { // MOSFET
PartFound = PART_FET; // N-Kanal-MOSFET
PartMode = PART_MODE_N_D_MOS; // Depletion-MOSFET
} else { // JFET (pn-passage between Gate and Source is conducting )
PartFound = PART_FET; // N-Kanal-JFET
PartMode = PART_MODE_N_JFET;
}
#if DebugOut == 5
lcd_data('N');
lcd_data('J');
#endif
if (adc.tp2<977) { // MOSFET
PartFound = PART_FET; // P-Kanal-MOSFET
PartMode = PART_MODE_P_D_MOS; // Depletion-MOSFET
} else { // JFET (pn-passage between Gate and Source is conducting)
PartFound = PART_FET; // P-Kanal-JFET
PartMode = PART_MODE_P_JFET;
}
#if DebugOut == 5
lcd_data('P');
lcd_data('J');
#endif
#ifdef COMMON_COLLECTOR
// Test circuit with common collector (Emitter follower) PNP
ADC_PORT = TXD_VAL;
ADC_DDR = LoADCm; // Collector direct to GND
R_PORT = HiPinRL; // switch R_L port for HighPin (Emitter) to VCC
R_DDR = TriPinRL | HiPinRL; // Base resistor R_L to GND
adc.hp1 = ADCconfig.U_AVCC - W5msReadADC(HighPin); // voltage at the Emitter
resistor
adc.tp1 = ReadADC(TristatePin); // voltage at the base resistor
#ifdef LONG_HFE
c_hfe = ((unsigned long)adc.hp1 * (unsigned long)(((unsigned long)R_H_VAL *
100) /
(unsigned int)RR680PL)) / (unsigned int)adc.tp1;
#else
c_hfe = ((adc.hp1 / ((RR680PL+500)/1000)) * (R_H_VAL/500)) / (adc.tp1/500);
#endif
} else {
c_hfe = (unsigned long)((adc.hp1 - adc.tp1) / adc.tp1);
}
#endif
#if DebugOut == 5
lcd_testpin(LowPin);
lcd_data('P');
lcd_testpin(HighPin);
lcd_space();
wait_about1s();
#endif
// Test to PNP
R_DDR = LoPinRL | TriPinRL; // switch R_L port for Tristate-Pin to output
(GND), for Test of PNP
adc.lp1 = W5msReadADC(LowPin); // measure voltage at LowPin
#ifdef COMMON_EMITTER
trans.uBE[PartReady] = ReadADC(HighPin) - adc.tp2; // Base Emitter Voltage
adc.tp2 = 53;
}
tmp16 = adc.lp1;
#ifdef LONG_HFE
trans.hfe[PartReady] = ((unsigned int)tmp16 * (unsigned long)(((unsigned
long)R_H_VAL * 100) /
(unsigned int)RR680MI)) / (unsigned int)adc.tp2;
#else
trans.hfe[PartReady] = ((tmp16 / ((RR680MI+500)/1000)) * (R_H_VAL/500)) /
(adc.tp2/500);
#endif
#endif
#ifdef COMMON_COLLECTOR
// current amplification factor for common Collector (Emitter follower)
// c_hFE = (Emitter current - Base current) / Base current
#ifdef COMMON_EMITTER
if (c_hfe > trans.hfe[PartReady]) {
#endif
trans.hfe[PartReady] = c_hfe;
trans.uBE[PartReady] = ADCconfig.U_AVCC - adc.hp1 - adc.tp1; // Base
Emitter Voltage common collector
#ifdef COMMON_EMITTER
}
#endif
#endif
if (PartFound != PART_THYRISTOR) {
if (adc.tp2 > 977) {
// PNP-Transistor is found (Base voltage moves to VCC)
PartFound = PART_TRANSISTOR;
PartMode = PART_MODE_PNP;
} else {
if ((adc.lp_otr < 97) && (adc.lp1 > 2000)) {
// is flow voltage low enough in the closed state?
// (since D-Mode-FET would be by mistake detected as E-Mode )
PartFound = PART_FET; // P-Kanal-MOSFET is found (Basis/Gate moves
not to VCC)
PartMode = PART_MODE_P_E_MOS;
for(ii=0;ii<11;ii++) {
wdt_reset();
ChargePin10ms(TriPinRL,1);
R_DDR = LoPinRL | TriPinRH; // switch R_H for Tristate-Pin (Basis)
to GND
trans.b = TristatePin;
trans.c = LowPin;
trans.e = HighPin;
} // end if PartFound != PART_THYRISTOR
} // end component has current => PNP
#ifdef COMMON_COLLECTOR
// Low-Pin=RL- HighPin=VCC
R_DDR = LoPinRL | TriPinRL;
R_PORT = TriPinRL; // TriPin=RL+ NPN with common Collector
adc.lp1 = W5msReadADC(LowPin); // voltage at Emitter resistor
adc.tp1 = ADCconfig.U_AVCC - ReadADC(TristatePin); // voltage at Base
resistor
#ifdef LONG_HFE
c_hfe = ((unsigned long)adc.lp1 * (unsigned long)(((unsigned long)R_H_VAL
* 100) /
(unsigned int)RR680MI)) / (unsigned int)adc.tp1;
#else
c_hfe = ((adc.lp1 / ((RR680MI+500)/1000)) * (R_H_VAL/500)) /
(adc.tp2/500);
#endif
} else {
c_hfe = (adc.lp1 - adc.tp1) / adc.tp1;
}
#if DebugOut == 5
lcd_line4();
lcd_clear_line();
lcd_line4();
lcd_data('L');
lcd_data('P');
lcd_string(utoa(adc.lp1,outval,10));
lcd_space();
lcd_data('T');
lcd_data('P');
lcd_string(utoa(adc.tp1,outval,10));
wait_about1s();
#endif
#endif
#if DebugOut == 5
lcd_testpin(LowPin);
lcd_data('N');
lcd_testpin(HighPin);
lcd_space();
wait_about1s();
#endif
if (PartReady==1) {
goto widmes;
}
R_PORT = 0; // switch R_L for High-Pin (probably Anode) to GND (turn off)
wait_about5ms();
R_PORT = HiPinRL; // switch R_L for High-Pin (probably Anode) again to
VCC
adc.hp2 = W5msReadADC(HighPin); // measure voltage at the High-Pin (probably
Anode) again
// Test if Triac
R_DDR = 0;
R_PORT = 0;
ADC_PORT = LoADCp; // Low-Pin fix to VCC
wait_about5ms();
R_PORT = HiPinRL; // switch R_L port for HighPin to VCC => switch off
holding current
wait_about5ms();
R_PORT = 0; // switch R_L port for HighPin again to GND; Triac should
now switched off
if(W5msReadADC(HighPin) > 244) {
goto savenresult; // measure voltage at the High-Pin (probably A2) ;
// if to high, component is not switched off =>
no Triac, abort
}
PartFound = PART_TRIAC;
PartReady = 1;
goto savenresult;
}
#if DebugOut == 5
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_data('H');
lcd_data('P');
lcd_string(utoa(adc.hp2,outval,10));
lcd_space();
lcd_data('T');
lcd_data('P');
lcd_string(utoa(adc.tp2,outval,10));
#endif
#ifdef COMMON_EMITTER
trans.uBE[PartReady] = ADCconfig.U_AVCC - adc.tp2 - ReadADC(LowPin);
#if DebugOut == 5
lcd_data('<');
lcd_data('5');
lcd_data('3');
#endif
adc.tp2 = 53;
}
tmp16 = adc.hp2;
if (tmp16 > adc.lp_otr) {
tmp16 -= adc.lp_otr;
}
#ifdef LONG_HFE
trans.hfe[PartReady] = ((unsigned int)tmp16 * (unsigned long)(((unsigned
long)R_H_VAL * 100) /
(unsigned int)RR680PL)) / (unsigned int)adc.tp2;
#else
trans.hfe[PartReady] = ((tmp16 / ((RR680PL+500)/1000)) * (R_H_VAL/500)) /
(adc.tp2/500);
#endif
#endif
#ifdef COMMON_COLLECTOR
// compare current amplification factor for common Collector (Emitter
follower)
// hFE = (Emitterstrom - Basisstrom) / Basisstrom
#ifdef COMMON_EMITTER
if (c_hfe > trans.hfe[PartReady]) {
#endif
trans.hfe[PartReady] = c_hfe;
trans.uBE[PartReady] = ADCconfig.U_AVCC - adc.lp1 - adc.tp1;
#ifdef COMMON_EMITTER
}
#endif
#endif
#if DebugOut == 5
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_data('N');
lcd_data('F');
wait_about1s();
#endif
for(ii=0;ii<11;ii++) {
wdt_reset();
ChargePin10ms(TriPinRL,0); // discharge Gate 10ms with RL
R_DDR = HiPinRL | TriPinRH; // slowly charge Gate
R_PORT = HiPinRL | TriPinRH;
while ((ADC_PIN&PinMSK)); // Wait, until the MOSFET switch and Drain
moved to low
// 0 is detected with input voltage of
2.12V to 2.24V (tested with mega168 & mega328)
R_DDR = HiPinRL; // switch off current
ADCSRA |= (1<<ADSC); // start ADC conversion
while (ADCSRA&(1<<ADSC)); // wait until ADC finished
gthvoltage += ADCW; // add result of ADC
}
savenresult:
trans.b = TristatePin; // save Pin-constellation
trans.c = HighPin;
trans.e = LowPin;
} // end component conduct => npn
// Finish
// end component has no connection between HighPin and LowPin
goto widmes;
}
for (ii=0;ii<200;ii++) {
ADC_DDR = LoADCm | HiADCm; // discharge by short of Low and High side
wait_about5ms(); // Low and Highpin to GND for discharge
ADC_DDR = LoADCm; // switch only Low-Pin fix to GND
adc.hp1 = ReadADC(HighPin); // read voltage at High-Pin
if (adc.hp1 < (150/8)) break;
}
/*
It is possible, that wrong Parts are detected without discharging, because
the gate of a MOSFET can be charged.
The additional measurement with the big resistor R_H is made, to differ
antiparallel diodes
from resistors.
A diode has a voltage, that is nearly independent from the current.
The voltage of a resistor is proportional to the current.
*/
#if 0
// first check with higher current (R_L=680)
// A diode is found better with a parallel mounted capacitor,
// but some capacitors can be detected a a diode.
R_DDR = HiPinRL; // switch R_L port for High-Pin to output (VCC)
R_PORT = HiPinRL;
ChargePin10ms(TriPinRL,1); // discharge of P-Kanal-MOSFET gate
adc.lp_otr = W5msReadADC(HighPin) - ReadADC(LowPin);
R_DDR = HiPinRH; // switch R_H port for High-Pin output (VCC)
R_PORT = HiPinRH;
adc.hp2 = W5msReadADC(HighPin); // M--|<--HP--R_H--VCC
#if DebugOut == 4
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_testpin(HighPin);
lcd_data('D');
lcd_testpin(LowPin);
lcd_space();
lcd_data('h');
lcd_string(utoa(adc.hp3,outval,10));
lcd_space();
lcd_data('L');
lcd_string(utoa(adc.hp1,outval,10));
lcd_space();
lcd_data('H');
lcd_string(utoa(adc.hp2,outval,10));
lcd_space();
wait_about1s();
#endif
//if((adc.hp1 > 150) && (adc.hp1 < 4640) && (adc.hp1 > (adc.hp3+(adc.hp3/8))) &&
(adc.hp3*8 > adc.hp1)) {
if((adc.hp1 > 150) && (adc.hp1 < 4640) && (adc.hp2 < adc.hp1) && (adc.hp1 >
(adc.hp3+(adc.hp3/8))) && (adc.hp3*16 > adc.hp1)) {
// voltage is above 0,15V and below 4,64V => Ok
if((PartFound == PART_NONE) || (PartFound == PART_RESISTOR)) {
PartFound = PART_DIODE; // mark for diode only, if no other component is
found
// since there is a problem with Transistors with a
protection diode
#if DebugOut == 4
lcd_data('D');
#endif
}
diodes[NumOfDiodes].Anode = HighPin;
diodes[NumOfDiodes].Cathode = LowPin;
diodes[NumOfDiodes].Voltage = adc.hp1; // voltage in Millivolt
NumOfDiodes++;
} // end voltage is above 0,15V and below 4,64V
#if DebugOut == 4
lcd_data(NumOfDiodes+'0');
#endif
widmes:
if (NumOfDiodes > 0) goto clean_ports;
// resistor measurement
wdt_reset();
ADC_PORT = TXD_VAL;
ADC_DDR = LoADCm; // switch Low-Pin to output (GND)
R_DDR = HiPinRL; // switch R_L port for High-Pin to output (VCC)
R_PORT = HiPinRL;
for (ii=1;ii<MAX_REPEAT;ii++) {
// wait until voltage is stable
adc.tp1 = W5msReadADC(LowPin); // low-voltage at Rx with load
adc.hp1 = ReadADC(HighPin); // voltage at resistor Rx with R_L
udiff = adc.hp1 - adc.hp2;
if (udiff < 0) udiff = -udiff;
if (udiff < 3) break;
adc.hp2 = adc.hp1;
wdt_reset();
}
R_PORT = 0;
R_DDR = HiPinRH; // switch R_H port for High-Pin to output (GND)
adc.hp2 = W5msReadADC(HighPin); // read voltage, should be down
#if DebugOut == 3
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_testpin(LowPin);
lcd_data('U');
lcd_testpin(HighPin);
lcd_data('A');
lcd_string(utoa(adc.hp1, outval, 10));
lcd_data('B');
lcd_string(utoa(adc.hp2, outval, 10));
lcd_space();
#endif
goto testend;
}
for (ii=1;ii<MAX_REPEAT;ii++) {
// wait until voltage is stable
adc.tp2 = W5msReadADC(HighPin); // high voltage with load
adc.lp1 = ReadADC(LowPin); // voltage at the other end of Rx
udiff = adc.lp1 - adc.lp2;
if (udiff < 0) udiff = -udiff;
if (udiff < 3) break;
adc.lp2 = adc.lp1;
wdt_reset();
}
#if DebugOut == 3
lcd_data('F');
#endif
goto testend;
}
#ifdef __AVR_ATmega8__
#define FAKT_LOW 2 // resolution is about twice as good
#else
#define FAKT_LOW 4 // resolution is about four times better
#endif
#ifdef AUTOSCALE_ADC
if (adc.hp2 < U_INT_LIMIT) {
lrx1 = (lirx1*FAKT_LOW + lirx2) / (FAKT_LOW+1); // weighted average of
both R_H measurements
} else if (adc.lp2 < U_INT_LIMIT){
lrx1 = (lirx2*FAKT_LOW + lirx1) / (FAKT_LOW+1); // weighted average of
both R_H measurements
} else
#endif
{
lrx1 = (lirx1 + lirx2) / 2; // average of both R_H measurements
}
lrx1 *= 100;
lrx1 += RH_OFFSET; // add constant for correction of systematic error
} else {
ii = 'L';
// two measurements with R_L resistors (680) are made:
// lirx1 (measurement at HighPin)
#ifdef AUTOSCALE_ADC
if (adc.hp1 < U_INT_LIMIT) {
lrx1 = (lirx1*FAKT_LOW + lirx2) / (FAKT_LOW+1); // weighted average of
both R_L measurements
} else if (adc.lp1 < U_INT_LIMIT) {
lrx1 = (lirx2*FAKT_LOW + lirx1) / (FAKT_LOW+1); // weighted average of
both R_L measurements
} else
#endif
{
lrx1 = (lirx1 + lirx2) / 2; // average of both R_L measurements
}
}
// lrx1 is tempory result
#if 0
// The zero resistance is in 0.01 Ohm units and usually so little, that
correction for resistors above 10 Ohm
// is not necassary
ii = eeprom_read_byte(&EE_ESR_ZEROtab[LowPin+HighPin]) / 10; // Resistance
offset in 0,1 Ohm units
if (ii < lrx1) {
lrx1 -= ii;
} else {
lrx1 = 0;
}
#endif
#if DebugOut == 3
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_testpin(LowPin);
lcd_data(ii);
lcd_testpin(HighPin);
lcd_space();
if (ii == 'H') {
lcd_data('X');
DisplayValue(lirx1,1,LCD_CHAR_OMEGA,4)
lcd_space();
lcd_data('Y');
DisplayValue(lirx2,1,LCD_CHAR_OMEGA,4)
lcd_space();
} else {
lcd_data('x');
DisplayValue(lirx1,-1,LCD_CHAR_OMEGA,4)
lcd_space();
lcd_data('y');
DisplayValue(lirx2,-1,LCD_CHAR_OMEGA,4)
}
lcd_space();
lcd_line4();
lcd_clear_line();
lcd_line4();
DisplayValue(lirx2,-1,LCD_CHAR_OMEGA,4)
lcd_space();
lcd_line2();
#endif
if (lirx1 > 0) {
#if DebugOut == 3
lcd_data('R');
lcd_data('!');
lcd_data('=');
DisplayValue(thisR->rx,-1,LCD_CHAR_OMEGA,3)
lcd_space();
DisplayValue(lirx1,-1,LCD_CHAR_OMEGA,3)
lcd_space();
#endif
PartFound = PART_RESISTOR;
goto testend;
} // end for
testend:
#if U_SCALE != 1
ADCconfig.U_AVCC /= U_SCALE; // scale back to mV resolution
ADCconfig.U_Bandgap /= U_SCALE;
#endif
#ifdef DebugOut
#if DebugOut < 10
wait_about2s();
#endif
#endif
clean_ports:
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
HiADC = pgm_read_byte(&PinADCtab[hipin]);
ADC_PORT = HiADC | TXD_VAL; // switch ADC port to high level
ADC_DDR = HiADC | TXD_MSK; // switch High Pin direct to VCC
LoPinR_L = pgm_read_byte(&PinRLtab[lopin]); // R_L mask for LowPin R_L load
R_PORT = 0; // switch R-Port to GND
R_DDR = LoPinR_L + LoPinR_L; // switch R_H port for LowPin to output (GND)
#ifdef WITH_IRMICRO
if (u_res < 2500) {
#endif
// R_H_VAL has units of 10 Ohm, u_res has units of mV, ir_nano has units of
nA
ir_nano = (unsigned long)(u_res * 100000UL) / R_H_VAL;
DisplayValue(ir_nano,-9,'A',2); // output two digits of current with nA units
#ifdef WITH_IRMICRO
} else {
R_DDR = LoPinR_L; // switch R_L port for LowPin to output (GND)
u_res = W5msReadADC(lopin); // read voltage
ir_nano = 0xffff; // set to max
// RR680MI has units of 0.1 Ohm, u_res has units of mV, ir_micro has units of
uA
ir_micro = (unsigned long)(u_res * 10000UL) / RR680MI;
DisplayValue(ir_micro,-6,'A',2); // output two digits of current in uA units
}
#endif
return;
}
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
/*
extern struct ADCconfig_t{
uint8_t Samples; // number of ADC samples to take
uint8_t RefFlag; // save Reference type VCC of IntRef
uint16_t U_Bandgap; // Reference Voltage in mV
uint16_t U_AVCC; // Voltage of AVCC
} ADCconfig;
*/
#ifdef INHIBIT_SLEEP_MODE
//#define StartADCwait() ADCSRA = (1<<ADSC) | (1<<ADEN) | (1<<ADIF) |
AUTO_CLOCK_DIV; /* enable ADC and start */
#define StartADCwait() ADCSRA = StartADCmsk; /* Start conversion */\
while (ADCSRA & (1 << ADSC)) /* wait until conversion is done */
#else
#define StartADCwait() ADCSRA = (1<<ADEN) | (1<<ADIF) | (1<<ADIE) |
AUTO_CLOCK_DIV; /* enable ADC and Interrupt */\
set_sleep_mode(SLEEP_MODE_ADC);\
sleep_mode(); /* Start ADC, return, if ADC has finished */
#endif
#ifdef AUTOSCALE_ADC
sample:
#endif
ADMUX = Probe; // set input channel and U reference
#ifdef AUTOSCALE_ADC
// if voltage reference changes, wait for voltage stabilization
if ((Probe & (1 << REFS1)) != 0) {
// switch to 1.1V Reference
#ifdef NO_AREF_CAP
wait100us(); // time for voltage stabilization
#else
wait_about10ms(); // time for voltage stabilization
#endif
}
#endif
#ifdef AUTOSCALE_ADC
// auto-switch voltage reference for low readings
if ((Samples == 4) && (ADCconfig.U_Bandgap > 255) && ((uint16_t)Value < 1024)
&& !(Probe & (1 << REFS1))) {
Probe |= (1 << REFS1); // select internal bandgap reference
#ifdef AUTOSCALE_ADC
// convert ADC reading to voltage - single sample: U = ADC reading * U_ref /
1024
// get voltage of reference used
if (Probe & (1 << REFS1)) U = ADCconfig.U_Bandgap; // bandgap reference
else U = ADCconfig.U_AVCC; // Vcc reference
#else
U = ADCconfig.U_AVCC; // Vcc reference
#endif
// convert to voltage
Value *= U; // ADC readings * U_ref
Value /= 1023; // / 1024 for 10bit ADC
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
#ifdef INHIBIT_SLEEP_MODE
unsigned int ovcnt16;
#endif
#ifdef AUTO_CAL
pin_combination = (HighPin * 3) + LowPin - 1; // coded Pin combination for
capacity zero offset
#endif
#if DebugOut == 10
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_testpin(LowPin);
lcd_data('C');
lcd_testpin(HighPin);
lcd_space();
#endif
if(PartFound == PART_RESISTOR) {
#if DebugOut == 10
lcd_data('R');
wait_about2s();
#endif
for (ii=0;ii<NumOfDiodes;ii++) {
if ((diodes[ii].Cathode == LowPin) && (diodes[ii].Anode == HighPin) &&
(diodes[ii].Voltage < 1500)) {
#if DebugOut == 10
lcd_data('D');
wait_about2s();
#endif
return;
}
}
#if FLASHEND > 0x1fff
cap.esr = 0; // set ESR of capacitor to zero
vloss = 0; // set lost voltage to zero
#endif
wdt_reset();
// wait 5ms and read voltage again, does the capacitor keep the voltage?
//adcv[1] = W5msReadADC(HighPin) - adcv[0];
//wdt_reset();
#if DebugOut == 10
DisplayValue(ovcnt16,0,' ',4);
DisplayValue(adcv[2],-3,'V',4);
#endif
#ifdef NO_CAP_HOLD_TIME
ChargePin10ms(HiPinR_H,0); // switch HighPin with R_H 10ms auf GND, then
currentless
adcv[3] = ReadADC(HighPin) - adcv[0]; // read voltage again, is discharged
only a little bit ?
#if DebugOut == 10
lcd_data('U');
lcd_data('3');
lcd_data(':');
lcd_string(utoa(adcv[3],outval,10));
lcd_space();
wait_about2s();
#endif
#if DebugOut == 10
lcd_data('H');
lcd_space();
wait_about1s();
#endif
if (ovcnt16 == 0 ) {
goto messe_mit_rh; // Voltage of more than 1300mV is reached in one
pulse, but not hold
}
cap.cval_uncorrected.dw = ovcnt16 + 1;
cap.cval_uncorrected.dw *= getRLmultip(adcv[2]); // get factor to convert time
to capacity from table
#else
// wait the half the time which was required for loading
adcv[3] = adcv[2]; // preset to prevent compiler warning
#if DebugOut == 10
lcd_data('L');
lcd_space();
wait_about1s();
#endif
if (ovcnt16 == 0 ) {
goto messe_mit_rh; // Voltage of more than 1300mV is reached in one
pulse, but not hold
}
goto keinC; // capacitor does not keep the voltage about 5ms
}
cap.cval_uncorrected.dw = ovcnt16 + 1;
// compute factor with load voltage + lost voltage during the voltage load time
cap.cval_uncorrected.dw *= getRLmultip(adcv[2]+adcv[3]); // get factor to
convert time to capacity from table
#endif
// cap.cval for this type is at least 40000nF, so the last digit will be never
shown
cap.cval *= (1000 - C_H_KORR); // correct with C_H_KORR with 0.1% resolution,
but prevent overflow
cap.cval /= 100;
#if DebugOut == 10
lcd_line3();
lcd_clear_line();
lcd_line3();
lcd_testpin(LowPin);
lcd_data('C');
lcd_testpin(HighPin);
lcd_space();
DisplayValue(cap.cval,cap.cpre,'F',4);
lcd_space();
lcd_string(utoa(ovcnt16,outval,10));
wait_about3s();
#endif
goto checkDiodes;
//=================================================================================
=
// Measurement of little capacity values
messe_mit_rh:
// little capacity value, about < 50 uF
EntladePins(); // discharge capacitor
// setup Counter1
ovcnt16 = 0;
TCCR1A = 0; // set Counter1 to normal Mode
TCNT1 = 0; // set Counter to 0
TI1_INT_FLAGS = (1<<ICF1) | (1<<OCF1B) | (1<<OCF1A) | (1<<TOV1); // clear
interrupt flags
#ifndef INHIBIT_SLEEP_MODE
TIMSK1 = (1<<TOIE1) | (1<<ICIE1); // enable Timer overflow interrupt and input
capture interrupt
unfinished = 1;
#endif
R_PORT = HiPinR_H; // switch R_H resistor port for HighPin to VCC
if(PartFound == PART_FET) {
// charge capacitor with R_H resistor
TCCR1B = (1<<CS10); //Start counter 1MHz or 8MHz
ADC_DDR = (((1<<TP1) | (1<<TP2) | (1<<TP3) | TXD_MSK) & ~(1<<HighPin)); //
release only HighPin ADC port
} else {
TCCR1B = (1<<CS10); // start counter 1MHz or 8MHz
ADC_DDR = LoADC; // stay LoADC Pin switched to GND, charge capacitor with
R_H slowly
}
//******************************
#ifdef INHIBIT_SLEEP_MODE
while(1) {
// Wait, until Input Capture is set
ii = TI1_INT_FLAGS; // read Timer flags
if(ovcnt16 == (F_CPU/5000)) {
break; // Timeout for Charging, above 12 s
}
}
}
#else
while(unfinished) {
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode(); // wait for interrupt
wdt_reset();
if(ovcnt16 == (F_CPU/5000)) {
break; // Timeout for Charging, above 12 s
}
}
//------------------------------------------------------------
ADCSRA = (1<<ADEN) | (1<<ADIF) | AUTO_CLOCK_DIV; // enable ADC
R_DDR = 0; // switch R_H resistor port for input
R_PORT = 0; // switch R_H resistor port pull up for HighPin off
adcv[2] = ReadADC(HighPin); // get loaded voltage
load_diff = adcv[2] + REF_C_KORR - ref_mv; // build difference of capacitor
voltage to Reference Voltage
//------------------------------------------------------------
#if DebugOut == 10
lcd_data('k');
wait_about1s();
#endif
if (cap.cpre == -12) {
#if COMP_SLEW1 > COMP_SLEW2
if (cap.cval < COMP_SLEW1) {
// add slew rate dependent offset
cap.cval += (COMP_SLEW1 / (cap.cval+COMP_SLEW2 ));
}
#endif
#ifdef AUTO_CAL
// auto calibration mode, cap_null can be updated in selftest section
tmpint = eeprom_read_byte(&c_zero_tab[pin_combination]); // read zero offset
#else
if (HighPin == TP2) cap.cval += TP2_CAP_OFFSET; // measurements with TP2 have
2pF less capacity
#if DebugOut == 10
R_DDR = 0; // switch all resistor ports to input
lcd_line4();
lcd_clear_line();
lcd_line4();
lcd_testpin(LowPin);
lcd_data('c');
lcd_testpin(HighPin);
lcd_space();
DisplayValue(cap.cval,cap.cpre,'F',4);
wait_about3s();
#endif
#if DebugOut == 10
lcd_data('<');
lcd_space();
wait_about1s();
#endif
checkDiodes:
#if DebugOut == 10
lcd_data('D');
lcd_space();
wait_about1s();
#endif
keinC:
return;
} // end ReadCapacity()
y1 = MEM_read_word(&RLtab[tabind]);
y2 = MEM_read_word(&RLtab[tabind+1]);
return ( ((y1 - y2) * tabres + (RL_Tab_Abstand/2)) / RL_Tab_Abstand + y2); //
interpolate table
}
void Scale_C_with_vcc(void) {
#ifndef INHIBIT_SLEEP_MODE
// Interrupt Service Routine for timer1 Overflow
ISR(TIMER1_OVF_vect, ISR_BLOCK)
{
ovcnt16++; // count overflow
}
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
//=================================================================
void ReadInductance(void) {
#if FLASHEND > 0x1fff
union t_combi{
unsigned long dw; // time_constant
uint16_t w[2];
} timeconstant;
if(PartFound != PART_RESISTOR) {
return; // We have found no resistor
}
if (ResistorsFound != 1) {
return; // do not search for inductance, more than 1 resistor
}
//for (found=0;found<ResistorsFound;found++) {
// if (resis[found].rx > 21000) continue;
if (count < 2) {
// first and second pass, direction 1
LowPin = resis[found].ra;
HighPin = resis[found].rb;
} else {
// third and fourth pass, direction 2
LowPin = resis[found].rb;
HighPin = resis[found].ra;
}
HiADC = pgm_read_byte(&PinADCtab[HighPin]);
LoPinR_L = pgm_read_byte(&PinRLtab[LowPin]); // R_L mask for HighPin R_L load
//=================================================================================
=
// Measurement of Inductance values
R_PORT = 0; // switch R port to GND
ADC_PORT = TXD_VAL; // switch ADC-Port to GND
// setup Counter1
timeconstant.w[1] = 0; // set ov counter to 0
TCCR1A = 0; // set Counter1 to normal Mode
TCNT1 = 0; // set Counter to 0
TI1_INT_FLAGS = (1<<ICF1) | (1<<OCF1B) | (1<<OCF1A) | (1<<TOV1); // reset TIFR
or TIFR1
HiADC |= TXD_VAL;
wait200us(); // wait for bandgap to start up
if(timeconstant.w[1] == (F_CPU/100000UL)) {
break; // Timeout for Charging, above 0.13 s
}
}
}
for (ii=0;ii<20;ii++) {
// wait for current is near zero
umax = W10msReadADC(LowPin);
total_r = ReadADC(HighPin);
if ((umax < 2) && (total_r < 2)) break; // low current detected
}
#define CNT_ZERO_42 6
#define CNT_ZERO_720 7
//cnt_diff = 0;
//if (total_r > 7000) cnt_diff = 1;
//if (total_r > 14000) cnt_diff = 2;
cnt_diff = total_r / ((14000UL * 8) / (F_CPU/1000000UL));
// Voltage of comparator in % of umax
#ifdef AUTO_CAL
tmpint = (ref_mv + (int16_t)eeprom_read_word((uint16_t *)(&ref_offset))) ;
#else
tmpint = (ref_mv + REF_C_KORR);
#endif
if ((count&0x01) == 1) {
// second pass with delayed counter start
timeconstant.dw += (3 * (F_CPU/1000000UL))+10;
}
// compute the maximum Voltage umax with the Resistor of the coil
umax = ((unsigned long)mess_r * (unsigned long)ADCconfig.U_AVCC) / total_r;
per_ref1 = ((unsigned long)tmpint * 1000) / umax;
//per_ref2 = (uint8_t)MEM2_read_byte(&LogTab[per_ref1]); // -log(1 -
per_ref1/100)
per_ref2 = get_log(per_ref1); // -log(1 - per_ref1/1000)
//*********************************************************
#if 0
if (count == 0) {
lcd_line3();
DisplayValue(count,0,' ',4);
DisplayValue(timeconstant.dw,0,'+',4);
DisplayValue(cnt_diff,0,' ',4);
DisplayValue(total_r,-1,'r',4);
lcd_space();
DisplayValue(per_ref1,-1,'%',4);
lcd_line4();
DisplayValue(tmpint,-3,'V',4);
lcd_space();
DisplayValue(umax,-3,'V',4);
lcd_space();
DisplayValue(per_ref2,-1,'%',4);
wait_about4s();
wait_about2s();
}
#endif
//*********************************************************
// lx in 0.01mH units, L = Tau * R
per_ref1 = ((per_ref2 * (F_CPU/1000000UL)) + 5) / 10;
inductance[count] = (timeconstant.dw * total_r ) / per_ref1;
wdt_reset();
} // end for count
#if 0
if (inductance[1] > inductance[0]) {
resis[found].lx = inductance[1]; // use value found with delayed counter
start
} else {
resis[found].lx = inductance[0];
}
#else
nr_pol1 = 0;
if (inductance[1] > inductance[0]) { nr_pol1 = 1; }
nr_pol2 = 2;
if (inductance[3] > inductance[2]) { nr_pol2 = 3; }
resis[found].lx = inductance[nr_pol1];
resis[found].lpre = -5; // 10 uH units
#endif
return;
} // end ReadInductance()
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
/* The sleep mode for ADC can be used. It is implemented for 8MHz and 16MHz
operation */
/* But the ESR result is allways higher than the results with wait mode. */
/* The time of ESR measurement is higher with the sleep mode (checked with
oszilloscope) */
/* The reason for the different time is unknown, the start of the next ADC
measurement */
/* should be initiated before the next ADC-clock (8 us). One ADC takes 13 ADC clock
+ 1 clock setup. */
/* The setting to sleep mode takes 10 clock tics, the wakeup takes about 24 clock
tics, but 8us are 64 clock tics. */
/* I have found no reason, why a reset of the ADC clock divider should occur during
ESR measurement. */
//#define ADC_Sleep_Mode
//#define ESR_DEBUG
#ifdef ADC_Sleep_Mode
//#define StartADCwait() ADCSRA = (1<<ADEN) | (1<<ADIF) | (1<<ADIE) |
AUTO_CLOCK_DIV; /* enable ADC and Interrupt */
//#define StartADCwait() set_sleep_mode(SLEEP_MODE_ADC);
//sleep_mode() /* Start ADC, return if ADC has finished */
#define StartADCwait() sleep_cpu()
#else
//#define StartADCwait() ADCSRA = (1<<ADSC) | (1<<ADEN) | (1<<ADIF) |
AUTO_CLOCK_DIV; /* enable ADC and start */
#define StartADCwait() ADCSRA = StartADCmsk; /* Start conversion */\
while (ADCSRA & (1 << ADSC)) /* wait until conversion is done */
#endif
/************************************************************************/
/* Predefine the wait time for switch off the load current for big caps */
/************************************************************************/
// wdt_reset(); // with wdt_reset the timing can be adjusted,
// when time is too short, voltage is down before SH of ADC
// when time is too long, capacitor will be overloaded.
// That will cause too high voltage without current.
#ifdef ADC_Sleep_Mode
// Interrupt mode, big cap
#if F_CPU == 8000000UL
#define DelayBigCap() wait10us(); /* 2.5 ADC clocks = 20us */ \
wait5us(); /* */ \
wait2us(); /* with only 17 us delay the voltage goes down before SH */
\
/* delay 17us + 3 clock tics (CALL instead of RCALL) = 17.375 us @ 8
MHz */ \
/* + 21 clock tics delay from interrupt return, +2.625us = 20.0 */ \
wdt_reset(); /* 20.125 us */ \
wdt_reset() /* 20.250 us */
#endif
#if F_CPU == 16000000UL
#define DelayBigCap() us500delay(18); /* 2.5 ADC clocks = 20us */ \
/* with only 18 us delay the voltage goes down before SH */ \
/* delay 18us 500ns + 1 clock tics (CALL instead of RCALL) = 18.5625 us
*/ \
/* + 21 clock tics delay from interrupt return, +1.3125us = 19.8750
*/ \
wdt_reset(); /* 19.9375 us */ \
wdt_reset(); /* 20.0000 us */ \
wdt_reset(); /* 20.0625 us */ \
wdt_reset(); /* 20.1250 us */ \
wdt_reset(); /* 20.1875 us */ \
wdt_reset() /* 20.2500 us */
#endif
#else
// Polling mode, big cap
#if F_CPU == 8000000UL
#define DelayBigCap() wait10us(); /* 2.5 ADC clocks = 20us */ \
wait5us(); /* */ \
wait4us(); /* pulse length 19.375 us */
/* delay 19us + 3 clock tics (CALL instead of RCALL) = 19.375 us @ 8
MHz */
/* + 7 clock tics delay from while loop, +0.875us = 20.250 */
// wdt_reset() /* 20.375 us + */
#endif
#if F_CPU == 16000000UL
#define DelayBigCap() delayMicroseconds(20)
// #define DelayBigCap() us500delay(19); /* 2.5 ADC clocks = 20us */ \
// /* with only 18 us delay the voltage goes down before SH */ \
// /* delay 19us 500ns + 1 clock tics (CALL instead of RCALL) = 19.5625
us */ \
// /* + 7 clock tics delay from "while (ADCSRA&(1<<ADSC))" loop =
20.0000 */ \
// wdt_reset(); /* 20.0625 us */ \
// wdt_reset(); /* 20.1250 us */ \
// wdt_reset(); /* 20.1875 us */ \
// wdt_reset() /* 20.2500 us */
#endif
#endif
/**************************************************************************/
/* Predefine the wait time for switch off the load current for small caps */
/**************************************************************************/
// SH at 2.5 ADC clocks behind start = 5 us
#ifdef ADC_Sleep_Mode
// Interrupt mode, small cap
#if F_CPU == 8000000UL
#define DelaySmallCap() wait2us(); /* with only 4 us delay the voltage goes
down before SH */ \
/* delay 2us + 1 clock tics (CALL instead of RCALL) = 2.125 us @ 8 MHz
*/ \
/* + 21 clock tics delay from interrupt return, +2.625us = 4.75 */ \
wdt_reset(); /* 4.875 us */ \
wdt_reset(); /* 5.000 us */ \
wdt_reset() /* 5.125 us */
#endif
#if F_CPU == 16000000UL
#define DelaySmallCap() us500delay(3); /* with only 18 us delay the voltage
goes down before SH */ \
/* delay 3us 500ns + 1 clock tics (CALL instead of RCALL) = 3.5625 us
*/ \
/* + 21 clock tics delay from interrupt return, +1.3125us = 4.875 */ \
wdt_reset(); /* 4.9375 us */ \
wdt_reset(); /* 5.0000 us */ \
wdt_reset(); /* 5.0625 us */ \
wdt_reset() /* 5.1250 us */
#endif
#else
// Polling mode, small cap
#if F_CPU == 8000000UL
#define DelaySmallCap() wait4us(); /* with only 4 us delay the voltage goes
down before SH */ \
/* delay 4us + 1 clock tics (CALL instead of RCALL) = 4.125 us @ 8 MHz
*/ \
/* + 7 clock tics delay from while loop, +0.875us = 5.000 */ \
wdt_reset() /* 5.125 us */
#endif
#if F_CPU == 16000000UL
#define DelaySmallCap() us500delay(4); /* with only 4 us delay the voltage
goes down before SH */ \
/* delay 4us 500ns + 1 clock tics (CALL instead of RCALL) = 4.5625 us
*/ \
/* + 7 clock tics delay from "while (ADCSRA&(1<<ADSC))" loop, +0.4375 =
5.0000 */ \
wdt_reset(); /* 5.0625 us */ \
wdt_reset() /* 5.1250 us */
#endif
#endif
//=================================================================
uint16_t GetESR(uint8_t hipin, uint8_t lopin) {
#if FLASHEND > 0x1fff
// measure the ESR value of capacitor
unsigned int adcv[4]; // array for 4 ADC readings
unsigned long sumvolt[4]; // array for 3 sums of ADC readings
unsigned long cap_val_nF;
uint16_t esrvalue;
uint8_t HiPinR_L; // used to switch 680 Ohm to HighPin
uint8_t HiADC; // used to switch Highpin directly to GND or VCC
uint8_t LoPinR_L; // used to switch 680 Ohm to LowPin
uint8_t LoADC; // used to switch Lowpin directly to GND or VCC
uint8_t ii,jj; // tempory values
uint8_t StartADCmsk; // Bit mask to start the ADC
uint8_t SelectLowPin,SelectHighPin;
uint8_t big_cap;
int8_t esr0; // used for ESR zero correction
big_cap = 1;
if (PartFound == PART_CAPACITOR) {
ii = cap.cpre_max;
cap_val_nF = cap.cval_max;
//} else {
//big_cap = 0;
//}
}
#ifdef NO_AREF_CAP
wait100us(); // time for voltage stabilization
#else
wait_about10ms(); // time for voltage stabilization with 100nF
#endif
// Measurement frequency is given by sum of ADC-Reads < 680 Hz for normal ADC
speed.
// For fast ADC mode the frequency is below 2720 Hz (used for capacity value
below 3.6 uF).
// ADC Sample and Hold (SH) is done 1.5 ADC clock number after real start of
conversion.
// Real ADC-conversion is started with the next ADC-Clock (125kHz) after setting
the ADSC bit.
for(ii=0;ii<MAX_CNT;ii++) {
ADC_DDR = LoADC; // switch Low-Pin to output (GND)
R_PORT = LoPinR_L; // switch R-Port to VCC
R_DDR = LoPinR_L; // switch R_L port for LowPin to output (VCC)
ADMUX = SelectLowPin;
StartADCwait(); // set ADCSRA Interrupt Mode, sleep
StartADCwait(); // set ADCSRA Interrupt Mode, sleep
adcv[0] = ADCW; // Voltage LowPin with current
ADMUX = SelectHighPin;
//if (big_cap != 0) {
//} else {
// StartADCwait(); // ADCSRA = (1<<ADEN) | (1<<ADIF) | (1<<ADIE) |
AUTO_CLOCK_DIV;
// R_PORT = HiPinR_L; // switch R-Port to VCC
// R_DDR = HiPinR_L; // switch R_L port for HighPin to output (VCC)
// ADCSRA = (1<<ADSC) | (1<<ADEN) | (1<<ADIF) | FAST_CLOCK_DIV; // enable ADC
and start with ADSC
// // SH at 2.5 ADC clocks behind start = 5 us
// DelaySmallCap(); // wait predefined time
//}
R_DDR = 0; // switch current off, SH is 1.5 ADC clock behind real start
R_PORT = 0;
while (ADCSRA&(1<<ADSC)); // wait for conversion finished
adcv[1] = ADCW; // Voltage HighPin with current
#ifdef ADC_Sleep_Mode
ADCSRA = StartADCmsk; // enable ADC and Interrupt
#endif
wdt_reset();
//} else {
// StartADCwait(); // set ADCSRA Interrupt Mode, sleep
// R_PORT = LoPinR_L;
// R_DDR = LoPinR_L; // switch LowPin with 680 Ohm to VCC
// ADCSRA = (1<<ADSC) | (1<<ADEN) | (1<<ADIF) | FAST_CLOCK_DIV; // enable ADC
and start with ADSC
// // 2.5 ADC clocks = 5 us
// DelaySmallCap(); // wait predefined time
//}
#ifdef ADC_Sleep_Mode
ADCSRA = StartADCmsk; // enable ADC and Interrupt
#endif
sumvolt[0] += sumvolt[2];
#ifdef ESR_DEBUG
lcd_testpin(hipin);
lcd_testpin(lopin);
lcd_data(' ');
DisplayValue(sumvolt[0],0,'L',4); // LowPin 1
lcd_line3();
DisplayValue(sumvolt[1],0,'h',4); // HighPin 1
lcd_data(' ');
DisplayValue(sumvolt[3],0,'H',4); // LowPin 2
lcd_line4();
#endif
if (PartFound == PART_CAPACITOR) {
sumvolt[2] -= (1745098UL*MAX_CNT) / (cap_val_nF * (cap_val_nF + 19));
}
#ifdef ESR_DEBUG
DisplayValue(sumvolt[2],0,'d',4); // HighPin - LowPin
lcd_data(' ');
#endif
#ifdef ADC_Sleep_Mode
SMCR = (0 << SM0) | (0 << SE); // clear ADC Noise Reduction and Sleep Enable
#endif
return (esrvalue);
#else
return (0);
#endif
}
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
//=================================================================
void GetVloss() {
#if FLASHEND > 0x1fff
// measure voltage drop after load pulse
unsigned int tmpint;
unsigned int adcv[4];
union t_combi{
unsigned long dw; // capacity value in 100nF units
uint16_t w[2];
} lval;
uint8_t ii;
uint8_t HiPinR_L;
uint8_t LoADC;
lval.dw = cap.cval_max;
//for (ii=cap.cpre_max+12;ii<5;ii++) {
for (ii=cap.cpre_max+12;ii<4;ii++) {
lval.dw = (lval.dw + 5) / 10;
}
#if 0
lcd_line3();
DisplayValue(adcv[2],0,' ',4);
DisplayValue(adcv[1],0,' ',4);
lcd_line4();
DisplayValue(lval.w[0],0,'x',4);
#endif
#endif
return;
} // end GetVloss()
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
void Calibrate_UR(void) {
// get reference voltage, calibrate VCC with external 2.5V and
// get the port output resistance
#ifdef AUTO_CAL
uint16_t sum_rm; // sum of 3 Pin voltages with 680 Ohm load
uint16_t sum_rp; // sum of 3 Pin voltages with 680 Ohm load
uint16_t u680; // 3 * (Voltage at 680 Ohm)
#endif
//--------------------------------------------
ADCconfig.U_AVCC = U_VCC; // set initial VCC Voltage
ADCconfig.Samples = 190; // set number of ADC reads near to maximum
#ifdef WITH_AUTO_REF
(void) ReadADC(MUX_INT_REF); // read reference voltage
ref_mv = W5msReadADC(MUX_INT_REF); // read reference voltage
RefVoltage(); // compute RHmultip = f(reference voltage)
#else
ref_mv = DEFAULT_BAND_GAP; // set to default Reference Voltage
#endif
//--------------------------------------------
#ifdef AUTO_CAL
// measurement of internal resistance of the ADC port outputs switched to GND
ADC_DDR = 1<<TP1 | TXD_MSK; // ADC-Pin 1 to output 0V
R_PORT = 1<<(TP1*2); // R_L-PORT 1 to VCC
R_DDR = 1<<(TP1*2); // Pin 1 to output and over R_L to VCC
sum_rm = W5msReadADC(TP1);
/* -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=- -=-
-=- -=- -=- -=- -=- -=- -=- -=- */
#ifdef STRIP_GRID_BOARD
#warning "strip-grid-board layout selected!"
#endif
switch(temp1) {
case LCD_CHAR_DIODE1: {
uart_putc('>'); uart_putc('|'); break;
}
case LCD_CHAR_DIODE2: {
uart_putc('|'); uart_putc('<'); break;
}
case LCD_CHAR_CAP: {
uart_putc('|'); uart_putc('|'); break;
}
case LCD_CHAR_RESIS1:
case LCD_CHAR_RESIS2: {
uart_putc('R'); break;
}
case LCD_CHAR_U: { // micro
uart_putc('u'); // ASCII u
break;
}
case LCD_CHAR_OMEGA: { // Omega
uart_putc('o'); // "ohm"
uart_putc('h');
uart_putc('m'); break;
}
default: {
uart_putc(temp1);
}
}
}
void lcd_clear(void) {
lcd.clear();
uart_newline();
}