'******************************************************************************* '**** Helligkeitsgeber mit ATmega328P-PU und dem Funkmodul RFM12B ***** '******************************************************************************* 'name : Helligkeitsgeber_V0.3.bas 'copyright : (c) 25.05.2019 jep 'purpose : Helligkeits- und Temperaturgeber 'micro : ATmega328P-PU ' : 'Changelog: >V0.2: Hauptprogramm neu strukturiert, ohne DCF ' ' '------------------------------------------------------------------------------- 'Bemerkung: ' 'Die Senderoutine kann vereinfacht werden. Die Sendedatenlänge ist fix. 'Tx-Protokoll: ' 1 2 3 4 5 6 7 8 9 10 ' +----+----+----+----+----+----+----+----+-----+-----+ ' | Ausgangsbytes | '+----+----+----+----+----+----+----+----+----+----+----+----+-----+-----+ '| AA | AA | 2D | D4 |LEN |DAB |SAB |CDB | TempD1 |Helligkei|CRC_h|CRC_l| '+----+----+----+----+----+----+----+----+----+----+----+----+-----+-----+ ' '============================================================================================================ $regfile = "m328Pdef.dat" $crystal = 8000000 '8MHz-Ceramic-Oszillator $hwstack = 80 $swstack = 80 $framesize = 100 $baud = 115200 Declare Sub Rfm12_init Declare Sub Rfm12_setfrequenz Declare Sub Rfm12_senden(byval Anzahl_s As Integer) Declare Function Decigrades(byval Sc(9) As Byte) As Integer Declare Function Spi_transfer(byval Dataout As Word) As Word '############################### SENSORADRESSE ################################# ' ## Const Senderadresse = 16 'eigene Adresse, fix## Const Allrufadresse = 200 'ist fix ## ' ## '################################################################################# '================================ Atmel328P als SPI MASTER ===================== ' Config PinC.0 = Input Set Portc.0 'Pullup A0 Alias Pinc.0 Config Pinc.1 = Input Set Portc.1 A1 Alias Pinc.1 Config Pinc.2 = Input Set Portc.2 Hell_Test Alias Pinc.2 'gibt laufend die Helligkeit aus Config PinC.3 = Input Set Portc.3 Debuggen Alias Pinc.3 'Debuggen = 0 => DIP-Schalter_3 ON Ledg Alias Portb.0 'grüne LED Config Ledg = Output Set Portb.0 Ledr Alias Portb.1 'rote LED Config Ledr = Output Set Portb.1 Hell_out Alias PortD.4 Config Hell_out = Input set Hell_out 'Pullup '=================== Timer0-Konfiguration Helligkeit =========================== Config Timer0 = Counter , Edge = Rising On Timer0 Helligkeit_addieren 'Interruptroutine Enable Timer0 Stop Timer0 '=================== Timer1-Konfiguration 1 sec Zeitgeber ====================== Config Timer1 = Timer , Prescale = 256 Const Timer1_Preload = 34286 Timer1 = Timer1_Preload Enable Timer1 On Timer1 sectic Enable Interrupts Dim neue_Sekunde as Byte '==================== Timer2-Konfiguration Messdauer =========================== Config Timer2 = Timer , Prescale = 1024 Const Timer2_preload = 22 'ergibt 15 ms On Timer2 Zeitinterrupt 'Interruptroutine Dim Messzeit as Byte 'zum aufaddieren bis 105 ms / 1.5 sec Enable Timer2 Stop Timer2 '========================= Watchdog-Konfiguration ============================== Config Watchdog = 4096 '4 sec Stop watchdog '======================== SPI des ATmega328P-PU ================================ Ss Alias Portb.2 Miso Alias Pinb.4 Mosi Alias Portb.3 Sck Alias Portb.5 Config Ss = Output 'Slave select Config Sck = Output 'SCK ----> SCK (RFM12B) Config Mosi = Output 'MOSI ----> SDI (RFM12B) Config Miso = Input 'MISO <---- SDO (RFM12B) Set Portb.2 'Pullup 'CONFIG SPI = soft , MISO = PinB.4 , MOSI = PortB.3 , clock = PortB.5 , SS = PortB.2 'CONFIG SPI = HARD , INTERRUPT = ON , DATA_ORDER = MSB , MASTER = YES , POLARITY = LOW , PHASE = 0 , CLOCKRATE = 16 , NOSS = 0 , SPIIN = 0 'spiinit '=============================== I2C/TWI Konfiguration ========================= $lib "I2C_TWI.LBX" 'Library für HW-I2C-Bus Config Scl = Portc.5 'we need to provide the SCL pin name Config Sda = Portc.4 'we need to provide the SDA pin name Config Twi = 100000 'DS1307 läuft nur mit 100kHz I2cinit 'Port´s nicht konfigurieren, 'sie sind HW-mässig festgelegt Const PCF8574 = &H40 'Adresse (write-Adresse) Dim Kopie_PCF as Byte Kopie_PCF = 0 'sie sind HW-mässig festgelegt '=========================== 1-Wire Konfiguration ============================== Config 1wire = Portd.7 '1-Wire-Port Dim Dg As Integer 'DECIgrades, I call it, cause I have no space for commas on the display.... Dim Degr As Single 'zur Darstellung umgewandelt Dim B As Byte Dim I As Byte Dim Temp_id1(8) As Byte 'Sensor 1 Adresse 64 bits incl CRC Dim Sc(9) As Byte 'Scratchpad 0-8 72 bits incl CRC für die Daten Dim Messung As Bit Messung = 1 'nach Start erste Messung durchführen '==================== ADC zur Messung der Betriebsspannung ===================== Config Adc = Single , Prescaler = Auto , Reference = Internal_1.1 Const Adc_multiplier = 5.75964 ' (1.1 * 1470) /(1024.0 * 270) * 1000 (etwas korrigiert) Dim Adcwert As Word 'Wandlerwert Dim Betriebsspannung As Single 'Betr_spg siehe bei Sendebytes '===================== Interrupt für Aufwecken aktivieren ===================== Config Pind.2 = Input 'INT0 Portd.2 = 1 'Pullup Nirq Alias Pind.2 Config Int0 = Falling On Int0 Rfm_irq Disable Int0 Disable Interrupts Dim Status As Word Const Read_status = &H0000 'Const Power_down = &H8203 'Dim Wakeup_timer As Word 'Wakeup_timer = &HE5A8 'r = 5, m = 168 --> ca. 5 sec 'Wakeup_timer = &HEA0A 't(ms) = m * 2hochr ; für Test: r = 10, m = 10 --> ca. 10 sec 'Const Wakeup_timer = &HEA39 'r = 10, m = 57 -> ca. 60 sec '======= Hier werden die zu SENDENDEN 12 BYTES (max 62 möglich) abgelegt ======== ' 1 2 3 4 5 6 7 8 9 10 11 12 '+----+----+----+----+----+----+----+----+----+----+-----+-----+ '| Ausgangsbytes | '+----+----+----+----+----+----+----+----+----+----+-----+-----+ '|LEN |DABs|SABs|CDB | TempD1 |Helligkei|Betr.Spg |CRC_h|CRC_l| '+----+----+----+----+----+----+----+----+----+----+-----+-----+ '| | | Ausgangsdaten |CRC_h|CRC_l| '| | +-----------------------------+-----+-----+ '| | |<--------- Anzahl Ausgangsdaten -------->| '| |<----------------- LEN (Anzahl Bytes ohne LEN) -------->| '|<----------------------- AnzahlByte_s ---------------------->| ' Dim Sendebytes(13) As Byte Dim Anzahlbyte_s As Byte 'Anzahl zu sendende Bytes Dim Lens As Byte At Sendebytes(1) Overlay 'Längenbyte Lens = &B00001011 'fix 12 Bytes Daten (11 da LEN NICHT mitgezählt wird) Dim Dabs As Byte At Sendebytes(2) Overlay 'Adresse an den die Daten geschickt werden (DAB) Dabs = Allrufadresse 'Allrufadresse ist 200 Dim Sabs As Byte At Sendebytes(3) Overlay 'eigene Adresse (SAB) SABs = Senderadresse 'eigene Adresse Dim Cdbs As Byte At Sendebytes(4) Overlay 'Kommandobyte fix Cdbs = &B00100000 'Datenmode, ohne ACK Dim Temp_daten1 As Integer at Sendebytes(5) Overlay 'Temperatur Dim Helligkeit As Word at Sendebytes(7) Overlay 'Helligkeit Dim Betr_spg As Word At Sendebytes(9) Overlay 'Betriebsspannung Dim Crc_16s As Word At Sendebytes(11) Overlay 'CRC16 für Senden Dim Paketzaehler As Byte Paketzaehler = 0 '------------------------------------------------------------------------------- Const Sendeintervall = 120 'Sendeintervall in sec Dim Restzeit as Word 'Restzeit bis zum erneuten Senden Dim H1 as Word Dim H2 as Word Dim T0_Ueberlaufzaehler as Byte 'Überlaufzähler für Timer0 Dim T2_Ueberlaufzaehler as Byte 'Überlaufzähler für Timer2 T2_Ueberlaufzaehler = 10 'gibt 10 x 15 ms = 150 ms Dim Messung_fertig as Byte Dim Frequ as DWord Dim Frequ1 as DWord '... des Intervalls wieder gesendet wird Dim D As Word Dim N As Byte Dim R As Word Dim X As Byte 'wird im Interrupt genutzt Dim Y As Byte '_______________________________________________________________________________ ' *************** ' ********************************** ' ******************************************************** '******************************************************************************* '***************************** PROGRAMMSTART *********************************** '******************************************************************************* Programmstart: Print Print Print "File: " ; Version(3) Print Print "eigene Adresse: " ; Str(sabs) Print Portc.3 = 1 'Pullups einschalten Portc.2 = 1 PortC.1 = 1 Portc.0 = 1 Enable Interrupts 'Temperatur-Sensor suchen und seriell ausgeben Temp_id1(1) = 1wsearchfirst() 'sucht die Adresse des 1. Temp.Bausteins if Debuggen = 0 then Print "1Wire-Adresse ID1: " ; For I = 1 To 8 Print Hex(temp_id1(i)) ; " " ; Next I Print Print end if Ss = 1 Sck = 0 Rfm12_init 'RFM12B initialisieren 'r=SPI_Transfer(&hE488) 'Timerzeit auf ca 2 Sekunden stellen R = Spi_transfer(&He5a8) 'Timerzeit auf ca 5 Sekunden stellen 'r=SPI_Transfer(&E8EA) 'Timerzeit auf ca 1 Minute stellen 'akt_Byte = 0 'Bytezähler löschen 'Timeout = 400 + Rnd(1000) 'WDTCR = &h1F 'Watchdog setzen vorbereiten 'WDTCR.3 = 0 'und Watchdog ausschalten Wait 1 Restzeit = 1 'für sofortigen Allruf Start Watchdog '############################## Hauptprogramm ################################## do if Hell_Test = 0 then Test_Helligkeit: ' Stop Watchdog 'sonst erfolgt nach 4 sec ein Reset gosub Helligkeit_messen wait 2 '2 sek warten if Hell_Test = 0 then goto Test_Helligkeit end if if neue_Sekunde = 1 then Toggle Kopie_PCF.4 'lässt rote LED im 1 sec-Takt blinken I2CSend PCF8574 , Kopie_PCF neue_Sekunde = 0 if Debuggen = 0 then Print Restzeit end if end if if Restzeit = 0 then gosub Allruf_senden 'und mit Helligkeit verteilen Restzeit = Sendeintervall 'Nächster Allruf nach Intervallzeit end if Reset Watchdog 'Watchdog resetten loop '############################################################################### Sectic: 'Der Sekundentakt Timer1 = Timer1_Preload neue_Sekunde = 1 Restzeit = Restzeit - 1 Toggle Ledr Return '############################## SUBROUTINEN ################################## Allruf_senden: Kopie_PCF.4 = 0 'rote LED ein I2CSend PCF8574 , Kopie_PCF 'und ausgeben ADCSRA.7 = 1 waitms 1 Adcwert = Getadc(7) 'Betriebsspannung messen Betriebsspannung = Adcwert * Adc_multiplier 'als Single konvertieren und multiplizieren Betr_spg = Betriebsspannung 'zum Senden wieder in ein Word umwandeln if Debuggen = 0 then Print Print "ADC-Faktor: " ; Adc_multiplier Print "Betriebsspannung ist: " ; Betr_spg ; " /1000" end if Gosub Temperaturmessung 'zuerst Temperatur messen if Debuggen = 0 then Print Print "Temperatur: " ; Print Str(temp_daten1) end if Gosub Helligkeit_messen if Debuggen = 0 then if Helligkeit < 32768 then Print "Dunkel: ... " ; Helligkeit Print else Print "Hell: ..... " ; Helligkeit Print end if end if Gosub Senden Waitms 200 Gosub Senden '2tes mal senden Kopie_PCF.4 = 1 'rote LED aus I2CSend PCF8574 , Kopie_PCF D = Spi_transfer(&H8203) 'Sender aus, Empfänger aus D = Spi_transfer(&Hb800) 'Senderinterrupt löschen D = Spi_transfer(&H0000) 'eventuelle weitere Interrupts löschen Return '***************************************** Temperaturmessung ********************************************* Temperaturmessung: 'die Temperaturmessung anstossen (Konvertierung starten) 1wreset '1-Wire-Bus zurücksetzen 1wwrite &HCC 'Adressrom´s überspringen 1wwrite &H44 'Temperaturkonverion für alle anstossen Wait 1 'Konvertierzeit 1wverify Temp_id1(1) '1. Sensor, sendet "Match ROM " If Err = 1 Then 'Error = 1: Fehler aufgetreten Temp_daten1 = 9999 'damit die Stelle nicht leer bleibt Else 'Sensor hat geantwortet 1wwrite &HBE Sc(1) = 1wread(9) '9 Bytes in Array einlesen If Sc(9) = Crc8(sc(1) , 8) Then 'CRC-Check If Temp_id1(1) = &H10 Then '1. Byte bestimmt Family Code; hier 18S20 Temp_daten1 = Decigrades(sc(9)) 'Umwandlung in ein Integer-Word (-32768...32767) zum abspeichern if Hell_Test = 0 then Print "---> Sensor ist 18S20" end if End If If Temp_id1(1) = &H28 Then '1. Byte bestimmt Family Code; hier 18B20 Temp_daten1 = Makeint(sc(1) , Sc(2)) 'Umwandeln in Integerwert, Temp_daten1 = Temp_daten1 * 10 'und Temp_daten1 = Temp_daten1 / 16 'Umrechnung in ein Integer-Word (-32768...32767) zum abspeichern if Hell_Test = 0 then Print "---> Sensor ist 18B20" end if End If Else Temp_daten1 = 9999 'damit bei CRC-Fehler die Stelle nicht leer bleibt End If End If Return '---------------------------------------------------------- Function Decigrades(byval Sc(9) As Byte) Dim Tmp As Byte , T1 As Integer , T2 As Integer Tmp = Sc(1) And 1 '0.1C Genauigkeit, Bit 0 ausmaskieren If Tmp = 1 Then Decr Sc(1) 'wenn 1 dann 1 abziehen T1 = Makeint(sc(1) , Sc(2)) 'Umwandeln in Integerwert, Anzahl 1/2° (Temp-Schritt ist 0.5°C) T1 = T1 * 50 'x50, da 1/100°-Schritte T1 = T1 - 25 'gemäss DS18S20 data sheet 0.25(*100) abziehen T2 = Sc(8) - Sc(7) T2 = T2 * 100 T2 = T2 / Sc(8) T1 = T1 + T2 Decigrades = T1 / 10 End Function '========================== Helligkeitsmessung ================================ 'Die Helligkeit wird als Word im Bereich von 0 ... 65000 dargestellt. Helligkeit_messen: Ledg = 0 Helligkeit = 0 'Zähler löschen Kopie_PCF = Kopie_PCF and &B11110000 'lower Nibbla auf 0 Kopie_PCF = Kopie_PCF or &B00000101 'min. Empfindlichkeit (x1) I2CSend PCF8574 , Kopie_PCF T2_Ueberlaufzaehler = 1 Gosub Helligkeit_Start while Messung_fertig = 0 NOP Wend H1 = Helligkeit Frequ1 = H1 * 100 Nachmessen: If Helligkeit > 32 then 'es ist hell Kopie_PCF = Kopie_PCF and &B11110000 'lower Nibbla auf 0 Kopie_PCF = Kopie_PCF or &B00000101 'min. Empfindlichkeit (x1) I2CSend PCF8574 , Kopie_PCF T2_Ueberlaufzaehler = 10 '100ms Messen Gosub Helligkeit_Start while Messung_fertig = 0 NOP Wend H2 = Helligkeit Frequ = H2 * 10 if Helligkeit < 32768 then Helligkeit.15 = 1 else Helligkeit = 65535 'auf Maximalwert limitieren end if ' goto Ende else 'zu dunkel Kopie_PCF = Kopie_PCF and &B11110000 'lower Nibbla auf 0 Kopie_PCF = Kopie_PCF or &b00000111 'Empfindlichkeit (x100) I2CSend PCF8574 , Kopie_PCF T2_Ueberlaufzaehler = 10 '100ms Gosub Helligkeit_Start while Messung_fertig = 0 NOP Wend H2 = Helligkeit Frequ = H2 * 10 if Helligkeit > 32768 then goto Nachmessen 'über der Grenze, nochmal nachmessen End if Ende: if Hell_Test = 0 then Print Print "T0 überlauf: " ; T0_Ueberlaufzaehler Print "Timer0: .... " ; Timer0 if Helligkeit < 32768 then Print "Dunkel: ....." ; Helligkeit else Print "Hell: ...... " ; Helligkeit end if Print "Stop Messung" Print end if Ledg = 1 Return '------------------------------------------------------------------------------- Helligkeit_Start: Messung_fertig = 0 'Merker zurücksetzen T0_Ueberlaufzaehler = 0 'Zähler zurücksetzen Timer0 = 0 'Timer resetten Timer2 = Timer2_preload 'Timer laden für 10ms Start Timer0 'Impulszählung beginnt Start Timer2 'Zeitüberwachung starten Return Helligkeit_addieren: incr T0_Ueberlaufzaehler 'Überlauf erfolgt Return Zeitinterrupt: 'alle 10 ms Timer2 = Timer2_preload decr T2_Ueberlaufzaehler if T2_Ueberlaufzaehler = 0 then ' Stop Timer0 'Impulszählung stoppen Stop Timer2 'Messzeit stoppen Helligkeit = T0_Ueberlaufzaehler * 255 'Helligkeit nachführen Helligkeit = Helligkeit + Timer0 '+ noch Timer0 Messung_fertig = 1 end if Return '======================== Sendet das Datenpaket =============================== 'Die Senderoutine ist für Polling des Senders geschrieben, 'es wird gewartet bis ein Byte gesendet ist Senden: Ledg = 0 Incr Paketzaehler 'würde hier gar nicht gebraucht If Paketzaehler >= 16 Then Paketzaehler = 0 'da nur ein Telegramm Cdbs = Paketzaehler Or &B0010_0000 'und mit dem Rest verknüpfen Crc_16s = Crc16(sendebytes(1) , 10) 'CRC rechnen über 10 Bytes if Debuggen = 0 or Hell_Test = 0 then Print "Sendedaten: " ; For Y = 1 To 12 Print Hex(sendebytes(y)) + " " ; Next Y Print end if Call Rfm12_senden(12) 'es sind 12 Bytes zu senden Waitus 10 Ledg = 1 Return '_______________________________________________________________________________ Sub Rfm12_senden(byval Anzahl_s As Integer) Anzahlbyte_s = Sendebytes(1) + 1 '+ LEN, damit alle Bytes übertragen werden D = Spi_transfer(&H8238) 'Enable Transmitter; enable Synthesizer ;enable Crystal Osc Gosub Rfm12_warten D = Spi_transfer(&Hb8aa) Gosub Rfm12_warten D = Spi_transfer(&Hb8aa) Gosub Rfm12_warten D = Spi_transfer(&Hb82d) Gosub Rfm12_warten D = Spi_transfer(&Hb8d4) For N = 1 To Anzahlbyte_s Gosub Rfm12_warten D = &HB800 + Sendebytes(n) D = Spi_transfer(d) Next N Gosub Rfm12_warten D = Spi_transfer(&Hb8aa) Gosub Rfm12_warten D = Spi_transfer(&Hb8aa) Gosub Rfm12_warten D = Spi_transfer(&H8201) 'Sender aus, Empfänger aus End Sub Rfm12_warten: Ss = 0 Do Loop Until Miso = 1 Return '_______________________________________________________________________________ Function Spi_transfer(byval Dataout As Word) As Word Local Nspi As Integer Local Dspi As Integer Local Dmiso As Word Ss = 0 Dmiso = 0 For Nspi = 1 To 16 Dspi = Dataout And &H8000 If Dspi = 0 Then Mosi = 0 Else Mosi = 1 End If Dataout = Dataout * 2 Dmiso = Dmiso * 2 Dmiso = Dmiso + Miso Sck = 1 Waitus 5 Sck = 0 Next Nspi Ss = 1 Spi_transfer = Dmiso End Function '_______________________________________________________________________________ 'RFM-Initialisierung Sub Rfm12_init Local Wert As Word X = 0 Restore Datainit3 'Initialisierungsfolge Do Read Wert D = Spi_transfer(wert) Incr X Loop Until Wert = 0 Waitms 200 R = Spi_transfer(&H0000) End Sub '_______________________________________________________________________________ 'Wird hier nur zum aufwecken genutzt da kein Empfang vorgesehen Rfm_irq: Status = Spi_transfer(read_status) If Status.12 = 1 Then 'Prüfen ob Wake-up Interrupt Disable Int0 Disable Interrupts End If Return End '******************************************************************** 'Funkmodul Initialisierungsdaten für 4800 Baud Funkübertragung Datainit3: Data &H80E8% ' Enable: 868 Mhz;XTAL cap=12pf; TX-Register; RX-Fifo Data &H82D9% ' Enable: Receiver; Crystal Osc; Base Band Block; Synthesizer, Disable Low-bat Detector; Transmitter; Wake-Up-Timer; Clock output Pin Data &HA67C% ' &Ha67c=frequenz 434,15 / 868,30 Mhz oder z.B. &HA538 für 433,34 /866,68 Mhz Data &HC647% ' &Hc647=Datenrate '4.8kbps; C623=9600kbps; C611 =19200 Data &H95C0% ' Vdi , Fast , 67 kHz , 0db , -79dbm !!!!!!!!!! Data &HC2AD% ' Fiter=Digital; Recover Mode=Auto; Quality Threshold=4; Recovery Speed=Slow Data &HCA81% ' FIFO INT Level=8; Sync on=2;Fifo Fill Start=Sync; Reset Sensitivity=High; Disable:FIFO Fill Enabled Data &HC483% ' Enable: AFC Mode; AFC; Frequency Offset Register Disable: High Accuracy; Strobe Data &H9820% ' Frequenz Shift=POS; Power Out=0 dB; Deviation=45 khz Data &HE000% ' WakeUp-Timer=0ms Data &HC800% ' Duty Cycle = Infinity % OFF Data &HC000% ' Low batterie=2,2V; Clock Pin=1 Mhz Data &HCED4% ' Synchron Pattern Data &HCC76% ' PLL Settings Data &H0000% ' Status lesen, irqs zurückstellen Data 0%