Programmare SlimLine Raspberry in “C”

  1. Home
  2. Knowledge Base
  3. Controllori SlimLine Raspberry
  4. Programmare SlimLine Raspberry in “C”

Il modulo SlimLine Raspberry oltre alla programmazione secondo la normativa IEC61131 in stile PLC, in ambiente CODESYS o LogicLab (Vedi articolo), può essere programmato in linguaggio "C". Questo permette di utilizzare le librerie disponibili su Internet e di poter gestire i moduli di estensione collegabili al modulo CPU grazie ad una libreria a noi fornita. Per lo sviluppo di applicazioni in "C" è possibile utilizzare qualsiasi compilatore, in questo articolo utilizzeremo il noto IDE Codelite. Per chi utilizza l'ambiente LogicLab e vuole aggiungere nuove funzioni ed FB scritte in linguaggio "C" può leggere questo articolo.

Installazione toolchain

Per poter compilare programmi eseguibili su Raspberry occorre scaricare la toolchain di cross-compilazione di Raspbian da GitHub, scompattare il file in una cartella di sistema esempio /home/elsist/dev. Ora aggiungere la cartella nel PATH di sistema, editare il file etc/profile inserendo in fondo il link alla toolchain nella cartella in cui è stata trasferita, di seguito il link per i sistemi a 32 bits sulla riga superiore e 64 bits sulla riga inferiore.

export PATH=/home/elsist/dev/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin:$PATH
export PATH=/home/elsist/dev/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH

Dopo aver modificato il file per renderlo attivo occorre da un terminale eseguire il comando source /etc/profile, è possibile verificare che il PATH sia attivo con il comando printenv. Se tutto è corretto è possibile compilare un semplice programma HelloWorld ed eseguirlo. Con un editor di testo creare il file main.c con il seguente contenuto :

#include 
int main()
{
    printf("Hello World!\r\n");
    return 0;
}

Compilare il programma con il comando arm-linux-gnueabihf-gcc main.c -g -o hello, verrà creato il file eseguibile hello che trasferito sulla Raspberry potrà essere eseguito. Anche se ora abbiamo tutto quello che serve per compilare un programma è preferibile affidarsi ad un IDE che permetta di gestire in modo più semplice lo sviluppo di applicazioni complesse, nel prosieguo utilizzeremo Codelite.

Installazione IDE

Codelite è un IDE open source gratuito disponibile per Windows, Linux e MacOS per lavorare con il linguaggio C, il programma è scaricabile dal sito ufficiale. Tralascio tutte le istruzioni per l'installazione che oltre ad essere molto semplici sono disponibili su una infinità di guide reperibili su Internet. Anche se il programma è disponibile per Windows, ne consiglio l'installazione su di una macchina Linux in quanto dovendo sviluppare applicazioni per Raspberry ci si trova già con tutte le librerie di base disponibili.

Ora è possibile creare un nuovo Workspace a cui aggiungere un nuovo progetto, nel progetto settare il compilatore della toolchain Raspberry, tasto destro sul nome progetto, scegliere Settings -> General -> Compiler ed impostare Cross GCC (arm-linux-gnueabihf). Ora è possibile compilare il progetto e nella cartella Debug del progetto verrà generato il file eseguibile HelloWorld. Eseguendo il download del programma dimostrativo nella cartella HelloWorld si trova il progetto Codelite pronto per il test.

Trasferire programma su Raspberry

Con il comando build da Codelite viene compilato il programma che è salvato nella cartella Debug o Release (In base alla selezione di compilazione) creata all'interno della cartella di progetto. Ora utilizzando un SFTP occorre trasferirlo sul modulo Raspberry per l'esecuzione. Esistono molti client SFTP con interfaccia grafica adatti allo scopo il più noto è Filezilla, ma è più comodo agire semplicemente da una finestra terminale utilizzando il comando scp abbinandolo al comando sshpass per inviare anche la password di connessione.

Ora ipotizzando che il file eseguibile CPhrAccess compilato da Codelite sia nella cartella /home/CPhrAccess e che il modulo Raspberry abbia credenziali pi:raspberry ed indirizzo IP 192.168.0.180, volendo trasferire l'eseguibile nella cartella /home/pi occorre utilizzare il comando (Se il comando sshpass non è presente occorre installarlo):

sshpass -p 'raspberry' scp /home/CPhrAccess/CPhrAccess/Release/CPhrAccess [email protected].168.0.180:/home/pi

Codelite può automaticamente al termine della compilazione eseguire il comando scp trasferendo il file sul modulo Raspberry, per impostarlo occorre nel menù Settings -> Pre/Post Build Commands -> Post Build inserire la riga di comando definita sopra.

Libreria libeS8CoreMng

Per lo sviluppo di applicazioni in "C" viene fornita la libreria libeS8CoreMng.a che contiene definizioni e funzioni per gestire l'hardware del sistema oltre a numerose funzioni utili. La libreria usa la gestione dei threads quindi per poter compilare il progetto occorre definire in Codelite nel menù Settings -> Linker -> Linker Options i parametri -pthread -lrt. A corredo forniamo un programma dimostrativo che contiene oltre alla libreria anche una serie di esempi di utilizzo (Download dimostrativo).

CPhrAccess: Inizializza il bus di estensione attivando il watchdog hardware. Gestiisce un modulo di I/O digitali connesso al  bus di estensione e con comandi da tastiera (Tramite accesso SSH) è possibile testare l'intervento del circuito di watchdog (Vedi articolo).

CPhrAccess (Ptp168)
// *****************************************************************************
// PROGRAM "CPhrAccess"
// *****************************************************************************
// A simple programs that shows how to access to peripheral modules attached to
// the SlimLine extension BUS.
// -----------------------------------------------------------------------------

#include <string.h>
#include <termio.h>
#include <unistd.h> 
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <StdDefs.h>
#include <Library.h>
#include <SystemTime.h>
#include <PhrI2cBus.h>
#include <LastError.h>
#include <PhrFcts.h>
#include <WatchDog.h>
using namespace Elsist; //Defines namespace

// -----------------------------------------------------------------------------
// KEYBOARD HIT FUNCTION
// -----------------------------------------------------------------------------
// The function returns true if a key on the keyboard has been pressed.

bool KbHit(void)
{
    struct termios original;
    tcgetattr(STDIN_FILENO, &original);

    struct termios term;
    memcpy(&term, &original, sizeof(term));

    term.c_lflag &= ~ICANON;
    tcsetattr(STDIN_FILENO, TCSANOW, &term);

    int Ch=0;
    ioctl(STDIN_FILENO, FIONREAD, &Ch);

    tcsetattr(STDIN_FILENO, TCSANOW, &original);
    return(Ch != 0);
}

// -----------------------------------------------------------------------------
// MAIN PROGRAM
// -----------------------------------------------------------------------------

int main(int argc, char **argv)
{
    // Define variables.

    uint32_t DInputs; //Digital inputs
    uint32_t DOutputs=0; //Digital outputs
    int8_t Result; //Function result
    int8_t Kb; //Key pressed

    // -------------------------------------------------------------------------
    // SYSTEM INITIALIZATION
    // -------------------------------------------------------------------------
    // A welcome message is displayed.

    printf("Elsist PTP168A000, CPhrAccess, Library:%s\n", eGetLibVersion());

    // Initialize the library, this must be done before use any function.
    // Function returns 0 if Ok or the error code.

    if ((Result=eLibInit()) != 0) {printf("eLibInit error %d\n", Result); return(false);}

    // Defines wich I2C device has been to used to manage the extension bus,
    // and initializes it. Function returns 0 if Ok or the error code.
    
    Result=ePhrI2cBusInit((char_t*)"/dev/i2c-4");
    switch(Result)
    {
        // Error on bus initializing there's some hardware problem.
        
        case -1: printf("Bus init error: %d\n", Result); return(false);
        
        // System has been restarted by a watchdog intervention.
        // "Result" returns the number of subsequent watchdog interventions.

        default:
        if (Result == 0) printf("System power up\n");
        if (Result != 0) printf("System has been rebooted for %d times\n", Result);
        
        // After a defined number of system reboots by watchdog interventions,
        // a decision must be taken. In this example the program is stopped.
        
        if (Result > 2)
        {
            printf("Too wdog reboot\n");
            eResetWDog(); //Watchdog reset, it reinits the reboot counter
            return(false);
        }
    }
    
    // Set the peripheral bus ready, this activates all the attached modules.
    // Set also the wdog timeout to 2 seconds. Time range (1 to 60000 mS).
    
    while (!ePhrI2cBusReady(true, 2000)); //Set ready signal on peripheral bus

    // -------------------------------------------------------------------------
    // PROGRAM LOOP
    // -------------------------------------------------------------------------
    // This is the main program loop, here all the program tasks has to be done
    // in this example the 8 digital outputs of an extension module are managed.

    while(true)
    {
        // The watchdog control has been set so it must be refreshed. If it's
        // not refreshed in the time set the system is rebooted.
        
        eWDogRefresh(); //Refresh the watchdog circuit

        // Read the digital inputs from the extension module.

        if (!eGetPhrDI(0, DI_MODE::DI_8_LL, &DInputs)) {printf("eGetPhrDi error: %u\n", eGetLastError()); return(1);}
        
        // Copy Di00 input status on Do00 output.
        
        if ((DInputs&eBITPATTERN(0)) == 0) eBITRESET(DOutputs, 0); else eBITSET(DOutputs, 0);

        // Blink the Do01 outputs.

        DOutputs=DOutputs^0x00000002; //Digital outputs

        // Transfer the counter value on the extension module digital outputs.

        if (!eSetPhrDO(0, DO_MODE::DO_8_LL, &DOutputs)) {printf("eSetPhrDO error: %u\n", eGetLastError()); return(1);}

        // Increase the counter value and sleep a while.

        // Check if a keyboard key has been pressed and read the key.

        if (KbHit())
        {
            read(0, &Kb, sizeof(Kb));
            switch (Kb&0xFF)
            {
                // On "s" Sleep command, the program sleeps for a time longer
                // than watchdog setting so the watchdog circuit reboots it.
                // Please remaind that the watchdog circuit is armed so if 
                // it's not reset, the system reboots every 1 minute.
                // To unarmed the watch dog control the eResetWDog() function
                // must be executed. Or the system must be manually rebooted.

                case 's': printf("Sleep for a while\n"); usleep(eMSEC(3000)); break;

                // On "x" Exit command, the program terminates, and the watchdog
                // circuit is unarmed.

                case 'x':
                printf("Exit command\n");
                eResetWDog(); //Watchdog reset, it reinits the reboot counter
                ePhrI2cBusReady(false, 0); //Reset ready signal on peripheral bus
                return(0);
            }
        }

        // Sleep for a while.

        usleep(eMSEC(100)); //Wait 100 mS 
    }
    return(0);
}

// [End of file]

Ti è stato utile questo articolo ?

Ultimo aggiornamento: 11 Dicembre 2019