La piattaforma hardware e software Arduino: parte IV
Corso di autoapprendimento
Tempo previsto: 3 – 4 ore
Prof. Angelo Monfroglio
In questa quarta parte parleremo della programmazione di Arduino nel linguaggio Processing, basato su
Java. Ma prima di tutto, dell’interfacciamento con i display LCD.
Generalità sul display LCD (Hitachi con controller HD44780)
E’ fatto apposta per essere usato con un micro controller e costa circa 10 euro. Può visualizzare i normali
caratteri alfanumerici, lettere greche, segni di interpunzione, simboli matematici e caratteri creati
dall’utente, attraverso 3 memorie di cui dispone:
-DDRAM (RAM per i dati)
-CGRAM (RAM per generare caratteri personalizzati)
-CGROM (ROM che contiene il generatore di caratteri interno).
Il messaggio può essere spostato automaticamente a destra e sinistra, si può controllare la forma del
cursore, e, come opzione, è disponibile la retroilluminazione. I piedini sono14, più 2 per la
retroilluminazione a LED.
Funzione
Pin
Nome
Valore
Descrizione
Massa
1
VSS
-
0V
Alimentazione
2
VDD
-
+5V
Contrasto
regolabile
3
VEE
-
Da 0 a VDD
Controllo
4
RS
0o1
0 = comando, 1
dato (pin D0 – D7)
Controllo
5
R/W
0o1
0 scrive, 1 legge
Controllo
6
E
0 o 1 o fronte di
discesa
0 accesso
disabilitato, 1
operativo, fronte =
trasferimento a
LCD
Dato o comando
Da 7 a 14
D0..D7
0o1
Dato o comando
Lo schermo visualizza 2 righe di 16 caratteri con matrice di 5x8 pixel (oppure 5x11). E’ anche possibile
regolare il contrasto: solitamente va regolato al massimo.
La memoria DDRAM è usata per memorizzare i caratteri da visualizzare: 80. Di questi 32 sono visibili
direttamente sul display. Si può configurare la DDRAM in modo che avvenga uno scorrimento automatico a
destra e deve essere fissato il primo indirizzo, ad esempio 00h. Ecco la mappa.
00h
27h
40h
4F
67h
Non
vis.
Visibile
La memoria CGROM, non volatile, contiene il set di base dei caratteri visualizzabili, sotto forma di matrici di
puntini (nel nostro caso 5 x 8). Gli indirizzi corrispondono in pratica ai caratteri ASCII. Occorre controllare
l’indirizzo effettivo di ogni simbolo sulla mappa.
Oltre ai simboli standard, l’utente può crearne di propri con la memoria CGRAM di 64 bytes. La matrice di
punti è 5 x 8 che significa 8 righe di 5 colonne:
*
*
*
* significa acceso
Gli indirizzi vanno da 00 a 3F e ovviamente ciascuna locazione usa solo 5 bit degli 8 perché ogni riga ha 5
colonne.
00
…
3K.
Il modulo LCD può essere interfacciato con il microcontrollore usando 8 bit di dati o 4 per volta. Il vantaggio
del primo modo è la facilità di gestione e la velocità, del secondo modo il risparmio di piedini usati per le
porte del microcontrollore. Se si usa un PIC da 28 piedini quest’ultima soluzione può essere preferibile. Si
può anche risparmiare un piedino mettendo a massa R/W e rinunciando a leggere da LCD, ma è
sconsigliabile. Ogni comando dura circa 2 milli secondi per essere eseguito. Quando il circuito è alimentato
LCD è azzerato., dopo 15 milli secondi, e posto nella condizione di default:
DL = 1
comunicazione a 8 bit
N=0
il dato su una linea
F=0
il formato della griglia è 5 x 8
D=0
display off
U=0
cursor off
B=0
lampeggio off
I/D = 0
gli indirizzi sono incrementati ogni volta automaticamente di 1
S=0
display shift off.
I comandi
Il valore sui pin D0-D7 può essere un comando o un dato. Se RS = 0 viene considerato un comando.
Comando RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
Tempo
Clear
0
0
0
0
0
0
0
0
0
1
1.64
mS
Home
0
0
0
0
0
0
0
0
1
X
1.64
Mode
0
0
0
0
0
0
0
1
I/D
S
40
Display
ON/OFF
0
0
0
0
0
0
1
D
U
B
40
Shift
0
0
0
0
0
1
D/C
R/L
X
X
40
Function
0
0
0
0
1
DL
N
F
X
X
40
Indirizzo
CGRAM
0
0
0
1
Addr
Addr
Addr
Addr
Addr
Addr
40
Indirizzo
DDRAM
0
0
1
ADDr
Addr
Addr
Addr
Addr
Addr
Addr
40
Legge
0
1
BF
Addr
Addr
Addr
Addr
Addr
Addr
Addr
40
flag busy
Scrive in 1
CGRAM o
in
DDRAM
0
D7
D6
D5
D4
D3
D2
D1
D0
40
Legge
1
D7
D6
D5
D4
D3
D2
D1
D0
40
1
Con i significati:
I/D = 1 incremento di 1, = 0 decremento
S = 1 shift del display on, 0 off
D = 1 display on, 0 off
U = 1 cursor on, 0 cursor off
B = 1 lampeggio, 0 non lampeggio
R/L = 1 sposta a destra, 0 a sinistra
DL = 1 interfaccia a 8 bit, 0 a 4 bit
N = 1 display su 2 linee, 0 su una linea
F = 1 matrice dei caratteri 5 x 10, = 0 5 x 7
D/C = 1 spostamento sul display, = 0 spostamento del cursore.
Se siete spaventati da tutti questi comandi, buone notizie: con Arduino è tutto più facile.
Il seguente esempio visualizza un messaggio sul display LCD e il tempo in secondi dall’ultimo reset
della scheda Arduino. Nella prima parte del nostro corso abbiamo detto che con Arduino non ha
senso scrivere Hello sul video come primo esempio. Ha senso invece farlo su un display esterno
LCD, anzi è molto istruttivo.
LiquidCrystal Library semplifica il commando del display. Non è necessario imparare le
istruzioni a basso livello. Il modulo LCD Hitachi si può controllore in due modi: con 4 o 8 bit. Il
modo a 4 bit richiede 7 piedini di Arduino; il modo a 8 bit 11. Il primo modo è sufficiente nella
maggior parte dei casi. L’esempio che segue riguarda il modo a 4 bit e la visualizzazione su 2 linnee
ognuna con 16 caratteri.
H a r d w a r e r i c h i es t o
Arduino Board
LCD Screen (compatibile con Hitachi HD44780 driver)
10k Potenziometro
breadboard
cavetti
C i r cu i t o
Collegare così il display ad Arduino:
LCD RS pin al digital pin 12
LCD Enable pin al digital pin 11
LCD D4 pin al digital pin 5
LCD D5 pin al digital pin 4
LCD D6 pin al digital pin 3
LCD D7 pin al digital pin 2
Inoltre, collegare il potenziometro da 10K pot a +5V e GND col il wiper (output) a LCD VO
pin (pin3).
Codice
/*
LiquidCrystal Library - Hello World
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
This sketch prints "Hello World!" to the LCD
and shows the time.
*
*
*
*
The circuit:
LCD RS pin to digital pin
LCD Enable pin to digital
LCD D4 pin to digital pin
LCD D5 pin to digital pin
12
pin 11
5
4
*
*
*
*
*
*
LCD D6 pin to digital pin 3
LCD D7 pin to digital pin 2
LCD R/W pin to ground
10K resistor:
ends to +5V and ground
wiper to LCD VO pin (pin 3)
Library originally added 18 Apr 2008
by David A. Mellis
library modified 5 Jul 2009
by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009
by Tom Igoe
modified 22 Nov 2010
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/LiquidCrystal
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with
0):
lcd.setCursor(0, 1);
// print the number of seconds since reset:
lcd.print(millis()/1000);
}
Vedi anche:
lcd.begin()
lcd.print()
lcd.setCursor()
Liquid Crystal Library
Blink: control of the block-style cursor.
Cursor: control of the underscore-style cursor.
Display: quickly blank the display without losing what's on it.
TextDirection: control which way text flows from the cursor.
Scroll: scroll text left and right.
Serial input: accepts serial input, displays it.
SetCursor: set the cursor position.
Autoscroll: shift text right
Display grafico LCD (Arduino shield)
Display grafico LCD per Arduino
Un programma esemplificativo
#ifndef LCD4884_h
#define LCD4884_h
#ifdef PD1
#define LCD_RST PD6
#define SPI_CS PD5
#define SPI_MOSI PD3
#define SPI_SCK PD2
#define LCD_DC PD4
#define LCD_BL PD7
#else
#define LCD_RST PORTD6
#define SPI_CS PORTD5
#define SPI_MOSI PORTD3
#define SPI_SCK PORTD2
#define LCD_DC PORTD4
#define LCD_BL PORTD7
#endif
//display mode -- normal / highlight
#define MENU_NORMAL
0
#define MENU_HIGHLIGHT 1
class LCD4884
{
public:
LCD4884();
void LCD_init(void);
void LCD_backlight(unsigned char dat);
void LCD_write_byte(unsigned char dat, unsigned char dat_type);
void LCD_draw_bmp_pixel(unsigned char X,unsigned char Y,unsigned char *map,unsigned char
Pix_x,unsigned char Pix_y);
void LCD_write_string(unsigned char X,unsigned char Y,char *s, char mode);
void LCD_write_chinese(unsigned char X, unsigned char Y,unsigned char *c,unsigned char
ch_with,unsigned char num,unsigned char line,unsigned char row);
void LCD_write_string_big ( unsigned char X,unsigned char Y, char *string, char mode );
void LCD_write_char_big (unsigned char X,unsigned char Y, unsigned char ch, char mode);
void LCD_write_char(unsigned char c, char mode);
void LCD_set_XY(unsigned char X, unsigned char Y);
void LCD_clear(void);
};
extern LCD4884 lcd;
#endif //#include "LCD4884.h"
#include "font_6x8.h"
#include "font_big.h"
extern "C"
{
#include <avr/pgmspace.h>
#include <avr/io.h>
#include "WConstants.h"
}
LCD4884::LCD4884()
{};
LCD4884 lcd = LCD4884();
void LCD4884::LCD_backlight(unsigned char dat)
{
if(dat==1)PORTD |= (1<<LCD_BL); // turn on backlight
else PORTD &= ~(1<<LCD_BL);
}
void LCD4884::LCD_init(void)
{
// LCD_RST = 0;
DDRD |=
(1<<SPI_CS)|(1<<LCD_DC)|(1<<LCD_RST)|(1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<LCD_BL);
PORTD &= ~(1<<LCD_RST);
delayMicroseconds(1);
PORTD |= (1<<LCD_RST);
PORTD &= ~(1<<SPI_CS);
delayMicroseconds(1);
PORTD |= (1<<SPI_CS);
delayMicroseconds(1);
PORTD |= (1<<LCD_BL); // turn on backlight
LCD_write_byte(0x21, 0);
LCD_write_byte(0xc0, 0);
LCD_write_byte(0x06, 0);
LCD_write_byte(0x13, 0);
LCD_write_byte(0x20, 0);
LCD_clear();
LCD_write_byte(0x0c, 0);
PORTD &= ~(1<<SPI_CS);
}
void LCD4884::LCD_write_byte(unsigned char dat, unsigned char dat_type)
{
unsigned int i;
PORTD &= ~(1<<SPI_CS);
if (dat_type == 0)
PORTD &= ~(1<<LCD_DC);
else
PORTD |= (1<<LCD_DC);
for(i=0;i<8;i++)
{
if(dat&0x80)
{
PORTD |= (1<<SPI_MOSI); //SDIN = 1;
}
else
{
PORTD &= ~(1<<SPI_MOSI); //SDIN = 0;
}
PORTD &= ~(1<<SPI_SCK); //SCLK = 0;
dat = dat << 1;
PORTD |= (1<<SPI_SCK); //SCLK = 1;
}
PORTD |= (1<<SPI_CS);
}
void LCD4884::LCD_draw_bmp_pixel(unsigned char X,unsigned char Y,unsigned char *map,
unsigned char Pix_x,unsigned char Pix_y)
{
unsigned int i,n;
unsigned char row;
if (Pix_y%8==0) row=Pix_y/8;
else
row=Pix_y/8+1;
for (n=0;n<row;n++)
{
LCD_set_XY(X,Y);
for(i=0; i<Pix_x; i++)
{
LCD_write_byte(map[i+n*Pix_x], 1);
}
Y++;
}
}
void LCD4884::LCD_write_string(unsigned char X,unsigned char Y,char *s, char mode)
{
LCD_set_XY(X,Y);
while (*s)
{
LCD_write_char(*s, mode);
s++;
}
}
void LCD4884::LCD_write_chinese(unsigned char X, unsigned char Y,unsigned char *c,unsigned
char ch_with,unsigned char num,unsigned char line,unsigned char row)
{
unsigned char i,n;
LCD_set_XY(X,Y);
for (i=0;i<num;)
{
for (n=0; n<ch_with*2; n++)
{
if (n==ch_with)
{
if (i==0) LCD_set_XY(X,Y+1);
else
{
LCD_set_XY((X+(ch_with+row)*i),Y+1);
}
}
LCD_write_byte(c[(i*ch_with*2)+n],1);
}
i++;
LCD_set_XY((X+(ch_with+row)*i),Y);
}
}
void LCD4884::LCD_write_string_big ( unsigned char X,unsigned char Y, char *string, char mode
)
{
while ( *string ){
LCD_write_char_big( X, Y, *string , mode );
if(*string++ == '.')
X += 5;
else
X += 12;
}
}
/* write char in big font */
void LCD4884::LCD_write_char_big (unsigned char X,unsigned char Y, unsigned char ch, char
mode)
{
unsigned char i, j;
unsigned char *pFont;
unsigned char ch_dat;
pFont = (unsigned char *) big_number;
if(ch == '.')
ch = 10;
else if (ch == '+')
ch = 11;
else if (ch == '-')
ch = 12;
else
ch = ch & 0x0f;
for(i=0;i<3;i++)
{
LCD_set_XY ( X, Y+i);
for(j=0; j<16; j++){
ch_dat = pgm_read_byte(pFont+ch*48 + i*16 +j);
LCD_write_byte( (mode == MENU_NORMAL)? ch_dat : (ch_dat^0xff), 1);
}
}
}
void LCD4884::LCD_write_char(unsigned char c, char mode)
{
unsigned char line;
unsigned char *pFont;
byte ch;
pFont = (unsigned char *)font6_8;
c -= 32;
for (line=0; line<6; line++){
ch = pgm_read_byte(pFont+c*6+line);
LCD_write_byte( (mode==MENU_NORMAL)? ch: (ch^ 0xff) , 1);
}
}
void LCD4884::LCD_set_XY(unsigned char X, unsigned char Y)
{
LCD_write_byte(0x40 | Y, 0);
LCD_write_byte(0x80 | X, 0);
}
void LCD4884::LCD_clear(void)
{
unsigned int i;
LCD_write_byte(0x0c, 0);
LCD_write_byte(0x80, 0);
for (i=0; i<504; i++)
// column
// row
LCD_write_byte(0, 1);
}// big font
#include <avr/pgmspace.h>
//******* VERY LARGE FONTS **********
//used here for displaying temperature
unsigned char big_number[13][3][16] PROGMEM = {
0,128,192,224,224,96,224,224, //'0'
192,128,0,0,0,0,0,0
,
112,255,255,1,0,0,0,0,
255,255,254,0,0,0,0,0
,
0,15,31,60,56,48,56,56,
31,15,3,0,0,0,0,0
,
0,0,0,0,128,224,224,0,
0,0,0,0,0,0,0,0
,
0,0,3,3,3,255,255,0,
0,0,0,0,0,0,0,0
,
//'1'
0,0,56,56,56,63,63,56,
56,56,0,0,0,0,0,0
,
0,192,192,224,96,96,224,224, //'2'
192,128,0,0,0,0,0,0
,
0,1,0,0,128,192,224,249,
63,31,0,0,0,0,0,0
,
0,60,62,63,63,59,57,56,
56,56,56,0,0,0,0,0
,
0,192,224,224,96,96,224,224, //'3'
192,192,0,0,0,0,0,0
,
0,1,0,0,48,48,56,125,
239,207,0,0,0,0,0,0
,
0,28,56,56,48,48,56,60,
31,15,1,0,0,0,0,0
,
0,0,0,0,0,128,192,224,
224,0,0,0,0,0,0,0
,
//'4'
224,240,248,222,207,199,193,255,
255,192,192,0,0,0,0,0
,
0,0,0,0,0,0,0,63,
63,0,0,0,0,0,0,0
,
0,224,224,224,224,224,224,224,
//'5'
224,224,224,0,0,0,0,0
,
0,63,63,63,56,56,48,112,
240,224,0,0,0,0,0,0
,
0,28,56,56,48,48,56,60,
31,15,1,0,0,0,0,0
,
0,0,128,192,192,224,96,96,
224,224,0,0,0,0,0,0
,
224,254,255,55,57,24,24,56,
240,240,192,0,0,0,0,0
,
0,15,31,28,56,48,48,56,
31,15,7,0,0,0,0,0
,
//'6'
0,224,224,224,224,224,224,224,
//'7'
224,224,224,0,0,0,0,0
,
0,0,0,0,128,224,248,126,
31,7,1,0,0,0,0,0
,
0,0,56,62,31,7,1,0,
0,0,0,0,0,0,0,0
,
0,128,192,224,224,96,96,224,
//'8'
192,192,0,0,0,0,0,0
,
0,207,255,127,56,48,112,112,
255,239,199,0,0,0,0,0
,
3,15,31,60,56,48,48,56,
31,31,15,0,0,0,0,0
,
0,128,192,224,224,96,224,224,
192,128,0,0,0,0,0,0
,
12,63,127,241,224,192,192,225,
255,255,254,0,0,0,0,0
,
0,0,56,48,48,56,56,30,
//'9'
15,7,0,0,0,0,0,0
,
0,0,0,0,0,0,0,0,
//'.'
0,0,0,0,0,0,0,0
,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
,
60,60,60,0,0,0,0,0,
0,0,0,0,0,0,0,0
,
0,0,0,0,0,0,0,0,
//'+'
0,0,0,0,0,0,0,0
,
0,0,64,64,64,64,64,254,
254,64,64,64,64,64,0,0
,
0,0,0,0,0,0,0,15,
15,0,0,0,0,0,0,0
,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
,
//'-'
0,64,64,64,64,64,64,0,
0,0,0,0,0,0,0,0
,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};// 6 x 8 font
// 1 pixel space at left and bottom
// index = ASCII - 32
#include <avr/pgmspace.h>
unsigned char font6_8[][6] PROGMEM =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // sp
{ 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 }, // !
{ 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
{ 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #
{ 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $
{ 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 }, // %
{ 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
{ 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
{ 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (
{ 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )
{ 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 }, // *
{ 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
{ 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 }, // ,
{ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 }, // { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
{ 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
{ 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
{ 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
{ 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
{ 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
{ 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
{ 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
{ 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
{ 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
{ 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
{ 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
{ 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
{ 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 }, // <
{ 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
{ 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 }, // >
{ 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
{ 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E }, // @
{ 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C }, // A
{ 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
{ 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
{ 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
{ 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
{ 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F
{ 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G
{ 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
{ 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
{ 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
{ 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
{ 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
{ 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M
{ 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
{ 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
{ 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
{ 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
{ 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
{ 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
{ 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
{ 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
{ 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
{ 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W
{ 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
{ 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y
{ 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
{ 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [
{ 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 }, // 55
{ 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 }, // ]
{ 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
{ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
{ 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 }, // '
{ 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
{ 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
{ 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
{ 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
{ 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
{ 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C }, // g
{ 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
{ 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
{ 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 }, // j
{ 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k
{ 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
{ 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
{ 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
{ 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 }, // p
{ 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC }, // q
{ 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
{ 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
{ 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
{ 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
{ 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
{ 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
{ 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
{ 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C }, // y
{ 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
{ 0x00,0x00, 0x06, 0x09, 0x09, 0x06 } // horiz lines
};
Il linguaggio Processing
Il linguaggio Processing è basato su Java. L’ambiente di sviluppo di Arduino è scritto in Processing.
Processing deve essere installato dopo averlo scaricato dal sito di Arduino. La programmazione è più
semplice del linguaggio Java usuale. E’ particolarmente adatto per programmi di grafica ed è stato usato
anche in ambiente artistico. Per familiarizzarsi conviene caricare un esempio già pronto. Caricare dagli
esempi, sezione Motion, Bounce. Premere Run. Avrete sperimentato un’applet Java.
L'ambiente di programmazione PROCESSING in generale
Processing è un ambiente di programmazione sviluppato al Media Lab del MIT, il cui
scopo è di permettere ad artisti, designer ed in generale a persone con scarse cognizioni
di informatica ma attratte dalle possibilità di applicazione dell'informatica all'arte e al
design di poter scrivere dei programmi, più o meno sofisticati, in breve tempo, utilizzando
uno strumento facile da usare ma sufficientemente potente per fare delle sperimentazioni
nel settore della "computer art" e dell' "interaction design".
Processing è un prodotto open source disponibile per le piattaforme Windows, Macintosh
e Linux; lo si può scaricare dal sito ufficiale.
.
Processing è molto semplice da usare: si scrive il testo di un programma e lo si esegue
(con il comando "run" o premendo il pulsante "Play" all'estrema sinistra della finestra
dell'applicazione). I programmi scritti possono ovviamente essere salvati e
successivamente modificati. Il tutto si fa in modo semplice e intuitivo, così che anche un
utente inesperto possa imparare in pochi minuti ad usarlo.
Java è un linguaggio relativamente recente ed è considerato il linguaggio più adatto per le
applicazioni distribuite e per Internet. E’ scaricabile gratuitamente. Consente una
programmazione procedurale classica, con sintassi simile al linguaggio C. E’ anche un
linguaggio orientato agli oggetti, con sintassi simile al C++. La programmazione per oggetti
non è semplicissima per chi non è abituato. Arduino con Processing rende le cose un po’
più facili.
Ecco un esempio di programmazione procedurale per disegnare figure:
void setup() {
size (256,256);
backgrond(0);
}
void draw() {
stroke(255);
strokeWeight(1);
ellipseMode(CORNER);
ellipse(72,100,110,130);
triangle(88,100,168,100,128,50);
stroke(140);
beginShape(TRIANGLES);
vertex(114,180);
vertex(mouseX,mouseY);
vertex(140,180);
endShape();
strokeWeight(4);
line(96,150,112,150);
line(150,150,166,150);
line(120,200,136,200);
}
E ora un esempio di programmazione orientata agli oggetti:
Puppet pinocchio;
void setup() {
size(256,256);
background(0);
color tempcolor = color(255,0,0);
pinocchio = new Puppet(tempcolor);
}
void draw() {
background(0);
pinocchio.draw();
}
class Puppet {
color colore;
colore = c_;
}
void draw () {
stroke(255);
strokeWight(1);
ellipseMode(CORNER);
ellipse(72,100,110,130);
stroke(colore);
beginShape(TRIANGLES);
vertex(114,180);
vertex(mouseX,mouseY);
vertex(140,180);
endShape();
strokeWeight(4);
line(96,150,112,150),
line(150,150,166,150);
}
}
Tipi di dati
Variabili: se si riferiscono a tipi primitivi B = A provoca la copia di a in b. Se i dati sono
oggetti e array, viene creato un puntatore.
Scope: è l’ambito in cui si può accedere ad una variabile. Global scope significa che la
variabile è visibile ovunque ed è dichiarata fuori da setup(). Local scope significa che è
definita all’interno di un blocco di programma ed visibile solo al suo interno.
Funzioni: come in C e C++ sono lo strumento principalee consentono una
programmazione modulare.
Classi e Oggetti
Una classe è un insieme di dati e funzioni. Un oggetto è un’istanza di una classe.
Processing su Arduino
Le strutture di controllo di un linguaggio di programmazione sono dei costrutti (frasi) del
linguaggio che controllano l’ordine di esecuzione delle istruzioni di un programma.



Sequenza: le istruzioni sono eseguite in sequenza una dopo l’altra.
Selezione: scelta dell’istruzione da eseguire tra più alternative.
Iterazione: ripetizione (un certo numero di volte) di un gruppo di istruzioni.
S e que nz a
Sequenza : giustapposizione di istruzioni separate da “;” (punto e virgola)
Una o più istruzioni possono essere raggruppate tra parentesi graffe
{I1; …; In;}
per formare una singola istruzione. Le istruzioni sono eseguite nell’ordine in cui appaiono:
I1, … , In
Esempio
Il primo esempio di programma Processing disegna cinque rette oblique tra loro parallele.
l'istruzione size(200, 200) crea una finestra di 200 per 200 pixel entro cui avviene il
disegno,
l'istruzione background(0) sceglie il nero come colore dello sfondo,
l'istruzione stroke(255) sceglie il bianco come colore per il disegno delle linee,
l'istruzione strokeWeight(5) imposta lo spessore delle linee a 5 pixel,
l'istruzione smooth()arrotonda l'estremità delle linee.
Ciascuna delle 5 linee di codice che seguono disegna una linea, ad es. l'istruzione
line(10, 80, 30, 40)disegna una linea con estremi nei punti di coordinate (10, 80) e (30,
40).
Il sistema di coordinate di Processing pone l'origine degli assi nell'angolo superiore sinistro
della finestra di disegno, per cui spostandosi verso destra aumenta il valore della prima
coordinata di un punto, mentre spostandosi verso il basso aumenta il valore della seconda
coordinata.
Si noti che l'immagine appare in bianco e nero, poiché è stato scelto di disegnare con
immagini a livelli di grigio, scelti tra 256 tonalità diverse: 0 per il nero e 255 per il bianco.
Ogni istruzione del programma è seguita da un commento, un testo inserito come
documentazione del programma, che non viene considerato come codice, ma viene
scartato durante l'esecuzione del programma. I commenti usati in questo programma sono
monoriga, ovvero iniziano dopo i simboli "//" e terminano in fondo alla riga.
Uso delle variabili
Se si osserva attentamente il programma precedente, le cinque righe parallele sono
disegnate incrementando di 10 unità la prima componente dei punti estremi di ogni retta.
Il prossimo esempio differisce dal precedente per l'introduzione di una variabile intera di
nome x a cui si assegna inizialmente il valore 0 con la dichiarazione
int x = 0
e dopo il disegno di ogni linea è incrementata di 10 unità con il comando di assegnamento
x=x+10 .
Una dichiarazione ha il compito di creare una variabile stabilendo il nome e l'insieme dei
valori che la variabile può assumere (ovvero il tipo della variabile, in questo caso di tipo int
che denota i numeri interi), nonché di riservare nella memoria del calcolatore lo spazio
necessario per memorizzare il valore corrente della variabile.
In Processing come in Java e tanti altri linguaggi, una variabile non può essere usata se
non è prima dichiarata. Invece in JavaScript la dichiarazione di una variabile non è
necessaria.
L'effetto finale del programma è sempre lo stesso, ma, a differenza del programma
precedente, il codice mette bene in evidenza la relazione tra le coordinate delle 5 linee.
I te r a z i one
I costrutti di iterazione eseguono un certo numero di volte un'istruzione, detta corpo. Un
costrutto di iterazione è anche detto istruzione di ciclo, o semplicemente ciclo.
Noi esamineremo due tipi di costrutti di iterazione:
comando while
while (<espressione logica> ) I
L'esecuzione di un comando while causa l'esecuzione dell'istruzione (il corpo del while) se
l’espressione logica (il test di while) è vera, poi si valuta di nuovo l’espressione logica: se è
vera si esegue di nuovo l’istruzione, e così via finché l’espressione logica diventa falsa.
Esempio di uso del comando while
Osservando il codice degli esempi precedenti, le cinque righe parallele sono disegnate
incrementando di 10 unità la prima componente dei punti estremi di ogni retta.
Si ha quindi una ripetizione (5 volte) dell'esecuzione del comando di tracciatura delle linee.
La tracciatura delle linee può avvenire senza scrivere 5 volte lo stesso comando, usando il
comando while.
Il corpo del ciclo while disegna una linea ed incrementa il valore della variabile intera x di
10 unità.
Pertanto, la variabile x assume i valori 0, 10, 20, 30, 40, in corrispondenza dei quali una
linea viene disegnata. Quando assume il valore 50, la guardia del ciclo while diventa falsa
e l'esecuzione del ciclo termina.
La figura seguente mostra come il ciclo while possa essere usato per calcolare i numeri
triangolari, ovvero i numeri interi positivi ottenuti come somma dei numeri interi compresi
tra 1 e un intero positivo n.
Il programma funziona in modo analogo.
comando for
for (I1 ; E ; I2 ) I3
I1 è l’istruzione di inizializzazione;
E è il test del for ;
I2 è l’istruzione di incremento o aggiornamento;
I3 è il corpo del for ;
l'esecuzione di un comando for avviene come segue: innanzi tutto è eseguita l'istruzione I1
di inizializzazione (che di solito assegna un valore ad una variabile, detta variabile di
controllo del ciclo for); se la guardia è vera si esegue il corpo I3 e l’aggiornamento I2 , poi si
valuta di nuovo la guardia: se è vera si esegue di nuovo il corpo e l’aggiornamento, finché
la guardia diventa falsa.
Esempio di uso del comando for
Questo esempio è una riscrittura del programma precedente usando il ciclo for. Si noti che
l'istruzione che assegna 0 alla variabile x è l'istruzione di inizializzazione del ciclo for,
mentre l'istruzione che incrementa di 10 unità il valore di x è l'istruzione di aggiornamento
del ciclo for. Il corpo del for è costituito dalla sola istruzione di tracciatura di una linea e
viene ripetuto 5 volte.
Attenzione: le istruzioni di ciclo non sono solo dei semplici sostituti del comando di
sequenzializzazione che permettono di abbreviare i programmi, ma permettono di fare
molto di più. Se non usiamo i cicli e vogliamo disegnare 10 righe anziché 5, dobbiamo
modificare il programma, aggiungendo 5 nuovi comandi di disegno.
Il prossimo esempio mostra come con le istruzioni di iterazione sia possibile disegnare un
numero di linee che dipende dal numero di secondi del tempo in cui si lancia l'esecuzione
del programma: non è pertanto stabilire a priori quante linee si devono disegnare e un tale
programma non si può realizzare con la sola sequenzializzazione di comandi.
Alla variabile intera s è assegnato il numero dei secondi letti dall'orologio del calcolatore.
Nell'immagine precedente il testo che appare nella finestra del terminale indica che il
valore assegnato ad s è 4. Il programma disegnerà pertanto quattro righe, come mostrato
nella figura seguente:
Il corpo
line(5*x+10, 40, 5*x+10, 80);
del comando for successivo che esegue la tracciatura di una linea verticale è eseguito un
numero di volte pari al valore della variabile s: infatti, la variabile x di conteggio del for è
inizializzata a 0 e fintanto che il suo valore è minore di quello di s, si traccia una linea e si
incrementa il valore di x.
In generale, se s è una variabile intera con un valore definito, l'esecuzione del ciclo
for(int
x
/*
=
corpo
0;
del
x<s;
for
x=x+1){
*/
};
provoca l'esecuzione ripetuta s volte del corpo del for.
Con le istruzioni di ciclo, si può incappare nel cosidetto "fencepost error" (errore dello
steccato e dei pali), che consiste nell'eseguire il corpo del ciclo una volta in più o in meno
del numero corretto di iterazioni. Per essere sicuri che il programma funzioni
correttamente, provate ad assegnare dei valori piccoli alla variabile s, ad es. 0 o 1 e
vedete cosa succede: se le prove hanno successo, allora il programma dovrebbe essere
corretto.
Per concludere l'analisi di quest'esempio, si noti il commento multiriga in fondo al codice.
Si tratta di un tipo di commento che inizia con i simboli "/*" , termina con i simboli "*/" e può
occupare un numero arbitrario di righe di testo.
S e l e z i one
I costrutti di selezione scelgono di eseguire un'istruzione piuttosto che un'altra in base al
valore di un'espressione logica ( espressione che assume solo due valori, vero o falso, e
pertanto una tale espressione è anche detta espressione booleana, da George Boole,
matematico e logico del diciannovesimo secolo).
Noi esamineremo due tipi di costrutti di selezione:
comando if
if (<espressione logica> ) I1
L'esecuzione di tale comando causa l'esecuzione dell'istruzione I1 se l’espressione logica
(detta guardia) è vera
Esempio di uso del comando if
Il seguente programma disegna 5 righe parallele di colore grigio se, al momento
dell'esecuzione del programma, l'orologio del calcolatore indica un'orario in cui il valore dei
secondi è inferiore a 30; in caso contrario, le righe sono di colore bianco. La decisione di
quale colore applicare è fatta con il costrutto if.
Il colore delle linee da tracciare viene preimpostato con la terza riga di codice
stroke(255)
che sceglie il colore bianco. Il successivo comando if
if (s<30){
stroke(128); // Set line value to gray
};
imposta con l'istruzione stroke(128)il colore grigio come colore di tracciatura se il numero
dei secondi, contenenuto nella variabiles è minore di 30.
comando if-else
if (<espressione logica> ) I1
else I2
L'esecuzione di tale comando causa l'esecuzione dell'istruzione I1 se l’espressione logica
è vera; dell'istruzione I2 in caso contrario.
Esempio di uso del comando if-else
Il seguente programma disegna 5 righe parallele di colore grigio se, al momento
dell'esecuzione del programma, l'orologio del calcolatore indica un'orario in cui il valore dei
secondi è inferiore a 30; in caso contrario, le righe sono di colore bianco. La decisione di
quale colore applicare è fatta con il costrutto if-else
A differenza dell'esempio precedente, il colore delle linee da tracciare non viene
preimpostato, ma viene determinato dal comando if-else
if (s<30){
stroke(128); // Set line value to gray
}
else {
stroke(255); // Set line value to white
};
che imposta con l'istruzione stroke(128)il colore grigio come colore di tracciatura se il
numero dei secondi, contenenuto nella variabiles è minore di 30, mentre in caso contrario
il colore di tracciatura è impostato al colore bianco con l'istruzionestroke(255).
P r i m o es e m pi o di gr a fi c a 2 D
Il prossimo semplicissimo programma mostra come disegnare semplici figure
geometriche. Per un approfondimento, si veda il link GRAFICA 2D e per informazioni
sull'uso delle primitive grafiche 2D (istruzioni per il disegno di figure geometriche
bidimensionali, si consulti l'elenco denominato "2D Primitives" alla pagina del manuale di
riferimento di Processing .
Il programma è quasi autoesplicativo. Gli unici commenti riguardano i comandistroke() e fill(), che
stabiliscono il colore di disegno dei contorni e rispettivamente dell'area interna di una figura. I tre
numeri interi che costituiscono gli argomenti di queste istruzioni rappresentano un colore in
formato RGB (Red, Green, Blue) . Al contrario, i metodi noStroke() e noFill() inibiscono il disegno
del contorno o dell'interno di una figura, fino all'esecuzione di un nuovo comando stroke() o fill().Il
comando bezier() disegna una curva di Beziér, definita da quattro punti: i punti estremi e due punti
di
controllo
che
ne
determinano
la
curvatura.
Per
comprendere
meglio
le
curve
di
Beziér,
segui
questo
link.
Per determinare il codice RGB di un colore o viceversa per determinare il colore di una
tripla RGB di numeri interi, si può usare nel menu "Tools" di Processing l'opzione "Color
selector".
Il
risultato
dell'esecuzione
del
programma
è
il
seguente
Note s ul l ' es e c uzione de i pr ogr a mm i
Come abbiamo visto, Processing dà la possibilità di scrivere ed eseguire programmi in
modo immediato. Il codice dei programmi scritti è memorizzato in un file con estensione
".pde" (sigla di Processing Development Environment).
Al momento della sua esecuzione, tale file viene tradotto in un codice detto bytecode,
contenuto insieme ad altri file all'interno di un file con estensione ".jar" (sigla di Java
ARchive).
Il bytecode all'interno del file jar viene eseguito dall'interprete Java, detto anche JRE (sigla
di Java Run-time Environment) o JVM (sigla di Java Virtual Machine).
Le fasi di traduzione (detta comunemente compilazione) del codice sorgente (il file pde) e
di esecuzione del bytecode avvengono in modo trasparente per l'utente. Tutti i file prodotti
mantengono lo stesso nome, cambiando solo l'estensione.
In realtà, il bytecode prodotto da Processing è un programma di tipo speciale, detto applet,
che può essere inserito all'interno di una pagina web con un'apposito marcatore <applet>.
In questo modo, il programma una volta compilato è inserito all'interno di una pagina web
e, al momento della visualizzazione della pagina, l'applet è eseguito. L'unica cosa
necessaria per la visualizzazione degli applet è che sul calcolatore sia installato l'interprete
Java, (JRE o JVM).
Attenzione, Processing crea l'applet solo se si esegue il comando "export".
In tal caso, esso genera il bytecode dell'applet ed una semplice pagina web di nome
index.html contenente un riferimento all'applet mediante il marcatore omonimo.
Di seguito sono elencati i collegamenti alle pagine web contenenti gli esempi visti finora,
più alcuni esempi supplementari.
Processing può anche creare un'applicazione se si esegue il comando "export
application".
In tal caso, esso genera oltre al bytecode dell'applet un file eseguibile che avvia a sua
volta l'esecuzione dell'applet. L'applicazione può essere generata per i sistemi Windows,
Mac e Linux.
Esempi vari
Ecco il programma Rimbalza (bounce)
/**
* Bounce.
*
* When the shape hits the edge of the window, it reverses its direction.
*
* Updated 1 September 2002
*/
import processing.serial.*;
String portname = "/dev/tty.usbserial-A4001qa8";
Serial port; // Create object from Serial class
int size = 60;
// Width of the shape
float xpos, ypos; // Starting position of shape
float xspeed = 3.9; // Speed of the shape
float yspeed = 3.1; // Speed of the shape
int xdirection = 1; // Left or Right
int ydirection = 1; // Top to Bottom
void setup()
{
size(400, 400);
colorMode(HSB, 255);
noStroke();
frameRate(30);
ellipseMode(CENTER); // draw from center out
smooth();
// Set the starting position of the shape
xpos = width/2;
ypos = height/2;
// Open the port that the board is connected to and use the same speed (19200 bps)
port = new Serial(this, portname, 19200);
}
void draw()
{
if (port.available() > 0) { // If data is available,
size = port.read();
// read it and store it as the new size
}
background(102);
// Update the position of the shape
xpos = xpos + ( xspeed * xdirection );
ypos = ypos + ( yspeed * ydirection );
// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
int halfsize = size/2; // because we're drawing from the circle's center
if (xpos + halfsize > width || xpos - halfsize < 0) {
xdirection *= -1;
}
if (ypos + halfsize > height || ypos - halfsize < 0) {
ydirection *= -1;
}
// Draw the shape
fill(size,255,255); // we're in HSB mode, so first value is color
ellipse(xpos, ypos, size, size);
}
Ora un gioco (Pong)
/**
*
* When the shape hits the edge of the window, it reverses its direction.
*
* Updated 1 September 2002
*/
import processing.serial.*;
String portname = "/dev/tty.usbserial-A4001qa8";
Serial port; // Create object from Serial class
int size = 60;
// Width of the shape
float xpos, ypos; // Starting position of shape
float xspeed = 3.9; // Speed of the shape
float yspeed = 3.1; // Speed of the shape
int xdirection = 1; // Left or Right
int ydirection = 1; // Top to Bottom
void setup()
{
size(400, 400);
colorMode(HSB, 255);
noStroke();
frameRate(30);
ellipseMode(CENTER); // draw from center out
smooth();
// Set the starting position of the shape
xpos = width/2;
ypos = height/2;
// Open the port that the board is connected to and use the same speed (19200 bps)
port = new Serial(this, portname, 19200);
}
void draw()
{
if (port.available() > 0) { // If data is available,
size = port.read();
// read it and store it as the new size
}
background(102);
// Update the position of the shape
xpos = xpos + ( xspeed * xdirection );
ypos = ypos + ( yspeed * ydirection );
// Test to see if the shape exceeds the boundaries of the screen
// If it does, reverse its direction by multiplying by -1
int halfsize = size/2; // because we're drawing from the circle's center
if (xpos + halfsize > width || xpos - halfsize < 0) {
xdirection *= -1;
}
if (ypos + halfsize > height || ypos - halfsize < 0) {
ydirection *= -1;
}
// Draw the shape
fill(size,255,255); // we're in HSB mode, so first value is color
ellipse(xpos, ypos, size, size);
}
Ecco un altro esempio
* Simple Read
*
* Read data from the serial port and change the color of a rectangle
* when a switch connected to a Wiring or Arduino board is pressed and
released.
* This example works with the Wiring / Arduino program that follows below.
*/
import processing.serial.*;
String portname = "/dev/tty.usbserial-A4001qa8";
Serial port; // Create object from Serial class
int val=100;
// Data received from the serial port, with an initial value
void setup()
{
size(400, 400);
colorMode(HSB, 255);
ellipseMode(CENTER);
noStroke();
frameRate(30);
smooth();
// draw from center out
// Open the port the board is connected to
port = new Serial(this, portname, 19200);
}
void draw()
// or "COM8"
{
if (port.available() > 0) { // If data is available,
val = port.read();
// read it and store it in val
}
background(99);
// Draw the shape
fill(val,255,255); // we're in HSB mode, so first value is color
ellipse(width/2, height/2, 250,250);
}
Ora Arduino suona!
* Arduino Sounds
*
* Play WAV or MP3 files when piezo knocks from an Arduino running the
* "PiezoKnock" sketch or when a computer keyboard key is pressed.
*
* Taken from the Minim "trigger" sketch:
*
* This sketch demonstrates how to use the <code>trigger</code> method of an
<code>AudioSample</code>. <br />
* <code>AudioSample</code>s can only be triggered, not cue'd and looped
* or anything else you might do with an <code>Playable</code> object. The
advantage, however, is that
* an <code>AudioSample</code> can be retriggered while it is still playing,
which will cause the sample to
* overlap with itself .
*/
import ddf.minim.*;
import processing.serial.*;
String portname = "/dev/tty.usbserial-A4001qa8";
Serial port; // Create object from Serial class
// or "COM8"
AudioSample sounds[];
String sound_names[] =
{
"cat.wav",
"fx.mp3",
"electric_wrench.wav",
"wehoa.mp3",
"oriental_gong_2.wav",
"yipee.wav",
"car_brake.wav"
// find more wav or mp3 files and put them in the "data" directory
};
void setup()
{
size(400, 400);
background(0);
stroke(255);
// always start Minim before you do anything with it
Minim.start(this);
Minim.debugOn();
sounds = new AudioSample[sound_names.length];
for( int i=0; i< sound_names.length; i++ ) {
sounds[i] = Minim.loadSample(sound_names[i], 512);
}
// Open the port that the board is connected to and use the same speed
(19200 bps)
port = new Serial(this, portname, 19200);
}
void draw()
{
// do the drawing on events
}
void soundball() {
int r = int(random(sounds.length));
println("picked sound #"+r);
sounds[r].trigger();
// play a random sound
int x = int(random(0,300));
int y = int(random(0,300));
fill(240,0,0);
ellipse(x,y, 40,40);
fill(30,0,0);
ellipse(x,y, 8,8);
}
void serialEvent(Serial p) {
char inByte = port.readChar();
println("received char: "+ inByte);
if( inByte == '!' ) { // '!' is end of "knock!"
soundball();
}
}
void keyPressed() {
if(key == ' ') {
background(40,40,40);
}
soundball();
}
// erase screen
void stop()
{
// always close Minim audio classes when you are done with them
for( int i=0; i<sounds.length; i++ ) {
sounds[i].close();
}
super.stop();
}
Bibliografia
-M. Banzi, Getting started with Arduino, O’Reilly, Cabridge,Beijing, 2009
-Tod E. Kurt, Bionic Arduino, MachineProject, 2007
-S. Monk, 30 Arduino Projects, McGrawHill, New York,2010
-M. Schmidt, Arduino, A Quick-Start Giude, The Pragmatic Programmers, 2011
-C. Reas and Ben Fry, Getting Started with Processing, O’Reilly, 2010
-www.arduino.cc
-www.webalice.it
-www.shiffman.net/itp
Grazie per l’attenzione. Buon apprendimento.
Scarica

La piattaforma hardware e software Arduino: parte IV