;******************************************************************************* ; * ; Filename: Logicprobe * ; Date: 23.10.2015 * ; File Version: 2.3 * ; Author: Heiner Kuhlmann * ; Company: * ; Description: Simple Logic Probe * ; * ;******************************************************************************* ;******************************************************************************* ; ; Die LogicProbe (Logikstift, Logiktester) ist ein einfaches Messgerät, ; mit dem man den Zustand eines Anschlusses in einer Logikschaltung einfach ; und schnell messen kann. ; Die LogicProbe verwendet einen PIC12F629. ; ;******************************************************************************* ;******************************************************************************* ; ; LogicProbe ist Copyright *Heiner Kuhlmann* hkuhlmann@dr-kuhlmann.com ; ; Dieses Programm ist Teil von LogicProbe. ; ; LogicProbe ist Freie Software und Hardware: ; Sie können es unter den Bedingungen ; der GNU General Public License, wie von der Free Software Foundation, ; Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren ; veröffentlichten Version, weiterverbreiten und/oder modifizieren. ; ; LogicProbe wird in der Hoffnung, dass es nützlich sein wird, aber ; OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite ; Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. ; Siehe die GNU General Public License für weitere Details. ; ; Sie sollten eine Kopie der GNU General Public License zusammen mit LogicProbe ; erhalten haben. Wenn nicht, siehe . ; ; ;******************************************************************************* ;******************************************************************************* ; * ; Revision History: 1.1 Statische Anzeige OK * ; CMOS / TTL Pegel kann umgeschaltet werden * ; 1.2 Statische und dynamische Anzeige Ok * ; 1.3 Erweiterte dynamische Anzeige mit Zwischenpegeln * ; 1.4 Genaueres Timing mit Timer 0 * ; Test kann eingeschaltet werden * ; 2.1 Bestimmung der Versorgungsspannung für TTL * ; Anzeige, das Versorgungsspannung zu niedrig für TTL * ; Einstellung des Pegels * ; Anzeige der Version * ; 2.2 Anpassung des LED-Stroms an Versorgungsspannung * ; Refactored: WAIT_xx über Timer0-Schleife * ; Einstellung der Versorgungsspannung für TTL * ; akzeptiert Bauteiltoleranzen im Eingangskreis. * ; Schaltet aus, wenn Versorgungsspannung zu klein. * ; 2.3 CMOS- / TTL- und Universal-Modus * ; Schaltet nicht mehr aus, * ; wenn Versorgungsspannung zu klein * ; Deaktiviert: * ; Nach 5min Inaktivität in Schlafmodus schalten * ;******************************************************************************* ;******************************************************************************* ; Beschreibung ;******************************************************************************* ; ;------------------------------------------------------------------------------- ; ; Takt ; interner Takt ; ;------------------------------------------------------------------------------- ; ; Zustand, analoger Pegel (Eingang) ; ; GP1/CIN- Analoger Eingang an Comparator - ; Comparator - von CVref Module ; CM2:CM0 = 100 ; ;------------------------------------------------------------------------------- ; ; Auswahl der Logik-Familie ; ; GP3 ; ; Anzeige: Pulse LED blinkt zwei mal pro Sekunde ; High LED blinkt mit Pulse LED: TTL ; Low LED blinkt mit Pulse LED: CMOS = default ; ;------------------------------------------------------------------------------- ; ; Zähler an T1 ; ; Externer Takt ; Kein Prescaler ; Betrieb asynchron ; Minimale Periode 60ns -> 16,67 MHz ; GP5/T1CLK Takteingang T1CLK (als Schmitt Trigger) ; ;------------------------------------------------------------------------------- ; ; LED (Ausgang) ; Ausgangsspannung "0" bei 8,5mA und Vdd=4,5V ~ 0,6V ; "1" bei -3,0mA und Vdd=4,5V ~ Vdd-0,7V ; LED ein bei "0" ; Vorwiderstand ~ (Vdd-2,5V-0,6V) / 8mA >= 175 Ohm ; ; GP0 Low LED grün ; GP2 High LED rot ; GP4 Pulse LED gelb ; ;------------------------------------------------------------------------------- ; ; TTL / CMOS Umschalter ; ; GP3/MCLR/Vpp frei (nur als Eingang nutzbar) ;******************************************************************************* ; Beschreibung der Funktion ;******************************************************************************* ; ; Messen der Eingangsspannung ;------------------------------------------------------------------------------- ; Die Eingangsspannung an GP1/CIN- wird periodisch mit ; definierten Pegeln verglichen. ; Ist die Eingangsspannung kleiner als Ulow (0,7V bei TTL), ; wird die LOW-LED aktiviert. ; Ist die Eingangsspannung größer als Uhigh (2,0V bei TTL), ; wird die HIGH-LED aktiviert. ; Wenn unzulässige Pegel am Eingang liegen z.B. offen, ist keine LED aktiv. ; ; Impulserkennung am Eingang ;------------------------------------------------------------------------------- ; Impulse werden durch die PULSE-LED (gelb) angezeigt. ; Wenn ein Impuls eintrifft wird sie für PULSE ms ausgeschaltet. ; Nach einem Impuls ist sie für mindestens PULSE ms an. ; Wenn keine weiteren Impulse eintreffen bleibt sie an. ; ; Wenn die PULSE-LED (gelb) leuchtet ist also mindestens ein Impuls ; erkannt worden. ; Wenn Pulse eintreffen blinkt sie. ; ; Impulse werden nicht über GP1/CIN- ausgewertet sondern über den Timer1 ; und den Eingang GP5/T1CLK. ; Der Eingang wird unmittelbar auf den Timer1 gegeben ohne Vorteiler. ; Timer1 wird asynchron betrieben. Damit sind bis zu 20MHz möglich. ; Der Eingang ist ein Schnitt-Trigger-Eingang, so dass nur eindeutige Wechsel ; akzeptiert werden. ; Der Wert des Timer1 wird periodisch abgefragt und mit dem bei der letzten ; Abfrage verglichen. ; Falls der Timer1 einen abweichenden Wert hat wurden ein oder mehrere Impulse ; empfangen. Dann wird die PULSE-LED (gelb) aktiviert. ; Sie wird für etwa PULSE ms eingeschaltet und dann für PULSE ms ausgeschaltet. ; Die PULSE-LED blinkt bei laufenden Impulsen. ; ; Durch die Taste wird die gelbe PULSE-LED zurückgesetzt, ist also aus. ; Der Eingang kann angeschlossen sein. ; Der nächste Impuls schaltet die gelbe PULSE-LED wieder ein. ; Damit können Einzelimpulse erkannt werden. ; ; Der Timer zählt beim Übergang LOW -> HIGH weiter. ; Bei langsamen Impulsen erlischt die PULSE-LED (gelb) kurz nach dem LOW -> HIGH ; Übergang für etwa 80 ms. ; ; Design ; ------ ; Die Periode für die Abfrage des Zählers ist etwa 512µs. ; Bei 20 MHz Eingangsfrequenz muss der 16-Bit-Zähler alle 64000/20MHz = 3,2ms ; abgefragt werden. Die Periode der Hauptschleife ist 512µs. ; Die Blink-Periode der PULSE-LED (gelb) muss aber im Bereich von 100ms liegen, ; damit das Blinken erkannt wird. ; Es wird ein weiterer Zähler benötigt, ; der per Software mit 8Bit realisiert wird ( 256 * 3ms > 100ms ); ; ; Pegel der Eingangsspannung ;------------------------------------------------------------------------------- ; Die Eingangspegel können auf CMOS und TTL eingestellt werden. ; Die Vergleichsspannung (Vref) wird von der Versorgungsspannung abgleitet. ; Bei TTL muss die Versorgungsspannung also im zulässigen Bereich von 5V +- 5% ; (4,75V - 5.25V) liegen. Bei CMOS werden die Pegel von der Versorgungsspannung ; abgeleitet. ; ; Der Eingang für die Pegelmessung wird über ein RC-Glied integriert. ; Damit ergibt sich eine Spannung, die etwas über das Impulsverhältnis aussagt. ; Dafür werden zwei weitere Pegel definiert. Sie teilen den Spannungsbereich ; zwischen ULOWmax und UHIGHmin in drei gleiche Bereiche ein. ; Ulower begrenzt das untere Drittel, Uupper das obere. ; ; Wenn Impulse erkannt wurden, wird die High-LED für 1/8 der Zeit aktiviert, ; wenn die integrierte Spannung im oberen Drittel liegt. ; Die Low-LED wird für 1/8 der Zeit aktiviert, wenn ; die integrierte Spannung im unteren Drittel liegt. ; Liegt die Spannung im mittleren Drittel, werden die High-LED und die ; Low-LED wird für 1/32 der Zeit aktiviert. ; Ist die integrierte Spannung über UHIGHmin oder unter ULOWmax werden ; die entsprechenden LED zu 100% eingeschaltet. ; Man kann dann anhand der Helligkeit der LED das Impulsverhältnis abschätzen. ; ; ; Design ;------- ; ; Familie ULOWmax UHIGHmin ULOWmax/U UHIGHmin/U Ulower/U Uupper/U ; TTL 0,8V 2,0V 0,16 0,4 0,24 0,32 ; CMOS 5V 1,5V 3,5V 0,3 0,7 0,43 0,57 ; CMOS 3,3V 0,8V 2,0V 0,24 0,6 0,36 0,48 ; CMOS 2,5V 0,7V 1,7V 0,28 0,85 0,47 0,66 ; CMOS 2,0V 0,5V 1,5V 0,25 0.75 0,42 0,58 ; Gewält ; Familie ULOWmax UHIGHmin ULOWmax/U UHIGHmin/U Ulower/U Uupper/U ; TTL 0,835V 2,03V 0.167 0,40625 0,25 0,3125 ; CMOS 5V 1,4065V 3,425V 0,28125 0,6875 0,40625 0,5625 ; CMOS 3,3V 0,928V 2,26V 0,28125 0,6875 0,40625 0,5625 ; CMOS 2,5V 0,703V 1,7125V 0,28125 0,6875 0,40625 0,5625 ; CMOS 2,0V 0,563V 1,37V 0,28125 0,6875 0,40625 0,5625 ; Uni 3,5V 0,729V 1,86V 0,20833 0,53125 - - ; Uni 3,0V 0,625V 1,67V 0,20833 0,53125 - - ; Die CMOS-Pegel sind ein Kompromiss zwischen den Versorgungsspannungen ; Der Impuls-Eingang GP5/T1CLK ist ein Schimtt-Trigger mit nach Spezifikation ; ULOWmax von 0,2 Udd = 1V bei 5V und UHIGHmin 0,8 Udd = 4V bei 5V. ; Gemessen wurde (indirekt durch Blinken der PULS-LED) UHIGH = 3V bei 5V ; Der Komparator hat eine Reaktionszeit von maximal 400ns. ; Er wird allerdings ohne Sample/Hold betrieben. ; Bei schnellen Änderungen am Eingang sind also keine eindeutigen Pegel zu ; erwarten. Daher ist auch ein integrierendes RC am Eingang des Komparators ; sinnvoll. ; Einstellung der Vergleichsspannung über den Referenzspannungs-Generator ; benötigt allerdings einen minimale Wartezeit von 10 µs. ; Das RC-Glied am Eingang des Komparators sollte mindestens 100 µs sein. ; Regelung der Helligkeit der LEDs ;------------------------------------------------------------------------------- ; ; Die Helligkeit der LEDs entspricht dem Strom der LEDs. In der Schaltung wird ; der Strom durch einen einfachen Vorwiderstand eingestellt. ; Der Strom ist damit von der Versorgungsspannung abhängig, ; genauer gesagt von Uv - Uled. ; Der mittlere Strom durch die LEDs kann durch eine Pulsbreitensteuerung ; angepasst werden. ; ; In der Logicprobe wird die Spannung Uv-Uled am Eingang GP0/Cin+ gemessen. ; Die Spannung wird mit der Referenzspannung verglichen. ; Die Referenzspannung, die gerade noch kleiner als Uv-Uled ist wird verwendet, ; um die Pulsbreite zu berechnen. Es ist einfach eine Zeit nach der die LED ; ausgeschaltet werden. Die Zeit bezieht sich auf den Hauptzyklus von 1024 µs. ; Am Anfang des Zyklus werden die LED eingeschaltet. ; ; Dieser einfache Algorithmus hält den Strom durch die LEDs im Bereich von ; Uv = 3.0 bis 5.5V auf 10% gleich. Unter 3V geht die Helligkeit der LEDs ; mit der Versorgungsspannung sehr zurück. ; Unter 2V leuchten die gelbe und grüne LED nicht mehr auf. ; ; Die Versogungsspannung wird beim Einschalten der LogicProbe und beim ; Einstellen der Logik-Familie gemessen. ; Auswahl der Logik-Familie ;------------------------------------------------------------------------------- ; ; A C H T U N G ; ************* ; Beim Einstellen der Logik-Familie sollte der Eingang offen sein. ; **************************************************************** ; ; Die Familien können durch einen Taster umgeschaltet werden. ; Der Eingang muss offen sein. ; Da der Taster auch zum Löschen der Impulserkennung benutzt wird, ; wird die Umschaltung erst nach längerem Drücken des Tasters, ; etwa 2 Sekunden, vorgenommen. ; Wenn der Taster länger gedrückt wurde, ; wird die Familie durch das Blinken der Familien-LED angezeigt: ; nur grün : Universal ; gelb und grün : CMOS ; gelb und rot : TTL ; gelb, grün und rot : TTL bei zu niedriger Versorgungsspannung ; Bei jedem Betätigen wird die Familie umgeschaltet. ; Nach dem Einschalten ist CMOS eingestellt. ; ; TTL sollte nur in einem begrenzten Spannungsbereich betrieben werden: ; Ucc = 4,75V bis 5,25V ; Wenn die Versorgungsspannung unter 4,75V ist wird diese durch Blinken der ; gelben, roten und grünen LED angezeigt. ; Es wird dennoch auf TTL umgeschaltet. ; ; Die Versorgungsspannung kann nicht absolut gemessen werden, weil der ; PIC12F629 keine interne Referenzspannung hat. ; Als Referenz wird eine LED verwendet. ; Aufgrund der Toleranzen der LED aber insbesondere aller Bauteile im ; Eingangskreis muss die Referenz für jede Schaltung geeicht werden. ; ; Wenn der Eingang nicht offen ist kann die Versorgungsspannung ; nicht gemessen werden. ; Dieses ist bei Umschaltung auf CMOS belanglos. ; Beim Umschalten auf TTL, wird er korrekte Pegel der Versorgungsspannung nicht ; angezeigt. Es wird dennoch auf TTL umgeschaltet. ; ;------------------------------------------------------------------------------- ; Eichung der Referenzspannung für TTL ;------------------------------------------------------------------------------- ; Die Eichung erfordert eine Versorgungsspannung mit der minimalen Ucc für TTL: ; 4,75 V. ; ; Vorgehen: ; 1. Der Eingang muss offen sein. ; 2. Eine Versorgungsspannung von möglichst genau 4,70V anlegen. ; Der Wert sollt etwas unter 4,75V sein, ; weil sonst 4,75V als fehlerhaft angesehen wird. ; Die meisten TTL-Chips laufen übrigens ohne Probleme bei 4,5V. ; Man kann also auch 4,45 einstellen. ; 3. Beim Einschalten der Versorgungsspannung die Taste halten. ; 4. Während der normalen Einschaltsequenz die Taste halten ; bis die LED flackern. ; 5. 2 Sekunden warten ; ; Dieser Eichwert wird im EEPROM des PIC12F629 gespeichert. ; Wenn die Versorgungsspannung dem Eichwert entspricht, wird sie als ; für TTL unzulässig angesehen. ; ; Messung der Versorgungsspannung ;------------------------------------------------------------------------------- ; Die Versorgungsspannung wird immer gemessen, wenn auf TTL umgeschaltet wird. ; Dazu muss der Eingang offen sein ; ; Messverfahren ;------------------------------------------------------------------------------- ; ; Der Komparator des PIC12F629 vergleicht die Versorgungsspannung ; mit der Spannung an einer LED als Referenz. ; An GP0/CIN+ liegt Udd - ULED. ; Der Eingang wird über einen Spannungsteiler an die Versorgungsspannung gelegt. ; Die Spannung an GP1/CIN- steigt über ein RC-Glied an. ; Wenn die Spannung an GP1/CIN- den Wert von GP0/CIN+ überschreitet, ; Wird es am Komparator erkannt. ; Die Zeit bis dieses eintritt ist ein Maß für die Versorgungsspannung. ; ; Initialisierung ;------------------------------------------------------------------------------- ; Nach dem Einschalten leuchten für etwa 1 Sekunde alle LED auf. ; Danach wird die Software-Version angezeigt. ; Eine halbe Sekunde die Primärversion und dann die Sekundärversion. ; Die Version ist in den LED kodiert. ; gelb Bit 0 ; rot Bit 1 ; grün Bit 2 ; Nach einer Pause von einer Sekunde wird die Logik-Familie angezeigt: ; CMOS, die gelbe und die grüne Familien-LED blinken. ; Offener Eingang ;------------------------------------------------------------------------------- ; Wenn der Eingang offen ist, ist der Pegel undefiniert. ; Die Eingangsspannung wird auf 0,38 (1,9V/5V) Versorgungsspannung gezogen. ; Dann leuchtet keine LED auf. ; In der Schaltung wird das durch einen Spannungsteiler mit 470kOhm ; und 300kOhm erreicht. ; Der Eingang des Zählers muss möglichst auf Uss/2 liegen. ; Der Pegel wird hier nicht gemessen, aber es ist ein Schmitt-Trigger-Eingang, ; der so korrekt arbeitet. ; LEDs nach 5 Minuten ausschalten. ;------------------------------------------------------------------------------- ; Wenn 5 Minuten kein Impuls empfangen wurde und sich außerdem weder die ; LOW- noch die HIGH-LED änderte, werden die leuchtenden LEDs ausgeschaltet ; und der PIC geht in den Schlafmodus, um Strom zu sparen. ; Die LogicProbe wird duch ein kurzes Betätigen der Taste wieder aktiviert. ;------------------------------------------------------------------------------- ; Anzeige ;------------------------------------------------------------------------------- ; ;-------------+-------------+--------------+------------------------------------ ; LOW_LED | HIGH_LED | PULSE_LED | Zustand am Eingang ;-------------+-------------+ -------------+------------------------------------ ; x | x | aus | noch keine Impuls empfangen ; x | x | an | Impuls(e) empfangen ; x | x | blinkt | Impulse werden empfangen ; aus | aus | blinkt nicht | offen ; sehr hell | aus | blinkt nicht | LOW ; aus | sehr hell | blinkt nicht | HIGH ; sehr hell | aus | blinkt | LOW mit sehr kurzen Impulsen ; wenig hell | aus | blinkt | LOW mit kurzen Impulsen ; wenig hell | wenig hell | blinkt | Impulse mit 1:1 ; aus | wenig hell | blinkt | HIGH mit kurzen Impulsen ; aus | sehr hell | blinkt | HIGH mit sehr kurzen Impulsen ; blinkt | aus | blinkt | Langsame sehr kurze HIGH Impulse ; blinkt | blinkt | blinkt | Langsame Impulse ; aus | blinkt | blinkt | Langsame sehr kurze LOW Impulse ; -------------+------------+--------------+------------------------------------ ; Taste betätigt | Spezial-Anzeige ;-------------+-------------+ -------------+------------------------------------ ; blinkt | aus | aus | Universal ; blinkt | aus | blinkt | CMOS ; aus | blinkt | blinkt | TTL, Versorgungsspannung OK ; blinkt | blinkt | blinkt | TTL, Versorgungsspannung zu klein ; -------------+------------+--------------+------------------------------------ ; Nach dem Einschalten | Spezial-Anzeige ; -------------+------------+--------------+------------------------------------ ; aus | aus | aus | Test ob LED OK, Pause ; -------------+------------+--------------+------------------------------------ ; Nach dem Einschalten und der 1. Pause | Version 1. primär 2. sekundär ;-------------+-------------+--------------+------------------------------------ ; an | an | an | Test ob LED OK ; aus | aus | an | Version 1 ; aus | an | aus | Version 2 ; aus | an | an | Version 3 ; an | aus | aus | Version 4 ; an | aus | an | Version 5 ; an | an | aus | Version 6 ; an | an | an | Version 7 ; -------------+------------+--------------+------------------------------------ ; Nach dem Einschalten und der Version | Universal-Familie ; -------------+------------+--------------+------------------------------------ ; aus | aus | blinkt | ; -------------+------------+--------------+------------------------------------ ; Nach längerem Betätigen des Tasters | Familie ; -------------+------------+--------------+------------------------------------ ; blinkt | aus | aus | Universal ; blinkt | aus | blinkt | CMOS ; aus | blinkt | blinkt | TTL OK ; blinkt | blinkt | blinkt | TTL, Versorgungsspannung zu klein ; -------------+------------+--------------+------------------------------------ ;******************************************************************************* ; PROGRAMM ;******************************************************************************* ; Processor Inclusion #include "/usr/local/microchip/mplabx/mpasmx/p12f629.inc" ; PIC12F629 Configuration Bit Settings ; OSC -- Oscillator Selection bits (bitmask:0x0007) ; WDTE -- Watchdog Timer Enable bit (bitmask:0x0008) ; PWRTE -- Power-Up Timer Enable bit (bitmask:0x0010) ; MCLRE -- GP3/MCLR pin function select (bitmask:0x0020) ; BOREN -- Brown-out Detect Enable bit (bitmask:0x0040) ; CP -- Code Protection bit (bitmask:0x0080) ; CPD -- Data Code Protection bit (bitmask:0x0100) __CONFIG _FOSC_INTRCIO & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _BOREN_OFF & _CP_OFF & _CPD_OFF ;******************************************************************************* ; Zeiten ;******************************************************************************* ; Alle Zeiten werden über die Periode einer Messung bestimmt. ; Die Periode wird durch Timer 0 synchronisiert. ; Timer 0 zählt die Befehlszyklen über einen Vorteiler von 1/2 ; Damit ist die Zeit für eine Periode genau 1024 µs. ; Wartezeit bis Umschaltung der Familie TTL/CMOS nach Betätigung des Button ; Die Wartezeit ist etwa 1s = 1000000 µs ; Die Wartezeit wird über den Periodenzähler periode mit 256 Perioden bestimmt. #define WAIT_FOR_FAMILY 4 ; ~ 1000000 / ( 1024 * 256 ) ; Minimale Zeit PULSE-LED an bzw aus = 80ms = 80000µs ; Die Zeit wird über die Zahl der Perioden bestimmt #define PULSE_DELAY .78 ; ~ 80000 / 1024 ;******************************************************************************* ; Konstanten ;******************************************************************************* ; Namen der Ein/Ausgänge LowLED EQU GP0 ; grün LED_Green EQU GP0 HighLED EQU GP2 ; rot LED_Red EQU GP2 PulseLED EQU GP4 ; gelb LED_Yellow EQU GP4 Pulse EQU GP5 ; Eingang In EQU GP1 ; parallel Button EQU GP3 ; Taster (normal offen) ; Werte für Vref ; VRR=20 = Low Range ; VRR= 0 = High Range ; CVref = VRR=20 : ( VR3:VR0 / 24 ) * VDD ; VRR= 0 : Vdd / 4 + ( VR3:VR0 / 32 ) * VDD UlowTTL EQU 0xA4 ; VREN=80 VRR=20 : (4 / 24 ) * VDD = 0.167 VDD UhighTTL EQU 0x86 ; VREN=80 VRR= 0 : (1/4+ 6/32) * VDD = 0.4375 VDD UlowCMOS EQU 0x81 ; VREN=80 VRR=20 : (1/4+ 1/32) * VDD = 0.28125 VDD UhighCMOS EQU 0x8E ; VREN=80 VRR= 0 : (1/4+14/32) * VDD = 0.6875 VDD UlowerTTL EQU 0xA6 ; VREN=80 VRR= 1 : (6 / 24 ) * VDD = 0.25 VDD UupperTTL EQU 0x82 ; VREN=80 VRR= 0 : (1/4+ 2/32) * VDD = 0.3125 VDD UlowerCMOS EQU 0x85 ; VREN=80 VRR= 0 : (1/4+ 5/32) * VDD = 0.40625 VDD UupperCMOS EQU 0x8A ; VREN=80 VRR= 0 : (1/4+10/32) * VDD = 0.5625 VDD UlowUniv EQU 0xA5 ; VREN=80 VRR= 1 : (5 / 24 ) * VDD = 0.20833 VDD UhighUniv EQU 0x89 ; VREN=80 VRR= 0 : (1/4+ 9/32) * VDD = 0.53125 VDD POWER_TTL EQU 0x8A ; VREN=80 VRR= 0 : (1/4+10/32) * VDD = 0.5625 VDD POWER_GPIO EQU 0x15 ; GP0, GP2, GP4 : 15 POWER_EN EQU 0x80 ; VREN=80 VRR= 0 POWER_START EQU 0x07 ; (1/4+ 7/32) * VDD = 0.46875 VDD POWER_HIGH EQU 0x0F ; (1/4+15/32) * VDD = 0.71875 VDD POWER_TIM0 EQU .254 ; 254 * 4 µs = 1016 µs -> immer ein ENABLE_SLEEP EQU 0 ; Schlafmodus ein (1) / aus (0) ;******************************************************************************* ; Variablen ;******************************************************************************* cblock 0x20 wait_10ms ; Zähler für Warteschleife ohne Timer0 wait_256 ; Zähler für Warteschleife ohne Timer0 delay ; Zähler für 1 ms Warteschleife mit Timer0 family ; 0 = universal, 1 = CMOS, 3 TTL soft_timer ; 3. Byte des Timer1 per Software timer_temp ; Zwischenspeicher für Timer-Werte timer_l ; Letzter gesehener Wert des Timer1 timer_h timer_s pulse_seen ; Impuls wurde erkannt pulse_high ; aktuelle Anzeigeperiode der PULSE-LED pulse_low ; aktuelle Anzeigeperiode der PULSE-LED button_active ; Knopf betätigt button_waiting ; > 0 warten bis Logik-Familie umschalten periods ; Zähler der Zyklen state_LEDs ; Zustand der LEDs Siehe unten 'Bits der LEDs' saved_state_LEDs ; Zustand der LEDs Siehe unten 'Bits der LEDs' timer_changed ; voltage ; Messwert für die Versorgungsspannung voltage_OK ; voltage_delay ; Dauer der Messschleife für --^ power_low ; Code für Versorgungsspannung power_gpio ; sichert gpio power_timer0 ; LEDs ausschalten, wenn timer0 > power_timer0 power_off ; Bit 0 : LEDs sind ausgeschaltet power_temp ; temporär enable_sleep ; Schlafmodus ein / aus five_minutes_l ; Millisekunden bis 5 Minuten five_minutes_m ; fife_minutes_h ; last_LED_state ; letzter Status der LEDs test_enabled ; temp ; Beliebig nur innerhalb eines Unterprogramms endc ;******************************************************************************* ; Version dieses Programms ;******************************************************************************* #define VERSION_PRIMARY 2 ; 1-6 sonst ist die Anzeige nicht eindeutig #define VERSION_SECONDARY 3 ; 1-7 ;******************************************************************************* ; Bits der LEDs ;******************************************************************************* #define LOW_LED 0 ; 01 #define HIGH_LED 1 ; 02 #define PULSE_LED 2 ; 04 #define LOWER_LED 3 ; 08 #define UPPER_LED 4 ; 10 ;******************************************************************************* ; Bits der Familie ;******************************************************************************* #define CMOS_OR_TTL 0 ; 01 #define TTL 1 ; 02 ;******************************************************************************* ; Bits von timer_changed ;******************************************************************************* #define CURRENT 0 #define PREVIOUS 1 ;******************************************************************************* ; Default-Werte für untere TTL Versorgungsspannung ; Die Werte verwenden, wenn keine Werte im EEPROM abgelegt wurden ;******************************************************************************* #define DEFAULT_TTL_LIMIT .150 #define DEFAULT_VOLTAGE_DELAY 0x0E ;******************************************************************************* ; voltage_delay darf nur Werte 0 .. 15 haben. ; VOLTAGE_DELAY_PATTERN blendet nur die gültigen Bits ein ; VOLTAGE_DELAY_OVERFLOW erkennt Fehler ;******************************************************************************* #define VOLTAGE_DELAY_PATTERN 0x0F #define VOLTAGE_DELAY_OVERFLOW 0xF0 ;******************************************************************************* ; Reset Vektor ;******************************************************************************* RES_VECT CODE 0x0000 ; Prozessor Reset Vektor GOTO START ; Zum Anfang des Programms ;******************************************************************************* ; Interrupt Service Routines ;******************************************************************************* ISR CODE 0x0004 ; interrupt vector location ; Angenommene Interrupts erzeugen ein kurzes Blinken der roten LED ; Dieses kommt nicht vor und dient nur Testzwecken. ; CALL TEST_GP2 RETFIE ;******************************************************************************* ; Kennung des Programms ;******************************************************************************* da "Program: Logicprobe " da "Date: 23.10.2015 " da "Version: 2.3 " da "Author: Heiner Kuhlmann" ;******************************************************************************* ; HAUPTPROGRAMM ;******************************************************************************* MAIN_PROG CODE ; Linker: Hauptprogramm START GOTO Main_Program ;********************************************* ; Sprungtabellen werden hier eingefügt. * ; Damit werden PC-Rechnereien vermieden * ;********************************************* ;******************************************************************************* ; Subprogram Count_Supply_Cycles_W ; ; Count_Supply_Cycles_W zählt die Zyklen bis der Integrator zur Messung ; der Versorgungsspannung Uv-Uref erreicht hat. ; Die Dauer eines Zyklus z wird durch das W-Register ( 0-15 ) bestimmt. ; Sie z = ( 5 + W ) µs ; Dieses Unterprogramm ist Teil von Supply_Voltage ; Es springt über eine Sprungtabelle die Unterprogramme Count_Supply_Cycles_z ; mit z der Dauer eines Zyklus. ; Da die Zyklen kurz ( 8µs bis 26µs ) sind, wird nicht mit DECFSZ gearbeitet. ;******************************************************************************* Count_Supply_Cycles_W ANDLW VOLTAGE_DELAY_PATTERN ; Nur 0-15 ist zulässig ADDWF PCL, F ; Offset in W zum PC addieren ; Erzeugt "Computed GOTO" GOTO Count_Supply_Cycles_8 ; W = 00 GOTO Count_Supply_Cycles_9 ; W = 01 GOTO Count_Supply_Cycles_10 ; W = 02 GOTO Count_Supply_Cycles_11 ; W = 03 GOTO Count_Supply_Cycles_12 ; W = 04 GOTO Count_Supply_Cycles_13 ; W = 05 GOTO Count_Supply_Cycles_14 ; W = 06 GOTO Count_Supply_Cycles_15 ; W = 07 GOTO Count_Supply_Cycles_16 ; W = 08 GOTO Count_Supply_Cycles_17 ; W = 09 GOTO Count_Supply_Cycles_18 ; W = 10 GOTO Count_Supply_Cycles_19 ; W = 11 GOTO Count_Supply_Cycles_20 ; W = 12 GOTO Count_Supply_Cycles_22 ; W = 13 GOTO Count_Supply_Cycles_24 ; W = 14 GOTO Count_Supply_Cycles_26 ; W = 14 ;******************************************************************************* ; Subprogram Power_Time_Table ; Berechnung der Zeit nach der LEDs ausgeschaltet werden. ; power_timer0 ~ 255 - (W - 7) * 23.4 ;******************************************************************************* Power_Time_Table ANDLW 0xF ; Nur 0-15 ist zulässig ADDWF PCL, F ; Offset in W zum PC addieren ; Erzeugt "Computed GOTO" RETLW .255 ; 0 RETLW .255 ; 1 RETLW .255 ; 2 RETLW .255 ; 3 RETLW .255 ; 4 RETLW .255 ; 5 RETLW .255 ; 6 RETLW .255 ; 7 RETLW .231 ; 8 RETLW .208 ; 9 RETLW .184 ; 10 RETLW .161 ; 11 RETLW .138 ; 12 RETLW .114 ; 13 RETLW .91 ; 14 RETLW .91 ; 15 ;------------------------------------------------------------------------------- ; Das Hauptprogramm ;------------------------------------------------------------------------------- Main_Program CALL DELAY_1Second CALL CONFIGURE_IO ;------------------------------------------------------------------------------- ; Internen Oszillator kalibrieren ; Sonst sind die Zeiten ungenau ;------------------------------------------------------------------------------- BSF STATUS, RP0 ; Bank 1 CALL 3FFh ; Den Kalibratorswert holen MOVWF OSCCAL ; kalibrieren BCF STATUS, RP0 ; Bank 0 ;------------------------------------------------------------------------------- ; Variablen initialisieren ;------------------------------------------------------------------------------- CLRF family ; 0 = universal, 1 = CMOS, 3 TTL CLRF soft_timer ; 3. Byte des Timer1 per Software CLRF pulse_seen ; Impuls wurde erkannt CLRF pulse_high ; aktuelle Anzeigeperiode der PULSE-LED CLRF pulse_low ; aktuelle Anzeigeperiode der PULSE-LED CLRF button_active ; Knopf betätigt CLRF button_waiting ; > 0 warten bis Logik-Familie umschalten CLRF periods ; Zähler der Zyklen CLRF delay ; Zähler für 1 ms Warteschleifen CLRF state_LEDs ; Zustand für LED : Alle LEDs aus CLRF timer_changed ; CLRF voltage_OK ; Bit 0 MOVLW POWER_START MOVWF power_low ; Code für Versorgungsspannung MOVLW POWER_TIM0 MOVWF power_timer0 ; LEDs ausschalten nach CLRF power_temp ; temporär CLRF power_off ; Bit 0 : LEDs sind ausgeschaltet MOVLW ENABLE_SLEEP MOVWF enable_sleep ; Schlafmodus ein / aus CLRF five_minutes_l ; CLRF five_minutes_m ; CLRF fife_minutes_h ; CLRF test_enabled ; ;------------------------------------------------------------------------------- ; Initialisierung ; 1. 1 Sekunde wurde bereits gewartet ; 2. Die Versorgungsspannung ermitteln ; 3. Button schon jetzt betätigt: eventuell Sonderstatus ; 4. Alle LED für 1 Sekunden an ; 5. Alle LED für 1/2 Sekunde aus ; 6. Version anzeigen und 1/2 Sekunde aus ; 7. Anzeige der Familie ( CMOS ) ; 8. Timer1 initialisieren ; 9. Sonderstatus: ; Wenn Button noch betätigt: Die Minimale TTL-Spannung einstellen. ; 10. Abschließend alle LED für 1 Sekunden an und Start der Hauptschleife. ;------------------------------------------------------------------------------- ; 2. Die Versorgungsspannung ermitteln CALL Check_Supply_Voltage ; Für TTL CALL Power_Voltage ; Für Helligkeit der LEDs ; 3. Sonderstatus: könnte sein, wenn bereits Button betätigt BCF STATUS, RP0 ; GPIO in Bank 0 BTFSS GPIO, Button ; Button betätigt -> 0 BSF button_active, 0 ; Sonderstatus ; 4. Alle LED für 1 Sekunden an BCF GPIO, LED_Green ; löschen = LED an BCF GPIO, LED_Red ; löschen = LED an BCF GPIO, LED_Yellow ; löschen = LED an CALL WAIT_1000 ; 5. Alle LED für 1/2 Sekunde aus BSF GPIO, LED_Green ; setzen = LED aus BSF GPIO, LED_Red ; setzen = LED aus BSF GPIO, LED_Yellow ; setzen = LED aus CALL WAIT_500 ; 6. Version anzeigen und 1/2 Sekunde aus CALL Show_Version BSF GPIO, LED_Green ; setzen = LED aus BSF GPIO, LED_Red ; setzen = LED aus BSF GPIO, LED_Yellow ; setzen = LED aus CALL WAIT_500 ; 7. Anzeige der Familie ( CMOS ) CALL FAMILY_LEDS ; dauert etwa 500 ms CALL FAMILY_LEDS CALL FAMILY_LEDS CALL FAMILY_LEDS BCF GPIO, LED_Green ; löschen = LED an BCF GPIO, LED_Red ; löschen = LED an BCF GPIO, LED_Yellow ; löschen = LED an ; 8. Timer1 initialisieren CALL Init_Timer ; Timer-Werte setzen CALL Store_Timer_State ;------------------------------------------------------------------------------- ; Sonderstatus ; Der Sonderstatus aktiviert, wenn beim Einschalten der Taster betätigt wird. ;------------------------------------------------------------------------------- ; 9. Sonderstatus: BTFSS button_active, 0 ; Sonderstatus schon erkannt? GOTO Start_Up ; Nein: keine weitere Überprüfung ; Sonderstatus, wenn Button noch betätigt BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, Button ; Button betätigt -> 0 GOTO Start_Up ; Sonderstatus : alle LED flackern solange Button betätigt ist Special_State BTFSC GPIO, Button ; Button GOTO Special_State_Action BCF GPIO, LED_Green ; löschen = LED an BCF GPIO, LED_Red ; löschen = LED an BCF GPIO, LED_Yellow ; löschen = LED an CALL WAIT_50 BSF GPIO, LED_Green ; setzen = LED aus BSF GPIO, LED_Red ; setzen = LED aus BSF GPIO, LED_Yellow ; setzen = LED aus CALL WAIT_50 GOTO Special_State Special_State_Action ; Wert für minimale TTL-Spannung speichern CALL Save_Supply_Voltage Start_Up BCF GPIO, LED_Green ; löschen = LED an BCF GPIO, LED_Red ; löschen = LED an BCF GPIO, LED_Yellow ; löschen = LED an ; Solange der Button betätigt LEDs an lassen BCF STATUS, RP0 ; GPIO in Bank 0 BTFSS GPIO, Button ; Button betätigt -> 0 GOTO Start_Up CALL WAIT_1000 ; LEDs 1 Sekunde an ; Ende Sonderstatus ; 10. Abschließend alle LED für 2 Sekunden an und Start der Hauptschleife. BSF GPIO, LED_Green ; setzen = LED aus BSF GPIO, LED_Red ; setzen = LED aus BSF GPIO, LED_Yellow ; setzen = LED aus CALL Restart_five_minutes ;------------------------------------------------------------------------------- ; Hauptschleife ;------------------------------------------------------------------------------- Main_Loop CALL Synchronize_To_Timer CALL Decrement_five_minutes ; 1 ms weniger bis SLEEP ;------------------------------------------------------------------------------- ; Taste erkennen ;------------------------------------------------------------------------------- ; Prüfen ob die Taste betätigt wurde. Button ist dann 0 BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, Button ; Button wird 0, wenn betätigt GOTO Button_Not_Pressed Button_Pressed ; Taste wurde betätigt ; Erkannte Impulse zurücksetzen und PulseLED aus CLRF pulse_seen CALL Restart_five_minutes BCF STATUS, RP0 ; GPIO in Bank 0 BSF GPIO, PulseLED ; setzen = LED aus BSF button_active, 0 GOTO Button_End Button_Not_Pressed ; Taste wurde nicht betätigt ; Die Wartezeit aktivieren button_waiting setzen MOVLW WAIT_FOR_FAMILY MOVWF button_waiting CLRF button_active Button_End ;------------------------------------------------------------------------------- ; Warten bis button_waiting abgelaufen und dann Select_Family aufrufen ; Dieses sollte nur dann geschehen, wenn der Button betätigt wurde. ; Aber wenn der Button nicht betätigt wurde, wird button_waiting zurückgesetzt. ; ; Wenn periods == 0 wird button_waiting decrementiert ;------------------------------------------------------------------------------- MOVF periods, F BTFSS STATUS, Z ; Zero Bit GOTO Waiting_Button_End ; Wenn button_waiting abgelaufen wird Select_Family aufgerufen DECFSZ button_waiting, F GOTO Waiting_Button_End GOTO Select_Family ; Timing wird ignoriert Waiting_Button_End ;------------------------------------------------------------------------------- ; Timer ; Wenn der Timer weitergezählt hat, sind Impulse angekommen. ; Dann wird die PulseLED zuerst für PULSE_DELAY eingeschaltet ; und anschließend für PULSE_DELAY ausgeschaltet. ; Erst dann wird wieder der Timer überprüft. ;------------------------------------------------------------------------------- ; Für die minimale Pulse-High-Zeit PulseLED nicht ändern ; Wenn pulse_low != 0 MOVF pulse_high, F ; Ist pulse_high 0? BTFSS STATUS, Z ; Zero Bit GOTO Wait_For_Pulse_High ; != 0 ; Für die minimale Pulse-Low-Zeit PulseLED nicht ändern ; Wenn pulse_low != 0 MOVF pulse_low, F ; Ist pulse_low 0? BTFSS STATUS, Z ; Zero Bit GOTO Wait_For_Pulse_Low ; != 0 ; PulseLED an, wenn Impuls erkannt BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC pulse_seen, 0 ; wurde Impuls erkannt BCF GPIO, PulseLED ; GP4 löschen = LED an CALL Check_Timer_Changed_And_Store ; in timer_changed, Bit 0 BTFSC button_active, 0 ; solange Knopf betätigt GOTO Timer_End ; keine Anzeige BTFSS timer_changed, CURRENT GOTO Timer_End ; Keine Impulse ; Impulse erkannt ; PULSE_DELAY ist die Zahl der Zyklen von 1024µs. MOVLW PULSE_DELAY ; MOVWF pulse_high MOVWF pulse_low BSF pulse_seen, 0 ; Impuls erkannt BCF STATUS, RP0 ; GPIO in Bank 0 BCF GPIO, PulseLED ; GP4 löschen = LED an CALL Restart_five_minutes ; weil Impuls erkannt GOTO Timer_End Wait_For_Pulse_Low BCF STATUS, RP0 ; GPIO in Bank 0 BSF GPIO, PulseLED ; setzen = LED aus DECF pulse_low, F GOTO Timer_End Wait_For_Pulse_High BCF STATUS, RP0 ; GPIO in Bank 0 BCF GPIO, PulseLED ; löschen = LED an DECF pulse_high, F Timer_End ; Derzeitigen Zustand der LEDs speichern ; Wird später benötigt, um Änderung zu erkennen MOVFW state_LEDs MOVWF saved_state_LEDs ;------------------------------------------------------------------------------- ; Eingangspegel messen ; Zunächst wird er Zustand der LEDs ermittelt ; und die LED selbst dann später entsprechend eingeschaltet. ; Es werden vier Pegel mithilfe des Komparators gemessen. ; Für Universal werden die Pegel für Lower und Uupper nicht ermittelt. ; Unterprogramme lohnen sich nicht, ; weil je ein Wert für Universal, CMOS und TTL nötig ist. ;------------------------------------------------------------------------------- ; Low messen BCF state_LEDs, LOW_LED ; Low aus MOVLW UlowCMOS BTFSC family, TTL ; 0 = universal, 1 = CMOS, 3 TTL MOVLW UlowTTL BTFSS family, CMOS_OR_TTL ; 0 = universal, 1 = CMOS, 3 TTL MOVLW UlowUniv BSF STATUS, RP0 ; VRCON in Bank 1 MOVWF VRCON CALL DELAY16 ; 10 µs reichen BCF STATUS, RP0 ; CMCON in Bank 0 BTFSC CMCON, COUT ; Vin- > Vin+=Vref BSF state_LEDs, LOW_LED ; Low an ; High messen BCF state_LEDs, HIGH_LED ; High aus MOVLW UhighCMOS BTFSC family, TTL ; 0 = universal, 1 = CMOS, 3 TTL MOVLW UhighTTL BTFSS family, CMOS_OR_TTL ; 0 = universal, 1 = CMOS, 3 TTL MOVLW UhighUniv BSF STATUS, RP0 ; VRCON in Bank 1 MOVWF VRCON CALL DELAY16 ; 10 µs reichen BCF STATUS, RP0 ; CMCON in Bank 0 BTFSS CMCON, COUT ; not (Vin- > Vin+=Vref) BSF state_LEDs, HIGH_LED ; High an ; Bei Universal werden Lower und Upper nicht gemessen BCF state_LEDs, LOWER_LED ; Lower aus BCF state_LEDs, UPPER_LED ; Upper aus BTFSS family, CMOS_OR_TTL ; 0 = universal, 1 = CMOS, 3 TTL GOTO Evaluate_LED_State ; Lower messen MOVLW UlowerCMOS BTFSC family, TTL ; 0 = universal, 1 = CMOS, 3 TTL MOVLW UlowerTTL BSF STATUS, RP0 ; VRCON in Bank 1 MOVWF VRCON CALL DELAY16 ; 10 µs reichen BCF STATUS, RP0 ; CMCON in Bank 0 BTFSC CMCON, COUT ; Vin- > Vin+=Vref BSF state_LEDs, LOWER_LED ; Lower an ; Upper messen MOVLW UupperCMOS BTFSC family, TTL ; 0 = universal, 1 = CMOS, 3 TTL MOVLW UupperTTL BSF STATUS, RP0 ; VRCON in Bank 1 MOVWF VRCON CALL DELAY16 ; 10 µs reichen BCF STATUS, RP0 ; CMCON in Bank 0 BTFSS CMCON, COUT ; not (Vin- > Vin+=Vref) BSF state_LEDs, UPPER_LED ; Upper an Evaluate_LED_State ; Hat sich der Zustand der LEDs geändert, ; dann wird die Wartezeit bis zur Schlafpause verkängert MOVFW state_LEDs XORWF saved_state_LEDs, W BTFSS STATUS, Z CALL Restart_five_minutes ; weil Änderung der LEDs ;------------------------------------------------------------------------------- ; Auswertung der LED-Zustände und schalten der LED ; Wenn der Timer Impulse erkannte, werden die Low- und High-LEDs ; etwas dunkler eingeschaltet, um das Tastverhältnis darzustellen. ; ; Das Tastverhältnis wird nur anzeiget, wenn in zwei aufeinander folgenden ; Zyklen Impulse erkannt wurden. ;------------------------------------------------------------------------------- ; Der Timer wurde bereits oben mit Check_Timer_Changed_And_Store geprüft ; Das Ergebnis steht in timer_changed, Bit 0 ; Ob sich davor der Timer auch änderte, ist in timer_changed, Bit 1 BTFSS timer_changed, PREVIOUS GOTO Set_LED ; keine Impulse BTFSS timer_changed, CURRENT GOTO Set_LED ; keine Impulse ; Geringere Helligkeit; ; Nur während jeder 8. Periode ( 1/8 Helligkeit ) Bit 0, Bit 1, Bit 2 BTFSC periods, 0 GOTO Set_LED ; jetzt nicht BTFSC periods, 1 GOTO Set_LED BTFSC periods, 2 GOTO Set_LED BTFSC state_LEDs, UPPER_LED ; Wenn Upper an BSF state_LEDs, HIGH_LED ; High an BTFSC state_LEDs, LOWER_LED ; Wenn Lower an BSF state_LEDs, LOW_LED ; Low an ; Wenn Impulse und weder Low- noch High-LED an dann beide LED an ; Impulse wurden schon erkannt BTFSC state_LEDs, HIGH_LED GOTO Set_LED BTFSC state_LEDs, LOW_LED GOTO Set_LED ; Beide LED einschalten BSF state_LEDs, HIGH_LED ; High an BSF state_LEDs, LOW_LED ; Low an Set_LED ; Die LED entsprechend low_LED und high_LED setzen ; Es können beide LED aktiv sein. ; Mit Low beginnen BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC state_LEDs, LOW_LED GOTO Set_Low_LED BSF GPIO, LowLED ; setzen = LED aus GOTO Set_Next_LED ; Set_Low_LED BCF GPIO, LowLED ; löschen = LED an ; Weiter mit High Set_Next_LED BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC state_LEDs, HIGH_LED GOTO Set_High_LED BSF GPIO, HighLED ; setzen = LED aus GOTO End_Set_LED Set_High_LED BCF GPIO, HighLED ; löschen = LED an End_Set_LED GOTO Main_Loop ;------------------------------------------------------------------------------- ; CMOS / TTL Familie auswählen und anzeigen ; Zustandsübergänge: universal -> CMOS -> TTL -> universal ;------------------------------------------------------------------------------- Select_Family CALL Check_Supply_Voltage CALL Power_Voltage BTFSS family, CMOS_OR_TTL ; 0 = universal, 1 = CMOS, 3 TTL GOTO Set_CMOS ; CMOS oder TTL BTFSS family, TTL ; 0 = universal, 1 = CMOS, 3 TTL GOTO Set_TTL ; ist CMOS Set_Universal CLRF family ; 0 = universal, 1 = CMOS, 3 TTL GOTO Show_Family Set_CMOS BSF family, CMOS_OR_TTL ; 0 = universal, 1 = CMOS, 3 TTL BCF family, TTL ; 0 = universal, 1 = CMOS, 3 TTL GOTO Show_Family Set_TTL BSF family, TTL ; 0 = universal, 1 = CMOS, 3 TTL Show_Family CALL FAMILY_LEDS ; dauert etwa 500 ms BTFSS GPIO, Button ; prellen ist schon lange vorbei GOTO Show_Family CALL Store_Timer_State ; Impulse während Show_Family ignorieren GOTO Main_Loop ;******************************************************************************* ; SUBPROGRAMS ;******************************************************************************* ;******************************************************************************* ; Subprogram CONFIGURE_IO ; I/O usw konfigurieren. ; Zuvor werden nötige Konstanten definiert. ;******************************************************************************* ; Input ; GP0 GP1 GP2 GP3 GP4 GP5 ; 01 02 04 08 10 20 00 = Ausg #define TRISIO_STANDARD 0x2A ; 00 02 00 08 00 20 #define TRISIO_INIT_TIMER 0x28 ; 00 00 00 08 00 20 #define TRISIO_VOLTAGE 0x0B ; 01 02 00 08 00 00 #define TRISIO_POWER 0x2B ; 01 02 00 08 00 20 #define TRISIO_SLEEP 0x09 ; 01 00 00 08 00 00 #define COMPARATOR_Standard 0x04 ; GP1=CIN-, GP0, GP2 als Daten ; Mode (CM2:CM0) = 110 = 0x04 ; GP1/CIN- als Eingang CIS = 1 = 0x08 ; nicht invertierend CINV = 0 = 0x00 #define COMPARATOR_Power 0x0E ; GP0=CIN+, GP1 offen, GP2 als Daten ; Mode (CM2:CM0) = 110 = 0x06 ; GP0/CIN+ als Eingang CIS = 1 = 0x08 ; nicht invertierend CINV = 0 = 0x00 #define COMPARATOR_VOLTAGE 0x02 ; GP0=CIN+, GP1=CIN-, GP2 als Daten ; Mode (CM2:CM0) = 010 = 0x02 ; nicht invertierend CINV = 0 = 0x00 #define COMPARATOR_LOW_POWER 0x00 ; Mode (CM2:CM0) = 000 = 0x00 #define OPTION_STATE 0x81 ; Timer 0 und Pullup ( OPTION_REG ) ; Kein Pullup NOT_GPPU OPTION_REG(7) = 1 : 80 ; Interrupt Edge: egal INTEDG OPTION_REG(6) = 0 : 00 ; Timer 0 Takt an CPU T0CS OPTION_REG(5) = 0 : 00 ; Prescaler an Timer 0 PSA OPTION_REG(4) = 0 : 00 ; Prescaler 1:4 PS OPTION_REG(0:2) = 1 : 01 #define TIMER_1_CONTROL 0x07 ; (00) TMR1GE = 0 -> Timer1 Gate ignored ; (00) T1CKPS1:TKCKPS0 = 00 -> 1:1 Prescale ; (04) T1SYNC = 1 -> asynchron ; (02) TMR1CS = 1 -> external clock ; (01) TMR1ON = 1 -> Timer1 ON CONFIGURE_IO BCF STATUS, RP0 ; GPIO in Bank 0 CLRF GPIO ; Init GPIO CALL COMP_TRISO_STANDARD ; Reference Voltage BSF STATUS, RP0 ; VRCON in Bank 1 MOVLW UlowCMOS ; MOVWF VRCON ; Timer 0 und Pullup ( OPTION_REG ) BSF STATUS, RP0 ; OPTION_REG in Bank 1 MOVLW OPTION_STATE ; MOVWF OPTION_REG ; Timer 0 zurücksetzen BCF STATUS, RP0 ; TMR0 in Bank 0 CLRF TMR0 ; Timer 0 auf 0 setzen ; Timer 1 MOVLW TIMER_1_CONTROL BCF STATUS, RP0 ; T1CON in Bank 0 MOVWF T1CON MOVF TMR1L, W ; Timer L lesen MOVWF timer_l ; letzter Wert MOVF TMR1H, W ; Timer H lesen MOVWF timer_h ; letzter Wert CLRF soft_timer CLRF timer_s RETURN ;******************************************************************************* ; Subprogram COMP_TRISO_STANDARD ; konfiguriert den Komparator und die GPIO für die Messung der ; Eingangsspannung mit der Referenzspannung ;******************************************************************************* COMP_TRISO_STANDARD ; Comparator BCF STATUS, RP0 ; CMON in Bank 0 MOVLW COMPARATOR_Standard MOVWF CMCON ; ; LEDs and Input MOVLW TRISIO_STANDARD BSF STATUS, RP0 ; TRISIO in Bank 1 MOVWF TRISIO BCF STATUS, RP0 ; Wieder Bank 0 RETURN ;******************************************************************************* ; Subprogram COMP_TRISO_Power_Voltage ; konfiguriert den Komparator und die GPIO für die Messung der ; Versorgungsspannung mit der Referenzspannung ;******************************************************************************* COMP_TRISO_Power_Voltage ; GP0/CIN+ als Eingang MOVLW TRISIO_POWER BSF STATUS, RP0 ; TRISIO in Bank 1 MOVWF TRISIO ; GP0/CIN+ an Komparator MOVLW COMPARATOR_Power BCF STATUS, RP0 ; CMCON in Bank 0 MOVWF CMCON ; wegen Stecktiefe kein CALL GOTO DELAY16 ; Eingang einschwingen lassen ;******************************************************************************* ; Subprogram Init_Timer ; Der Timer erkennt den ersten Impuls nicht. ; Er bekommt ein paar von GP1 (In) Impulse ;******************************************************************************* Init_Timer MOVLW TRISIO_INIT_TIMER ; GP1 auch als Ausgang BSF STATUS, RP0 ; TRISIO in Bank 1 MOVWF TRISIO BCF STATUS, RP0 ; Wieder Bank 0 CALL WAIT_50 ; nötig, weil Kondensator am Ausgang BCF GPIO, In CALL WAIT_50 ; nötig, weil Kondensator am Ausgang BSF GPIO, In CALL WAIT_50 ; nötig, weil Kondensator am Ausgang BCF GPIO, In CALL WAIT_50 ; nötig, weil Kondensator am Ausgang MOVLW TRISIO_STANDARD BSF STATUS, RP0 ; TRISIO in Bank 1 MOVWF TRISIO BCF STATUS, RP0 ; Wieder Bank 0 CALL WAIT_50 ; nötig, weil Kondensator am Ausgang RETURN ;******************************************************************************* ; Subprogram Synchronize_To_Timer ; 1. Versorgungspannung prüfen ; 2. Synchronisieren auf Timer 0 ; Timer 0 läuft mit einem Prescaler von 4 damit ist die Periode 1024 µs ; 3. Zählt die Perioden ; 4. Timer 1 Überlauf erkennen und soft_timer inkrementieren ;******************************************************************************* Synchronize_To_Timer ; GPIO in power_gpio sichern BCF STATUS, RP0 ; GPIO, INTCON in Bank 0 MOVFW GPIO MOVWF power_gpio Wait_For_Synchronize ; Prüfen ob TOIF Interrupt-Bit gesetzt ist BTFSC INTCON, T0IF GOTO Synchronized BTFSC power_off, 0 ; LEDs sind schon aus GOTO Wait_For_Synchronize ; Warten bis LEDs auschalten MOVFW TMR0 SUBWF power_timer0, W ; power_timer0 - TMR0 BTFSC STATUS, C ; power_timer0 - TMR0 < 0 GOTO Wait_For_Synchronize ; Alle LEDs aus BSF GPIO, LED_Green ; LED aus BSF GPIO, LED_Red ; LED aus BSF GPIO, LED_Yellow ; LED aus BSF power_off, 0 GOTO Wait_For_Synchronize Synchronized BCF INTCON, T0IF ; Timer 0 Flag zurücksetzen ; Status der LEDs restaurieren MOVFW power_gpio ANDLW POWER_GPIO MOVWF GPIO CLRF power_off ;------------------------------------------------------------------------------- ; Timer 1 Überlauf erkennen und soft_timer inkrementieren ;------------------------------------------------------------------------------- BCF STATUS, RP0 ; PIR1 in Bank 0 BTFSS PIR1, TMR1IF ; Timer1 Überlauf GOTO No_Timer_Overflow BCF PIR1, TMR1IF ; Timer1 Überlauf löschen GOTO No_Timer_Overflow No_Timer_Overflow ;------------------------------------------------------------------------------- ; Perioden zählen ;------------------------------------------------------------------------------- INCF periods, F ; Perioden zählen RETURN ;******************************************************************************* ; Subprogram Family_LEDs ; Anzeige der Logik-Familie über LEDS ; grün -> universal ; gelb und grün -> CMOS ; gelb und rot -> TTL ; Die LEDs blinken, wenn Family_LEDs mehrfach nacheinander aufgerufen wird. ; Ein Binkzyklus dauert etwa 500 ms. ;******************************************************************************* FAMILY_LEDS BCF STATUS, RP0 ; GPIO in Bank 0 BSF GPIO, LED_Green ; LED aus BSF GPIO, LED_Red ; LED aus ; TTL und universal gibt es nicht gleichzeitig ; universal : gelbe LED aus BTFSC family, CMOS_OR_TTL ; 0 = universal, 1 = CMOS, 3 TTL BCF GPIO, LED_Yellow ; LED an BTFSS family, TTL ; 0 = universal, 1 = CMOS, 3 TTL GOTO Is_CMOS ; TTL BCF GPIO, LED_Red ; LED an BTFSS voltage_OK, 0 ; Versorgungsspannung nicht Ok BCF GPIO, LED_Green ; LED an GOTO Family_End Is_CMOS BCF GPIO, LED_Green ; LED an Family_End CALL WAIT_250 ; Blinken: alle LED aus BSF GPIO, LED_Green ; LED aus BSF GPIO, LED_Red ; LED aus BSF GPIO, LED_Yellow ; LED aus CALL WAIT_250 RETURN ;******************************************************************************* ; Subprogram Restart_five_minutes ; Wartezeit bis 5 Minuten ohne Aktivität neu starten. ; (4 * 256 + 148) * 256 = 300032 ms = 300,032 s ~ 5min ;******************************************************************************* #define FIVE_MINUTES_H .4 #define FIVE_MINUTES_M .148 Restart_five_minutes BTFSS enable_sleep, 1 RETURN CLRF five_minutes_l ; Millisekunden bis 5 Minuten MOVLW FIVE_MINUTES_M MOVWF five_minutes_m MOVLW FIVE_MINUTES_H MOVWF fife_minutes_h RETURN ;******************************************************************************* ; Subprogram Decrement_five_minutes ; Wartezeit bis 5 Minuten ohne Aktivität neu starten. ; Die ms werden rumtergezählt. ;******************************************************************************* Decrement_five_minutes BTFSS enable_sleep, 1 RETURN DECFSZ five_minutes_l, F ; Millisekunden bis 5 Minuten RETURN DECFSZ five_minutes_m, F ; RETURN DECFSZ fife_minutes_h, F ; RETURN ; 5 Minuten sind um: LEDs aus BCF STATUS, RP0 ; GPIO in Bank 0 BSF GPIO, LED_Green ; LED aus BSF GPIO, LED_Red ; LED aus BSF GPIO, LED_Yellow ; LED aus ;------------------------------------------------------------------------------- ; Stromverbrauch reduzieren: ; 1. Referenzspannungsgenerator aus ; 2. Komparator aus ; 3. GP1 auf Vss ; 4. GP5 auf Vss ; ; Interrupts für SLEEP vorbereiten ; GEI ist nicht aktiviert: Ein Interrupt-Flag wird SLEEP beenden, ; aber keinen Interrupt auslösen. ;------------------------------------------------------------------------------- BCF STATUS, RP0 ; CMON in Bank 0 MOVLW COMPARATOR_LOW_POWER MOVWF CMCON ; Comparator aus BSF STATUS, RP0 ; VRCON und TRISIO in Bank 1 CLRF VRCON ; Referenz aus MOVLW TRISIO_SLEEP MOVWF TRISIO BCF STATUS, RP0 ; GPIO in Bank 0 BCF GPIO, GP1 ; GP1 auf Vss BCF GPIO, GP5 ; GP5 auf Vss BSF STATUS, RP0 ; IOC in Bank 1 BSF IOC, IOC3 ; GP3 Interrupt-on-change ein BSF INTCON, GPIE ; Port Change Interrupt Enable SLEEP NOP BCF STATUS, RP0 ; GPIO in Bank 0 MOVFW GPIO ; Änderung akzeptieren BSF STATUS, RP0 ; IOC in Bank 1 BCF IOC, IOC3 ; GP3 Interrupt-on-change aus BCF INTCON, GPIF BCF INTCON, GPIE BCF INTCON, INTF ; C2 aufladen BCF STATUS, RP0 ; GPIO in Bank 0 BSF GPIO, GP1 ; GP1 auf VDD CALL COMP_TRISO_STANDARD CALL Store_Timer_State GOTO Restart_five_minutes ;******************************************************************************* ; Subprogram Power_Voltage ; Messen der Versorgungsspannung durch Vergleich mit dem Komparator und LED ; ; Das Ergebnis steht in power_low ; Wert der letzten Messung ( 0h bis Fh ) ; ; Es wird die Spannung GP0/CIN+ mit der Referenzspannung verglichen. ; Die Referenzspannung ist q * Uv ( 0 < q < 1 ) ; ; Voraussetzung: ; 1. Die relative Eingangsspannung ist immer q > 0.25 Uv ; 2. Die relative Eingangsspannung ist immer q < 0.72 Uv ; ; Es wird nur 0.5 <= q <= 0.7 ausgewertet. ; 0.25 -> VR3:VRO = 0x0 ; 0.72 -> VR3:VRO = 0xF ; ; In power_low steht der Wert VR3:VRO, der bei der letzten Messung kleiner war. ; ; Wennb power_low zu kein war, wird der Wert um 1 erhöht und eine neue Messung ; durchgeführt. ; ;******************************************************************************* Power_Voltage ; GPIO in power_gpio sichern BCF STATUS, RP0 ; GPIO in Bank 0 MOVFW GPIO MOVWF power_gpio CALL COMP_TRISO_Power_Voltage CALL DELAY32 MOVLW POWER_START ; Mit dem kleinsten Wert beginnen MOVWF power_low Power_Try ; Messung mit Wert von power_low CALL TEST_GP2 MOVFW power_low IORLW POWER_EN BSF STATUS, RP0 ; VRCON in Bank 1 MOVWF VRCON CALL DELAY16 ; 10 µs reichen BCF STATUS, RP0 ; CMCON in Bank 0 BTFSC CMCON, COUT ; skip if Vin- > Vin+ = Vref GOTO Power_OK ; power_low + 1, wenn nicht zu hoch INCF power_low, W SUBLW POWER_HIGH BTFSC STATUS, Z ; skip wenn nicht gleich GOTO Power_OK INCF power_low, F GOTO Power_Try Power_OK CALL Power_Votage_To_Time CALL COMP_TRISO_STANDARD ; Restore GP0 aus power_gpio ; Status der LEDs restaurieren MOVFW power_gpio ANDLW POWER_GPIO MOVWF GPIO RETURN ;******************************************************************************* ; Subprogram Power_Votage_To_Time ; Berechnung der Zeit nach der LEDs ausgeschaltet werden. ; power_timer0 ~ 255 - (power_low - 4) * 21 ;******************************************************************************* Power_Votage_To_Time MOVFW power_low CALL Power_Time_Table MOVWF power_timer0 RETURN ;******************************************************************************* ; Subprogram Supply_Voltage ; Supply_Voltage bestimmt den Wert voltage, ; der ein Mass für die Versorgungsspannung ist. ; ; Der Komparator vergleicht die Versorgungsspannung Udd ; mit der Spannung an einer LED als Referenz. ; An GP0/CIN+ liegt Udd-ULED. ; Diese Spannung wird zunächst mit einer Referenzspannung Udd * POWER_TTL. ; Wenn die Spannung am Eingang höher als diese Referenz ist, ; wird überhaupt weiter gemessen. Sonst wird voltage auf 0 gesetzt. ; ; An GP0/CIN+ liegt Udd-ULED. Diese liegt auch an GP1/CIN-. ; Am offenen Eingang liegt Ue0 ~ Uv / 2 ~ 2,5V bei 5V Versorgungsspannung. ; Der Eingang wird dann über den Widerstand R2 ; an die Versorgungsspannung gelegt. ; Die Spannung an GP1/CIN- steigt über ein RC-Glied R2, R3, R4 und C2 an. ; Wenn die Spannung an GP1/CIN- den Wert von GP0/CIN+ überschreitet, ; Wird es am Komparator erkannt. ; Die Zeit bis dieses eintritt, ist ein Maß für die Versorgungsspannung. ; Die Zeitkonstante dieses RC-Gliedes liegt bei 2ms. ; Die Messzeit wird als unter 10 * 2ms liegen. ; ; Nach der Messung muss der Kondensator C2 sich wieder auf Ue0 einstellen. ; Die Zeitkonstante bestimmt das RC-Glied R1, R2, R3, R4 und C2 und ist < 5ms. ; Nach 100 ms ist Ue0 sicher erreicht. ; ; Die Messung hängt stark vom Eingangskreis ab. ; Es werden einfach die Messzyklen bis GP1/CIN- > GP0/CIN+ gezählt. ; Die Dauer eines Messzyklus ist in voltage_delay abgelegt. ; voltage_delay wird beim Start aus dem EEPROM gelesen. ; ; Da ein Messzyklus zwischen 8 ms und 26 ms liegen kann, wird einfach für alle ; möglichen Messzyklen je ein eigenes Programmteil ; Count_Supply_Cycles_z ( mit z = 8 .. 26 ) verwendet. ; Diese Programmteil wird über die Sprungtabelle Count_Supply_Cycles_W ; angesprungen. ; Der Wert in W bestimmt den wert von z. ; W wird mit dem oben erwähnten Wert voltage_delay geladen. ; voltage_delay darf nur die Werte 0 .. 15 annehmen. ; Die Zuordnung von voltage_delay -> Count_Supply_Cycles_z kann man ; Count_Supply_Cycles_W entnehmen. ; ; Sowohl Count_Supply_Cycles_W als auch die Count_Supply_Cycles_z sind KEINE ; Unterprogramme. Sie werden einfach angesprungen und springen schließlich ; Voltage_overflow oder Voltage_End an. ; ;******************************************************************************* Supply_Voltage CLRF voltage ; Messwert CALL COMP_TRISO_Power_Voltage CALL DELAY32 ; Messung, ob Spannung überhaupt hoch genug MOVLW POWER_TTL BSF STATUS, RP0 ; VRCON in Bank 1 MOVWF VRCON CALL DELAY16 ; 10 µs reichen BCF STATUS, RP0 ; CMCON in Bank 0 BTFSC CMCON, COUT ; skip if Vin- > Vin+ = Vref GOTO Voltage_to_low_for_TTL CALL COMP_TRISO_STANDARD BCF STATUS, RP0 ; CMCON in Bank 0 MOVLW COMPARATOR_VOLTAGE MOVWF CMCON ; Erst jetzt Ausgang aktivieren MOVLW TRISIO_VOLTAGE ; GP1 auch als Ausgang BSF STATUS, RP0 ; TRISIO in Bank 1 MOVWF TRISIO BCF STATUS, RP0 ; Wieder Bank 0 BSF GPIO, GP5 ; Versorgungsspannung an GP5 CALL DELAY32 ; Minimale Zeit damit voltage ; nicht überläuft MOVFW voltage_delay ; Dauer eines Messzyklus GOTO Count_Supply_Cycles_W Voltage_to_low_for_TTL CALL COMP_TRISO_STANDARD RETURN ; in voltage steht 0 ;------------------------------------------------------------------------------- ; Die Werte 0x00 und 0xFF sind für den Default-Wert reserviert. ; Es wird dann 0xFE gesetzt Voltage_overflow ; voltage ist übergelaufen also 00h ; voltage auf 0xFF setzen DECF voltage, F Voltage_End ; Wenn voltage = 0xFF auf 0xFE setzen INCFSZ voltage, W ; FF -> 0 voltage wird nicht verändert DECF voltage, F ; Ergebnis steht in voltage ; Konfiguration wieder auf Standard setzen ; Standard-Modus wieder herstellen MOVLW TRISIO_STANDARD BSF STATUS, RP0 ; TRISIO in Bank 1 MOVWF TRISIO BCF STATUS, RP0 ; Wieder Bank 0 MOVLW COMPARATOR_Standard MOVWF CMCON RETURN ;******************************************************************************* ; Subprogram Count_Supply_Cycles_z ( z = 8 .. 26 ) ; Count_Supply_Cycles_z zählt die Zyklen bis der Integrator zur Messung ; der Versorgungsspannung Uv-Uref erreicht hat. ; Die Dauer eines Zyklus ist z µs. ; ; Die Count_Supply_Cycles_z sind Teil Supply_Voltage ; Die Count_Supply_Cycles_z sind kein Unterprogramm im eigentlichen Sinne, ; vielmehr werden die Label in Count_Supply_Cycles_W über ein ; "Computed GOTO" angesprungen. ; Von Count_Supply_Cycles_z werden dann Voltage_End oder Voltage_overflow ; in Supply_Voltage angesprungen. ; ;******************************************************************************* Count_Supply_Cycles_8 NOP NOP NOP ; 3µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_8 ; 2µs ; Summe 3µs + 5µs = 8µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_9 CALL DELAY4 ; 4µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_9 ; 2µs ; Summe 4µs + 5µs = 9µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_10 CALL DELAY4 NOP ; 5µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_10 ; 2µs ; Summe 5µs + 5µs = 10µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_11 CALL DELAY4 NOP NOP ; 6µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_11 ; 2µs ; Summe 6µs + 5µs = 11µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_12 CALL DELAY4 NOP NOP NOP ; 7µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_12 ; 2µs ; Summe 7µs + 5µs = 12µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_13 CALL DELAY8 ; 8µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_13 ; 2µs ; Summe 8µs + 5µs = 13µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_14 CALL DELAY8 NOP ; 9µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_14 ; 2µs ; Summe 9µs + 5µs = 14µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_15 CALL DELAY8 NOP NOP ; 10µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_15 ; 2µs ; Summe 10µs + 5µs = 15µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_16 CALL DELAY8 NOP NOP NOP ; 11µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_16 ; 2µs ; Summe 11µs + 5µs = 16µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_17 CALL DELAY12 ; 12µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_17 ; 2µs ; Summe 12µs + 5µs = 17µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_18 CALL DELAY4 CALL DELAY4 CALL DELAY4 NOP ; 13µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_18 ; 2µs ; Summe 13µs + 5µs = 18µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_19 CALL DELAY12 NOP NOP ; 14µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_19 ; 2µs ; Summe 14µs + 5µs = 19µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_20 CALL DELAY12 NOP NOP NOP ; 15µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_20 ; 2µs ; Summe 15µs + 5µs = 20µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_22 CALL DELAY16 NOP ; 17µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_20 ; 2µs ; Summe 17µs + 5µs = 22µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_24 CALL DELAY16 NOP NOP NOP ; 19µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_20 ; 2µs ; Summe 19µs + 5µs = 24µs GOTO Voltage_overflow ; Überlauf erkannt Count_Supply_Cycles_26 CALL DELAY20 NOP ; 21µs BTFSS CMCON, COUT ; Vin- > Vin+ 2µs = 1µs + 1µs GOTO Voltage_End ; Messung beendet: Wert in voltage ; Überlauf von voltage erkennen INCFSZ voltage, F ; Zyklen zählen 1µs GOTO Count_Supply_Cycles_20 ; 2µs ; Summe 21µs + 5µs = 26µs GOTO Voltage_overflow ; Überlauf erkannt ;******************************************************************************* ; Subprogram Check_Supply_Voltage ; Misst die Versorgungsspannung und prüft, ob sie für TTL geeignet ist. ; In voltage steht der Wert für die Versorgungsspannung. ; In voltage_OK Bit 0 steht, ob die Versorgungsspannung für TTL geeignet ist. ;******************************************************************************* Check_Supply_Voltage CALL Get_Voltage_Delay ; in voltage_delay CALL DELAY256 ; Die Eingangsspannung stabilisieren CALL Supply_Voltage CLRF voltage_OK ; voltage mit Voltage_Limit vergleichen CALL Get_Voltage_Limit ; in W SUBWF voltage, W BTFSC STATUS, C ; wenn voltage < Voltage_Limit BSF voltage_OK, 0 CALL Store_Timer_State ; Die Messung löste Impulse aus RETURN ;******************************************************************************* ; Subprogram Save_Supply_Voltage ; ; Voraussetzung: ; 1. Der Eingang der LogicProbe ist offen. ; 2. Die Versorgungsspannung ist der untere zulässige Wert für TTL ; ; Misst die Versorgungsspannung und die passende voltage_delay. ; ; Bei zu kurzen Werten von voltage_delay kommt es zum Überlauf von voltage. ; Dann wird es mit einem größeren voltage_delay versucht. ; ; Die Werte von voltage und voltage_delay werden ins EEPROM geschieben. ; Sie werden später verwendet, um zu prüfen, ob die Versogungsspannung für ; TTL gültig ist ( Check_Supply_Voltage ); ; ;******************************************************************************* Save_Supply_Voltage CALL WAIT_1000 ; Die Eingangsspannung stabilisieren CLRF voltage_delay Try_Voltage ; mit voltage_delay MOVFW voltage_delay ANDLW VOLTAGE_DELAY_OVERFLOW BTFSS STATUS, Z ; Überlauf? GOTO Illegal_Supply_Voltage CALL WAIT_100 ; Kondensator C2 auf Ue0 CALL Supply_Voltage MOVFW voltage ADDLW .25 BTFSS STATUS, C ; Überlauf GOTO Save_Supply_Values ; Nein, dann verwenden INCF voltage_delay, F ; Nächster Versuch GOTO Try_Voltage Save_Supply_Values ; Messung Ok: Speichern CALL Set_Voltage_Limit CALL Set_Voltage_Delay Illegal_Supply_Voltage CALL Store_Timer_State ; Die Messung löste Impulse aus RETURN ;******************************************************************************* ; Subprogram Get_Voltage_Limit ; Lädt voltage limit aus dem EEPROM in W ; Wenn noch kein Wert gespeichert wurde, wird das EEPROM 0xFF liefern. ; Dann wird ein Defaultwert ausgegeben. ;******************************************************************************* ; Adresse für voltage limit in EEPROM #define EE_VOLTAGE_ADR 1 Get_Voltage_Limit BSF STATUS, RP0 ; EExx in Bank1 MOVLW EE_VOLTAGE_ADR MOVWF EEADR BSF EECON1, RD ; EE Read MOVF EEDATA, W ; voltage limit in W BCF STATUS, RP0 ; Wieder Bank0 ; Wenn der Wert 0 ist, wird der Default-Wert genommen BTFSC STATUS, Z GOTO Voltage_Limit_Illegal ; Prüfen, ob der Wert 0xFF ist MOVWF temp COMF temp, W BTFSC STATUS, Z GOTO Voltage_Limit_Illegal MOVF temp, W RETURN Voltage_Limit_Illegal MOVLW DEFAULT_TTL_LIMIT RETURN ;******************************************************************************* ; Subprogram Get_Voltage_Delay ; Lädt die voltage delay aus dem EEPROM in die Variable voltage_delay ; Wenn noch kein Wert gespeichert wurde, wird das EEPROM 0xFF liefern. ; Dann wird ein Defaultwert gesetzt. ;******************************************************************************* ; Adresse für voltage delay in EEPROM #define EE_VOLTAGE_DELAY_ADR 2 Get_Voltage_Delay BSF STATUS, RP0 ; EExx in Bank1 MOVLW EE_VOLTAGE_DELAY_ADR MOVWF EEADR BSF EECON1, RD ; EE Read MOVF EEDATA, W ; voltage limit in W BCF STATUS, RP0 ; Wieder Bank0 ; Prüfen, ob der Wert 0xFF ist MOVWF voltage_delay COMF voltage_delay, W BTFSC STATUS, Z GOTO Voltage_Delay_Illegal RETURN Voltage_Delay_Illegal MOVLW DEFAULT_VOLTAGE_DELAY MOVWF voltage_delay RETURN ;******************************************************************************* ; Subprogram Set_Voltage_Limit ; Schreibt den Wert in voltage als voltage limit in das EEPROM ;******************************************************************************* Set_Voltage_Limit BSF STATUS, RP0 ; EExx in Bank1 MOVLW EE_VOLTAGE_ADR MOVWF EEADR MOVF voltage, W MOVWF EEDATA BSF EECON1,WREN ; Enable Write MOVLW 0x55 ; Unlock Write MOVWF EECON2 MOVLW 0xAA MOVWF EECON2 BSF EECON1, WR ; Start Write BCF EECON1,WREN ; Disable Write BCF STATUS, RP0 ; Wieder Bank0 Wait_For_EE_Write BTFSS PIR1, EEIF ; Auf EEIF warten GOTO Wait_For_EE_Write BCF PIR1, EEIF ; Löschen RETURN ;******************************************************************************* ; Subprogram Set_Voltage_Delay ; Schreibt den Wert in voltage_delay als voltage delay in das EEPROM ; ; Verwendet Wait_For_EE_Write aus Set_Voltage_Limit ;******************************************************************************* Set_Voltage_Delay BSF STATUS, RP0 ; EExx in Bank1 MOVLW EE_VOLTAGE_DELAY_ADR MOVWF EEADR MOVF voltage_delay, W MOVWF EEDATA BSF EECON1,WREN ; Enable Write MOVLW 0x55 ; Unlock Write MOVWF EECON2 MOVLW 0xAA MOVWF EECON2 BSF EECON1, WR ; Start Write BCF EECON1,WREN ; Disable Write BCF STATUS, RP0 ; Wieder Bank0 GOTO Wait_For_EE_Write ;******************************************************************************* ; Subprogram Store_Timer_State ; Den aktuellen Wert des Timers speichern in ; timer_l, timer_h und timer_s ;******************************************************************************* Store_Timer_State MOVF TMR1L, W ; Timer L lesen MOVWF timer_l ; letzter Wert MOVF TMR1H, W ; Timer H lesen MOVWF timer_h ; letzter Wert MOVF soft_timer, W ; Timer 3. Byte MOVWF timer_s ; letzter Wert RETURN ;******************************************************************************* ; Subprogram Check_Timer_Changed_And_Store ; Prüfen ob Timer sich änderte. ; Dabei wird der aktuelle Wert des Timers zwischengespeichert ; Das Ergebnis steht in timer_changed ; ; Der Wert von TMR1L bzw. TMR1H wird zwischengespeichert, verglichen ; und der zwischengespeicherte Wert dann gesichert. ; Dadurch werden Änderungen des Timers zwischen der Abfrage und der ; Speicherung vermieden. ; Das könnte zu nicht erkannten Impulsen führen. ;******************************************************************************* Check_Timer_Changed_And_Store BCF timer_changed, PREVIOUS BTFSC timer_changed, CURRENT BSF timer_changed, PREVIOUS BCF timer_changed, CURRENT BCF STATUS, RP0 ; TMR1L/H in Bank 0 MOVF TMR1L, W ; 1. Timer Byte MOVWF timer_temp ; zwischenspeichern SUBWF timer_l, W ; Vergleichen mit altem Wert BTFSS STATUS, Z ; Zero Bit gesetzt: keine Änderung BSF timer_changed, CURRENT MOVF timer_temp, W ; zwischengespeicherten Wert speichern MOVWF timer_l MOVF TMR1H, W ; 2. Timer Byte MOVWF timer_temp ; zwischenspeichern SUBWF timer_h, W ; Vergleichen mit altem Wert BTFSS STATUS, Z ; Zero Bit gesetzt: keine Änderung BSF timer_changed, CURRENT MOVF timer_temp, W ; zwischengespeicherten Wert speichern MOVWF timer_h ; Hier kein timer_temp, weil timer_s sich nicht ändern kann MOVF soft_timer, W ; 3.Timer Byte SUBWF timer_s, W ; Vergleichen mit altem Wert BTFSS STATUS, Z ; Zero Bit gesetzt: keine Änderung BSF timer_changed, CURRENT MOVF soft_timer, W ; Timer 3. Byte MOVWF timer_s ; letzter Wert RETURN ;******************************************************************************* ; Subprogram Show_Version ; Die Version des Programms über LEDs anzeigen ; Bit 0 gelb ; Bit 1 rot ; Bit 2 grün ; Anordnung der LED in dieser Reihenfolge von links. ;******************************************************************************* Show_Version MOVLW VERSION_PRIMARY CALL Show_Number MOVLW VERSION_SECONDARY CALL Show_Number RETURN ;******************************************************************************* ; Subprogram Show_Number ; Eine Zahl 0-7 über LEDs anzeigen ; Bit 0 gelb ; Bit 1 rot ; Bit 2 grün ; Anordnung der LED in dieser Reihenfolge von links. ;******************************************************************************* Show_Number MOVWF temp BSF GPIO, LED_Yellow ; gelbe LED aus BSF GPIO, LED_Red ; rote LED aus BSF GPIO, LED_Green ; grüne LED aus CALL WAIT_250 ; LEDs kurz aus BTFSC temp, 0 BCF GPIO, LED_Yellow ; gelbe LED an BTFSC temp, 1 BCF GPIO, LED_Red ; rote LED an BTFSC temp, 2 BCF GPIO, LED_Green ; grüne LED an CALL WAIT_1000 ; 1 Sekunde anzeigen RETURN ;******************************************************************************* ; Subprogram DELAY_W_10ms ; Einfache Verzögerung ohne Timer um W * 10 Millisekunden ;******************************************************************************* DELAY_W_10ms MOVWF wait_10ms ;## die Delay_10ms-Schleife verzögert ~10 ms = 40 * 256µs Delay_10ms MOVLW .40 MOVWF wait_256 ;## die Delay_256-Schleife verzögert 256µs Delay_256 CALL DELAY256 DECFSZ wait_256, F GOTO Delay_256 DECFSZ wait_10ms, F GOTO Delay_10ms RETURN ;******************************************************************************* ; Subprogram DELAY_1Second ; Einfache Verzögerung um etwa 1 Sekunde ohne Timer ;******************************************************************************* DELAY_1Second MOVLW .100 ; 100 * 10 ms GOTO DELAY_W_10ms ;******************************************************************************* ; Subprogram DELAYxx ; Dealy xx in µs ; DELAYxx ist rekursiv maximale Stacktiefe von 3 ;******************************************************************************* DELAY256 CALL DELAY32 ; verwendet Stacktiefe 3 DELAY224 CALL DELAY32 DELAY192 CALL DELAY32 DELAY160 CALL DELAY32 DELAY128 CALL DELAY32 DELAY96 CALL DELAY32 DELAY64 CALL DELAY32 DELAY32 CALL DELAY4 ; verwendet Stacktiefe 2 DELAY28 CALL DELAY4 DELAY24 CALL DELAY4 DELAY20 CALL DELAY4 DELAY16 CALL DELAY4 DELAY12 CALL DELAY4 DELAY8 CALL DELAY4 DELAY4 RETURN ; verwendet Stacktiefe 1 ;******************************************************************************* ; Subprogram WAIT_xxx ; WAIT xxx in ms ; WAIT_xxx ist rekursiv maximale Stacktiefe von 3 ; ; WAIT_XXX erwartet die Wartezeit in ms im W-Register ; Die Zeit wird von der Periode von Timer0 = 1024 µs abgeleitet. ; Dadurch ergibt sich eine Ungenauigkeit von bis zu 1024 µs ; für alle WAIT_xxx ; Weil die Periode 1024 µs und nicht 1000 µs = 1 ms, ; ergibt sich einen weitere Ungenauigkeit. ; Durch den Aufruf von Synchronize_To_Timer können aber wichtige zyklische ; Aufgaben durchgeführt werden. ; ; WAIT_50 geht unmittelbar zu WAIT_XXX. ; ; Die übrigen Wartezeiten werden durch rekursiven Aufruf von WAIT_250 ; erzeugt. Das letzte WAIT_250 steht deshalb in der Sequenz. ; Ebenso steht WAIT_XXX unmittelbar hinter WAIT_250. ; Das RETURN für alle Unterprogramme ist das von WAIT_XXX. ;******************************************************************************* WAIT_50 ; verwendet Stacktiefe 1 MOVLW .50 MOVWF delay GOTO WAIT_XXX WAIT_100 ; verwendet Stacktiefe 1 MOVLW .100 MOVWF delay GOTO WAIT_XXX WAIT_1000 CALL WAIT_250 ; verwendet Stacktiefe 2 WAIT_750 CALL WAIT_250 WAIT_500 CALL WAIT_250 WAIT_250 ; verwendet Stacktiefe 1 MOVLW .250 WAIT_XXX ; XXX in W MOVWF delay ; Zähler für 1 ms Warteschleifen Wait_more CALL Synchronize_To_Timer DECFSZ delay, F GOTO Wait_more RETURN ;------------------------------------------------------------------------------- ; Subprogram TEST_GP0, TEST_GP2, TEST_GP4, TEST_GP22, TEST_GP42 ; Durch dieses Programm wird ein kurzer Impuls ; an GPIO 0, GPIO 2 bzw. GPIO 4 erzeugt. ; Die Impulse können mit einem Logikanalysator ausgewertet werden. ; ; Der Impuls an GPx ist 2 Befehlszyklen, bei 4 MHz entspricht das 2 µs. ; Der Impuls an GPx2 ist 4 Befehlszyklen, bei 4 MHz entspricht das 4 µs. ; ; TEST_GPx dauert 11 µs inklusive CALL und RETURN ; TEST_GPx2 dauert 13 µs inklusive CALL und RETURN ; ; Vor dem Impuls sind 7 Befehlszyklen inklusive call ; Nach dem Impuls sind 2 Befehlszyklen inklusive return ; ; Aufruf: ; ;TEST--------------------------******------------------------------------------- ; BTFSC test_enabled, 0 ; Kein Test, dann überspringen ; CALL TEST_GPx ;------------------------------******------------------------------------------- ; ;------------------------------------------------------------------------------- TEST_GP0 BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, GP0 GOTO GP0_is_on GP0_is_off NOP ; Ausgleich für GOTO GP0_is_on BSF GPIO, GP0 NOP BCF GPIO, GP0 RETURN GP0_is_on BCF GPIO, GP0 NOP BSF GPIO, GP0 RETURN ;------------------------------------------------------------------------------- TEST_GP2 BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, GP2 GOTO GP2_is_on GP2_is_off NOP ; Ausgleich für GOTO GP2_is_on BSF GPIO, GP2 NOP BCF GPIO, GP2 RETURN GP2_is_on BCF GPIO, GP2 NOP BSF GPIO, GP2 RETURN ;------------------------------------------------------------------------------- TEST_GP22 BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, GP2 GOTO GP22_is_on GP22_is_off NOP ; Ausgleich für GOTO GP2_is_on BSF GPIO, GP2 NOP NOP NOP NOP BCF GPIO, GP2 RETURN GP22_is_on BCF GPIO, GP2 NOP NOP NOP NOP BSF GPIO, GP2 RETURN ;------------------------------------------------------------------------------- TEST_GP4 BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, GP4 GOTO GP4_is_on GP4_is_off NOP ; Ausgleich für GOTO GP4_is_on BSF GPIO, GP4 NOP BCF GPIO, GP4 RETURN GP4_is_on BCF GPIO, GP4 NOP BSF GPIO, GP4 RETURN ;------------------------------------------------------------------------------- TEST_GP42 BCF STATUS, RP0 ; GPIO in Bank 0 BTFSC GPIO, GP4 GOTO GP42_is_on GP42_is_off NOP ; Ausgleich für GOTO GP4_is_on BSF GPIO, GP4 NOP NOP NOP NOP BCF GPIO, GP4 RETURN GP42_is_on BCF GPIO, GP4 NOP NOP NOP NOP BSF GPIO, GP4 RETURN ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- END