terça-feira, 31 de agosto de 2010

Criando um servidor Web no PIC

Olá, pessoal. Muito tempo sem postar por aqui...
Bem, estive ocupado em meu serviço tentando descobrir como criar um servidor Web usando os microcontroladores da família PIC. O grande lance destes microcontroladores é que a Microchip já fornece gratuitamente as bibliotecas necessárias para fazer isto. A questão é que não é muito simples de se configurar, sem muita documentação sobre isto. Por isto resolvi fazer uma descrição sobre este tema aqui.

Preparando terreno

Para que todos possam entender como se configura este projeto a partir do zero, resolvi detalhar todo o processo a partir do download dos arquivos necessários, no site da Microchip.
Assim, o primeiro passo é fazer o download, para quem ainda não fez, do MPLAB, que é a IDE para desenvolvimento de projetos no PIC. Para mim, este é um passo fundamental, já que através do MPLAB, você configura e depura projetos com o PIC muito facilmente. O link para o download do MPLAB (última versão), está aqui:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en019469&part=SW007002

Mas este não será o único download no site da Microchip. É importante também fazer o download de algum compilador C deste fabricante. Como este compilador dependerá do microcontrolador que você irá usar, então haverá escolhas diferentes aqui. Como exemplo, irei usar o compilador C18. A página abaixo possui um link para os vários compiladores disponíveis:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en534868&page=wwwCompilers

Pode-se fazer o download da versão lite destes compiladores, que são versões que não usam todas as otimizações do compilador versão full. Para mim está de bom tamanho para fazer este tipo de desenvolvimento, já que estes compiladores costumam ser muito caros para hobistas.
Tendo feito o download do compilador, resta agora fazer o download das bibliotecas da Microchip para TCP/IP e outros. Isto pode ser feito no link abaixo:
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2680&dDocName=en547784

Muito bem, terminamos com as etapas de downloads... Agora vamos para a parte de instalação, que não é muito complicada. Só para garantir que tudo dará certo, vamos instalar o MPLAB primeiro, o C18 depois e por fim as bibliotecas da Microchip. Não tenho nenhuma observação a fazer aqui, embora eu recomende que deixe que as instalações sejam feitas na raiz da unidade C, para diminuir o caminho a ser incluido nos projetos. Agora estamos prontos para iniciar nosso projeto.

Iniciando o projeto

Quando procurei saber como iniciar um projeto de servidor HTTP no PIC, encontrei várias sugestões me indicando o projeto TCPIP Demo App, que é instalado junto com as bibliotecas da Microchip. Pessoalmente não gostei muito disto, pois o projeto por se tratar de uma demonstração, foi feito para incluir vários tipos de demonstração. Acho que não é necessário copiar todos os arquivos desta pasta. Os arquivos que são necessários para o projeto são os arquivos TCPIPConfig.h e HardwareProfile.h. Através destes arquivos, você poderá configurar seu projeto. Você precisará mudar manualmente o arquivo HardwareProfile.h.
Eu por exemplo tenho aqui uma placa Explorer16BR, da Mosaico. Todo mundo poderia achar que pelo fato de haver uma definição EXPLORER_16 neste arquivo, bastaria habilitá-la para que tudo funcione perfeitamente, certo? Bem, a verdade é que a Mosaico andou alterando alguns pinos nesta placa, e entre eles está justamente o pino de habilitação do Driver Ethernet. Portanto, se alguém estiver usando esta placa, procure pela definição
#else // SPI1 for all other processors
 #define ENC_CS_TRIS (TRISDbits.TRISD14)
 #define ENC_CS_IO (LATDbits.LATD14)
E altere para:
#else // SPI1 for all other processors
 #define ENC_CS_TRIS (TRISCbits.TRISC4)
 #define ENC_CS_IO (LATCbits.LATC4)
Há também a opção de se criar o arquivo do zero. Neste caso, a pessoa deve criar algumas definições obrigatórias neste arquivo, como está abaixo:
#ifndef __HARDWARE_PROFILE_H
#define __HARDWARE_PROFILE_H

#include "GenericTypeDefs.h"
#include "Compiler.h"

// Define os fusíveis de configuração (apenas uma vez)
#if defined(THIS_IS_STACK_APPLICATION)
 #if defined(__18CXX)
  #if defined(__EXTENDED18__)
   #pragma config XINST=ON
  #elif !defined(HI_TECH_C)
   #pragma config XINST=OFF
  #endif
  
  #pragma config WDT=OFF, FOSC2=ON, FOSC=HSPLL, ETHLED=ON

 #endif
#endif // Previne a definição de mais de uma vez dos mesmos fusíveis

// Valor da frequência de clock.
// Este valor é usado para calcular o valor de Tick Counter
#define GetSystemClock()      (41666667ul)      // Hz
#define GetInstructionClock() (GetSystemClock()/4)
#define GetPeripheralClock()  GetInstructionClock()
No caso, as definições que devem ser feitas são as definições de clock do sistema. Você precisa verificar qual as configurações de frequência você está usando, para criar estas definições.
Feito isto, podemos agora configurar a parte de TCP/IP. Para isto, a Microchip desenvolveu um executável que faz toda a configuração para nós. Este executável se encontra na pasta:
[Diretório instalado]\Microchip Solutions\Microchip\TCPIP Stack\Utilities

E o executável se chama TCPIPConfig.exe. Execute ele e forneça o caminho para seu projeto. Não se esqueça de marcar a opção Show Advanced Settings, para podermos configurar nosso projeto nos mínimos detalhes. Na próxima tela teremos várias opções de projeto:



Selecionaremos apenas Web Server. Selecionando Next, teremos várias opções de códigos de exemplo. Não iremos selecionar nenhuma destas opções aqui. Clicando-se novamente em Next, teremos uma seleção de módulos:


Aqui selecionamos ICMP Client, ICMP Server e o NetBIOS Name Service. Os dois ICMP são necessários para que a aplicação possa fazer PING em computadores e para que ela possa também responder a este comando, muito útil para verificar a conectividade de dispositivos. O NetBIOS Name Service será importante para que você possa acessar seu dispositivo pelo Browser digitando o nome deste dispositivo na barra de endereços.
É na próxima tela que você configurará o endereço IP de seu projeto, nome do dispositivo, máscara de sub-rede, endereço MAC, etc...


Configure de forma que o dispositivo seja reconhecido em sua rede. Assim que isto for feito, clique em Next, e você será perguntado sobre qual biblioteca HTTP você pretende usar em seu projeto.


Vamos usar o HTTP2, pois ele traz inúmeras vantagens, como a possibilidade de usar métodos POST em formulários e o uso de variáveis dinâmicas. Feito isto, na próxima tela temos a seleção de configurações da biblioteca:


Como é um teste simples, vamos habilitar apenas os métodos POST. A página inicial será a página index.htm, e permitiremos apenas duas conecções por vez. Na próxima tela temos a seleção do sistema de arquivos, mas o HTTP2 da Microchip possibilita apenas o uso do sistema de arquivos MPFS2. Depois desta seleção, podemos escolher onde os arquivos serão gravados. No meu projeto, preferi salvar os arquivos dentro da Flash de programa do microcontrolador, que tinha espaço suficiente para todos os arquivos. Outras opções são:


O próximo passo é o mais complicado. Neste passo, você determinará a quantidade de memória usada para cada conecção.


Como não usamos nenhum outro tipo de conecção, determinaremos memória apenas para o HTTP_SERVER. Verifique se os outros tipos de Sockets estão com seu Count diferente de 0. O Count determina quantas conecções daquele tipo existirão. Como só temos duas conecções HTTP, só neste tipo de Socket é que deveremos ter um valor diferente de 0. A próxima tela permite você escolher quantas conecções UDP sua aplicação terá, e finalmente você poderá concluir esta configuração. O programa vai sobreescrever os valores disponíveis no seu arquivo TCPIPConfig.h. Estamos prontos para dar início a nosso projeto.

Arquivo principal do projeto

O arquivo principal do projeto deverá seguir alguns procedimentos básicos. O primeiro é que ele deve trazer a seguinte definição:
#define THIS_IS_STACK_APPLICATION
Isto indicará ao compilador qual é o arquivo principal. O segundo passo é que sua aplicação deverá definir uma instância da estrutura APP_CONFIG chamada de AppConfig. Esta estrutura contém as configurações de TCP/IP do projeto. Adicione a linha:
APP_CONFIG AppConfig;
Esta será uma variável global.
Nós temos também que definir o tratamento de interrupções de tempo, pois o Stack TCP/IP da Microchip usa os timers para o gerador de ticks. O tratamento de interrupção pode ser feito através do seguinte código:
#pragma interruptlow LowISR
void LowISR(void)
{
 TickUpdate();
}
 
#pragma interruptlow HighISR
void HighISR(void)
{
}
 
#pragma code lowVector=0x18
void LowVector(void){_asm goto LowISR _endasm}
#pragma code highVector=0x8
void HighVector(void){_asm goto HighISR _endasm}
#pragma code // Volta para a seção padrão de código
Para um servidor HTTP, as funções de tratamento de mensagens GET e POST (quando habilitadas) serão chamadas. Mas as bibliotecas da Microchip deixam a definição destas funções a cargo da aplicação, para que o programador trate destas mensagens da forma que ele deseja. Como estamos no início do projeto e a intenção é apenas gerar um servidor sem formulários no começo, vamos definir funções que não fazem nenhum tratamento:
HTTP_IO_RESULT HTTPExecuteGet(void)
{
  return HTTP_IO_DONE;
}

HTTP_IO_RESULT HTTPExecutePost(void) 
{
  return HTTP_IO_DONE;
}
Retornando HTTP_IO_DONE em ambas funções, dizemos às bibliotecas TCP/IP da microchip que o tratamento destas funções foi bem-sucedido, o que não deixa de ser verdade.
Como antes criamos uma instância da estrutura APP_CONFIG, precisamos agora preenchê-la com os dados necessários à aplicação. Os detalhes desta função podem ser vistos no programa de demonstração da Microchip, mas para facilitar esta tarefa, estarei colocando a função que criei aqui:
static ROM BYTE SerializedMACAddress[6] = {MY_DEFAULT_MAC_BYTE1, MY_DEFAULT_MAC_BYTE2, MY_DEFAULT_MAC_BYTE3, MY_DEFAULT_MAC_BYTE4, MY_DEFAULT_MAC_BYTE5, MY_DEFAULT_MAC_BYTE6};

static void InitAppConfig(void)
{
 AppConfig.Flags.bIsDHCPEnabled = TRUE;
 AppConfig.Flags.bInConfigMode = TRUE;
 memcpypgm2ram((void*)&AppConfig.MyMACAddr, (ROM void*)SerializedMACAddress, sizeof(AppConfig.MyMACAddr));
 AppConfig.MyIPAddr.Val = MY_DEFAULT_IP_ADDR_BYTE1 |  MY_DEFAULT_IP_ADDR_BYTE2<<8ul | MY_DEFAULT_IP_ADDR_BYTE3<<16ul | MY_DEFAULT_IP_ADDR_BYTE4<<24ul; AppConfig.DefaultIPAddr.Val = AppConfig.MyIPAddr.Val; AppConfig.MyMask.Val = MY_DEFAULT_MASK_BYTE1 | MY_DEFAULT_MASK_BYTE2<<8ul | MY_DEFAULT_MASK_BYTE3<<16ul | MY_DEFAULT_MASK_BYTE4<<24ul; AppConfig.DefaultMask.Val = AppConfig.MyMask.Val; AppConfig.MyGateway.Val = MY_DEFAULT_GATE_BYTE1 | MY_DEFAULT_GATE_BYTE2<<8ul | MY_DEFAULT_GATE_BYTE3<<16ul | MY_DEFAULT_GATE_BYTE4<<24ul; AppConfig.PrimaryDNSServer.Val = MY_DEFAULT_PRIMARY_DNS_BYTE1 | MY_DEFAULT_PRIMARY_DNS_BYTE2<<8ul | MY_DEFAULT_PRIMARY_DNS_BYTE3<<16ul | MY_DEFAULT_PRIMARY_DNS_BYTE4<<24ul; AppConfig.SecondaryDNSServer.Val = MY_DEFAULT_SECONDARY_DNS_BYTE1 | MY_DEFAULT_SECONDARY_DNS_BYTE2<<8ul | MY_DEFAULT_SECONDARY_DNS_BYTE3<<16ul | MY_DEFAULT_SECONDARY_DNS_BYTE4<<24ul; memcpypgm2ram(AppConfig.NetBIOSName, (ROM void*)MY_DEFAULT_HOST_NAME, 16); FormatNetBIOSName(AppConfig.NetBIOSName);
}
Por fim, nossa função main. Aqui há algumas observações a se fazer... As funções de inicialização do protocolo devem seguir uma ordem para serem executadas, pois do contrário o nosso servidor não funcionará. A ordem é a seguinte:
InitAppConfig();
TickInit();
MPFSInit();
StackInit();
O loop principal de seu programa deve executar estas duas funções:
StackTask();
StackApplications();
São estas as funções que devem ser usadas no seu projeto.

Configurando o projeto

Devemos incluir os arquivos para o projeto. Antes disto, devemos configurar o projeto para que inclua os cabeçalhos da Microchip na hora de compilar. Vamos ao menu Project, Build Options... Em Directories, clicando no menu Drop Down, selecionamos a opção Include Search Path. Vamos incluir aqui o diretório do projeto ".", o diretório de includes da Microchip Solutions, e o diretório de includes do C18. Em Library Search Path incluiremos também o diretório de livrarias do C18. Feito isto, estamos prontos para incluir os arquivos do projeto.
Para compilar o projeto, precisamos incluir os seguintes arquivos: ARP.c, Delay.c, DNS.c, ENC28J60.c, Helpers.c, HTTP2.c, ICMP.c, IP.c, MPFS2.c, NBNS.c, StackTsk.c, TCP.c, Tick.c, UDP.c. Agora nos resta criar os arquivos html para o servidor web.

Arquivos do servidor

Na sua pasta de projeto, crie uma pasta para guardar os arquivos html do servidor. É importante criar o arquivo index.htm que nós colocamos antes como o arquivo inicial do servidor. Neste primeiro passo, vamos criar apenas arquivos estáticos.
Assim que os arquivos forem criados, poderemos voltar na pasta Utilities onde encontramos o executável de configuração de TCP/IP. Agora vamos executar o programa MPFS2.exe.


Este programa irá converter os arquivos da pasta que você indicar para o sistema de arquivos MPFS. Como desejamos gravar na memória de programa do PIC, iremos converter nossos arquivos em um arquivo .c, que deverá ser incluído também no projeto. Assim que você clicar Generate, dois arquivos serão criados na pasta de projeto que você especificou. Depois disto, inclua o arquivo HTTPPrint.h que o programa gerar.
Pronto! Nosso projeto está completo e poderá ser compilado.

Voltaremos a falar sobre este tema posteriormente, explicando como usar formulários e variáveis dinâmicas. Por fim, ensinaremos a usar AJAX com nosso servidor web.

18 comentários:

  1. Otimo material publicado. Agradeço a ajuda em que este tópico forneceu.Estou aguardando a sequencia dos posts.

    ResponderExcluir
  2. Ainda não consegui entender como achar o programa MPFS2.exe, ele vem junto com a pilha?

    ResponderExcluir
  3. Olá, roquetti. Sim, ele é instalado com a pilha TCP/IP, e fica na pasta [Raiz]\Microchip Solutions\Microchip\TCPIP Stack\Utilities.

    ResponderExcluir
  4. Saudações amigo.
    Parabéns pelo post.Um dos mais completos que já econtrei.
    Estou há alguns meses procurando informações sobre o uso do ENC28J60 com PIC e tenho penado para encontrar material aproveitável, e certamente o seu está sendo muito útil.
    Mas confesso que ainda estou apanhando aqui.
    Estou usando o 16F876 para controlar o ENC e o compilador da CCS, e até agora nada.
    Se tiver alguma dica a mais, eu agradeço.
    Abraço.

    ResponderExcluir
  5. Olá, Paulo...
    Teremos que ver qual exatamente é seu problema... O CCS não aproveita muito as bibliotecas da Microchip, então você deverá descobrir se o compilador já possui alguma coisa pronta. Se não, você terá que desenvolver, e aí, vai precisar muito dos datasheets. Se eu puder, ainda escreverei sobre isto...

    ResponderExcluir
  6. Olá, gostaria de saber se você pode me ajudar. Preciso ligar um PIC18F4550 (como um servidor WEB)em um módulo ethernet usando o ENC28J60 para acender e apagar leds, mas estou confuso de como começar a fazer a programação. Poderia me ajudar? Obrigado!

    ResponderExcluir
  7. Olá, Alessandro.

    O básico do projeto com o ENC28J60 é o que está por aqui. Observe atentamente as configurações para o Explorer 16, pois ele usa este chip. Se não me engano, há até o esquemático desta placa disponível gratuitamente, então se você estiver com dúvidas sobre como ligá-lo, lá você poderá ver como se faz.

    Abraços.

    ResponderExcluir
  8. Boa noite.
    Antes de tudo, parabéns pelo conteúdo. Como você disse, é dificil encontral material sobre o assunto. Como estudante, agradeço muito as dicas e parabéns pela iniciativa.

    Sou estudante de Eng. da Computação e estou começando um projeto de TCC. O projeto é basicamente o que está postado: controlar dispositivos residenciais a partir da internet.
    Gostaria de saber, se é possível me enviar o esquema de coneção desse módulo ENC28J60 com a interface SPI do PIC18F4550. Estou iniciando em microcontroladores, e ainda tenho muitas dificuldades.
    A página WEB deve ser salva na memória FLASH do PIC, ou vc utiliza memória externa?

    guilherme.perozini@gmail.com

    abraços..

    ResponderExcluir
    Respostas
    1. Olá, Guilherme... Sinto muito pela demora em responder...

      Eu não tenho o esquema desenhado ainda para enviar, mas assim que eu fizer, eu o postarei no blog. Quanto à página Web, seguindo os passos que passei, elas serão salvas na própria memória de código do microcontrolador.

      Excluir
  9. oi!
    este projecto está muito interessante. só preciso de uma coisa.
    o esquema com o pic. será que é possível colocar aqui o mesmo???

    um abraço

    ResponderExcluir
    Respostas
    1. Olá, Filipe...

      Desculpa pela demora em responder... O esquemático eu não o tenho em um formato que eu possa publicar, mas vou ver se consigo um tempo para desenhá-lo e então postarei por aqui.

      Excluir
  10. Boa Noite.

    Qual o valor do Cristal que está usando?

    Como faço para calcular o GetSystemClock() para um Cristal de 20Mhz com PLL desabilitado?

    Obrigado.

    ResponderExcluir
    Respostas
    1. Olá e me desculpe pela demora...

      Para usar o microcontrolador para projetos com Ethernet, o cristal deve ser de 25MHz. A tabela 2-2 na página 46 do datasheet explica os valores possíveis de clock e como obtê-los. Você irá colocar o valor que a tabela te fornecer.

      Excluir
  11. Olá, bom dia. Gostaria de saber se vc conhece a placa Pic Web da Olimex, tenho uma na versão B. Estou com planos de fazer o controle das saidas e leituras das entradas via internet, porem não encontro informações. Vc conhece algo sobre isto que possa me ajudar?
    Obrigado.

    ResponderExcluir
    Respostas
    1. Sinto muito, Tiago, mas não conheço esta placa. No entanto, se a Olimex te fornecer o esquemático desta placa, você poderá fazer as configurações necessárias.

      Excluir
  12. Olá ADM ou alguem aqui do Blog...
    tenho um projeto para entregar na minha faculdade sobre este tema
    Acionar rele Usando micro controlador PIC com servidor WEB...
    segui este tutorial e empaquei nos codigos..
    por favor, me de uma ajuda.
    se puder me mandar um projeto simples pronto, para mim estudar, ou algo que me ajude claramente a montar este projeto,, ficarei muito grato.
    meu e-mail: maxivane@bol.com.br.... OBRIGADO

    ResponderExcluir
  13. Boa noite..Estou desenvolvendo um projeto parecido com este..porem parei no desenvolvimento dos códigos..tenho que controlar 5 saídas do pic através da net..Alguem poderia me ajudar..Grato!!!
    diegoventania@hotmail.com

    ResponderExcluir
  14. Olá
    Parabéns pelo site!

    Eu gostaria de saber como faço para pingar do PIC para um IP da rede. O inverso eu já fiz, consigo pingar para o PIC + o módulo ENC28J60 e consigo abrir o browser e controlar um LED.

    Gostaria que o PIC pingasse um IP e caso não recebesse resposta em um tempo, executasse uma ação. Eu programo no compilador CCS.

    Vc poderia me ajudar?

    ResponderExcluir

Você também poderá gostar de