Et si un tachymètre de bateau affichait l’utilisation de mon processeur ?

alternate text

J’aime bien me rendre au marché aux puces, on tombe toujours sur des objets loufoques. L’autre jour j’ai aperçu ce tachymètre avec son grand cadran étalonné en noeuds. Je l’ai acheté au vendeur tout content de se “débarrasser des objets lourds”.

Il y a deux affichages sur l’écran, la vitesse du bateau en noeuds (avec une graduation phosphorescente) et la distance totale parcourue en milles marins. Sous le nom du modèle Electralog il y a deux sélecteurs rotatifs. On, Off et Battery (il doit indiquer le voltage de la batterie pour dépanner). A droite R1, R2 et R3 changent la graduation et modifie les chiffres. Ici ils vont de 1 à 6, R2 va de 1 à 12 et R3 de 1 à 24.

Bon, c’est bête, j’ai pas de bateau à moteur chez moi alors j’ai très vite décidé de tenter d’en faire une utilisation bien geek : afficher le pourcentage de charge du processeur de mon ordinateur portable. Il faut donc que je puisse commander l’aiguille depuis mon PC. L’outil tout désigné pour cela est mon microcontrôleur Arduino Uno.

Ces tachymètres alimentés par le moteur ou la batterie fonctionnent sous 12 ou 24 V DC. A l’arrière il y a une prise dont je n’ai trouvé aucune documentation sur internet. J’ai donc ouvert le boîtier, démonté le circuit de contrôle, sorti de galvanomètre et son aiguille et j’ai branché le galvanomètre directement sur Arduino pour tester quelles valeurs je peux y mettre. J’ai déterminé les bornes inférieures, supérieures ainsi que les incréments pour avoir un positionnement convenable de l’aiguille. Ensuite j’ai remonté le tout en branchant le galvanomètre directement sur la prise arrière.

J’ai attaqué le programme sur le PC qui me calcule la charge du processeur et l’envoie au microcontrôleur. Il s’avère qu’il n’y a pas d’API Windows qui renvoie a charge du processeur aisément. Le gestionnaire des tâches utilise une API non documentée mais heureusement il y a un autre moyen. C’est un bidouillage à l’aide de la fonction GetSystemTimes(). Il semblerait que cela ne donne pas la bonne information sur les processeurs avec de multiples coeurs mais de ce que j’ai observé c’est assez juste.

Le code de mon petit programme :

#define _WIN32_WINNT 0x0601
#include
#include
#include "TKTime.h"
#include "SerialClass.h"

using namespace std;

int main()
{
    TKTime last_idleTime;
    TKTime last_kernelTime;
    TKTime last_userTime;

    TKTime idleTime;
    TKTime kernelTime;
    TKTime userTime;

    Serial arduino((char *)"COM6");
    Sleep(500);
    if(!arduino.IsConnected())
    {
         cout << "Pas pu se connecter à Arduino\n";
         return 0;
    }

    while(true)
    {
        //inspiré de http://www.codeproject.com/Articles/9113/Get-CPU-Usage-with-GetSystemTimes
        GetSystemTimes( (LPFILETIME) &last_idleTime, (LPFILETIME) &last_kernelTime, (LPFILETIME) &last_userTime );
        Sleep(500);
        GetSystemTimes(  (LPFILETIME)&idleTime,  (LPFILETIME)&kernelTime, (LPFILETIME)&userTime );

        TKTime usr = userTime - last_userTime;
        TKTime ker = kernelTime - last_kernelTime;
        TKTime idl = idleTime - last_idleTime;

        TKTime sys = ker + usr;

        //calcul de la charge parmi 17 valeurs discrètes
        int cpu = int( (sys - idl) *17 / sys );

        //envoi de lettres par le serial (A,B,C...) selon la charge
        char* buffer = new char('A'+cpu);
        arduino.WriteData(buffer,1);
    }

    return 0;
}

Le code sur mon Arduino :

int pin = 3; //numéro de la prise du galvanomètre
int sup = 17; //borne supérieure

void setup() {
  pinMode(pin,OUTPUT);
  Serial.begin(9600);
}

void loop(){
  if(Serial.available() > 0) //si quelquechose nous est
                                //envoyé par USB
  {
    charge = Serial.read(); //on lit la valeur
    charge -= 65;
    if((charge >= 0) && (charge < = sup))
      analogWrite(pin,charge); //on met à jour la valeur
    Serial.flush();
  }
  delay(100);
}