'*******************************************************************************
'**** Temperatursender mit ATmega328P und dem Funkmodul RFM12 / RFM12B *****
'**** mit NEUEM Funkprotokoll OHNE Quittungserwartung *****
'*******************************************************************************
'name : TemperaturA_Tx_v0.3.bas
'copyright : (c) 31.12.2016 jep
'purpose : Temperatursender mit Protokoll via HW-SPI
'micro : Atmel328P
'
'Changelog: : CRC in LEN inbegriffen
'
'offene Punkte : Es wird nach dem Senden nicht auf einen Befehl gewartet
'-------------------------------------------------------------------------------
'Bemerkung: Es wird mit einem Temperatursensor gearbeitet. Der Empfang wird nicht bestätigt da nach
'1 Minuten die nächste Meldung folgt.
'Bei der Adressfestlegung bei mehreren Sensoren ist die Adresse des Sensors nicht bekannt.
'Man weiss deshalb nicht, welcher Sensor welcher ist, wenn man sie einfach anschliesst.
'Das Programm sucht mit 1wsearchfirst.
'
'Die Senderoutine kann für den Temperatursensor stark vereinfacht werden. Die Sendedatenlänge ist fix.
'Nach dem Senden soll der Sensor schlafen gehen.
'Tx-Protokoll:
' 1 2 3 4 5 6 7 8 9 10 11 12
' +----+----+----+----+----+----+----+----+----+----+-----+-----+
' | Ausgangsbytes |
'+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-----+-----+
'| AA | AA | 2D | D4 |LEN |DAB |SAB |CDB | TempD1 | Feuchte | Betr.Spg|CRC_h|CRC_l|
'+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-----+-----+
'
'============================================================================================================
$regfile = "m328Pdef.dat"
$crystal = 16000000 '16MHz-Oszillator
$hwstack = 80
$swstack = 80
$framesize = 100
$Baud = 19200
Declare Sub Rfm12_init
Declare Sub Rfm12_setfrequenz
Declare Function Decigrades(byval Sc(9) As Byte) as Integer
Declare Function SPI_Transfer(byval Dataout As Word) As Word
'############################### SENSORADRESSE #################################
' ##
Dim Sensoradresse as Byte ' ##
'Sensoradresse = 6 ' ##
Dim Zentralenadresse as Byte ' ##
Zentralenadresse = 85 'ist fix ##
' ##
'#################################################################################
'================================ Atmel328P als SPI MASTER =====================
'Adresseingabe des Senders: A0...A3 = 16 Adressen
A0 Alias PinC.0
Config A0 = Input
Set PortC.0
A1 Alias PinC.1
Config A1 = Input
Set PortC.1
A2 Alias PinC.2
Config A2 = Input
Set PortC.2
A3 Alias PinC.3
Config A3 = Input
Set PortC.3
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
'======================== SPI des ATmega328P ====================================
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
'===================== 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
'======= Hier werden die zu SENDENDEN 14 BYTES (max 62 möglich) abgelegt ========
' 1 2 3 4 5 6 7 8 9 10 11 12
'+----+----+----+----+----+----+----+----+----+----+-----+-----+
'| Sendebytes |
'+----+----+----+----+----+----+----+----+----+----+-----+-----+
'|LENs|DABs|SABs|CDBs| Temp_D1 | Feuchte | Betr_spg| CRC_16s |
'+----+----+----+----+----+----+----+----+----+----+-----+-----+
'| | | Ausgangsdaten |CRC_h|CRC_l|
'| | +-----------------------------+-----+-----+
'| | |<--- Anzahl Ausgangsdaten -->| |
'| |<------------ LEN (Anzahl Bytes ohne LEN) ------------->|
'|<--------------------- AnzahlByte_s ------------------------>|
'
Dim Sendebytes(12) As Byte 'Anzahl ist fix (mit CRC)
Dim Anzahlbyte_s as Byte 'Anzahl zu sendende Bytes
Dim LENs as Byte at Sendebytes(1) Overlay 'Längenbyte
LENs = &b00001011 'Datenmode, 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 = Zentralenadresse 'Zentralenadresse ist 85
Dim SABs as Byte at Sendebytes(3) Overlay 'eigene Adresse (SAB)
'SABs = Sensoradresse
Dim CDBs as Byte at Sendebytes(4) Overlay 'Kommandobyte fix
CDBs = &b00100000 'Datenmode, ohne ACK
Dim Temp_Daten1 as Integer at Sendebytes(5) Overlay
Dim Feuchte as Integer at Sendebytes(7) Overlay 'Platzhalter für Feuchte
Feuchte = &HAAAA 'Dummywert
Dim Betr_spg as Word at Sendebytes(9) Overlay
Dim CRC_16s as Word at Sendebytes(11) Overlay 'CRC16 für Senden
Dim Paketzaehler as Byte
Paketzaehler = 0
'==================== 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
Dim ADCWert as Word 'Wandlerwert
Dim Betriebsspannung as Single 'Betr_spg siehe bei Sendebytes
'=========================== 1-Wire Konfiguration ==============================
Config 1wire = PortD.6 '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
'-------------------------------------------------------------------------------
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)
Sensoradresse = PINC AND &b00001111 'Sensoradresse ab DIP holen
SABs = Sensoradresse
Print "Adresse: " ; str(SABs)
Print
'Temperatur-Sensor suchen und seriell ausgeben
Temp_id1(1) = 1wsearchfirst() 'sucht die Adresse des 1. Temp.Bausteins
Print "1Wire-Adresse ID1: " ;
For I = 1 To 8
Print Hex(temp_id1(i)) ; " " ;
Next I
Print
Print
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)
wait 1
'############################## Hauptprogramm ##################################
Do
ADCWert = GETADC(7) 'Wandlerwert als Word
Betriebsspannung = ADCWert * ADC_Multiplier 'als Single konvertieren und multiplizieren
Betr_spg = Betriebsspannung 'zum Senden wieder in ein Integer umwandeln
Print
Print ADC_Multiplier
Print "Betriebsspannung ist: " ; Betr_spg ; " /1000"
Print
Ledr = 0
gosub Temperaturmessung 'zuerst Temperatur messen
Print
Print "Temperatur: " ;
Print str(Temp_Daten1)
Print
Ledr = 1
Gosub Senden
waitms 500
gosub Senden '2tes mal senden
Print
Print "gehe Schlafen "
Print
D = SPI_Transfer(&H8203) 'Sender aus, Empfänger aus
D = SPI_Transfer(wakeup_timer) 'Wake up Timer Command
D = SPI_Transfer(&Hb800) 'Senderinterrupt löschen
D = SPI_Transfer(&H0000) 'eventuelle weitere Interrupts löschen
D = SPI_Transfer(power_down) 'RFM12 Power down Kommando
Config Int0 = Low Level
Enable Int0
Enable Interrupts
Print "328 geht schlafen"
Print
Config Powermode = Powerdown 'ATmega328 schlafen legen
waitms 20
Print
Print "bin wieder da "
Print
Loop
'###############################################################################
'=========================================== SUBROUTINEN ===============================================
'***************************************** 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
Print "---> Sensor ist 18S20"
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
Print "---> Sensor ist 18B20"
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
'======================== 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
Print "Sendedaten: " ;
for y = 1 to 12
Print hex(Sendebytes(y)) + " " ;
next y
Print
gosub Rfm12_senden 'es sind 12 Bytes zu senden
Waitus 10
Ledg = 1
Return
'_______________________________________________________________________________
RFM12_senden:
AnzahlByte_s = Sendebytes(1) + 1 'damit alle Bytes übertragen werden (+ LEN)
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
Return
Rfm12_warten:
Ss = 0
Do
Loop Until MISO = 1
Return
'_______________________________________________________________________________
'(
Function Spi_transfer(byval Dataout As Word) As Word
Local Dat_in_h as Byte
Local Dat_in_l as Byte
Dat_in_h = Spimove(High(Dataout))
Dat_in_l = Spimove(Low(Dataout))
Spi_transfer = makeint(Dat_in_l , Dat_in_h)
End Function
')
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 Mhz oder z.B. &HA538 für 433,34 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 &HE5A8% ' WakeUp-Timer=5s
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%