Per NTP Protokoll lässt sich relativ einfach die aktuelle Zeit holen und verwerten. Die relevanten Instruktionen als Terminalmitschnitt lauten
AT+CIPSTART=1,"UDP","193.67.79.202",37
1,CONNECT
OK
AT+CIPSEND=1,3
OK
> X
SEND OK
+IPD,1,4:пы./
OK
AT+CIPCLOSE=1
1,CLOSED
OK
Grün sind die gesendeten AT-Befehle, magenta hinterlegt die Rückgabe und in gelber Schrift die vier Byte mit der eigentlichen Zeitinformation
Die Rückgabe ist ein Wert vom Typ Long:
"[..] Die Zeitstempel im NTP sind 64 Bits lang. 32 Bits kodieren die Sekunden seit dem 1. Januar 1900 00:00:00 Uhr, weitere 32 Bits den Sekundenbruchteil. Auf diese Weise lässt sich ein Zeitraum von 232 Sekunden (etwa 136 Jahre) mit einer Auflösung von 2−32 Sekunden (etwa 0,23 Nanosekunden) darstellen.[..]" [1]
Bascom erfordert noch ein wenig eine Umrechnung und Korrektur, kann dann aber den gewonnen Long-Wert einfach in die eigene Systemzeit umrechnen
Im Folgenden ist ein Code dargestellt, der alle fünf Sekunden via NTP die aktuelle Zeit holt und im AVR die Systemzeit stellt. Hier ist eine User-Clock verwendet, die Zeitinformation wird aber nicht wirklich gespeichert. Dazu wäre noch eine externe RTC notwending. Sofern ein LCD angeschlossen und aktiviert ist, wird Zeit und Datum dort dargestellt
' ------------------------------------------------------------------------------
' µC holt NTP und stellt dar
'
' HW:tr045-R06
' - ESP8266 am seriellen Port
' - LCD für Statusausgabe (optional)
' - Baudratenclock
'
' V1.0:
' V1.1: NTP auswerten ohne DST Korrektur (nur manueller Fixwert => Offset_gmt)
' V1.2: mit DST Korrektur
'
' ------------------------------------------------------------------------------
$Regfile="m8def.dat"
$Crystal=14745600 ' externer Baudratenclock
$hwstack=40
$swstack=16
$framesize=32
$baud=57600
$version 1,2,0
' ------------------ Konstanten
const mySSID = "meineSSID"
const myPW = "meinPW"
const NotausgangZeit = 10000
const LCD_Ausgabe = 1
const Offset_gmt = 7200
' ------------------ Subroutinen deklarieren
declare sub Warte_OK_Error(byval Suchstring as string*10,byval NoDelete as byte)
declare Sub Ntp_dst_correction
' ------------------ Deklarationen
' Variablen
dim i as byte, j as byte
dim Empfangs_Ticker as word
dim Sendestring as string * 250, headerstring as string * 100, SendeKanal as string*1
dim myIPAdress as string *15
dim strdummy as string *10
dim Flagbyte as byte
Flag_ok alias Flagbyte.0
Flag_Error alias Flagbyte.1
' Ntp Stuff
Dim Tt(4) As String * 1
Dim Ss(4) As Byte
Dim L1 As Long At Ss Overlay ' Overlay a long variable to receive-string
Dim L2 As Long ' with overlay you need no transfer from the byte-array to a long-variable
' UART ISR
const Uart_string_laenge=45
Dim Uart_get_char As Byte , Uart_string_len As Byte , Uart_char As String * 1 , Uart_string As String * Uart_string_laenge ', Str_laenge As Byte
' Timer
Config Timer0 = Timer , Prescale = 64
Const Timer0_preload = 131' Timer1 tickt im Sekundentakt
On Timer0 Timer0_isr
'I2C
Config Scl = Portc.5
Config Sda = Portc.4
#if LCD_Ausgabe=1
' LCD
Config Lcdpin = Pin , Db4 = Portd.7 , Db5 = Portd.6 , Db6 = Portd.5 , Db7 = Portd.4 , E = Portb.1 , Rs = Portb.0
Config Lcd = 16 * 2
initlcd
Cls
Cursor Off
LCDLight alias portb.2:config LCDLight = output:set lcdlight ' Pin für LCD Beleuchtung
#endif
'Config Clock
Config Clock = User
Config Date = Dmy , Separator = .
' Interrupts
On Urxc Uart_isr
' ------------------ Hauptschleife ---------------------------------------------
#if LCD_Ausgabe=1
lcd Version(1)
lowerline:lcd version(2)
#endif
wait 1
Enable Urxc
enable timer0
enable interrupts
' ESP8266 initialisieren
$include "ESP8266Init.bas"
do
Print "AT+CIPMUX=1"
call Warte_OK_Error("",0)
Print "AT+CIPSTART=1," ; Chr(34) ; "UDP" ; Chr(34) ; "," ; Chr(34) ; "193.67.79.202" ; Chr(34) ; ",37"
call Warte_OK_Error("",0)
Print "AT+CIPSEND=1,3"
call Warte_OK_Error("",0)
uart_string=""
Print "X"
call Warte_OK_Error("+IPD",1)
waitms 100
i = instr(uart_string,"+IPD")
if i>0 then
i = i + 9
strdummy = mid(uart_string,i,4)
Tt(1) = Mid(strdummy , 4 , 1) 'from big endian to little endian
Tt(2) = Mid(strdummy , 3 , 1) 'swap the bytes
Tt(3) = Mid(strdummy , 2 , 1)
Tt(4) = Mid(strdummy , 1 , 1)
Ss(1) = Asc(tt(1)) 'this is L1 split in 4s by overlay
Ss(2) = Asc(tt(2))
Ss(3) = Asc(tt(3))
Ss(4) = Asc(tt(4))
L2 = L1 + 1139293696
call Ntp_dst_correction
Time$ = Time(l2) 'set the time
Date$ = Date(l2) 'set the date
#if LCD_Ausgabe=1
cls
lcd time$; " ";_day;".";_month;". "
lowerline
lcd "Stamp:";l2
'lcd date$
#endif
end if
uart_string = ""
Print "AT+CIPCLOSE=1"
call Warte_OK_Error("",0)
wait 5
loop
end
' ------------------------------------------------------------------------------
' -- Subroutinen ---
' ------------------------------------------------------------------------------
Sub Warte_OK_Error(byval Suchstring as string*10,byval NoDelete as byte)
Empfangs_Ticker=0
if Suchstring="" then
' warte bis OK oder ERROR empfangen wird
while instr(Uart_string,"OK")=0 AND instr(uart_string,"ERROR")=0
if Empfangs_Ticker > NotausgangZeit then
exit while 'Notausgang
end if
wend
else
while instr(Uart_string,Suchstring)=0
if Empfangs_Ticker > NotausgangZeit then
exit while 'Notausgang
end if
wend
end if
' lösche nur, wenn NoDelete-Byte =0
if NoDelete <>1 then
Uart_string = ""
end if
Flag_error = 0
Flag_ok = 0
Empfangs_Ticker = 0
end sub
Sub Ntp_dst_correction
'Dont change order of time and date variables !!! This order is required for Date/Time functions used.
'this routine is orginated by framuel
Local Second As Byte
Local Minute As Byte
Local Hour As Byte
Local Day As Byte
Local Month As Byte
Local Year As Byte
Local Dow As Byte 'Day of week
Day = Date(l2) 'set 3 variables: Day, Month, Year, so Year contains now current year
'DST starts at the last sunday of March, so let's see what weekday the 1st of April is
Month = 4
Day = 1
Hour = 2
Minute = 0
Second = 0
Dow = Dayofweek(day) '0 = Monday to 6 = Sunday
Day = 31 - Dow 'Now count back the days until last sunday
Month = 3 'and set month to March
If l2 >= Syssec(second) Then
'DST ends at the last sunday of October, so let's see what weekday the 1st of November is
Day = 1
Month = 11
Dow = Dayofweek(day) '0 = Monday to 6 = Sunday
Day = 31 - Dow 'Now count back the days until last sunday
Month = 10 'and set month to October
If l2 < Syssec(second) Then
l2 = l2 + 7200 'subtract one hour
End If
End If
End Sub
' ISR Routinene -------------------------------------------------------------
Uart_isr:
Uart_get_char = Udr
Uart_char = Chr(uart_get_char)
Uart_string =Uart_string + Uart_char
' warte auf Schlüsselwörter
Empfangs_Ticker=0 ' Wartewatchdog zurücksetzten, da Daten reinkamen
if instr(Uart_string,"OK")>0 then
Flag_ok=1
elseif instr(uart_string,"ERROR")>0 then
Flag_Error=1
else
Flag_ok=0
Flag_Error=0
end if
Return
' Diese Routine wird jede mSekunde aufgerufen wenn Timer0 aktiviert ist
Timer0_isr:
' Timer0 wieder neu vorladen
Timer0 = Timer0_preload
incr Empfangs_Ticker
return
'******************* local Subroutines **********************************
'clock routines
Setdate:
Return
Settime:
Return
Getdatetime:
Return
Die notwendinge ESP8266Init.bas ist im Downloadbereich unten verfügbar