Obsah

Ethernet řadič ENC28J60

Zadání projektu

Připojte řadič ENC28J60 k desce FRDM-KL25Z, zprovozněte TCP/IP stack a vytvořte jednoduchý TELNET server, pomocí kterého bude možné příkazy ovládat RGB LED.

Použitý hardware

Projekt je navržen na vývojové desce FRDM-KL25Z od společnosti Freescale. Tato vývojová deska má na sobě již implementovanou RGB LED diodu, která bude v projektu použita. Ethernetový řadič ENC28J60 je použitý v podobě kitu určeného pro Arduino a již obsahuje všechny podpůrné součástky. Zároveň má na hřebínek vyvedeny komunikační piny. Obvod komunikuje pomocí sběrnice SPI. Celé zapojení tedy spočívá pouze v propojení SPI komunikačních pinů. KL25Z má implementovány dvě SPI sběrnice (SPI_0, SPI_1). Je použita SPI_0 s piny které zobrazuje obrázek 1 s menší obměnou u SCK pinu. Je totiž společný pro modrou diodu, která slouží jako signalizace komunikace. Tím by byla modrá dioda blokována, a proto je použit pin PTC5. Všechny použite piny na vývojové desce shrnuje následující tabulka.

 Pinout vývojové desky FDRM-KL25Z

 obr.1 Pinout vývojové desky FDRM-KL25Z 

 Arduino kit ENC28J60

 obr.2 Arduino kit ENC28J60    
Tabulka zapojení pinů
FDRM-KL25Z ENC28J60
PTD3 MISO
PTD2 MOSI
PTC5 SCK
PTD0 CS
3V3 VCC
GND GND

Použitý software

Řídicí program je psán a kompilován ve webovém vývojovém prostředí mbed.org . Tento výběr byl učiněn kvůli absenci nutnosti instalace nějakého prostředí na PC a s tím spojené možné komplikace. Dále tak bylo proto, že prostředí má velikou podporu komunity a mnoho knihoven. Jednou z nich je právě knihovna UIPEthernet. Jejím použitím je zajištěna komunikace s modulem ENC28J60 a odpadá zdlouhavá a pracná činnost na tvorbě knihovny vlastní.

 Zapojení

 obr.3 Zapojení   

Popis funkce

Po zapnutí dojde k inicializaci kitu ENC28J60 a program otevře server který čeká na 23 portu (telnet) na spojení. Pokud dojde k připojení klienta, server odešle uvítací zprávu a čeká na příkazy. Možné příkazy jsou následovné:

V programu je možné definicí preprocesorové proměnné #DHCP přepínat mezi IP adresou statickou nebo IP adresou získávanou z DHCP serveru.

Demonstrace

Následující video ukazuje funkčnost projektu. Jsou použity dvě náhodně vygenerované barvy pro ověření správného zobrazení:

Zdrojový kód

#include "mbed.h"
#include <string>
#include "UIPEthernet.h"
#include "UIPServer.h"
#include "UIPClient.h"
 
//setting led's ports 
PwmOut gled(LED_GREEN); 
PwmOut bled(LED_BLUE); 
PwmOut rled(LED_RED);  
 
Serial pc(USBTX, USBRX); //debug over serial port
 
//#define DHCP    1   // if you'd like to use static IP address comment out this line 
 
#if defined(TARGET_LPC1768)
UIPEthernetClass    UIPEthernet(p11, p12, p13, p8);         // mosi, miso, sck, cs
#elif defined(TARGET_NUCLEO_F103RB) || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_F030R8)  \
   || defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F302R8) || defined(TARGET_NUCLEO_L053R8)  \
   || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F334R8) || defined(TARGET_NUCLEO_F072RB)  \
   || defined(TARGET_NUCLEO_F091RC) || defined(TARGET_NUCLEO_F303RE) || defined(TARGET_NUCLEO_F070RB)  \
   || defined(TARGET_KL25Z ) || defined(TARGET_KL46Z) || defined(TARGET_K64F) || defined(TARGET_KL05Z) \
   || defined(TARGET_K20D50M) || defined(TARGET_K22F) \
   || defined(TARGET_NRF51822) \
   || defined(TARGET_RZ_A1H)
UIPEthernetClass    UIPEthernet(D11, D12, PTC5, D10);        // mosi, miso, sck, cs
#endif
 
//prototypes and global variables
void print_line(string text);
EthernetClient client;
 
//MAC address
const uint8_t   MY_MAC[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
const uint16_t  MY_PORT = 23;
EthernetServer  server = EthernetServer(MY_PORT);
 
int main(void)
{
    //turning off all LEDs
    rled = 1;
    bled = 1;
    gled = 1;    
 
// setting IP address    
#if defined(DHCP)
    pc.printf("Searching for DHCP server..\r\n");
    if(UIPEthernet.begin(MY_MAC) != 1) {
        pc.printf("No DHCP server found.\r\n");
        pc.printf("Exiting application.\r\n");
        return 0;
    }
    pc.printf("DHCP server found.\r\n");
#else
    const IPAddress MY_IP(192, 168, 1, 10);
    UIPEthernet.begin(MY_MAC, MY_IP);
#endif
    IPAddress   localIP = UIPEthernet.localIP();
    pc.printf("Local IP = ");
    for(uint8_t i = 0; i < 3; i++)
        pc.printf("%d.", localIP[i]);
    pc.printf("%d\r\n", localIP[3]);
    server.begin();
 
 //main cycle
    while(1)
    {        
        uint8_t size;
        char buffer[256];
 
        if (client = server.available())
        {
                pc.printf("Client connected.\r\n");                  
                //welcome message
                print_line("RGB telnet server");
                print_line(" - Write help for options..\n");
                client.write((uint8_t*)"> ", 2);
 
                while(1)
                {                   
                    size = client.available();
                    if (size <= 0) continue;
 
                    //get incoming string to buffer                                                        
                    uint8_t* msg = (uint8_t*)malloc(size);
                    size = client.read(msg,size);                                     
                    sprintf(buffer,"%s",msg);
                    buffer[size] = '\0';
 
                    //color setting                    
                    if (strncmp(buffer, "color",5) == 0)
                    {                     
                        char color[2];    
                        uint8_t col;                                            
 
                        sprintf(color, "%c%c",buffer[6],buffer[7]); //get HEX char                    
                        sscanf(color, "%x", &col); 
                        sprintf(color, "%u", col); // convert to DEC number
                        rled = (float)(~atoi(color) & 0xff)/255; // inverse number, set value to PWM between 0-1
 
                        sprintf(color, "%c%c",buffer[8],buffer[9]);                     
                        sscanf(color, "%x", &col);
                        sprintf(color, "%u", col);
                        gled = (float)(~atoi(color) & 0xff)/255;  
 
                        sprintf(color, "%c%c",buffer[10],buffer[11]);                     
                        sscanf(color, "%x", &col);
                        sprintf(color, "%u", col);
                        bled = (float)(~atoi(color) & 0xff)/255;                     
                    }
                    //turning off all LEDs
                    else if (strncmp(buffer, "stop",4) == 0)
                    {
                        rled = 1;
                        bled = 1;
                        gled = 1;
                    }
                    //disconnecting
                    else if (strncmp(buffer, "exit",4) == 0) break;                    
                    //help message
                    else if (strncmp(buffer, "help",4) == 0)
                    {               
                        print_line("-----Help-----");
                        print_line("color HEX_COLOR_CODE - set color");
                        print_line("      HEX_COLOR_CODE - in hex rrggbb (white = ffffff)");
                        print_line("stop - ALL LEDs OFF");
                        print_line("exit - end connection");
                        print_line("--------------");
                    }
                    else if (strchr(buffer, '\n') != NULL)
                    {               
                        client.write((uint8_t*)"> ", 2);
                    }                                                          
                 }
                 client.stop();
                 pc.printf("Client disconnected.\r\n");                  
        }         
    }
}
 
//printing out line of string
void print_line(string text)
{
    char buffer[256];
    sprintf(buffer, "%s\r\n",text);
    client.write((uint8_t*)buffer, strlen(buffer));
    return;
}

Závěr

Zadaní projektu bylo kompletně splněno a vše je funkční tak jak má být. Během řešení jsem neměl s ničím problém a na zadání jsem byl dostatečně připraven jak z předchozích zkušeností tak z předmětu MPOA.
Velikou výhodou bylo nalezení již hotové knihovny k řadiči ENC28J60. Bez toho bych byl nucen strávit několik dní studiem datasheetu k obvodu a následným experimentováním. Použití HEXa barevného kódu pro nastavování barvy mi přijde jako zajímavé řešení, kterým je využit celý rozsah možností RGB LED diody.