'*******************************************************************************
'**** 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%