Der Webserver ist eine einfache Möglichkeit, HTML Seiten zu senden. Es sei gleich darauf hingewiesen, dass zum Seitenaufbau viel RAM benötigt wird, was sehr schnell an die Grenzen dieser Methode stossen lässt - prinzipiell funktioniert dies aber :-)
Das vorliegende Programm ist eine äußerst primitive Website, die einfache Daten zurückgibt. An das Limit kommt man eigentlich nur, wenn das HTML File mehr oder weniger im RAM des µC gehalten werden muss. Es gibt aber einige Ansatze (siehe dazu auch unter Links [4])
Der ESP8266 wird dabei als Station initialisiert und über Port 8080 angesprochen. In dieser Lauerstellung wartet der Webserver auf eine "GET"-Anforderung und baut darauf hin die Website zusammen.
Im Beispiel verwende ich einen TMP100 am IC-Bus - stattdessen kann natürlich auch ein (interner) ADC oder eine beliebige andere Größe verwendet werden.
' ------------------------------------------------------------------------------' µC misst über TMP100 Temperatur und stellt diese dem Webserver bereit'' HW:tr045-R06' - ESP8266 am seriellen Port' - LCD für Statusausgabe (optional)' - Baudratenclock'' V1.0: funktionierende Version, erlaubt aber nur einen Client(SendeKanal) 03/05/15' V1.1: MultiClient läuft 14/5/15'' ------------------------------------------------------------------------------$Regfile="m8def.dat"$Crystal=14745600 ' externer Baudratenclock$hwstack=40$swstack=16$framesize=32$baud=57600$version 1,1,1' ------------------ Konstanten const Adr_TMP101w = 144 const mySSID = "meinSSID" const myPW = "meinPW" const myPort ="8080" const NotausgangZeit = 10000 const CrLf ="{013}{010}" const LCD_Ausgabe = 1 ' ------------------ Subroutinen deklarieren declare Function Temp_tmp100(byval Adresse As Byte) As Single declare Sub Init_tmp100(byval Adresse As Byte) declare sub Warte_OK_Error(byval Suchstring as string*10,byval NoDelete as byte) ' ------------------ Deklarationen ' Variablen dim i as byte, j as byte dim Lbyte as byte, Hbyte as byte,Big_Byte as integer at lbyte overlay dim Temperature as single 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 ' 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 ' Interrupts On Urxc Uart_isr' ------------------ Hauptschleife --------------------------------------------- call Init_tmp100(Adr_TMP101w) #if LCD_Ausgabe=1 lcd Version(1) lowerline:lcd version(2) #endif wait 1 Enable Urxc enable timer0 enable interrupts' ESP8266 initialisieren #if LCD_Ausgabe=1 cls LCD "ESP8266 Init" #endif wait 3 ' warte ab, bis nach Kaltstart der ESP bereit ist print"AT+RST" #if LCD_Ausgabe=1 lowerline:lcd "." #endif call Warte_OK_Error("",0) wait 3 ' und jetzt warte die Bereitschaft nach dem Softstart ab print "AT+CIPMUX=1" #if LCD_Ausgabe=1 lcd "." #endif call Warte_OK_Error("",0) print "AT+CIPSERVER=1,";myPort #if LCD_Ausgabe=1 lcd "." #endif call Warte_OK_Error("",0) print "AT+CIPSTO=0" #if LCD_Ausgabe=1 lcd "." #endif call Warte_OK_Error("",0) print "AT+CWJAP={034}";mySSID;"{034},{034}";myPW;"{034}" #if LCD_Ausgabe=1 lcd "." #endif call Warte_OK_Error("",0) print "AT+CIFSR" #if LCD_Ausgabe=1 lcd "." #endif call Warte_OK_Error("",1) ' isoliere IP Adresse i = instr(uart_string,"STAIP,") i = i + 7 j = instr(i,uart_string,"{034}") j = j-i myIPAdress = mid(uart_string,i,j) Uart_string="" #if LCD_Ausgabe=1 cls lcd myIPAdress wait 2 #endif Empfangs_Ticker = 0 #if LCD_Ausgabe=1 cls #endifdo Temperature = Temp_tmp100(Adr_TMP101w) if instr(uart_string,"GET")<>0 then ' GET wurde angefordert ' isoliere Sendekanal i=instr(uart_string,"+IPD,") i=i+5 SendeKanal = mid(uart_string,i,1) #if LCD_Ausgabe=1 upperline lcd "HTML requested" locate 2,1:lcd "Kanal ";SendeKanal #endif Uart_string="" 'löschen um Mehrfachaufruf zu verhindern strdummy = fusing(temperature,"#.#") ' HTML File zusammensetzten Sendestring = "<html><body bgcolor="#CCFFFF"><h1>Temperatur=" + strdummy Sendestring =Sendestring + "</h1></html>" ' Header zusammensetzten headerstring = "HTTP/1.1 200 OK{013}{010}" i=len(Sendestring) ' länge des HTML Files bestimmen und übergeben headerstring = headerstring + "Content-Length:" + str(i) + "{013}{010}{013}{010}" 'Header ausgeben print "AT+CIPSEND="; SendeKanal ; ","; print len(HeaderString) call Warte_OK_Error(">",0) print HeaderString call Warte_OK_Error("SEND OK",0) 'HTML ausgeben print "AT+CIPSEND="; SendeKanal ; ","; print len(SendeString) call Warte_OK_Error(">",0) print SendeString; call Warte_OK_Error("SEND OK",0) else #if LCD_Ausgabe=1 upperline 'lcd spc(16) lcd myIPAdress #endif end if #if LCD_Ausgabe=1 lowerline lcd Temperature;" " #endifloopend' ------------------ Subroutinen -----------------------------------------------Function Temp_tmp100(byval Adresse As Byte) As Single Local Tmp100_w As Byte , Tmp100_r As Byte Tmp100_w = Adresse Tmp100_r = Tmp100_w + 1 I2cstart 'repeated start I2cwbyte Tmp100_r 'slave address (read) I2crbyte Hbyte , Ack 'read byte I2crbyte Lbyte , Ack I2cstop shift big_byte,right,4 Temp_tmp100 = big_byte*0.0625End FunctionSub Init_tmp100(byval Adresse As Byte) Local Tmp100_w As Byte Tmp100_w = Adresse ' Temperatursensor initialisieren I2cstart I2cwbyte Tmp100_w 'Addressw 'slave adsress I2cwbyte 1 I2cwbyte &H20 'vorher &H60 I2cstop I2cstart 'generate start I2cwbyte Tmp100_w 'Addressw 'slave adsress I2cwbyte 0 I2cstopEnd SubSub 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 = 0end 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 returnTiming
Das Timing - sprich Wartezeiten - nach den AT Befehlen kann einen zur Verzweiflung bringen. Das Beste ist es, auf 'OK', 'ERROR' usw auszuwerten. In der obigen SW wird dies mit der Subroutine
Sub Warte_OK_Error(byval Suchstring as string*10)realisiert und erlaubt auch noch individuelle Suchbegriffe abzuwarten
Header Aufbau
Dieser MUSS aus der Zeile HTTP/1.1 200 OK bestehen, gefolgt von einem weiteren CrLf (Carrige Return + Line Feed oder "\r\n"). Selbstverständlich muss die Anzahl der zu sendenden Daten in der "AT+CIPSEND" auch die beiden zusätzlichen Zeichen gezählt haben! Dieser Aufbau und die Richtigkeit hat mich trotz seiner beschaulichen Größe Stunden an Fehlersuche gekostet
Spezielle Header-Daten
Der Eintrag von "Content-Length" ist wohl nicht zwingend, beschleunigt aber deutlich die Übergabe an den Browser, von daher empfehle ich die Verwendung.