SPI Ethernet Library
The ENC28J60
is a stand-alone Ethernet controller with an industry standard Serial Peripheral Interface (SPIā¢). It is designed to serve as an Ethernet network interface for any controller equipped with SPI.
The ENC28J60
meets all of the IEEE 802.3 specifications. It incorporates a number of packet filtering
schemes to limit incoming packets. It also provides an internal DMA module for fast data throughput and hardware
assisted IP checksum calculations. Communication with the host controller is implemented via two interrupt pins and the SPI, with data rates of up to 10 Mb/s. Two dedicated pins are used for LED link and network activity indication.
This library is designed to simplify handling of the underlying hardware (ENC28J60
). It works with any PIC MCU with
integrated SPI and more than 4 Kb ROM memory. 38 to 40 MHz clock is recommended to get from 8 to 10 Mhz SPI clock, otherwise PIC should be clocked by ENC28J60
clock output due to its silicon bug in SPI hardware. If you try lower PIC clock speed, there might be board hang or miss some requests.
SPI Ethernet library supports:
- IPv4 protocol.
- ARP requests.
- ICMP echo requests.
- UDP requests.
- TCP requests (no stack, no packet reconstruction).
- ARP client with cache.
- DNS client.
- UDP client.
- DHCP client.
- packet fragmentation is NOT supported.

- Due to PIC16 RAM/Flash limitations PIC16 library does NOT have ARP, DNS, UDP and DHCP client support implemented.
- Global library variable
SPI_Ethernet_userTimerSec
is used to keep track of time for all client implementations (ARP, DNS, UDP and DHCP). It is user responsibility to increment this variable each second in it's code if any of the clients is used. - For advanced users there is
__EthEnc28j60Private.mbas
module in Uses\P16 and Uses\P18 folders of the compiler with description of all routines and global variables, relevant to the user, implemented in the SPI Ethernet Library. - The appropriate hardware SPI module must be initialized before using any of the SPI Ethernet library routines. Refer to SPI Library.
- For MCUs with two SPI modules it is possible to initialize both of them and then switch by using the
SPI_Set_Active()
routine.
Library Dependency Tree

External dependencies of SPI Ethernet Library
The following variables must be defined in all projects using SPI Ethernet Library: | Description : | Examples : |
---|---|---|
dim SPI_Ethernet_CS as sbit sfr external |
ENC28J60 chip select pin. | dim SPI_Ethernet_CS as sbit at RC1_bit |
dim SPI_Ethernet_RST as sbit sfr external |
ENC28J60 reset pin. | dim SPI_Ethernet_RST as sbit at RC0_bit |
dim SPI_Ethernet_CS_Direction as sbit sfr external |
Direction of the ENC28J60 chip select pin. | dim SPI_Ethernet_CS_Direction as sbit at TRISC1_bit |
dim SPI_Ethernet_RST_Direction as sbit sfr external |
Direction of the ENC28J60 reset pin. | dim SPI_Ethernet_RST_Direction as sbit at TRISC0_bit |
The following routines must be defined in all project using SPI Ethernet Library: | Description: | Examples: |
---|---|---|
sub function SPI_Ethernet_UserTCP(dim byref remoteHost as byte[4], dim remotePort as word, dim localPort as word, dim reqLength as word, dim byref flags as TEthPktFlags) as word |
TCP request handler. |
Refer to the library example at the bottom of this page for code implementation. |
sub function SPI_Ethernet_UserUDP(dim byref remoteHost as byte[4], dim remotePort as word, dim destPort as word, dim reqLength as word, dim byref flags as TEthPktFlags) as word |
UDP request handler. |
Refer to the library example at the bottom of this page for code implementation. |
Library Routines
PIC16 and PIC18:
- SPI_Ethernet_Init
- SPI_Ethernet_Enable
- SPI_Ethernet_Disable
- SPI_Ethernet_doPacket
- SPI_Ethernet_putByte
- SPI_Ethernet_putBytes
- SPI_Ethernet_putString
- SPI_Ethernet_putConstString
- SPI_Ethernet_putConstBytes
- SPI_Ethernet_getByte
- SPI_Ethernet_getBytes
- SPI_Ethernet_UserTCP
- SPI_Ethernet_UserUDP
- SPI_Ethernet_setUserHandlers
PIC18 Only:
- SPI_Ethernet_getIpAddress
- SPI_Ethernet_getGwIpAddress
- SPI_Ethernet_getDnsIpAddress
- SPI_Ethernet_getIpMask
- SPI_Ethernet_confNetwork
- SPI_Ethernet_arpResolve
- SPI_Ethernet_sendUDP
- SPI_Ethernet_dnsResolve
- SPI_Ethernet_initDHCP
- SPI_Ethernet_doDHCPLeaseTime
- SPI_Ethernet_renewDHCP
SPI_Ethernet_Init
Prototype |
sub procedure SPI_Ethernet_Init(dim mac as ^byte, dim ip as ^byte, dim fullDuplex as byte) |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It initializes
Parameters:
|
Requires |
Global variables :
|
Example |
' mE ehternet NIC pinout dim SPI_Ethernet_RST as sbit at RC0_bit dim SPI_Ethernet_CS as sbit at RC1_bit dim SPI_Ethernet_RST_Direction as sbit at TRISC0_bit dim SPI_Ethernet_CS_Direction as sbit at TRISC1_bit ' end mE ehternet NIC pinout const SPI_Ethernet_HALFDUPLEX = 0 const SPI_Ethernet_FULLDUPLEX = 1 myMacAddr as byte[6] ' my MAC address myIpAddr as byte[4] ' my IP addr ... myMacAddr[0] = 0x00 myMacAddr[1] = 0x14 myMacAddr[2] = 0xA5 myMacAddr[3] = 0x76 myMacAddr[4] = 0x19 myMacAddr[5] = 0x3F myIpAddr[0] = 192 myIpAddr[1] = 168 myIpAddr[2] = 20 myIpAddr[3] = 60 SPI1_Init() SPI_Ethernet_Init(myMacAddr, myIpAddr, SPI_Ethernet_FULLDUPLEX) |
SPI_Ethernet_Enable
Prototype |
sub procedure SPI_Ethernet_Enable(dim enFlt as byte) |
||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Returns |
Nothing. |
||||||||||||||||||||||||||||||||||||
Description |
This is MAC module routine. This routine enables appropriate network traffic on the Parameters:
![]() |
||||||||||||||||||||||||||||||||||||
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
||||||||||||||||||||||||||||||||||||
Example |
SPI_Ethernet_Enable(_SPI_Ethernet_CRC or _SPI_Ethernet_UNICAST) ' enable CRC checking and Unicast traffic |
SPI_Ethernet_Disable
Prototype |
sub procedure SPI_Ethernet_Disable(dim disFlt as byte) |
||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Returns |
Nothing. |
||||||||||||||||||||||||||||||||||||
Description |
This is MAC module routine. This routine disables appropriate network traffic on the Parameters:
![]() |
||||||||||||||||||||||||||||||||||||
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
||||||||||||||||||||||||||||||||||||
Example |
SPI_Ethernet_Disable(_SPI_Ethernet_CRC or _SPI_Ethernet_UNICAST) ' disable CRC checking and Unicast traffic |
SPI_Ethernet_doPacket
Prototype |
sub function SPI_Ethernet_doPacket() as byte |
---|---|
Returns |
|
Description |
This is MAC module routine. It processes next received packet if such exists. Packets are processed in the following manner:
![]() SPI_Ethernet_doPacket must be called as often as possible in user's code.
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
while TRUE ... SPI_Ethernet_doPacket() ' process received packets ... wend |
SPI_Ethernet_putByte
Prototype |
sub procedure SPI_Ethernet_putByte(dim v as byte) |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It stores one byte to address pointed by the current Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
dim data as byte ... SPI_Ethernet_putByte(data) ' put an byte into ENC28J60 buffer |
SPI_Ethernet_putBytes
Prototype |
sub procedure SPI_Ethernet_putBytes(dim ptr as ^byte, dim n as word) |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It stores requested number of bytes into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
dim buffer as byte[17] ... buffer = "mikroElektronika" ... SPI_Ethernet_putBytes(buffer, 16) ' put an RAM array into ENC28J60 buffer |
SPI_Ethernet_putConstBytes
Prototype |
sub procedure SPI_Ethernet_putConstBytes(const ptr as ^byte, dim n as word) |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It stores requested number of const bytes into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
const buffer as byte[17] ... buffer = "mikroElektronika" ... SPI_Ethernet_putConstBytes(buffer, 16) ' put a const array into ENC28J60 buffer |
SPI_Ethernet_putString
Prototype |
sub function SPI_Ethernet_putString(dim ptr as ^byte) as word |
---|---|
Returns |
Number of bytes written into |
Description |
This is MAC module routine. It stores whole string (excluding null termination) into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
dim buffer as string[16] ... buffer = "mikroElektronika" ... SPI_Ethernet_putString(buffer) ' put a RAM string into ENC28J60 buffer |
SPI_Ethernet_putConstString
Prototype |
sub function SPI_Ethernet_putConstString(const ptr as ^byte) as word |
---|---|
Returns |
Number of bytes written into |
Description |
This is MAC module routine. It stores whole const string (excluding null termination) into Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
const buffer as string[16] ... buffer = "mikroElektronika" ... SPI_Ethernet_putConstString(buffer) ' put a const string into ENC28J60 buffer |
SPI_Ethernet_getByte
Prototype |
sub function SPI_Ethernet_getByte() as byte |
---|---|
Returns |
Byte read from |
Description |
This is MAC module routine. It fetches a byte from address pointed to by current |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
dim buffer as byte<>
...
buffer = SPI_Ethernet_getByte() ' read a byte from
|
SPI_Ethernet_getBytes
Prototype |
sub procedure SPI_Ethernet_getBytes(dim ptr as ^byte, dim addr as word, dim n as word) |
---|---|
Returns |
Nothing. |
Description |
This is MAC module routine. It fetches equested number of bytes from Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
dim buffer as byte[16] ... SPI_Ethernet_getBytes(buffer, 0x100, 16) ' read 16 bytes, starting from address 0x100 |
SPI_Ethernet_UserTCP
Prototype |
sub function SPI_Ethernet_UserTCP(dim byref remoteHost as byte[4], dim remotePort as word, dim localPort as word, dim reqLength as word, dim byref flags as TEthPktFlags) as word |
---|---|
Returns |
|
Description |
This is TCP module routine. It is internally called by the library. The user accesses to the TCP request by using some of the SPI_Ethernet_get routines. The user puts data in the transmit buffer by using some of the SPI_Ethernet_put routines. The function must return the length in bytes of the TCP reply, or 0 if there is nothing to transmit. If there is no need to reply to the TCP requests, just define this function with return(0) as a single statement. Parameters:
![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
This function is internally called by the library and should not be called by the user's code. |
SPI_Ethernet_UserUDP
Prototype |
sub function SPI_Ethernet_UserUDP(dim byref remoteHost as byte[4], dim remotePort as word, dim destPort as word, dim reqLength as word, dim byref flags as TEthPktFlags) as word |
---|---|
Returns |
|
Description |
This is UDP module routine. It is internally called by the library. The user accesses to the UDP request by using some of the SPI_Ethernet_get routines. The user puts data in the transmit buffer by using some of the SPI_Ethernet_put routines. The function must return the length in bytes of the UDP reply, or 0 if nothing to transmit. If you don't need to reply to the UDP requests, just define this function with a return(0) as single statement. Parameters:
![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. |
Example |
This function is internally called by the library and should not be called by the user's code. |
SPI_Ethernet_setUserHandlers
Prototype |
sub procedure SPI_Ethernet_setUserHandlers(dim TCPHandler as ^TSPI_Ethernet_UserTCP, dim UDPHandler as ^TSPI_Ethernet_UserUDP) |
---|---|
Returns |
Nothing. |
Description |
Sets pointers to User TCP and UDP handler function implementations, which are automatically called by SPI Ethernet library. Parameters:
|
Requires |
SPI_Ethernet_UserTCP and SPI_Ethernet_UserUDP have to be previously defined. |
Example |
SPI_Ethernet_setUserHandlers(@SPI_Ethernet_UserTCP, @SPI_Ethernet_UserUDP) |
SPI_Ethernet_getIpAddress
Prototype |
sub function SPI_Ethernet_getIpAddress() as ^byte
|
---|---|
Returns | Pointer to the global variable holding IP address. |
Description |
This routine should be used when DHCP server is present on the network to fetch assigned IP address. ![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim ipAddr as byte[4] ' user IP address buffer ... memcpy(ipAddr, SPI_Ethernet_getIpAddress(), 4) ' fetch IP address |
SPI_Ethernet_getGwIpAddress
Prototype |
sub function SPI_Ethernet_getGwIpAddress() as ^byte
|
---|---|
Returns | Pointer to the global variable holding gateway IP address. |
Description |
This routine should be used when DHCP server is present on the network to fetch assigned gateway IP address. ![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim gwIpAddr as byte[4] ' user gateway IP address buffer ... memcpy(gwIpAddr, SPI_Ethernet_getGwIpAddress(), 4) ' fetch gateway IP address |
SPI_Ethernet_getDnsIpAddress
Prototype |
sub function SPI_Ethernet_getDnsIpAddress() as ^byte
|
---|---|
Returns | Pointer to the global variable holding DNS IP address. |
Description |
This routine should be used when DHCP server is present on the network to fetch assigned DNS IP address. ![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim dnsIpAddr as byte[4] ' user DNS IP address buffer ... memcpy(dnsIpAddr, SPI_Ethernet_getDnsIpAddress(), 4) ' fetch DNS server address |
SPI_Ethernet_getIpMask
Prototype |
sub function SPI_Ethernet_getIpMask() as ^byte
|
---|---|
Returns | Pointer to the global variable holding IP subnet mask. |
Description |
This routine should be used when DHCP server is present on the network to fetch assigned IP subnet mask. ![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim IpMask as byte[4] ' user IP subnet mask buffer ... memcpy(IpMask, SPI_Ethernet_getIpMask(), 4) ' fetch IP subnet mask |
SPI_Ethernet_confNetwork
Prototype |
sub procedure SPI_Ethernet_confNetwork(dim byref ipMask, gwIpAddr, dnsIpAddr as byte[4])
|
---|---|
Returns | Nothing. |
Description |
Configures network parameters (IP subnet mask, gateway IP address, DNS IP address) when DHCP is not used. Parameters:
![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim ipMask as byte[4] ' network mask (for example : 255.255.255.0) gwIpAddr as byte[4] ' gateway (router) IP address dnsIpAddr as byte[4] ' DNS server IP address ... gwIpAddr[0] = 192 gwIpAddr[1] = 168 gwIpAddr[2] = 20 gwIpAddr[3] = 6 dnsIpAddr[0] = 192 dnsIpAddr[1] = 168 dnsIpAddr[2] = 20 dnsIpAddr[3] = 100 ipMask[0] = 255 ipMask[1] = 255 ipMask[2] = 255 ipMask[3] = 0 ... SPI_Ethernet_confNetwork(ipMask, gwIpAddr, dnsIpAddr) ' set network configuration parameters |
SPI_Ethernet_arpResolve
Prototype |
sub function SPI_Ethernet_arpResolve(dim byref ip as byte[4], dim tmax as byte) as ^byte |
---|---|
Returns |
|
Description |
This is ARP module routine. It sends an ARP request for given IP address and waits for ARP reply.
If the requested IP address was resolved, an ARP cash entry is used for storing the configuration.
ARP cash can store up to 3 entries. For ARP cash structure refer to Parameters:
![]() |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim IpAddr as byte[4] ' IP address ... IpAddr[0] = 192 IpAddr[0] = 168 IpAddr[0] = 1 IpAddr[0] = 1 ... SPI_Ethernet_arpResolve(IpAddr, 5) ' get MAC address behind the above IP address, wait 5 secs for the response |
SPI_Ethernet_sendUDP
Prototype |
sub function SPI_Ethernet_sendUDP(dim byref destIP as byte[4], dim sourcePort, destPort as word, dim pkt as ^byte, dim pktLen as word) as byte |
---|---|
Returns |
|
Description |
This is UDP module routine. It sends an UDP packet on the network. Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim IpAddr as byte[4] ' remote IP address ... IpAddr[0] = 192 IpAddr[0] = 168 IpAddr[0] = 1 IpAddr[0] = 1 ... SPI_Ethernet_sendUDP(IpAddr, 10001, 10001, "Hello", 5) ' send Hello message to the above IP address, from UDP port 10001 to UDP port 10001 |
SPI_Ethernet_dnsResolve
Prototype |
sub function SPI_Ethernet_dnsResolve(dim byref host as string, dim tmax as byte) as ^byte |
---|---|
Returns |
|
Description |
This is DNS module routine. It sends an DNS request for given host name and waits for DNS reply.
If the requested host name was resolved, it's IP address is stored in library global variable
and a pointer containing this address is returned by the routine. UDP port Parameters:
![]()
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
dim remoteHostIpAddr as string ' user host IP address buffer ... ' SNTP server: ' Zurich, Switzerland: Integrated Systems Lab, Swiss Fed. Inst. of Technology ' 129.132.2.21: swisstime.ethz.ch ' Service Area: Switzerland and Europe memcpy(remoteHostIpAddr, SPI_Ethernet_dnsResolve("swisstime.ethz.ch", 5), 4) |
SPI_Ethernet_initDHCP
Prototype |
sub function SPI_Ethernet_initDHCP(dim tmax as byte) as byte |
---|---|
Returns |
|
Description |
This is DHCP module routine. It sends an DHCP request for network parameters (IP, gateway, DNS addresses and IP subnet mask) and waits for DHCP reply. If the requested parameters were obtained successfully, their values are stored into the library global variables. These parameters can be fetched by using appropriate library IP get routines:
UDP port Parameters: ![]()
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
... SPI_Ethernet_initDHCP(5) ' get network configuration from DHCP server, wait 5 sec for the response ... |
SPI_Ethernet_doDHCPLeaseTime
Prototype |
sub function SPI_Ethernet_doDHCPLeaseTime() as byte |
---|---|
Returns |
|
Description |
This is DHCP module routine. It takes care of IP address lease time by decrementing the global lease time library counter. When this time expires, it's time to contact DHCP server and renew the lease. |
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
while true ... if(SPI_Ethernet_doDHCPLeaseTime() <> 0) then ... ' it's time to renew the IP address lease end if wend |
SPI_Ethernet_renewDHCP
Prototype |
sub function SPI_Ethernet_renewDHCP(dim tmax as byte) as byte |
---|---|
Returns |
|
Description |
This is DHCP module routine. It sends IP address lease time renewal request to DHCP server. Parameters:
|
Requires |
Ethernet module has to be initialized. See SPI_Ethernet_Init. Available for PIC18 family MCUs only. |
Example |
while true ... if(SPI_Ethernet_doDHCPLeaseTime() <> 0) then SPI_Ethernet_renewDHCP(5) ' it's time to renew the IP address lease, with 5 secs for a reply end if ... wend |
Library Example
This code shows how to use the PIC
mini Ethernet library :
- the board will reply to ARP & ICMP echo requests
- the board will reply to UDP requests on any port :
- returns the request in upper char with a header made of remote host IP & port number
- the board will reply to HTTP requests on port 80, GET method with pathnames :
- / will return the HTML main page
- /s will return board status as text string
- /t0 ... /t7 will toggle P3.b0 to P3.b7 bit and return HTML main page
- all other requests return also HTML main page.
Main program code:
program enc_ethernet ' *********************************** ' * RAM variables ' * dim myMacAddr as byte[6] ' my MAC address myIpAddr as byte[4] ' my IP address ' mE ehternet NIC pinout SPI_Ethernet_Rst as sbit at RC0_bit SPI_Ethernet_CS as sbit at RC1_bit SPI_Ethernet_Rst_Direction as sbit at TRISC0_bit SPI_Ethernet_CS_Direction as sbit at TRISC1_bit ' end ethernet NIC definitions ' ************************************************************ ' * ROM constant strings ' * const httpHeader as string[31] = "HTTP/1.1 200 OK"+chr(10)+"Content-type: " ' HTTP header const httpMimeTypeHTML as string[13] = "text/html"+chr(10)+chr(10) ' HTML MIME type const httpMimeTypeScript as string[14] = "text/plain"+chr(10)+chr(10) ' TEXT MIME type const httpMethod as string[5] = "GET /" ' * ' * web page, splited into 2 parts : ' * when coming short of ROM, fragmented data is handled more efficiently by linker ' * ' * this HTML page calls the boards to get its status, and builds itself with javascript ' * const indexPage as string[763] = "<meta http-equiv=" + Chr(34) + "refresh" + Chr(34) + " content=" + Chr(34) + "3;url=http://192.168.20.60" + Chr(34) + ">" + "<HTML><HEAD></HEAD><BODY>"+ "<h1>PIC + ENC28J60 Mini Web Server</h1>"+ "<a href=/>Reload</a>"+ "<script src=/s></script>"+ "<table><tr><td valign=top><table border=1 style="+chr(34)+"font-size:20px ;font-family: terminal ;"+chr(34)+"> "+ "<tr><th colspan=2>ADC</th></tr>"+ "<tr><td>AN2</td><td><script>document.write(AN2)</script></td></tr>"+ "<tr><td>AN3</td><td><script>document.write(AN3)</script></td></tr>"+ "</table></td><td><table border=1 style="+chr(34)+"font-size:20px ;font-family: terminal ;"+chr(34)+"> "+ "<tr><th colspan=2>PORTB</th></tr>"+ "<script>"+ "var str,i;"+ "str="+chr(34)+chr(34)+"; "+ "for(i=0;i<8;i++)"+ "{str+="+chr(34)+"<tr><td bgcolor=pink>BUTTON #"+chr(34)+"+i+"+chr(34)+"</td>"+chr(34)+"; "+ "if(PORTB&(1<<i)){str+="+chr(34)+"<td bgcolor=red>ON"+chr(34)+";}"+ "else {str+="+chr(34)+"<td bgcolor=#cccccc>OFF"+chr(34)+";}"+ "str+="+chr(34)+"</td></tr>"+chr(34)+";}"+ "document.write(str) ;"+ "</script>" const indexPage2 as string[470] = "</table></td><td>"+ "<table border=1 style="+chr(34)+"font-size:20px ;font-family: terminal ;"+chr(34)+"> "+ "<tr><th colspan=3>PORTD</th></tr>"+ "<script>"+ "var str,i;"+ "str="+chr(34)+chr(34)+"; "+ "for(i=0;i<8;i++)"+ "{str+="+chr(34)+"<tr><td bgcolor=yellow>LED #"+chr(34)+"+i+"+chr(34)+"</td>"+chr(34)+"; "+ "if(PORTD&(1<<i)){str+="+chr(34)+"<td bgcolor=red>ON"+chr(34)+";}"+ "else {str+="+chr(34)+"<td bgcolor=#cccccc>OFF"+chr(34)+";}"+ "str+="+chr(34)+"</td><td><a href=/t"+chr(34)+"+i+"+chr(34)+">Toggle</a></td></tr>"+chr(34)+";}"+ "document.write(str) ;"+ "</script>"+ "</table></td></tr></table>"+ "This is HTTP request #<script>document.write(REQ)</script></BODY></HTML>" dim getRequest as byte[15] ' HTTP request buffer dyna as char[30] ' buffer for dynamic response httpCounter as word ' counter of HTTP requests tmp as string[11] ' ******************************************* ' * user defined sub functions ' * ' * ' * this sub function is called by the library ' * the user accesses to the HTTP request by successive calls to SPI_Ethernet_getByte() ' * the user puts data in the transmit buffer by successive calls to SPI_Ethernet_putByte() ' * the sub function must return the length in bytes of the HTTP reply, or 0 if nothing to transmit ' * ' * if you don"t need to reply to HTTP requests, ' * just define this sub function with a return(0) as single statement ' * ' * sub function Spi_Ethernet_UserTCP(dim byref remoteHost as byte[4], dim remotePort, localPort, reqLength as word, dim byref flags as TEthPktFlags) as word dim i as word ' general purpose integer bitMask as byte ' for bit mask result = 0 ' should we close tcp socket after response is sent? ' library closes tcp socket by default if canClose flag is not reset here ' canClose = 0 ' 0 - do not close socket ' otherwise - close socket if(localPort <> 80) then ' I listen only to web request on port 80 result = 0 exit end if ' get 10 first bytes only of the request, the rest does not matter here for i = 0 to 10 getRequest[i] = Spi_Ethernet_getByte() next i getRequest[i] = 0 ' copy httpMethod to ram for use in memcmp routine for i = 0 to 4 tmp[i] = httpMethod[i] next i if(memcmp(@getRequest, @tmp, 5) <> 0) then ' only GET method is supported here result = 0 exit end if Inc(httpCounter) ' one more request done if(getRequest[5] = "s") then ' if request path name starts with s, store dynamic data in transmit buffer ' the text string replied by this request can be interpreted as javascript statements ' by browsers result = SPI_Ethernet_putConstString(@httpHeader) ' HTTP header result = result + SPI_Ethernet_putConstString(@httpMimeTypeScript) ' with text MIME type ' add AN2 value to reply WordToStr(ADC_Read(2), dyna) tmp = "var AN2=" result = result + SPI_Ethernet_putString(@tmp) result = result + SPI_Ethernet_putString(@dyna) tmp = ";" result = result + SPI_Ethernet_putString(@tmp) ' add AN3 value to reply WordToStr(ADC_Read(3), dyna) tmp = "var AN3=" result = result + SPI_Ethernet_putString(@tmp) result = result + SPI_Ethernet_putString(@dyna) tmp = ";" result = result + SPI_Ethernet_putString(@tmp) ' add PORTB value (buttons) to reply tmp = "var PORTB= " result = result + SPI_Ethernet_putString(@tmp) WordToStr(PORTB, dyna) result = result + SPI_Ethernet_putString(@dyna) tmp = ";" result = result + SPI_Ethernet_putString(@tmp) ' add PORTD value (LEDs) to reply tmp = "var PORTD= " result = result + SPI_Ethernet_putString(@tmp) WordToStr(PORTD, dyna) result = result + SPI_Ethernet_putString(@dyna) tmp = ";" result = result + SPI_Ethernet_putString(@tmp) ' add HTTP requests counter to reply WordToStr(httpCounter, dyna) tmp = "var REQ= " result = result + SPI_Ethernet_putString(@tmp) result = result + SPI_Ethernet_putString(@dyna) tmp = ";" result = result + SPI_Ethernet_putString(@tmp) else if(getRequest[5] = "t") then ' if request path name starts with t, toggle PORTD (LED) bit number that comes after bitMask = 0 if(isdigit(getRequest[6]) <> 0) then ' if 0 <= bit number <= 9, bits 8 & 9 does not exist but does not matter bitMask = getRequest[6] - "0" ' convert ASCII to integer bitMask = 1 << bitMask ' create bit mask PORTD = PORTD xor bitMask ' toggle PORTD with xor operator end if end if end if if(result = 0) then ' what do to by default result = SPI_Ethernet_putConstString(@httpHeader) ' HTTP header result = result + SPI_Ethernet_putConstString(@httpMimeTypeHTML) ' with HTML MIME type result = result + SPI_Ethernet_putConstString(@indexPage) ' HTML page first part result = result + SPI_Ethernet_putConstString(@indexPage2) ' HTML page second part end if ' return to the library with the number of bytes to transmit end sub ' * ' * this sub function is called by the library ' * the user accesses to the UDP request by successive calls to SPI_Ethernet_getByte() ' * the user puts data in the transmit buffer by successive calls to SPI_Ethernet_putByte() ' * the sub function must return the length in bytes of the UDP reply, or 0 if nothing to transmit ' * ' * if you don"t need to reply to UDP requests, ' * just define this sub function with a return(0) as single statement ' * ' * sub function Spi_Ethernet_UserUDP(dim byref remoteHost as byte[4], dim remotePort, destPort, reqLength as word, dim byref flags as TEthPktFlags) as word result = 0 ' reply is made of the remote host IP address in human readable format byteToStr(remoteHost[0], dyna) ' first IP address byte dyna[3] = "." byteToStr(remoteHost[1], tmp) ' second dyna[4] = tmp[0] dyna[5] = tmp[1] dyna[6] = tmp[2] dyna[7] = "." byteToStr(remoteHost[2], tmp) ' second dyna[8] = tmp[0] dyna[9] = tmp[1] dyna[10] = tmp[2] dyna[11] = "." byteToStr(remoteHost[3], tmp) ' second dyna[12] = tmp[0] dyna[13] = tmp[1] dyna[14] = tmp[2] dyna[15] = ":" ' add separator ' then remote host port number WordToStr(remotePort, tmp) dyna[16] = tmp[0] dyna[17] = tmp[1] dyna[18] = tmp[2] dyna[19] = tmp[3] dyna[20] = tmp[4] dyna[21] = "[" WordToStr(destPort, tmp) dyna[22] = tmp[0] dyna[23] = tmp[1] dyna[24] = tmp[2] dyna[25] = tmp[3] dyna[26] = tmp[4] dyna[27] = "]" dyna[28] = 0 ' the total length of the request is the length of the dynamic string plus the text of the request result = 28 + reqLength ' puts the dynamic string into the transmit buffer SPI_Ethernet_putBytes(@dyna, 28) ' then puts the request string converted into upper char into the transmit buffer while(reqLength <> 0) SPI_Ethernet_putByte(SPI_Ethernet_getByte()) reqLength = reqLength - 1 wend ' back to the library with the length of the UDP reply end sub main: ANSEL = 0x0C ' AN2 and AN3 convertors will be used PORTA = 0 TRISA = 0xff ' set PORTA as input for ADC ANSELH = 0 ' Configure other AN pins as digital I/O PORTB = 0 TRISB = 0xff ' set PORTB as input for buttons PORTD = 0 TRISD = 0 ' set PORTD as output httpCounter = 0 ' set mac address myMacAddr[0] = 0x00 myMacAddr[1] = 0x14 myMacAddr[2] = 0xA5 myMacAddr[3] = 0x76 myMacAddr[4] = 0x19 myMacAddr[5] = 0x3F ' set IP address myIpAddr[0] = 192 myIpAddr[1] = 168 myIpAddr[2] = 20 myIpAddr[3] = 60 ' * ' * starts ENC28J60 with : ' * reset bit on PORTC.B0 ' * CS bit on PORTC.B1 ' * my MAC & IP address ' * full duplex ' * SPI1_Init() ' init spi module SPI_Ethernet_Init(myMacAddr, myIpAddr, _SPI_Ethernet_FULLDUPLEX) ' init ethernet module SPI_Ethernet_setUserHandlers(@SPI_Ethernet_UserTCP, @SPI_Ethernet_UserUDP) ' set user handlers while TRUE ' endless loop SPI_Ethernet_doPacket() ' process incoming Ethernet packets ' * ' * add your stuff here if needed ' * SPI_Ethernet_doPacket() must be called as often as possible ' * otherwise packets could be lost ' * wend end.
HW Connection
What do you think about this topic ? Send us feedback!