News:

Let's find out together what makes a PIC Tick!

Main Menu

How to create a small server on a LAN network

Started by Mapo, Oct 22, 2026, 12:19 PM

Previous topic - Next topic

Mapo

Hello everyone,
I have always wanted the ability to put some small projects on a LAN, but I could never find clear information on how to set this up—specifically, how the PIC should respond to a browser's request.
With some help from Claude, I've put together a practical example of how to create an interactive web page that allows you to turn an LED on and off.
I thought it might be helpful to share the code here.
For the LAN interface, I used an inexpensive module based on the CH9121 chip, which communicates with the PIC via a serial connection.


            Device = 18F26K22
            Declare Xtal = 64

Config_Start
            FOSC = HSHP    ;HS oscillator (high power > 16 MHz)
            PLLCFG = On    ;Oscillator multiplied by 4
            PRICLKEN = On    ;Primary clock enabled
            FCMEN = OFF    ;Fail-Safe Clock Monitor disabled
            IESO = OFF    ;Oscillator Switchover mode disabled
            PWRTEN = OFF    ;Power up timer disabled
            BOREN = OFF    ;Brown-out Reset disabled in hardware and software
            BORV = 190    ;VBOR set to 1.90 V nominal
            WDTEN = OFF    ;Watch dog timer is always disabled. SWDTEN has no effect.
            WDTPS = 32768    ;1:32768
            CCP2MX = PORTC1    ;CCP2 input/output is multiplexed with RC1
            PBADEN = OFF    ;PORTB<5:0> pins are configured as digital I/O on Reset
            CCP3MX = PORTB5    ;P3A/CCP3 input/output is multiplexed with RB5
            HFOFST = OFF    ;HFINTOSC output and ready status are delayed by the oscillator stable status
            T3CMX = PORTC0    ;T3CKI is on RC0
            P2BMX = PORTC0    ;P2B is on RC0
            MCLRE = INTMCLR    ;RE3 input pin enabled; MCLR disabled
            STVREN = On    ;Stack full/underflow will cause Reset
            LVP = OFF    ;Single-Supply ICSP disabled
            XINST = OFF    ;Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
            Debug = OFF    ;Disabled
            Cp0 = OFF    ;Block 0 (000800-003FFFh) not code-protected
            CP1 = OFF    ;Block 1 (004000-007FFFh) not code-protected
            CP2 = OFF    ;Block 2 (008000-00BFFFh) not code-protected
            CP3 = OFF    ;Block 3 (00C000-00FFFFh) not code-protected
            CPB = OFF    ;Boot block (000000-0007FFh) not code-protected
            CPD = OFF    ;Data EEPROM not code-protected
            WRT0 = OFF    ;Block 0 (000800-003FFFh) not write-protected
            WRT1 = OFF    ;Block 1 (004000-007FFFh) not write-protected
            WRT2 = OFF    ;Block 2 (008000-00BFFFh) not write-protected
            WRT3 = OFF    ;Block 3 (00C000-00FFFFh) not write-protected
            WRTC = OFF    ;Configuration registers (300000-3000FFh) not write-protected
            WRTB = OFF    ;Boot Block (000000-0007FFh) not write-protected
            WRTD = OFF    ;Data EEPROM not write-protected
            EBTR0 = OFF    ;Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
            EBTR1 = OFF    ;Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
            EBTR2 = OFF    ;Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
            EBTR3 = OFF    ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
            EBTRB = OFF    ;Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------

            Declare Hserial_Baud  = 115200
            Declare Hserial_Clear = On

            Symbol LED = PORTB.0

            Dim Conteggio As Word
            Dim LedState  As Bit
            Dim Ch        As Byte
            Dim Dummy     As Byte
            Dim Lung      As Word
            Dim Dinamica  As String * 255          ' max 255!

            Dim Pag_Inizio As Flash8 = "<!DOCTYPE html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width'><title>PIC18F26K22</title></head><body style='background:#e8e8e8'><h1>Scheda PIC + CH9121</h1>", 0
            Dim Pag_Fine   As Flash8 = "<p><a href='/1'>Accendi</a> | <a href='/0'>Spegni</a> | <a href='/'>Aggiorna</a></p></body></html>", 0

'------------------------------------------------
Init:
              OSCCON = %01110000        ' oscillatore interno 16 MHz
              OSCTUNE.6 = 1             ' PLL x4 -> 64 MHz
              ANSELB = 0 : ANSELC = 0
              TRISB.0 = 0
              Low LED
              LedState = 0
              Conteggio = 0


'------------------------------------------------
Main:
              HSerIn [Wait("GET /"), Ch]     ' aspetta una richiesta, legge il 1° carattere dell'URL
              GoSub Flush_Request            ' scarta il resto delle intestazioni del browser

              Select Ch
                Case "1"                     ' http://ip/1
                  High LED : LedState = 1
                Case "0"                     ' http://ip/0
                  Low LED  : LedState = 0
                Case "f"                     ' /favicon.ico -> 404 vuoto
                  HSerOut ["HTTP/1.1 404 Not Found", 13, 10, "Content-Length: 0", 13, 10, 13, 10]
                  GoTo Main
              EndSelect

              Inc Conteggio
              GoSub Build_Page
              GoSub Send_Page
              GoTo Main

'------------------------------------------------
Flush_Request:                   ' legge finché la seriale resta muta per 20 ms
              HSerIn 20, Flush_End, [Dummy]
              GoTo Flush_Request
Flush_End:
              Return

'------------------------------------------------
'------------------------------------------------
Build_Page:                      ' solo la parte che cambia
              Dinamica = "<p>Richieste servite: " + Str$(Dec Conteggio) + "</p>"
              If LedState = 1 Then
                Dinamica = Dinamica + "<p>LED: <b>ACCESO</b></p>"
              Else
                Dinamica = Dinamica + "<p>LED: <b>SPENTO</b></p>"
              EndIf
              Return

'------------------------------------------------
Send_Page:
              Lung = Len(Pag_Inizio)
              Lung = Lung + Len(Dinamica)
              Lung = Lung + Len(Pag_Fine)
              HSerOut ["HTTP/1.1 200 OK", 13, 10]
              HSerOut ["Content-Type: text/html", 13, 10]
              HSerOut ["Content-Length: ", Dec Lung, 13, 10, 13, 10]
              HSerOut [Pag_Inizio]
              HSerOut [Dinamica]
              HSerOut [Pag_Fine]
              Return[attach id=6355]Pic_Web.txt[/attach][attach id=6355]Pic_Web.txt[/attach] 

Screenshot 2026-10-21 165856.png
Screenshot browser

Screenshot 2026-10-22 141823.png


John Drew

Thanks Mapo, I'll put the code into my great ideas folder for future use.
John

Teo


Dompie

Oh, that is a very simple and clear Positron program. Do you have an example of how to easily generate this GET request from Windows?
My knowledge regarding the Windows side of this issue is very limited.

Johan

▲