'############################################################################### '# Projekt : Groupiemebtron/serielle Signal- und Weichenkarte # '# Revision : 1.1 # '# Controller : ATMEGA16 # '# Compiler : BASCOM-AVR 2.0.4.0 # '# Sprache : Bascom-Basic # '# Author : Andreas Wolfram # '# WWW : http://www.groupiemebtron.de # '# Mail : # '# Datum : 30.06.2012 # '# Kontakt : peter@groupiemebtron.de # '############################################################################### '# Beschreibung: Die beiden µC Module setzen die bestehenden Baugruppen # '# für die serielle Signal und Weichen Steuerung in # '# softwarebasierenden Lösung um. # '# Funktion : ermitteln der Impulslänge - durch eine L/H Flanke des # '# Eingangssignal wird ein Interrupt ausgelöst und ein Timer # '# gestartet, nach 3ms (Timerüberlauf bei voreingestelltem Timer)# '# wird der Zustand geprüft # '# Signalkarte - entsprechend des Signals wird im x-Array ein # '# Vor- oder Rückwärtszähler gesetz, welcher PWM_Data_Zeiger # '# im y-Array verändert, ins z-Array wird der PWM-Wert # '# geladen und im 0,074 ms Takt auf die Ausgänge geschrieben # '# Weichenkarte - im x-Array H/L Status des Signals gespeichert # '# und im nächsten Schleifendurchlauf mit dem Signal verglichen # '# (Flankendetektion) und gegebenenfalls die Weichenimpulslänge # '# ins y-Array geladen. Ohne Preload hat Timer0 eine Impulslänge # '# von 0,128ms * 78 ergibt einen Interrupt aller ca. 10ms, # '# mit dem Countdown im y-Array von WK_Impuls -> 0 ergibt sich # '# die Signallänge des Weichenimpulses. # '# Changelog : Erweitert für Signale mit eletromagnetischen Antrieb # '# Flagtyp 2 eingeführt, Routine der Weichen mit mit Signalver- # '# arbeitung kombiniert # '# 26.08.2012: Data-Werte vertauscht wegen Rot-Grün-Reihenfolge, # '# diese soll identisch zu Standardkarte sein. Ebenso Port- # '# Reihenfolge in "select case Flg_typ" # '############################################################################### $prog &HFF , &HFF , &HC9 , &H00 'Wichtig! Das JTAG-IF muss abgeschaltet werden! $regfile = "m16def.dat" '$regfile = "m16adef.dat" $crystal = 16000000 $hwstack = 32 $swstack = 8 $framesize = 24 'Config Com1 = 9600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0 'Wird zum debuggen auf dem Evalutionsboard aktiviert 'Config Serialout = Buffered , Size = 128 Dim Flg_typ As Byte 'speichert den Kartentyp (Signal oder Weichenkarte) Dim Wcapture As Word 'speichert den aktuellen Timerwert Dim Wcaptureold As Word 'speichert den vorhergehenden Timerwert Dim Period As Word 'berechneter Wert zwischen zwei Impulsfolgen vom seriellen Sender Dim Bitcounter As Byte 'Anzahl empfangener Bits einer Impulsfolge Dim Flag_command_ok As Bit 'gültigen Befehl von 8 Bits empfangen Dim Cmd_ch1 As Byte 'speichert Impulsfolge (Befehl) Channel1 Dim Cmd_ch2 As Byte 'speichert Impulsfolge (Befehl) Channel2 Dim X(16) As Integer 'SK: Zählrichtung PWM_Data Positionzeiger; WK: Impulsflankenerkennung Dim Y(16) As Byte 'SK: PWM_Data Positionzeiger; WK: Impulslänge Dim Z(16) As Byte 'SK: PWM_Wert (Helligkeit der LED); WK: unbenutzt Dim Tik As Byte 'Hilfszähler für die PWM-Dauer Dim N As Byte 'Schleifenindex Dim M As Byte 'Impulslängenzähler Const Tmr0_preload = 108 'Durch den Preload 108 wird der Int aller 0,0784375ms aufgerufen, mal Tik als Byte (255)= 20ms = 50Hz Const Tmr2_preload = 208 '3ms Abtastimpuls Const Wk_impuls = 50 '0,5s Weichenimpuls Ddrd.2 = 0 'Pin PD2/Int0 ist Eingang Portd.2 = 1 'PullUp von Pin PD2/Int0 aktivieren Ddrd.3 = 0 'Pin PD3/Int1 ist Eingang Portd.3 = 1 'PullUp von Pin PD3/Int1 aktivieren Ddrd.6 = 0 'Pin PD0/ICP1 ist Eingang Portd.6 = 1 'PullUp von Pin PD0/ICP1 aktivieren Ddrd.7 = 0 'Pin PD7 ist Eingang Portd.7 = 1 'PullUp von Pin PD7 aktivieren Ddrb.0 = 0 'Pin PB0 ist Eingang Portb.0 = 1 'PullUp von Pin PD0 aktivieren Config Porta = Output 'Konfig Port A und C als Ausgang Config Portc = Output Porta = 0 'Setze Port A und C low Portc = 0 Config Int0 = Rising 'Interrupt bei steigender Flanke; durch Optokoppler inverse Logik On Int0 Int_isr 'Deklaration Serviceroutine Enable Int0 'Interrupt Int0 aktiv 'Config Int1 = Rising 'Interrupt Int1 wird nicht benötigt, 'On Int1 Int_isr 'da Channel 1 und 2, wenn beide benötigt werden, 'Enable Int1 'eh synchron sind 'Timer0 wird für die PWM der LED oder Länge des Weichenimpulses benutzt Config Timer0 = Timer , Prescale = 8 'Konfig Timer0 zur PWM der Signale Timer0 = Tmr0_preload 'Preload für Int aller 0,074 ms * 255 Impulse ^= ca. 50Hz 'ohne Preload Int aller 0,128ms * 78 Int ^= ca. 10ms * WK_Impuls ^= 0,5s On Timer0 Pwms 'Deklaration Serviceroutine Enable Timer0 'Interrupt Timer0 aktiv Config Timer1 = Timer , Prescale = 1024 'Resetdetect für die Eingangspulserkennung t = 0,064ms * 235 ^= 15,4ms bzw. 125 ^= 8ms, 'd.h. ein Eingangsimpuls muss in einem Fenster von 8ms bis 15ms nach dem eines Vorhergehenden eintreffen, sonst Reset 'Config Timer1 = Counter , Prescale = 1024 , Capture Edge = Rising , Noise Cancel = 1 'On Icp1 Oncapture 'Enable Icp1 Config Timer2 = Timer , Prescale = 1024 'Timer2 erzeugt Impuls 3,07ms nach H/L des Eingangsimpulses zur Abtastung Timer2 = Tmr2_preload 'Preload für 3ms On Ovf2 Tmr2_int 'Interruptserviceroutine Enable Ovf2 'Interrupt Timer2 aktiv Enable Interrupts 'alle Interrupst aktiv Start Timer0 'Start Timer0 Stop Timer2 'Stop Timer2 Flg_typ = 0 Flg_typ.0 = Pind.7 'flg_typ=0 Signal, flg_typ=1 Weiche, flg_typ=2 Signal mit el.-mag. Antrieb Flg_typ.1 = Not Pinb.0 Select Case Flg_typ Case 0 Y(1) = 15 : Y(3) = 15 : Y(5) = 15 : Y(7) = 15 'PWM_Data Positionzeiger Y(9) = 15 : Y(11) = 15 : Y(13) = 15 : Y(15) = 15 Z(1) = 255 : Z(3) = 255 : Z(5) = 255 : Z(7) = 255 'PWM_Wert = 255, LED grün an Z(9) = 255 : Z(11) = 255 : Z(13) = 255 : Z(15) = 255 Case 1 To 3 Y(1) = 0 : Y(2) = 0 : Y(3) = 0 : Y(4) = 0 'Weichenimpulslängenzähler = 0 Y(5) = 0 : Y(6) = 0 : Y(7) = 0 : Y(8) = 0 Y(9) = 0 : Y(10) = 0 : Y(11) = 0 : Y(12) = 0 Y(13) = 0 : Y(14) = 0 : Y(15) = 0 : Y(16) = 0 End Select Main: 'Hauptschleife If Flag_command_ok = 1 Then 'Befehl i.O. Reset Flag_command_ok 'Befehl i.O. wieder zurücksetzen If Flg_typ = 2 Then '2 ^= Signalkarte mit elektromagnetischen Antrieb Cmd_ch2 = Cmd_ch1 Xor &HFF 'Cmd_ch2 ist bitkompliment zu Cmd_ch1 End If Select Case Flg_typ Case 0 'Ist 0 ^= Signalkarte If Cmd_ch1.0 = 0 Then : X(1) = 1 : X(2) = -1 : Else : X(1) = -1 : X(2) = 1 : End If 'Befehlsauswertung Bit 0 - 7 des 1. Channels If Cmd_ch1.1 = 0 Then : X(3) = 1 : X(4) = -1 : Else : X(3) = -1 : X(4) = 1 : End If 'entsprechend des Bitwertes wird die Zählrichtung If Cmd_ch1.2 = 0 Then : X(5) = 1 : X(6) = -1 : Else : X(5) = -1 : X(6) = 1 : End If 'des PWM_Data Zeigers eingestellt, d.h. If Cmd_ch1.3 = 0 Then : X(7) = 1 : X(8) = -1 : Else : X(7) = -1 : X(8) = 1 : End If 'Ein- oder Ausblenden jeder LED If Cmd_ch1.4 = 0 Then : X(9) = 1 : X(10) = -1 : Else : X(9) = -1 : X(10) = 1 : End If If Cmd_ch1.5 = 0 Then : X(11) = 1 : X(12) = -1 : Else : X(11) = -1 : X(12) = 1 : End If If Cmd_ch1.6 = 0 Then : X(13) = 1 : X(14) = -1 : Else : X(13) = -1 : X(14) = 1 : End If If Cmd_ch1.7 = 0 Then : X(15) = 1 : X(16) = -1 : Else : X(15) = -1 : X(16) = 1 : End If Case 1 To 3 'Ist 1 ^= Weicenkarte, 2 ^= Signalkarte mit elektromagnetischen Antrieb If Cmd_ch1.0 = 0 Then 'Befehlsauswertung Bit 0 - 7 des 1. und 2. Channels If X(1) = 1 Then X(1) = 0 Y(1) = Wk_impuls End If Else X(1) = 1 End If If Cmd_ch2.0 = 0 Then : If X(2) = 1 Then : X(2) = 0 : Y(2) = Wk_impuls : End If : Else : X(2) = 1 : End If '1. Ermitteln des momentanen Bitwertes If Cmd_ch1.1 = 0 Then : If X(3) = 1 Then : X(3) = 0 : Y(3) = Wk_impuls : End If : Else : X(3) = 1 : End If '2. Auswertung der Impulsflanke durch Vergleich mit Vorgängerwert If Cmd_ch2.1 = 0 Then : If X(4) = 1 Then : X(4) = 0 : Y(4) = Wk_impuls : End If : Else : X(4) = 1 : End If '3. bei H/L Flanke setzender Impulsdauer = WK_Impuls If Cmd_ch1.2 = 0 Then : If X(5) = 1 Then : X(5) = 0 : Y(5) = Wk_impuls : End If : Else : X(5) = 1 : End If If Cmd_ch2.2 = 0 Then : If X(6) = 1 Then : X(6) = 0 : Y(6) = Wk_impuls : End If : Else : X(6) = 1 : End If If Cmd_ch1.3 = 0 Then : If X(7) = 1 Then : X(7) = 0 : Y(7) = Wk_impuls : End If : Else : X(7) = 1 : End If If Cmd_ch2.3 = 0 Then : If X(8) = 1 Then : X(8) = 0 : Y(8) = Wk_impuls : End If : Else : X(8) = 1 : End If If Cmd_ch1.4 = 0 Then : If X(9) = 1 Then : X(9) = 0 : Y(9) = Wk_impuls : End If : Else : X(9) = 1 : End If If Cmd_ch2.4 = 0 Then : If X(10) = 1 Then : X(10) = 0 : Y(10) = Wk_impuls : End If : Else : X(10) = 1 : End If If Cmd_ch1.5 = 0 Then : If X(11) = 1 Then : X(11) = 0 : Y(11) = Wk_impuls : End If : Else : X(11) = 1 : End If If Cmd_ch2.5 = 0 Then : If X(12) = 1 Then : X(12) = 0 : Y(12) = Wk_impuls : End If : Else : X(12) = 1 : End If If Cmd_ch1.6 = 0 Then : If X(13) = 1 Then : X(13) = 0 : Y(13) = Wk_impuls : End If : Else : X(13) = 1 : End If If Cmd_ch2.6 = 0 Then : If X(14) = 1 Then : X(14) = 0 : Y(14) = Wk_impuls : End If : Else : X(14) = 1 : End If If Cmd_ch1.7 = 0 Then : If X(15) = 1 Then : X(15) = 0 : Y(15) = Wk_impuls : End If : Else : X(15) = 1 : End If If Cmd_ch2.7 = 0 Then : If X(16) = 1 Then : X(16) = 0 : Y(16) = Wk_impuls : End If : Else : X(16) = 1 : End If End Select End If Select Case Flg_typ Case 0 'Ist 0 ^= Signalkarte For N = 1 To 16 'für jede LED If X(n) > 0 Then Z(n) = Lookup(y(n) , Pwm_data_sig_on) 'ermitteln der Ein- oder Ausblendrichtung If X(n) < 0 Then Z(n) = Lookup(y(n) , Pwm_data_sig_off) 'und setzen des momentanen PWM-Wertes If Y(n) = 15 And X(n) > 0 Then X(n) = 0 'Einblenden und größter Wert des PWM_Data Zeigers erreicht, zurücksetzen der Zählrichtung If Y(n) = 0 And X(n) < 0 Then X(n) = 0 'Ausblenden und kleinster Wert des PWM_Data Zeigers erreicht, zurücksetzen der Zählrichtung Y(n) = Y(n) + X(n) 'neue Position des PWM_Data Zeigers Next N Waitms 25 'hier wird zwangsgewartet, damit man des Blenden auch sieht Case 1 To 3 'ab hier Weichenkarte '26.08.2012: Reihenfolge der Ports vertauscht wegen Kompatibilität zu Standardkarte 'vorher 0,1,2,3,... nachher 1,0,3,2,... If Y(1) > 0 Then Porta.1 = 1 Else Porta.1 = 0 'die Impulslänge wird im Interrupt nach unten gezählt If Y(2) > 0 Then Porta.0 = 1 Else Porta.0 = 0 'ist Impulsdauer > 0 dann Port aktiv If Y(3) > 0 Then Porta.3 = 1 Else Porta.3 = 0 If Y(4) > 0 Then Porta.2 = 1 Else Porta.2 = 0 If Y(5) > 0 Then Porta.5 = 1 Else Porta.5 = 0 If Y(6) > 0 Then Porta.4 = 1 Else Porta.4 = 0 If Y(7) > 0 Then Porta.7 = 1 Else Porta.7 = 0 If Y(8) > 0 Then Porta.6 = 1 Else Porta.6 = 0 If Y(9) > 0 Then Portc.6 = 1 Else Portc.6 = 0 If Y(10) > 0 Then Portc.7 = 1 Else Portc.7 = 0 If Y(11) > 0 Then Portc.4 = 1 Else Portc.4 = 0 If Y(12) > 0 Then Portc.5 = 1 Else Portc.5 = 0 If Y(13) > 0 Then Portc.2 = 1 Else Portc.2 = 0 If Y(14) > 0 Then Portc.3 = 1 Else Portc.3 = 0 If Y(15) > 0 Then Portc.0 = 1 Else Portc.0 = 0 If Y(16) > 0 Then Portc.1 = 1 Else Portc.1 = 0 Waitms 1 'kurze Pause End Select Goto Main '---------------------------------------------------------- Int_isr: 'Interruptservice Wcaptureold = Wcapture 'Berechnen der Dauer zwischen zwei Interrupts Wcapture = Timer1 Period = Wcapture - Wcaptureold 'Period beinhaltet die Differenz If Period < 125 Or Period > 235 Then 'Ein Interrupt innerhalb eines Befehls wird aller 10ms ausgelöst Bitcounter = 8 'erfolgt innerhalb von 235 ^= 15ms kein Interrupt oder End If 'erfolgt in Interrupt vor 125 ^= 8ms sind Fehler aufgetreten Decr Bitcounter 'der Bitzähler wird zurück gesetzt Start Timer2 'Start des 3ms Timers 'Print Timer1 Return 'Oncapture: 'Wcaptureold = Wcapture 'Wcapture = Capture1 'Period = Wcapture - Wcaptureold 'If Period < 125 Or Period > 235 Then 'Bitcounter = 8 'End If 'Decr Bitcounter 'Start Timer2 'Return Tmr2_int: Stop Timer2 'Stop Des 3ms Timers Cmd_ch1.bitcounter = Pind.2 'Befehl Zusammensetzen Cmd_ch2.bitcounter = Pind.3 'Cmd_ch1.bitcounter = Pind.6 Timer2 = Tmr2_preload 'Timer voreinstellen If Bitcounter = 0 Then '8 Bits erkannt Set Flag_command_ok 'Befehl komplett 'Print Bin(cmd_ch1) ; " - " ; Bin(cmd_ch2) End If Return Pwms: 'Interruptroutine Timer0 Select Case Flg_typ Case 0 'Ist 0 ^= Signalkarte Timer0 = Tmr0_preload 'Timer laden 0,074 ms Takt Incr Tik 'Tik als Byte = 256 Durchläufe ^= ca. 52Hz If Tik < Z(1) Then Porta.0 = 1 Else Porta.0 = 0 'Schalten der LED Ausgänge If Tik < Z(2) Then Porta.1 = 1 Else Porta.1 = 0 If Tik < Z(3) Then Porta.2 = 1 Else Porta.2 = 0 If Tik < Z(4) Then Porta.3 = 1 Else Porta.3 = 0 If Tik < Z(5) Then Porta.4 = 1 Else Porta.4 = 0 If Tik < Z(6) Then Porta.5 = 1 Else Porta.5 = 0 If Tik < Z(7) Then Porta.6 = 1 Else Porta.6 = 0 If Tik < Z(8) Then Porta.7 = 1 Else Porta.7 = 0 If Tik < Z(9) Then Portc.7 = 1 Else Portc.7 = 0 If Tik < Z(10) Then Portc.6 = 1 Else Portc.6 = 0 If Tik < Z(11) Then Portc.5 = 1 Else Portc.5 = 0 If Tik < Z(12) Then Portc.4 = 1 Else Portc.4 = 0 If Tik < Z(13) Then Portc.3 = 1 Else Portc.3 = 0 If Tik < Z(14) Then Portc.2 = 1 Else Portc.2 = 0 If Tik < Z(15) Then Portc.1 = 1 Else Portc.1 = 0 If Tik < Z(16) Then Portc.0 = 1 Else Portc.0 = 0 Case 1 To 3 '1 ^= Weichenkarte If M = 78 Then 'Interupt aller 0,128ms * 78 ca. 10ms If Y(1) > 0 Then Decr Y(1) 'Countdown des Impulslängenzählers If Y(2) > 0 Then Decr Y(2) If Y(3) > 0 Then Decr Y(3) If Y(4) > 0 Then Decr Y(4) If Y(5) > 0 Then Decr Y(5) If Y(6) > 0 Then Decr Y(6) If Y(7) > 0 Then Decr Y(7) If Y(8) > 0 Then Decr Y(8) If Y(9) > 0 Then Decr Y(9) If Y(10) > 0 Then Decr Y(10) If Y(11) > 0 Then Decr Y(11) If Y(12) > 0 Then Decr Y(12) If Y(13) > 0 Then Decr Y(13) If Y(14) > 0 Then Decr Y(14) If Y(15) > 0 Then Decr Y(15) If Y(16) > 0 Then Decr Y(16) M = 0 Else Incr M 'Beeinflussung Schleifenzähler End If End Select Return 'Änderung von 27.04.2011 zu 26.08.2012: Reihenfolge der Werte in den beiden Data-Zeilen vertauscht um 'Anschlussfolge rot und grün zu vertauschen damit Anschluss identisch zu Standardkarte Pwm_data_sig_on: 'Data 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 20 , 70 , 200 , 253 , 255 'PWM-Wert blendet in 16 Stufen mit 255 Helligkeitswerten Data 255 , 253 , 200 , 70 , 20 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 'Ein-und Ausblenden getrennt einstellbar Pwm_data_sig_off: 'max und min Helligkeit der LED einstellbar 'Data 0 , 1 , 2 , 3 , 4 , 5 , 7 , 10 , 20 , 50 , 70 , 120 , 180 , 230 , 253 , 255 '0 = LEDaus; 255 = LED max Helligkeit Data 255 , 253 , 230 , 180 , 120 , 70 , 50 , 20 , 10 , 7 , 5 , 4 , 3 , 2 , 1 , 0