Code:
'DEMO für FT-PC Kommunikation
'Speicherung des Datenstroms vom PC in ein I2C EEPROM
'Datenstruktur
' Beginn der Kommunikation wird mit E0h eingeleitet
' -> Interface schaltet in den Programmiermodus
' Datenstruktur Byte 0 = Länge des 1. Blocks (B1)
' Byte 1 bis n = 1. empfangener Block
' Byte n+1 = Länge des 2. Blocks (B2)
' Byte n+2 ... = 2. empfangener Block
' letztes Byte = &H00 als Endemarkierung
'
' |---| bezeichnet einen kompletten Datensatz (Block) der vom FT-Interface bestätigt wird
' Länge von 1 bis 119 Byte
'
' |S1|---|S2|-----|S3|---------|...|-------|00
' | 1. 2. 3. n. Block
' |
' |---------------------------->Block_Count Platzhalter bis Blocklänge bekannt
' |------------------------------------>I2C_Count letztes empfangenes Zeichen
'
' Page_Count = 1...16
' Alle empfangenen Zeichen werden in dem Array Page(Page_Count) gespeichert
' und als 16 Byte Page ins EEPROM gewschrieben
'
' LED an Portb.1 signalisiert Schreibvorgänge zum EEPROM bzw. zum Interface
'
' Version 1.0 vom 18.12.06
$regfile = "m8def.dat" 'Die Anweisung bestimmt Controllertyp, hier AVR Mega 16
$framesize = 32 'Stackanweisungen, die eigentlich nur bei größeren Programmen
$swstack = 32 'wirklich nötig werden
$hwstack = 64
$crystal = 8000000 'Die Frequenz des verwendeten Quarzes
'Hardware UART
Config Serialin = Buffered , Size = 120 'serial input buffer to PC , max 120 Byte je Datensatz
$baud = 9600 'Die Baudrate für RS232 Ausgabe.
'Software UART
Open "comD.4:9600,8,n,1" For Output As #1 'pin for output
Open "comD.2:9600,8,n,1" For Input As #2 'INT0 pin for input
'Hardware TWI
$lib "I2C_TWI.LBX"
Config Twi = 200000 'Bustakt in Hz
Config Sda = Portc.4
Config Scl = Portc.5
I2cinit
'LED
Config Pinb.1 = Output 'LED 1
Portb.1 = 0
Led1 Alias Portb.1
'Taster
Config Pinb.3 = Input 'Taster 1
Portb.3 = 1 'Pull Up Taster 1
Taster1 Alias Pinb.3
'Funktionen für EEPROM 24C256 definieren
Declare Sub Page_write
Declare Sub Write_eeprom(byval Adr As Word , Byval Value As Byte)
'Declare Sub Read_eeprom(byval Adr As Word , Value As Byte)
Const Addressw = &HA0 'slave write address
Const Addressr = &HA1 'slave read address
Dim Adresse As Word , Value As Byte , T1 As Byte
Dim Block(16) As Byte '16 Byte Array als Rollspeicher (Abbild des EEPROM)
'die beiden Hauptmodule
Declare Sub Transfer2eeprom
Declare Sub Transfer2ft
'*************** Soft UART ******************************************************
'Initialise INT0 für Soft UART
On Int0 Int0_int 'Nosave würde 52 Takte = 6,5uS sparen
Enable Int0
Config Int0 = Change
Dim S As Byte 'Variable der INT0-Routine
'***************Timer0 für RC5 ******************************************************
Config Portd.3 = 0 'INT 1
Rc5_pin Alias Pind.3 'Pin für TSOP1736
Config Timer0 = Timer , Prescale = 8
On Timer0 Timer_irq
Const Timervorgabe = 78 'Timeraufruf alle 178µs (10 Samples = 1 Bit = 1,778ms)
Enable Timer0 'Hier wird der Timer aktiviert
'Timing für 10 Samples Per Bit = 1,778ms
Const Samples_early = 8 'Flanke Frühestens Nach 8 Samples
Const Samples_late = 12 'Flanke Spätestens Nach 12 Samples
Const Samples_min = 3 'Flanke Vor 3 Samples - > Paket Verwerfen
'Variablen der ISR
Dim Sample As Byte 'eigentlich Bit, spart aber 46Byte ROM
Dim Ir_lastsample As Byte 'zuletzt gelesenes Sample
Dim Ir_bittimer As Byte 'zählt die Aufrufe von Timer_IRQ
Dim Ir_data_tmp As Word 'Bitstream
Dim Ir_bitcount As Byte 'Anzahl gelesener Bits
'Rückgabewerte der ISR
Dim Address_rc5 As Byte , Command_rc5 As Byte , Rc5_getflag As Bit
Dim Rc5_sendflag As Bit
'************* TIME OUT Timer: 8000 = 1sec **************************************************************************
'Timer
Config Timer1 = Timer , Prescale = 1024
Enable Timer1
Const Time_out = 39063 ' *1024 Takte (5,0sec) bis Abbruch des Downloads
'************************************************************************
'Interrupts aktivieren
Enable Interrupts
'Variablen
Dim A As Byte , B As Byte , Page As Byte
Dim I As Word , J As Word , K As Word
Dim End_flag As Bit
Dim I2c_count As Word , Block_count As Word , Page_count As Word
Dim Rc5(11) As Byte 'Vektor Zuordnung RC5 -> FT-Codes
Reset End_flag 'Erkennung für String Anfang
I2c_count = 0
'main
Restore Rc5_codes
For B = 1 To 11 'einlesen der FT Fernsteuercodes
Read Rc5(b)
Next
Reset Rc5_getflag
Reset Rc5_sendflag
Do
If Rc5_getflag = 1 Then
If Address_rc5 = &H1E Then 'FT Remote Control Channel 2
Timer1 = 0
Command_rc5 = Command_rc5 And &B01111111 'clear the RC5 toggle bit
A = Rc5(command_rc5) 'Printbin auf Array ist fehlerhaft
Disable Timer0 'Timer0 Interrupt alle 178µs stört Soft-UART
Printbin #1 , &HC1 ; A 'Ausgabe an FT
Enable Timer0
Printbin Address_rc5 ; Command_rc5 ; &HC1 ; A 'Kontrollausgabe an PC ******************
Reset Rc5_getflag
Set Rc5_sendflag 'Schaltsignal an FT (Motoren schalten erst mach 300msec alleine ab)
End If
End If
If Rc5_sendflag = 1 Then 'wenn >150msec kein neuer RC5-Code schalte Motoren ab
If Timer1 >= 1170 Then '=150msec
Reset Rc5_sendflag
Disable Timer0 'Timer0 Interrupt alle 178µs stört Soft-UART
Printbin #1 , &HC1 ; &H00
Enable Timer0
Printbin &HC1 ; &H00 'Kontrollausgabe an PC ******************
End If
End If
If Taster1 = 0 Then 'Taste gedrückt => Ausgabe des ROM
Disable Timer0
Gosub Transfer2ft
Enable Timer0
End If
While Ischarwaiting() = 1
Disable Timer0
A = Inkey() 'get it from PC
Printbin #1 , A 'send to FT
If End_flag = 1 And A = &HE0 Then 'neuer String beginnt Startkriterium E0h
Call Transfer2eeprom
End If
Reset End_flag
Enable Timer0
Wend
Loop
End
'**************************** Soft UART ********************************
'INT0 lesen eines Byte von FT mit Soft-UART
Int0_int: 'Interrupt Handler For Int0
S = Inkey(#2) 'get it from FT
Printbin S 'send to PC
Set End_flag 'Flag für FT sendet Daten
Timer1 = 0 'Timer zurücksetzen
Gifr = Gifr Or &H40 'clear Flag Int0
Return
'************************** RC5 ***************************************
'RC5 FT Steuercodes
Rc5_codes:
Data 16 , 32 , 64 , 128 , 0 , 0 , 1 , 2 , 4 , 8 , 0
'Lesen der RC5 Codes
Timer_irq:
Timer0 = Timervorgabe
Sample = Not Rc5_pin
'bittimer erhöhen (bleibt bei 255 stehen)
If Ir_bittimer < 255 Then Incr Ir_bittimer
'flankenwechsel erkennen
If Ir_lastsample <> Sample Then
If Ir_bittimer <= Samples_min Then
'flanke kommt zu früh: paket verwerfen
Ir_bitcount = 0
Else
'nur Flankenwechsel in Bit-Mitte berücksichtigen
If Ir_bittimer >= Samples_early Then
If Ir_bittimer <= Samples_late Then
'Bit speichern
Shift Ir_data_tmp , Left , 1
Ir_data_tmp = Ir_data_tmp + Sample
Incr Ir_bitcount
Else
'Flankenwechsel zu spät: Neuanfang mit gemessener Flanke
Ir_bitcount = 1
Ir_data_tmp = Sample
End If
'bittimer zurücksetzen wenn Timer > Samples_early
Ir_bittimer = 0
End If
End If
'Kontrolle des Startbits auf 1
If Ir_bitcount = 1 Then Ir_bitcount = Ir_data_tmp.0
'Alle 14 Bits gelesen?
If Ir_bitcount >= 14 Then
Command_rc5 = Ir_data_tmp 'Bit 6 und 7 siehe unten
Shift Ir_data_tmp , Right , 6
Address_rc5 = Ir_data_tmp And &B00011111
'For extended RC5 code, the extended bit is bit 6 of the command.
Command_rc5.6 = Not Ir_data_tmp.6
'The toggle bit is stored in bit 7 of the command
Command_rc5.7 = Ir_data_tmp.5
'Paket erfolgreich gelesen
Set Rc5_getflag
'paket zurücksetzen
Ir_bitcount = 0
End If
End If
'sample im samplepuffer ablegen
Ir_lastsample = Sample
Return
'******************** SUB *******************************************************
'Download vom PC to EEPROM
Sub Transfer2eeprom 'sub without parameters
'Timer1 = 0 'Timer für TimeOut ca. 0,5sec
Block_count = 0 'erster Platzhalter für erste Blocklänge
I2c_count = 0 'Startadresse des ersten Zeichens
Page_count = 0 'Startadresse des nächsten Page_Write
Page = 1 'wegen Platzhalter 1. Block (Counter für Array)
Gosub Push_byte_a 'Startzeichen &HE0 sichern -> Page_Count=2
Do
If Ischarwaiting() = 1 Then 'neues Zeichen vom PC
A = Inkey() 'get it from PC
If End_flag = 1 Then 'Anfang eines neuen Blocks erkannt
Gosub Save_block_count 'bekannte Blocklänge sichern
Gosub Push_byte_a 'neuer Platzhalter für Blocklänge
Block_count = I2c_count 'Adresse Platzhalter sichern
Reset End_flag 'warten auf Begin eines neuen Blocks
End If
Gosub Push_byte_a 'empfangenes Byte sichern
Printbin #1 , A 'zu FT senden, wenn EEPROM Speicherung abgeschlossen
'erst am Ende - wichtig für Timing von 1-Byte Befehlen
End If
I = I2c_count - Block_count
Loop Until I > 130 Or Timer1 > Time_out 'd.h. FT reagiert nicht mehr (ready)
Gosub Save_block_count 'bekannte Blocklänge sichern
A = 0
For I = 1 To 17 'Auffüllen
Gosub Push_byte_a 'Ende Markierung 00 setzen und mind. eine Page schreiben
Next
End Sub
'Platzhalter mit Blocklänge füllen
Save_block_count:
I = I2c_count - Block_count 'Länge des letzen Blocks
If I < Page Then 'Testen ob Platzhalter noch in ungesicherter Page liegt
B = Page - I
Block(b) = I
Else
Waitms 10
B = Low(i) 'wait for 10 milliseconds - see datasheet
Call Write_eeprom(block_count , B) 'Platzhalter im EEPROM mit Blocklänge füllen
Waitms 10
End If
Return
'Byte in das Array ablegen
Push_byte_a:
Incr Page 'Zähler hochzählen
Incr I2c_count
Block(page) = A
If Page = 16 Then 'Page ist voll
Call Page_write '16 Byte ins EEPROM schreiben
Page = 0 'Zähler zurücksetzen
End If
Return
'16 Byte page write to EEPROM AT24Cxx
Sub Page_write 'Page_Count Byte ab Adresse I2C_Count schreiben
Led1 = 1
I2cstart 'start condition
I2cwbyte Addressw 'slave address
T1 = High(page_count)
I2cwbyte T1 'upper address of EEPROM
T1 = Low(page_count)
I2cwbyte T1 'lower address of EEPROM
For B = 1 To 16
I2cwbyte Block(b) 'Page write 16 Byte
Next
Page_count = Page_count + 16 'neue Startposition
I2cstop 'stop condition
'waitms 10 'entfällt da im Hauptprogramm
Led1 = 0
End Sub
'page read from EEPROM AT24Cxx and send to FT
Sub Transfer2ft
'Printbin #1 , &HD2 ; &H00 ; &H0A
'Gosub Wait_ft
I2c_count = 0
I2cstart 'generate start
I2cwbyte Addressw 'slave adsress (write)
I2cwbyte 0 'upper address of EEPROM
I2cwbyte 0 'lower address of EEPROM
I2cstart 'repeated start
I2cwbyte Addressr 'slave address (read)
I2crbyte Value , Ack '1. Blocklänge lesen
While Value > 0
K = Value 'Blocklänge byte -> word
For I = 1 To K
Incr I2c_count
I2crbyte Value , Ack 'Block lesen
'Printbin Value '******* send to pc
Printbin #1 , Value 'send to ft
Next
Reset End_flag
Led1 = 1 'Aktiviere Warte-LED
Timer1 = 0 'Zähler Warteschleife zurücksetzen
Do
Waitms 10 'warten ob FT antwortet
Loop Until End_flag = 1 Or Timer1 > Time_out 'Abbruch nach max xx sec Umschaltstartsequenz [E0] -> E0 / [05 05 05] ->3,1sec-> 10 30
'Printbin &HAB 'Endemarkierung an PC senden
Do 'warten bis FT nicht mehr antwortet
Reset End_flag
Waitms 20
Loop Until End_flag = 0 'End_flag wird bei INT0 gesetzt
Led1 = 0 'Warte-LED löschen
I2crbyte Value , Ack 'nächste Blocklänge mit ACK bestätigen
Wend
I2crbyte Value , Nack 'read last byte with NO ACK
I2cstop 'generate stop
End Sub
'writing a byte to EEPROM AT24Cxx
Sub Write_eeprom(byval Adr As Word , Byval Value As Byte)
I2cstart 'start condition
I2cwbyte Addressw 'slave address
T1 = High(adr)
I2cwbyte T1 'upper address of EEPROM
T1 = Low(adr)
I2cwbyte T1 'lower address of EEPROM
I2cwbyte Value 'value to write
I2cstop 'stop condition
'Waitms 10 'wait for 10 milliseconds - see datasheet
End Sub
Lesezeichen