Skyduino:~#
Articles
arduino, programmation, projet

[Arduino] Arduinoscillo – Mini oscilloscope

Le but :
Faire un mini oscilloscope portable sur une base arduino et un écran tactile.

Description :
Ce projet est un des plus complexe que je doit réaliser, le but est pourtant simple: afficher une courbe représentative d’un signal analogique.
En théorie c’est simple, en pratique c’est très dur, l’écran lcd (un MI0283QT-2) possède un temps de refresh désastreux et pour compensé il faut géré un algo de refresh partiel, un travail de fou.

L’interface tactile :
Le GUI se présente sous la forme d’un canvas à gauche ou se trouve la courbe, d’une colonne servant de menu sur la droite, d’un titre sur le haut, du barre de statut sur le bas ainsi que d’une colonne annexe contenant les icônes des sous menu entre le canvas et le menu.

Hardware :
Pour le moment aucun, j’utilise juste uniquement les entrées analogique de l’ATmega.

Hardware Plug & Play Easy !

GUI version alpha-1 en vert les slot pour les icones, petit bug du texte du menu, canvas sans ligne horinzontal pour le moment.

Comme vous pouvez le voir seul les lignes verticales sont pour le moment dessinée il me reste encore beaucoup de travail !

Pour le moment seul la partie GUI est achevée, toute la partie capture et traitement du signal reste à faire.

Pour ceux qui serait intéressée voici la partie GUI :

arduinoscillo.pde (Initialisation et fonction principal du programme)

#include <MI0283QT2.h>
#include <ADS7846.h>
#include <SD.h>
#include <avr/pgmspace.h>
prog_char noEntry[] PROGMEM = "  ";

File myFile;
MI0283QT2 lcd;
ADS7846 tp;

void setup()
{
  /* STARTING NOW */
  lcd.init(2);
  pinMode(10, OUTPUT);
  lcd.clear(COLOR_BLACK);
  appendTextLcd(PSTR("[>] Booting up"));

  /* MOUNTING SD CARD */
  appendTextLcd(PSTR("[>] Mounting SD card"));
  if (!SD.begin(4)) {
    appendTextLcd(PSTR("[!] Mounting failed"));
    while(1);
  }
  appendTextLcd(PSTR("[-] Mounting done"));

  /* INITIALIZE TOUCH SCREEN */
  appendTextLcd(PSTR("[>] Init touch screen"));
  tp.init();
  tp.service();
  appendTextLcd(PSTR("[-] Init touch done"));

  /* CHECK FOR EEPROM CALIBRATION OR BYPASS MODE*/
  appendTextLcd(PSTR("[>] Calibration check"));
  if(tp.getPressure() > 5){
    appendTextLcd(PSTR("[>] Bypass EEprom"));
    tp_calibration(0);
  }
  else{
    appendTextLcd(PSTR("[>] Check EEprom"));
    tp_calibration(1);
  }
  appendTextLcd(PSTR("[-] Calibration done"));

  /* FINAL STEP - LOADING GUI */
  appendTextLcd(PSTR("Loading GUI ..."));
  drawAll();
  
  printSlot1(PSTR("CHANNEL A"),PSTR("DISABLE"),noEntry);
  printSlot2(PSTR("CHANNEL B"),PSTR("DISABLE"),noEntry);
  
  /* Wake Up delay */
  delay(1000);
}

boolean channelA = false;
boolean channelB = false;

void loop()
{
  /* CHECK FOR USER INPUT */
  tp.service();
  if(tp.getPressure() > 5)
    pollSlot(tp.getX(),tp.getY());

}

draw.pde (fonction d’affichage sur le lcd)

#include "point.h" // coord point map


/* DRAWING FUNCTION */

/* Draw all screen (for first refresh) */
void drawAll(){
  drawTitle();
  drawLine();
  drawStatus();
  drawCanvas();
  drawInfo();
  drawMenu();
  showVersion();
  updateStatusPGM(PSTR("Loading GUI done !"));
}

/* draw title graphic */
void drawTitle(){
  lcd.setArea(XY_1_TITLE, XY_2_TITLE);
  lcd.drawStart();
  for(word k=0;k<5120 /*320x16*/;k++)
    lcd.draw(COLOR_BLUE);
  lcd.drawStop();

  lcd.drawTextPGM(XY_T1_TITLE, PSTR("ArduinOscillo by SkyWodd"), 1, COLOR_RED, COLOR_BLUE);
}

/* Print version in title bar */
inline void showVersion(){
  lcd.drawTextPGM(XY_T_TITLE, PSTR("Alpha v1"), 1, COLOR_BLACK, COLOR_BLUE);
}

/* Draw empty canvas with row & col */
void drawCanvas(){
  lcd.fillRect(XY_1_CANVAS, XY_2_CANVAS, COLOR_BLACK);
  lcd.drawRect(XY_1_CANVAS, XY_2_CANVAS, COLOR_GRAY);
  for(int i=0;i<220;i++)
    redrawCanvas(i);
}

/* redraw Canvas for specified col */
void redrawCanvas(int x){
  switch(x){
  case 0:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 22:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 44:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 66:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 88:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 110:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 132:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 154:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 176:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 198:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  case 220:
    lcd.drawLine(x,20,x,219,COLOR_GRAY);
    break;
  }
}

/* Draw Info Panel with icon */
void drawInfo(){
  lcd.fillRect(XY_1_INFO, XY_2_INFO, COLOR_BLUE);
  // TODO fill with graphics
  lcd.fillRect(XY_1_INFO_1, XY_2_INFO_1, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_2, XY_2_INFO_2, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_3, XY_2_INFO_3, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_4, XY_2_INFO_4, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_5, XY_2_INFO_5, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_6, XY_2_INFO_6, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_7, XY_2_INFO_7, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_8, XY_2_INFO_8, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_9, XY_2_INFO_9, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_10, XY_2_INFO_10, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_11, XY_2_INFO_11, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_12, XY_2_INFO_12, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_13, XY_2_INFO_13, COLOR_GREEN);
  lcd.fillRect(XY_1_INFO_14, XY_2_INFO_14, COLOR_GREEN);
}

/* Draw Menu with power-up option */
void drawMenu(){
  lcd.fillRect(XY_1_MENU, XY_2_MENU, COLOR_BLUE);
  lcd.fillRect(XY_1_MENU_1, XY_2_MENU_1, COLOR_GRAY);
  lcd.fillRect(XY_1_MENU_2, XY_2_MENU_2, COLOR_GRAY);
  lcd.fillRect(XY_1_MENU_3, XY_2_MENU_3, COLOR_GRAY);
  lcd.fillRect(XY_1_MENU_4, XY_2_MENU_4, COLOR_GRAY);
  lcd.fillRect(XY_1_MENU_5, XY_2_MENU_5, COLOR_GRAY);
}

/* Draw status bar */
void drawStatus(){
  lcd.fillRect(XY_1_STATUS, XY_2_STATUS, COLOR_BLUE);
}

/* Update status bar */
inline void updateStatus(char* msg){
  drawStatus();
  lcd.drawText(XY_T_STATUS, msg, 1, COLOR_WHITE, COLOR_BLUE);
}
inline void updateStatusPGM(PGM_P msg){
  drawStatus();
  lcd.drawTextPGM(XY_T_STATUS, msg, 1, COLOR_WHITE, COLOR_BLUE);
}

/* Draw separator line horizontal first (vertical overlay) */
void drawLine(){
  lcd.drawLine(XY_1_LINE_1A, XY_2_LINE_1A, COLOR_GRAY);
  lcd.drawLine(XY_1_LINE_1B, XY_2_LINE_1B, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_1C, XY_2_LINE_1C, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_1D, XY_2_LINE_1D, COLOR_GRAY);

  lcd.drawLine(XY_1_LINE_2A, XY_2_LINE_2A, COLOR_GRAY);
  lcd.drawLine(XY_1_LINE_2B, XY_2_LINE_2B, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_2C, XY_2_LINE_2C, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_2D, XY_2_LINE_2D, COLOR_GRAY);

  lcd.drawLine(XY_1_LINE_3A, XY_2_LINE_3A, COLOR_GRAY);
  lcd.drawLine(XY_1_LINE_3B, XY_2_LINE_3B, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_3C, XY_2_LINE_3C, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_3D, XY_2_LINE_3D, COLOR_GRAY);

  lcd.drawLine(XY_1_LINE_4A, XY_2_LINE_4A, COLOR_GRAY);
  lcd.drawLine(XY_1_LINE_4B, XY_2_LINE_4B, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_4C, XY_2_LINE_4C, COLOR_BLACK);
  lcd.drawLine(XY_1_LINE_4D, XY_2_LINE_4D, COLOR_GRAY);
}

/* Print progmem text in Console-Style format */
int index = 0;
void appendTextLcd(PGM_P text){
  if(index >= 240)
    index =0;
  lcd.drawTextPGM(5, index + 5, text, 1, COLOR_WHITE, COLOR_BLACK);
  index += 15;
}

info.pde (Gestion des slot de menu et de la status-bar)

/* INFO TRIGGER HANDLING FUNCTION*/

void triggerInfoSlot1(){
  // TODO
  updateStatus("Info Slot 1");
}

void triggerInfoSlot2(){
  // TODO
  updateStatus("Info Slot 2");
}

void triggerInfoSlot3(){
  // TODO
  updateStatus("Info Slot 3");
}

void triggerInfoSlot4(){
  // TODO
  updateStatus("Info Slot 4");
}

void triggerInfoSlot5(){
  // TODO
  updateStatus("Info Slot 5");
}

void triggerInfoSlot6(){
  // TODO
  updateStatus("Info Slot 6");
}

void triggerInfoSlot7(){
  // TODO
  updateStatus("Info Slot 7");
}

void triggerInfoSlot8(){
  // TODO
  updateStatus("Info Slot 8");
}

void triggerInfoSlot9(){
  // TODO
  updateStatus("Info Slot 9");
}

void triggerInfoSlot10(){
  // TODO
  updateStatus("Info Slot 10");
}

void triggerInfoSlot11(){
  // TODO
  updateStatus("Info Slot 11");
}

void triggerInfoSlot12(){
  // TODO
  updateStatus("Info Slot 12");
}

void triggerInfoSlot13(){
  // TODO
  updateStatus("Info Slot 13");
}

void triggerInfoSlot14(){
  // TODO
  updateStatus("Info Slot 14");
}

menu.pde (Gestion du menu)

#include "point.h" // coord point map

/* MENU TRIGGER HANDLING FUNCTION*/

void triggerMenuSlot1(){
  // TODO
  updateStatus("Menu Slot 1");
}

void triggerMenuSlot2(){
  // TODO
  updateStatus("Menu Slot 2");
}

void triggerMenuSlot3(){
  // TODO
  updateStatus("Menu Slot 3");
}

void triggerMenuSlot4(){
  // TODO
  updateStatus("Menu Slot 4");
}

void triggerMenuSlot5(){
  // TODO
  updateStatus("Menu Slot 5");
}

void printSlot1(PGM_P line1, PGM_P line2, PGM_P line3){
  lcd.drawTextPGM(XY_T1_MENU_1,line1,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T2_MENU_1,line2,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T3_MENU_1,line3,1,COLOR_BLACK,COLOR_GRAY);
}

void printSlot2(PGM_P line1, PGM_P line2, PGM_P line3){
  lcd.drawTextPGM(XY_T1_MENU_2,line1,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T2_MENU_2,line2,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T3_MENU_2,line3,1,COLOR_BLACK,COLOR_GRAY);
}

void printSlot3(PGM_P line1, PGM_P line2, PGM_P line3){
  lcd.drawTextPGM(XY_T1_MENU_3,line1,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T2_MENU_3,line2,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T3_MENU_3,line3,1,COLOR_BLACK,COLOR_GRAY);
}

void printSlot4(PGM_P line1, PGM_P line2, PGM_P line3){
  lcd.drawTextPGM(XY_T1_MENU_4,line1,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T2_MENU_4,line2,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T3_MENU_4,line3,1,COLOR_BLACK,COLOR_GRAY);
}

void printSlot5(PGM_P line1, PGM_P line2, PGM_P line3){
  lcd.drawTextPGM(XY_T1_MENU_5,line1,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T2_MENU_5,line2,1,COLOR_BLACK,COLOR_GRAY);
  lcd.drawTextPGM(XY_T3_MENU_5,line3,1,COLOR_BLACK,COLOR_GRAY);
}

touch.pde (Gestion du tactile)

#include "point.h" // coord point map

/* TOUCH-SCREN FUNCTION */

#define TP_EEPROMADDR (0x00) //eeprom address for calibration data

void tp_calibration(uint8_t check_eeprom)
{
  int i;
  CAL_POINT lcd_points[3] = {
    {
      CAL_POINT_X1,CAL_POINT_Y1                            }
    ,
    {
      CAL_POINT_X2,CAL_POINT_Y2                            }
    ,
    {
      CAL_POINT_X3,CAL_POINT_Y3                            }
  };
  CAL_POINT tp_points[3], *p;

  if(tp.readCalibration(TP_EEPROMADDR) && check_eeprom)
  {
    return;
  }

  lcd.clear(COLOR_WHITE);
  lcd.drawText((lcd.getWidth()/2)-50, (lcd.getHeight()/2)-10, "Calibration", 1, COLOR_BLACK, COLOR_WHITE);
  while(tp.getPressure() > 5){ 
    tp.service(); 
  };

  i = 0;
  do
  {
    lcd.drawCircle(lcd_points[i].x, lcd_points[i].y, 1, RGB(0,0,0));
    lcd.drawCircle(lcd_points[i].x, lcd_points[i].y, 4, RGB(0,0,0));
    lcd.drawCircle(lcd_points[i].x, lcd_points[i].y, 8, RGB(255,0,0));

    tp.service();

    if(tp.getPressure() > 5)
    {
      tp_points[i].x = tp.getXraw();
      tp_points[i].y = tp.getYraw();
      i++;
      lcd.clear(COLOR_WHITE);
      delay(100);
    }
  }
  while(i<3);

  tp.setCalibration(lcd_points, tp_points);
  tp.writeCalibration(TP_EEPROMADDR);
}

void pollSlot(int x, int y){
  if(isBoxed(x,y,XY_1_MENU_1,XY_2_MENU_1))
    triggerMenuSlot1();

  if(isBoxed(x,y,XY_1_MENU_2,XY_2_MENU_2))
    triggerMenuSlot2();

  if(isBoxed(x,y,XY_1_MENU_3,XY_2_MENU_3))
    triggerMenuSlot3();

  if(isBoxed(x,y,XY_1_MENU_4,XY_2_MENU_4))
    triggerMenuSlot4();

  if(isBoxed(x,y,XY_1_MENU_5,XY_2_MENU_5))
    triggerMenuSlot5();

  if(isBoxed(x,y,XY_1_INFO_1,XY_2_INFO_1))
    triggerInfoSlot1();

  if(isBoxed(x,y,XY_1_INFO_2,XY_2_INFO_2))
    triggerInfoSlot2();

  if(isBoxed(x,y,XY_1_INFO_3,XY_2_INFO_3))
    triggerInfoSlot3();

  if(isBoxed(x,y,XY_1_INFO_4,XY_2_INFO_4))
    triggerInfoSlot4();

  if(isBoxed(x,y,XY_1_INFO_5,XY_2_INFO_5))
    triggerInfoSlot5();

  if(isBoxed(x,y,XY_1_INFO_6,XY_2_INFO_6))
    triggerInfoSlot6();

  if(isBoxed(x,y,XY_1_INFO_7,XY_2_INFO_7))
    triggerInfoSlot7();

  if(isBoxed(x,y,XY_1_INFO_8,XY_2_INFO_8))
    triggerInfoSlot8();

  if(isBoxed(x,y,XY_1_INFO_9,XY_2_INFO_9))
    triggerInfoSlot9();

  if(isBoxed(x,y,XY_1_INFO_10,XY_2_INFO_10))
    triggerInfoSlot10();

  if(isBoxed(x,y,XY_1_INFO_11,XY_2_INFO_11))
    triggerInfoSlot11();

  if(isBoxed(x,y,XY_1_INFO_12,XY_2_INFO_12))
    triggerInfoSlot12();
    
   if(isBoxed(x,y,XY_1_INFO_13,XY_2_INFO_13))
    triggerInfoSlot13();
    
  if(isBoxed(x,y,XY_1_INFO_14,XY_2_INFO_14))
    triggerInfoSlot14();
}

boolean isBoxed(int x, int y, int x1, int y1, int x2, int y2){
  if((x>=x1) && (x<=x2) && (y>=y1) && (y<=y2))
    return true;
  else 
    return false;
}

point.h (Fichier contenant les emplacements des coordonnées des graphismes sur l’écran)

#ifndef POINT_H
#define POINT_H

/* TITLE DEFINITION - TITLE & VERSION TEXT - 320x16 px */
#define XY_1_TITLE 0,0
#define XY_2_TITLE 319,15
#define XY_T_TITLE 240,3 // 10 char max
#define XY_T1_TITLE 2,3 // arduinoscillo
#define XY_3_TITLE 116,15


/* STATUS DEFINITION - STATUS TEXT - 240x16 px */
#define XY_1_STATUS 0,224
#define XY_2_STATUS 239,239
#define XY_T_STATUS 2,226 // 27 char max


/* CANVAS DEFINITION - SIGNAL DRAWABLE REGION - 220x200 px */
#define XY_1_CANVAS 0,20
#define XY_2_CANVAS 219,219


/* MENU DEFINITION - MENU & CASE REGION - x px */
#define XY_1_MENU 244,20
#define XY_2_MENU 319,239

#define XY_1_MENU_1 247,24
#define XY_2_MENU_1 317,64
#define XY_T1_MENU_1 249,25
#define XY_T2_MENU_1 249,38
#define XY_T3_MENU_1 249,51

#define XY_1_MENU_2 247,67
#define XY_2_MENU_2 317,107
#define XY_T1_MENU_2 249,48
#define XY_T2_MENU_2 249,61
#define XY_T3_MENU_2 249,74

#define XY_1_MENU_3 247,110
#define XY_2_MENU_3 317,150
#define XY_T1_MENU_3 249,91
#define XY_T2_MENU_3 249,104
#define XY_T3_MENU_3 249,117

#define XY_1_MENU_4 247,153
#define XY_2_MENU_4 317,193
#define XY_T1_MENU_4 249,134
#define XY_T2_MENU_4 249,147
#define XY_T3_MENU_4 249,160

#define XY_1_MENU_5 247,196
#define XY_2_MENU_5 317,236
#define XY_T1_MENU_5 249,176
#define XY_T2_MENU_5 249,189
#define XY_T3_MENU_5 249,202

/* INFO DEFINITION - INFO REGION - 16x200 px */
/* INFO ZONE MUST BE USED TO SHOW LITTLE 12x12 ICON (MAX 13) */
#define XY_1_INFO 224,20
#define XY_2_INFO 239,219

#define XY_1_INFO_1 226,23
#define XY_2_INFO_1 238,35

#define XY_1_INFO_2 226,37
#define XY_2_INFO_2 238,49

#define XY_1_INFO_3 226,51
#define XY_2_INFO_3 238,63

#define XY_1_INFO_4 226,65
#define XY_2_INFO_4 238,77

#define XY_1_INFO_5 226,79
#define XY_2_INFO_5 238,91

#define XY_1_INFO_6 226,93
#define XY_2_INFO_6 238,105

#define XY_1_INFO_7 226,107
#define XY_2_INFO_7 238,119

#define XY_1_INFO_8 226,121
#define XY_2_INFO_8 238,133

#define XY_1_INFO_9 226,135
#define XY_2_INFO_9 238,147

#define XY_1_INFO_10 226,149
#define XY_2_INFO_10 238,161

#define XY_1_INFO_11 226,163
#define XY_2_INFO_11 238,175

#define XY_1_INFO_12 226,177
#define XY_2_INFO_12 238,189

#define XY_1_INFO_13 226,191
#define XY_2_INFO_13 238,203

#define XY_1_INFO_14 226,205
#define XY_2_INFO_14 238,217

/* LINE DEFINITION - SEPARATOR LINE (4 LINE = 1 SEPARATOR)*/
//title underline - horizontal
#define XY_1_LINE_1A 0,16
#define XY_2_LINE_1A 319,16
#define XY_1_LINE_1B 0,17
#define XY_2_LINE_1B 319,17
#define XY_1_LINE_1C 0,18
#define XY_2_LINE_1C 319,18
#define XY_1_LINE_1D 0,19
#define XY_2_LINE_1D 319,19

//status upline - horizontal
#define XY_1_LINE_2A 0,220
#define XY_2_LINE_2A 239,220
#define XY_1_LINE_2B 0,221
#define XY_2_LINE_2B 239,221
#define XY_1_LINE_2C 0,222
#define XY_2_LINE_2C 239,222
#define XY_1_LINE_2D 0,223
#define XY_2_LINE_2D 239,223

//canvas leftline - vertical
#define XY_1_LINE_3A 220,19
#define XY_2_LINE_3A 220,220
#define XY_1_LINE_3B 221,19
#define XY_2_LINE_3B 221,220
#define XY_1_LINE_3C 222,19
#define XY_2_LINE_3C 222,220
#define XY_1_LINE_3D 223,19
#define XY_2_LINE_3D 223,220

//menu rigthline - vertical
#define XY_1_LINE_4A 240,19
#define XY_2_LINE_4A 240,239
#define XY_1_LINE_4B 241,19
#define XY_2_LINE_4B 241,239
#define XY_1_LINE_4C 242,19
#define XY_2_LINE_4C 242,239
#define XY_1_LINE_4D 243,19
#define XY_2_LINE_4D 243,239

#endif
Publicités

Discussion

Une réflexion sur “[Arduino] Arduinoscillo – Mini oscilloscope

  1. Hello,
    there is another MI0283QT2 based Arduino oscilloscope project on
    http://code.google.com/p/simple-touch-screen-dso-software/
    Best regards
    Armin

    Publié par Armin | 16 mars 2013, 10 h 29 min

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.