program Version2 'CONFIG: 0x3F71 '4MHz, XT-Oszillator 'Tochter-Uhr-Steuerung 'Portbelegungen: 'LED 1 RB4 'Led 2 RB3 'Positiver Puls RB2 'Negativer Puls RB1 'Taste 1 RA1 'Taste 2 RA2 'Taste 3 RA3 'Taste 4 RA5 'Spannungsmessung RA0 'DS3231, 32k RA4 'DS3231, SQW RB0 'DS3231, SCL RC3 'DS3231, SDA RC4 'Seriell TxD RC6 'Seriell RxD RC7 Symbol LED1 = PORTB.4 Symbol LED2 = PORTB.3 Symbol Positiv = PORTB.2 Symbol Negativ = PORTB.1 Symbol CR = Chr(13) Symbol LF = Chr(10) Symbol plus1stunde = PORTA.1 Symbol plus1minute = PORTA.2 Symbol minus1minute = PORTA.3 Symbol minus1stunde = PORTA.5 'variables declarations Dim zaehler, tochteruhrzeit, echtzeit, spannung, puls as word Dim text as string[20] Dim empfangen as longword Dim sekunden, hilfssekunden, minuten, stunden, polaritaet as byte Dim stelle, zeichen, fertig, checksumme as byte Dim taste1, taste2, taste3, taste4 as byte sub procedure Interrupt() If PIR1.RCIF Then 'Seriell-Empfänger-Interrupt? zeichen = RCREG 'Empfangsregister in Byte kopieren 'PIR1.RCIF = 0 'brauchts nicht, wird durch RCREG lesen zurückgesetzt If zeichen > 12 Then 'Lf (10) ausblenden, nur Cr (13) durchlassen If zeichen = 13 Then 'wenn Cr empfangen fertig = 1 'Zahl ganz empfangen Else 'sonst auf den String warten empfangen = empfangen * 16 '4 Bit nach links schieben empfangen = empfangen + zeichen - 48 'empfangene Zahl stelle = stelle + 1 'Zeichenzähler inkrementieren End if End if End if if (INTCON.2) then 'TMR0IF INTCON.2 = 0 'TMR0IF TMR0 = 6 'für 1ms Inc(zaehler) if puls > 0 then 'puls um 1 erniedrigen wenn >1 Dec(puls) end if if puls > 200 then 'wenn der Zähler bei >200 steht if polaritaet = 1 then 'und je nach Polarität... Positiv = 1 'Puls ausgeben LED1 =1 else Negativ = 1 'oder Negativen LED2 = 1 end if end if if puls = 199 then 'bei 199 Ausschalten... Positiv = 0 LED1 =0 Negativ = 0 LED2 = 0 end if if puls = 1 then 'und bei 1 if polaritaet = 1 then 'und Polaritaet für nächses Mal umkehren polaritaet = 0 else polaritaet =1 end if end if end if end sub sub function messen() as word ADCON0.3 = 0 ADCON0.4 = 0 ADCON0.5 = 0 zaehler = 0 ADCON0.2 = 1 'Wandlung starten asm NOP BTFSC ADCON0, 2 ; ist der ADC fertig? GOTO $-2 ; nein, weiter warten end asm result = (ADRESH * 256) + ADRESL end sub sub procedure lesen() 'liest die Zeit aus DS3231 I2C_Start I2C_Wr(%11010000) 'Adresse %1101000 plus 0 für Write I2C_Wr(%00000000) 'zu lesende Adresse I2C_Repeated_Start I2C_Wr(%11010001) 'Adresse %1101000 plus 1 für Read sekunden = I2C_Rd(1) minuten = I2C_Rd(1) stunden = I2C_Rd(0) I2C_Stop stunden = Bcd2Dec(stunden) minuten = Bcd2Dec(minuten) sekunden = Bcd2Dec(sekunden) end sub sub procedure schreiben(dim zeit as longword) 'schreibt die Zeit in den DS3231 LED1 = 1 LED2 = 1 I2C_Start I2C_Wr(%11010000) 'Adresse %1101000 plus 0 für Write I2C_Wr(%00000000) 'zu lesende Adresse 'I2C_Repeated_Start 'I2C_Wr(%11010000) 'Adresse %1101000 plus 1 für Read I2C_Wr(Lo(zeit)) 'Sekunden schicken I2C_Wr(Hi(zeit)) 'Minuten schicken I2C_Wr(Higher(zeit)) 'Stunden schicken I2C_Stop LED1 = 0 LED2 = 0 end sub sub procedure senden() 'schickt die Uhrzeit über die serielle Schnittstelle if hilfssekunden <> sekunden then Usart_Write_Text("TUZ:") WordToStr(tochteruhrzeit, text) Usart_Write_Text(text) Usart_Write_Text(" RTC:") WordToStr(echtzeit, text) Usart_Write_Text(text) Usart_Write_Text(" UHR:") ByteToStr(stunden, text) Usart_Write_Text(text) Usart_Write_Text(":") ByteToStr(minuten, text) Usart_Write_Text(text) Usart_Write_Text(":") ByteToStr(sekunden, text) text[3] = 13 text[4] = 10 text[5] = 0 Usart_Write_Text(text) hilfssekunden = sekunden end if end sub sub procedure tasten() if plus1stunde = 0 then 'Uhr 1 Stunde vor Inc(taste1) if taste1 = 10 then tochteruhrzeit = tochteruhrzeit - 60 end if else taste1 = 0 end if if plus1minute = 0 then 'Uhr 1 Minute vor Inc(taste2) if taste2 = 10 then tochteruhrzeit = tochteruhrzeit - 1 end if else taste2 = 0 end if if minus1minute = 0 then 'Uhr 1 Minute zurück Inc(taste3) if taste3 = 10 then tochteruhrzeit = tochteruhrzeit + 1 end if else taste3 = 0 end if if minus1stunde = 0 then 'Uhr 1 Stunde zurück Inc(taste4) if taste4 = 10 then tochteruhrzeit = tochteruhrzeit + 60 end if else taste4 = 0 end if end sub main: Delay_ms(15) TRISC = 255 'PORTC is input TRISB = %11100001 '1=input, 0=output TRISA = %00111111 OPTION_REG.7 = 1 '1 = PORTB pull-ups are disabled PIE1.RCIE = 1 'Enable Seriell-Empfänger-Interrupt PIR1 = 0 'alle interruptflags löschen PIR2 = 0 INTCON.PEIE = 1 'interrupts von peripheriegeräten erlauben INTCON.GIE = 1 'Interrupt generell erlauben 'Timer0 'Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time: 1 ms OPTION_REG = 0x81 'für 1ms TMR0 = 6 'für 1ms INTCON = 0xA0 zaehler = 0 stelle = 0 empfangen = 0 'gespeicherte Tochter-Uhrzeit lesen vorm letztem Stromunterbruch: tochteruhrzeit = (Eeprom_Read($0001) + (Eeprom_Read($0000) * 256)) polaritaet = Eeprom_Read($0002) ADCON0.0 = 1 'ADC einschalten ADCON0.3 = 0 'AN0 vorwählen ADCON0.4 = 0 'AN0 vorwählen ADCON0.5 = 0 'AN0 vorwählen ADCON0.6 = 1 'Fosc/8 ADCON0.7 = 0 'Fosc/8 ADCON1 = %10001110 'AN0 = ADC-Eingang, Rest Digital-I/O Delay_ms(15) I2C_Init(100000) 'Initialize full master mode Usart_Init(9600) while TRUE 'Endlosschlaufe 'LED1 = TestBit(zaehler, 7) 'Delay_ms(100) lesen 'Zeit auslesen 'Spannung am Analogeingang messen while messen < 675 'ist sie kleiner als 675 (915 entspr. 41.5V) if tochteruhrzeit <> (Eeprom_Read($0001) + (Eeprom_Read($0000) * 256)) then 'Usart_Write_Text("Messen:") 'WordToStr(messen, text) 'Usart_Write_Text(text) INTCON.GIE = 0 Eeprom_Write($0000, hi(tochteruhrzeit)) Eeprom_Write($0001, lo(tochteruhrzeit)) Eeprom_Write($0002, polaritaet) INTCON.GIE = 1 end if wend senden tasten echtzeit = stunden * 60 echtzeit = echtzeit + minuten '0 ... 1439 (minuten) 'wenn der letzte Puls fertig ist, kann ein Neuer gestartet werden if (tochteruhrzeit < echtzeit) and (puls = 0) then puls = 400 'Pulslänge 200ms wird gestartet Inc(tochteruhrzeit) if tochteruhrzeit > 1439 then 'Bei Mitternacht tochteruhrzeit = 0 'auf Null end if end if 'wenn der Empfang auf dem USART fertig ist, RTC richten if fertig then checksumme = Higher(empfangen) + Hi(empfangen) + Lo(empfangen) 'Die Prüfsumme ist einfach alle sechs Zahlen zusammenzählen 'in die siebte und achte Zahl packen if checksumme = Highest(empfangen) then schreiben(empfangen) 'RTC richten end if empfangen = 0 'Empfangspuffer leeren fertig = 0 'Flag löschen end if wend end.