Cours:DevoirRPI

De troyesGEII
Aller à : navigation, rechercher


Projet QT rpi 2 points

Question.jpg Faire un projet QT vierge (type QWidget) et vérifier que le programme s'exécute correctement sur la carte raspberry Pi (/1)

Question.jpg Ajouter un bouton pour fermer l'application (/1)

Classe lampe 6.5 points

On vous donne les fichiers suivants :

lampe.h

#ifndef LAMPE_H
#define LAMPE_H

#include <QObject>
#include "gpio.h"
using namespace exploringRPi;

class Lampe : public QObject
{
    Q_OBJECT
public:
    Lampe(int nbBroche);

private :
    bool etat;
    GPIO broche;

signals:
    void nouvelEtat(bool etat);
public slots:
    void allumer();
    void eteindre();
    void setValue(bool e);
};

#endif // LAMPE_H

lampe.cpp

#include "lampe.h"

Lampe::Lampe(int nbBroche) : QObject(), broche(nbBroche)
{
    broche.setDirection(OUTPUT);
    setValue(false);
}

void Lampe::allumer()
{
    setValue(true);
}

void Lampe::eteindre()
{
    setValue(false);
}

void Lampe::setValue(bool e)
{
    if (e==true) broche.setValue(HIGH);
            else broche.setValue(LOW);
    etat = e;
    emit nouvelEtat(etat);
}

Question.jpg Remplissez le tableau suivant : (/3)

Nom de la classe (/0.5)
Attributs (/1)
Méthodes/slots (/1)
Signaux (/0.5)
Gpio rpi3.png

Il s'agit maintenant d'utiliser cette classe pour commander une led.

Pour la partie matérielle :

Todo.jpg Brancher une led (avec une résistance en série !) qui s'allume sur niveau logique haut sur le GPIO 21.


Question.jpg Modifier votre programme pour commander cette led de la façon suivante : (/3.5)

  • ajouter 2 boutons (bpAllumer et bpEteindre) sur votre interface graphique (/0.5)
  • ajouter un attribut nommé led de type Lampe dans la classe MainWindow (/1)
  • dans le constructeur de la classe MainWindow
    • indiquer le numéro de GPIO pour l'attribut led (/1)
    • faire les connections signaux/slots nécessaires (/1)

Vous aurez besoin des fichiers pour la classe GPIO :

gpio.h

#ifndef GPIO_H
#define GPIO_H


#include<string>
#include<fstream>
using std::string;
using std::ofstream;

#define GPIO_PATH "/sys/class/gpio/"

namespace exploringRPi {

enum GPIO_DIRECTION{ INPUT, OUTPUT };
enum GPIO_VALUE{ LOW=0, HIGH=1 };
enum GPIO_EDGE{ NONE, RISING, FALLING, BOTH };

class GPIO {
private:
    int number;
    string name, path;
public:
    GPIO(int number);                     // constructor exports pin
    virtual int getNumber() { return number; }

    // General Input and Output Settings
    virtual int  setDirection(GPIO_DIRECTION);
    virtual GPIO_DIRECTION getDirection();
    virtual int  setValue(GPIO_VALUE);
    virtual GPIO_VALUE getValue();


    // Advanced input: detect input edges -- threaded and non-threaded
    virtual int  setEdgeType(GPIO_EDGE);
    virtual GPIO_EDGE getEdgeType();

    virtual ~GPIO();  // destructor unexports the pin
private:
    int write(string path, string filename, string value);
    int write(string path, string filename, int value);
    string read(string path, string filename);
    int exportGPIO();
    int unexportGPIO();
};
} /* namespace exploringRPi */
#endif // GPIO_H

gpio.cpp

#include "gpio.h"

#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include<cstdlib>
#include<cstdio>
#include<fcntl.h>
#include<unistd.h>
#include<sys/epoll.h>
#include<pthread.h>
using namespace std;

namespace exploringRPi {

/**
 *
 * @param number The GPIO number for the RPi
 */
GPIO::GPIO(int number) {
    this->number = number;

    ostringstream s;
    s << "gpio" << number;
    this->name = string(s.str());
    this->path = GPIO_PATH + this->name + "/";
    this->exportGPIO();
    // need to give Linux time to set up the sysfs structure
    usleep(250000); // 250ms delay
}

int GPIO::write(string path, string filename, string value){
   ofstream fs;
   fs.open((path + filename).c_str());
   if (!fs.is_open()){
       perror("GPIO: write failed to open file ");
       return -1;
   }
   fs << value;
   fs.close();
   return 0;
}

string GPIO::read(string path, string filename){
   ifstream fs;
   fs.open((path + filename).c_str());
   if (!fs.is_open()){
       perror("GPIO: read failed to open file ");
    }
   string input;
   getline(fs,input);
   fs.close();
   return input;
}

int GPIO::write(string path, string filename, int value){
   stringstream s;
   s << value;
   return this->write(path,filename,s.str());
}

int GPIO::exportGPIO(){
   return this->write(GPIO_PATH, "export", this->number);
}

int GPIO::unexportGPIO(){
   return this->write(GPIO_PATH, "unexport", this->number);
}

int GPIO::setDirection(GPIO_DIRECTION dir){
   switch(dir){
   case INPUT: return this->write(this->path, "direction", "in");
      break;
   case OUTPUT:return this->write(this->path, "direction", "out");
      break;
   }
   return -1;
}

int GPIO::setValue(GPIO_VALUE value){
   switch(value){
   case HIGH: return this->write(this->path, "value", "1");
      break;
   case LOW: return this->write(this->path, "value", "0");
      break;
   }
   return -1;
}

int GPIO::setEdgeType(GPIO_EDGE value){
   switch(value){
   case NONE: return this->write(this->path, "edge", "none");
      break;
   case RISING: return this->write(this->path, "edge", "rising");
      break;
   case FALLING: return this->write(this->path, "edge", "falling");
      break;
   case BOTH: return this->write(this->path, "edge", "both");
      break;
   }
   return -1;
}

GPIO_VALUE GPIO::getValue(){
    string input = this->read(this->path, "value");
    if (input == "0") return LOW;
    else return HIGH;
}

GPIO_DIRECTION GPIO::getDirection(){
    string input = this->read(this->path, "direction");
    if (input == "in") return INPUT;
    else return OUTPUT;
}

GPIO_EDGE GPIO::getEdgeType(){
    string input = this->read(this->path, "edge");
    if (input == "rising") return RISING;
    else if (input == "falling") return FALLING;
    else if (input == "both") return BOTH;
    else return NONE;
}



GPIO::~GPIO() {
    this->unexportGPIO();
}

} /* namespace exploringRPi */

Ajout de slot 4 points

On souhaite ajouter un slot toggle à la classe Lampe, qui devra modifier l'état de la led.

Question.jpg Faire les modifications suivantes :

  • déclarer le prototype de la méthode toggle dans le header
  • définir la méthode dans le fichier cpp
  • ajouter un bouton dans l'interface graphique
  • connecter ce bouton à la méthode toggle

Classe bouton 5 points

Les fichiers ci-dessous vous permettrons d'utiliser facilement un bouton connecté sur un GPIO.

Todo.jpg Connecter un bouton avec résistance de pull-up (10k) sur la gpio20.

Question.jpg Modifier votre programme ainsi :

  • ajouter un attribut nommé bp, de type Bouton dans la classe MainWindow (/0.5)
  • ajouter le prototype du slot gpioChange() dans la classe MainWindow (/0.5)
  • dans le constructeur de MainWindow :
    • initialiser le bouton bp en précisant la broche (GPIO20) et le type de front observé (front descendant cf gpio.h). (/1)
    • connecter le signal émis par le bouton sur le slot gpioChange (/1)
  • déclarer le slot gpioChange() : doit afficher un message ("appui") sur la console (avec qDebug() par ex). (/1)

Question.jpg Faire en sorte qu'un appui sur le bouton change l'état de la led /1

bouton.h

#ifndef BOUTON_H
#define BOUTON_H

#include <QObject>
#include <QFileSystemWatcher>
#include "gpio.h"
using namespace exploringRPi;

class Bouton : public QObject
{
    Q_OBJECT
public:
    explicit Bouton(int nbBroche,GPIO_EDGE typeFront);
private:
    GPIO broche;
    QFileSystemWatcher fileScanner;
signals:
    void change();
public slots:
    void evenementBroche();
};

#endif // BOUTON_H

bouton.cpp

#include "bouton.h"

Bouton::Bouton(int nbBroche, GPIO_EDGE typeFront) : QObject(), broche(nbBroche)
{
    broche.setDirection(INPUT);
    broche.setEdgeType(typeFront);
    fileScanner.addPath(QString("/sys/class/gpio/gpio%1/value").arg(nbBroche));
    connect(&fileScanner,SIGNAL(fileChanged(QString)),this,SLOT(evenementBroche()));
}

void Bouton::evenementBroche()
{
    emit change();
}

Classe controler 2.5 points

On utilise maintenant 3 leds.

On pourra augmenter ou diminuer le nombre de leds allumées.

On utilisera 2 boutons sur l'écran graphique (+ et -) et un bouton poussoir physique (extinction)

Il s'agit de créer une classe controler qui aura au moins les propriétés suivantes :

  • attributs
    • 3 lampes
    • nbLedsAllumees
  • méthodes/slots
    • augmenter
    • diminuer
    • eteindre

Question.jpg Vous devez répondre au cahier des charges.

Rque : Vous pourrez à minimum montrer que vous arrivez à allumer/eteindre plusieurs leds.