Per gestire i file generati da Sqlite su Windows puo' essere utile usare il programma che si scarica gratuitamente da questo link
venerdì 29 marzo 2013
QTimer in Qt
Questo componente non visuale permette di gestire eventi a tempi predefiniti
La sintassi e' piuttosto semplice: si crea l'oggetto e si associa una funzione che viene richiamata ogni volta che l'oggetto genera un evento
La sintassi e' piuttosto semplice: si crea l'oggetto e si associa una funzione che viene richiamata ogni volta che l'oggetto genera un evento
Nell'esempio seguente gli eventi vengono generati ogni secondo
------------------------------------------#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
void TimerEvent();
private:
Ui::MainWindow *ui;
QTimer timer;
unsigned contatore;
};
#endif // MAINWINDOW_H
------------------------------------------
------------------------------------------
#include "mainwindow.h"#include "ui_mainwindow.h"#include <QTimer>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow){ui->setupUi(this);}MainWindow::~MainWindow(){delete ui;}void MainWindow::on_pushButton_clicked(){contatore = 0;
connect(&timer, SIGNAL(timeout()), this, SLOT(TimerEvent()));
this->timer.start(1000);
}void MainWindow::TimerEvent()
{
contatore++;
QString str;
str.append(QString("%1").arg(contatore));
ui->pushButton->setText(str);
qDebug()<< contatore;
}
------------------------------------------
Importare Progetti Qt in QtCreator da Windows a Linux
Per poter spostare un progetto in Qt/QtCreator sviluppato su Windows in una Linux Box non e' sufficiente copiare la directory dei sorgenti in quanto una volta aperto il file .pro in QtCreator si avranno errori in particolare sul file Make
e' quindi necessario, prima di aprire il file .pro
1) Cancellare la directory di debug/release
2) Cancellare Makefile, Makefile.debug, Makefile.Release
3) cancella object_script*.*
4) cancellare il file *.pro.user (attenzione non file .pro)
a questo punto si puo' aprire il file .pro e compilare.
I file mancanti verranno ricostruiti sulla base delle impostazione Linux
(informazione ripresa da qui)
e' quindi necessario, prima di aprire il file .pro
1) Cancellare la directory di debug/release
2) Cancellare Makefile, Makefile.debug, Makefile.Release
3) cancella object_script*.*
4) cancellare il file *.pro.user (attenzione non file .pro)
a questo punto si puo' aprire il file .pro e compilare.
I file mancanti verranno ricostruiti sulla base delle impostazione Linux
(informazione ripresa da qui)
Spedire pacchetti UDP con Netcat
Per fare delle prove di server UDP puo' essere utile il programma netcat (che non e' installato di default in Debian ma deve essere aggiunto con apt-get install netcat)
una volta avviato il server UDP si puo' inviare pacchetti UDP con la seguente sintassu
dove localhost e' l'indirizzo del server (in questo caso in locale) e 21567 e' la porta di ascolto del server
echo -n "hello" | nc -u -w1 localhost 21567
una volta avviato il server UDP si puo' inviare pacchetti UDP con la seguente sintassu
dove localhost e' l'indirizzo del server (in questo caso in locale) e 21567 e' la porta di ascolto del server
echo -n "hello" | nc -u -w1 localhost 21567
giovedì 28 marzo 2013
Deploy Application in Qt su Windows
Una volta creata una applicazione Qt funzionante in Window puo' venire il momento di distribuirla
Per prima cosa si deve creare il file eseguibile dentro a QtCreator selezionando l'opzione Release nei metodi di compilazione. Nella cartella del progetto viene quindi creata una sottocartella Release con l'eseguibile
Per visualizzare le dipendenza si puo' usare il programma Depend (scaricabile a questo link)
Si copiano quindi nella directory release dell'eseguibile le DLL necessarie copiandole da C:\QtSDK\Desktop\Qt\4.7.3\mingw\bin
che nel caso in esame sono
QtCore4.dll
QtGui4.dll
QtSql4.dll
a queste vanno aggiunte
libgcc_s_dw2-1.dll
mingwm10.dll
si zippa il contenuto della directory e tramite il software NSIS si crea un installer scegliendo l'opzione "Installer based in Zip File"
Per prima cosa si deve creare il file eseguibile dentro a QtCreator selezionando l'opzione Release nei metodi di compilazione. Nella cartella del progetto viene quindi creata una sottocartella Release con l'eseguibile
Per visualizzare le dipendenza si puo' usare il programma Depend (scaricabile a questo link)
Si copiano quindi nella directory release dell'eseguibile le DLL necessarie copiandole da C:\QtSDK\Desktop\Qt\4.7.3\mingw\bin
che nel caso in esame sono
QtCore4.dll
QtGui4.dll
QtSql4.dll
a queste vanno aggiunte
libgcc_s_dw2-1.dll
mingwm10.dll
si zippa il contenuto della directory e tramite il software NSIS si crea un installer scegliendo l'opzione "Installer based in Zip File"
Mouse Bluetooth su Debian
Questa e' una delle classiche cose che ti fa odiare Linux
Ho provato a connettere il mouse Bluetooth (recuperato di regalo) Sony VGP-BMS30 alla mia Debian Box e sono iniziati i problemi
apt-get install bluez-compat bluetooth
hcitool scan
si legge l'ID del mouse (in questo caso 00:03:C9:D1:61:B3) e poi si lancia
Ho provato a connettere il mouse Bluetooth (recuperato di regalo) Sony VGP-BMS30 alla mia Debian Box e sono iniziati i problemi
La connessione e' piuttosto semplice da eseguire
apt-get install bluez-compat bluetooth
hcitool scan
si legge l'ID del mouse (in questo caso 00:03:C9:D1:61:B3) e poi si lancia
hidd --connect 00:03:C9:D1:61:B3
a questo punto sono iniziati i problemi
L'accoppiamento e' stato eseguito in modo corretto ma lasciando il mouse fermo per qualche decina di secondi questo sembrava essersi messo in modalita' sleep e non dava segni di vita
lanciando il comando
echo on > `readlink -f /sys/class/bluetooth/hci0`/../../../power/level
e' possibile disattivare l'autosospend
e' possibile disattivare l'autosospend
Problemi finiti ??? Nemmeno per idea
Il mouse a questo punto ha iniziato a muoversi con un ritardo notevole ed anche erratico sullo schermo senza un ragione precisa. Consultando questa pagina ho potuto verificare che si tratta di un bug conosciuto dello stack bluez quindi...mi compro un Logitech wireless da 2.4GHz
Cross compilare Qt su WIndows e Linux
Qt permette di scrivere applicazione che possono essere eseguite su piu' piattaforme ma non e' banale utilizzando una sola piattaforma creare eseguibili per tutti i sistemi operativi supportati (per esempio per compilare eseguibili Windows partendo da Qt SDK su Linux)
La soluzione piu' banale e' salvare la cartella del progetto, portarla su una macchina con montato il sistema operativo target e l'SDK installato, e ricompilare qui il progetto....non e' necessario infatti fare nessuna modifica
Nel caso in esempio il progetto e' stato sviluppato su Windows
ed e' stato portato su Linux digitando esclusivamente il comando make all'interno della cartella del progetto
Ci sono ovviamente delle piccole differenze relative ai Window Manager ma la cosa interessante e' che non e' stata effettuata nessuna modifica ne' sul codice ne' sul progetto
La soluzione piu' banale e' salvare la cartella del progetto, portarla su una macchina con montato il sistema operativo target e l'SDK installato, e ricompilare qui il progetto....non e' necessario infatti fare nessuna modifica
Nel caso in esempio il progetto e' stato sviluppato su Windows
ed e' stato portato su Linux digitando esclusivamente il comando make all'interno della cartella del progetto
Ci sono ovviamente delle piccole differenze relative ai Window Manager ma la cosa interessante e' che non e' stata effettuata nessuna modifica ne' sul codice ne' sul progetto
mercoledì 27 marzo 2013
UDP Server in Qt
Creare un server UDP in Qt non e' banalissimo
per prima cosa si deve modificare il file .pro per aggiungere il modulo network
-------------------------------------------------
QT += core gui network
successivamente sul file .h della finestra si aggiungono i riferimenti evidenziati in giallo
-------------------------------------------------
per testare il tutto si puo' usare questo semplice codice di client UDP in Python
per prima cosa si deve modificare il file .pro per aggiungere il modulo network
-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = udp_server
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui-------------------------------------------------
successivamente sul file .h della finestra si aggiungono i riferimenti evidenziati in giallo
-------------------------------------------------
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QUdpSocket>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QUdpSocket *udpSocket;
private slots:
void processPendingDatagrams();
};
#endif // MAINWINDOW_H
-------------------------------------------------
ed ecco la parte di codice che gestisce direttamente il server
in pratica si apre la porta di ascolto (in questo caso la 64009) e si connette una funzione di ascolto (processPendingData)
ed ecco la parte di codice che gestisce direttamente il server
in pratica si apre la porta di ascolto (in questo caso la 64009) e si connette una funzione di ascolto (processPendingData)
-------------------------------------------------
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtNetwork>
#include <QUdpSocket>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
udpSocket = new QUdpSocket(this);
QHostAddress myAddr = QHostAddress("192.168.0.100") ;udpSocket->bind(myAddr, 7755);
bool result = connect(udpSocket, SIGNAL(readyRead()),this, SLOT(processPendingDatagrams()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::processPendingDatagrams()
{
QByteArray datagram;
do {
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
qDebug() << datagram.data();
} while (udpSocket->hasPendingDatagrams());
}
-------------------------------------------------
per testare il tutto si puo' usare questo semplice codice di client UDP in Python
-------------------------------------------------
import socket
IPADDR = '192.168.0.100'
PORTNUM = 7755
PACKETDATA = 'Luca'
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
s.connect((IPADDR, PORTNUM))
s.send(PACKETDATA)
s.close()
-------------------------------------------------
Sensore ad ultrasuoni HC SR04 su Arduino
Questo modulo ad ultrasuoni permette di calcolare la distanza di oggetti con Arduino (e di farsi anche un Theremin digitale
Il modulo ha 4 cavi
Vcc
Gnd
Trigger
Echo
Nello sketch successivo(ripreso da qui) i pint digitali 7 ed 8 devono essere collegati al Trigger ed ad Echo
La distanza massima misurabile e' dell'ordine di 40-50 cm (dipende anche dalle dimensioni ed il materiale del bersaglio)
---------------------------------------------------------------------
//HC RS04 Sensore ultrasuoni
int triggerPort = 8;
int echoPort = 7;
void setup() {
pinMode( triggerPort, OUTPUT );
pinMode( echoPort, INPUT );
Serial.begin( 9600 );
Serial.println( "Sensore ultrasuoni: ");
}
void loop() {
//porta bassa l'uscita del trigger
digitalWrite( triggerPort, LOW );
//invia un impulso di 10microsec su trigger
digitalWrite( triggerPort, HIGH );
delayMicroseconds( 10 );
digitalWrite( triggerPort, LOW );
long duration = pulseIn( echoPort, HIGH );
long r = 0.034 * duration / 2;
Serial.print( "durata: " );
Serial.print( duration );
Serial.print( " , " );
Serial.print( "distanza: " );
//dopo 38ms è fuori dalla portata del sensore
if( duration > 38000 ) Serial.println( "fuori portata");
else { Serial.print( r ); Serial.println( "cm" );}
//aspetta 1.5 secondi
delay( 1500 );
}
----------------------------------------------
Alcuni utenti usano una libreria alternativa (Arduino New Ping) che sembra garantire prestazioni migliori
Il modulo ha 4 cavi
Vcc
Gnd
Trigger
Echo
Nello sketch successivo(ripreso da qui) i pint digitali 7 ed 8 devono essere collegati al Trigger ed ad Echo
La distanza massima misurabile e' dell'ordine di 40-50 cm (dipende anche dalle dimensioni ed il materiale del bersaglio)
---------------------------------------------------------------------
//HC RS04 Sensore ultrasuoni
int triggerPort = 8;
int echoPort = 7;
void setup() {
pinMode( triggerPort, OUTPUT );
pinMode( echoPort, INPUT );
Serial.begin( 9600 );
Serial.println( "Sensore ultrasuoni: ");
}
void loop() {
//porta bassa l'uscita del trigger
digitalWrite( triggerPort, LOW );
//invia un impulso di 10microsec su trigger
digitalWrite( triggerPort, HIGH );
delayMicroseconds( 10 );
digitalWrite( triggerPort, LOW );
long duration = pulseIn( echoPort, HIGH );
long r = 0.034 * duration / 2;
Serial.print( "durata: " );
Serial.print( duration );
Serial.print( " , " );
Serial.print( "distanza: " );
//dopo 38ms è fuori dalla portata del sensore
if( duration > 38000 ) Serial.println( "fuori portata");
else { Serial.print( r ); Serial.println( "cm" );}
//aspetta 1.5 secondi
delay( 1500 );
}
----------------------------------------------
Alcuni utenti usano una libreria alternativa (Arduino New Ping) che sembra garantire prestazioni migliori
Buzzer su Arduino
In questo esempio viene presentato l'utilizzo di un Buzzer alimentato su Arduino
Utilizzare questo componente permette di ottenere un suono di volume piu' alto rispetto ad un buzzer passivo
La pedinatura e' piuttosto semplice (+,- ed S) che corrispondono a (VCC,GND e Segnale)
Nello sketch successivo (ricopiato dal Playground di Arduino) il segnale e' collegato al Pin Digitale 4
-----------------------------------------------------------
#define SPEAKER_Pin 4
int length = 15; // the number of notes
char notes[] = "ccggaagffeeddc "; // a space represents a rest
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;
void playTone(int tone, int duration)
{
for (long i = 0; i < duration * 1000L; i += tone * 2)
{
digitalWrite(SPEAKER_Pin, HIGH);
delayMicroseconds(tone);
digitalWrite(SPEAKER_Pin, LOW);
delayMicroseconds(tone);
}
}
void playNote(char note, int duration)
{
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };
// play the tone corresponding to the note name
for (int i = 0; i < 8; i++) {
if (names[i] == note) {
playTone(tones[i], duration);
}
}
}
void setup()
{
pinMode(SPEAKER_Pin, OUTPUT);
}
void loop()
{
for (int i = 0; i < length; i++) {
if (notes[i] == ' ') {
delay(beats[i] * tempo); // rest
} else {
playNote(notes[i], beats[i] * tempo);
}
// pause between notes
delay(tempo / 2);
}
}
---------------------------------------------------
Aggiornamento:
a distanza di tempo mi sono reso conto che il codice e' poco leggibile e ridondante. Il codice minimale per emettere un suono e' il seguente
----------------------------------------------------
int speakerPin = 9;
void playTone(int tone, int duration) {
for (long i = 0; i < duration * 1000L; i += tone * 2) {
digitalWrite(speakerPin, HIGH);
delayMicroseconds(tone);
digitalWrite(speakerPin, LOW);
delayMicroseconds(tone);
}
}
void setup() {
pinMode(speakerPin, OUTPUT);
}
void loop() {
playTone(400,1000);
delay(1000);
}
Utilizzare questo componente permette di ottenere un suono di volume piu' alto rispetto ad un buzzer passivo
Quando arriva il componente e' dotato di una pellicola di protezione che deve essere rimossa dopo la saldatura
La pedinatura e' piuttosto semplice (+,- ed S) che corrispondono a (VCC,GND e Segnale)
Nello sketch successivo (ricopiato dal Playground di Arduino) il segnale e' collegato al Pin Digitale 4
-----------------------------------------------------------
#define SPEAKER_Pin 4
int length = 15; // the number of notes
char notes[] = "ccggaagffeeddc "; // a space represents a rest
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;
void playTone(int tone, int duration)
{
for (long i = 0; i < duration * 1000L; i += tone * 2)
{
digitalWrite(SPEAKER_Pin, HIGH);
delayMicroseconds(tone);
digitalWrite(SPEAKER_Pin, LOW);
delayMicroseconds(tone);
}
}
void playNote(char note, int duration)
{
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };
// play the tone corresponding to the note name
for (int i = 0; i < 8; i++) {
if (names[i] == note) {
playTone(tones[i], duration);
}
}
}
void setup()
{
pinMode(SPEAKER_Pin, OUTPUT);
}
void loop()
{
for (int i = 0; i < length; i++) {
if (notes[i] == ' ') {
delay(beats[i] * tempo); // rest
} else {
playNote(notes[i], beats[i] * tempo);
}
// pause between notes
delay(tempo / 2);
}
}
---------------------------------------------------
Aggiornamento:
a distanza di tempo mi sono reso conto che il codice e' poco leggibile e ridondante. Il codice minimale per emettere un suono e' il seguente
----------------------------------------------------
int speakerPin = 9;
void playTone(int tone, int duration) {
for (long i = 0; i < duration * 1000L; i += tone * 2) {
digitalWrite(speakerPin, HIGH);
delayMicroseconds(tone);
digitalWrite(speakerPin, LOW);
delayMicroseconds(tone);
}
}
void setup() {
pinMode(speakerPin, OUTPUT);
}
void loop() {
playTone(400,1000);
delay(1000);
}
Real Time Clock (RTC) con DS1302 ed Arduino
L'Arduino ha un orologio interno ma non ha una batteria interna per cui quando si spenge l'alimentazione si perdono le informazioni sul tempo
Per supplire a questa funzione si puo' accoppiare un circiuto esterno di RTC (Real Time Clcok) basata sull'integrato DS1302.In commercio esistono delle schedine che integrano il DS1302 e le connessioni di base.
Si faccia presente che il nome dei piedini (ma non la funzione)puo' cambiare per cui le indicazioni presenti sulle foto possono non corrispondere a tutte le schede DS1302 (in particolare il pin Reset si puo' chiamare Chip Enable)
I collegamenti con la Arduino sono
SCLK_PIN 6 // Pin Digitale 6 Serial Clock
IO_PIN 7 // Pin Digitale 7 Data I/O
CE_PIN 8 // Pin Digitale 8 Chip Enable
in piu' si devono inserire i due cavi di alimentazione
lo sketch, ripreso direttamente dal Playground di Arduino, non e' banale ma funziona molto bene
-----------------------------------------------------------------------------
#include <Wire.h>
// DS1302 RTC
// ----------
//
// Open Source / Public Domain
//
// Version 1
// By arduino.cc user "Krodal".
// June 2012
// Using Arduino 1.0.1
// Version 2
// By arduino.cc user "Krodal"
// March 2013
// Using Arduino 1.0.3, 1.5.2
// The code is no longer compatible with older versions.
// Added bcd2bin, bin2bcd_h, bin2bcd_l
// A few minor changes.
//
//
// Documentation: datasheet
//
// The DS1302 uses a 3-wire interface:
// - bidirectional data.
// - clock
// - chip select
// It is not I2C, not OneWire, and not SPI.
// So the standard libraries can not be used.
// Even the shiftOut() function is not used, since it
// could be too fast (it might be slow enough,
// but that's not certain).
//
// I wrote my own interface code according to the datasheet.
// Any three pins of the Arduino can be used.
// See the first defines below this comment,
// to set your own pins.
//
// The "Chip Enable" pin was called "/Reset" before.
//
// The chip has internal pull-down registers.
// This keeps the chip disabled, even if the pins of
// the Arduino are floating.
//
//
// Range
// -----
// seconds : 00-59
// minutes : 00-59
// hour : 1-12 or 0-23
// date : 1-31
// month : 1-12
// day : 1-7
// year : 00-99
//
//
// Burst mode
// ----------
// In burst mode, all the clock data is read at once.
// This is to prevent a rollover of a digit during reading.
// The read data is from an internal buffer.
//
// The burst registers are commands, rather than addresses.
// Clock Data Read in Burst Mode
// Start by writing 0xBF (as the address),
// after that: read clock data
// Clock Data Write in Burst Mode
// Start by writing 0xBE (as the address),
// after that: write clock data
// Ram Data Read in Burst Mode
// Start by writing 0xFF (as the address),
// after that: read ram data
// Ram Data Write in Burst Mode
// Start by writing 0xFE (as the address),
// after that: write ram data
//
//
// Ram
// ---
// The DS1302 has 31 of ram, which can be used to store data.
// The contents will be lost if the Arduino is off,
// and the backup battery gets empty.
// It is better to store data in the EEPROM of the Arduino.
// The burst read or burst write for ram is not implemented
// in this code.
//
//
// Trickle charge
// --------------
// The DS1302 has a build-in trickle charger.
// That can be used for example with a lithium battery
// or a supercap.
// Using the trickle charger has not been implemented
// in this code.
//
// Set your own pins with these defines !
#define DS1302_SCLK_PIN 6 // Arduino pin for the Serial Clock
#define DS1302_IO_PIN 7 // Arduino pin for the Data I/O
#define DS1302_CE_PIN 8 // Arduino pin for the Chip Enable
// Macros to convert the bcd values of the registers to normal
// integer variables.
// The code uses seperate variables for the high byte and the low byte
// of the bcd, so these macros handle both bytes seperately.
#define bcd2bin(h,l) (((h)*10) + (l))
#define bin2bcd_h(x) ((x)/10)
#define bin2bcd_l(x) ((x)%10)
// Register names.
// Since the highest bit is always '1',
// the registers start at 0x80
// If the register is read, the lowest bit should be '1'.
#define DS1302_SECONDS 0x80
#define DS1302_MINUTES 0x82
#define DS1302_HOURS 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_ENABLE 0x8E
#define DS1302_TRICKLE 0x90
#define DS1302_CLOCK_BURST 0xBE
#define DS1302_CLOCK_BURST_WRITE 0xBE
#define DS1302_CLOCK_BURST_READ 0xBF
#define DS1302_RAMSTART 0xC0
#define DS1302_RAMEND 0xFC
#define DS1302_RAM_BURST 0xFE
#define DS1302_RAM_BURST_WRITE 0xFE
#define DS1302_RAM_BURST_READ 0xFF
// Defines for the bits, to be able to change
// between bit number and binary definition.
// By using the bit number, using the DS1302
// is like programming an AVR microcontroller.
// But instead of using "(1<<X)", or "_BV(X)",
// the Arduino "bit(X)" is used.
#define DS1302_D0 0
#define DS1302_D1 1
#define DS1302_D2 2
#define DS1302_D3 3
#define DS1302_D4 4
#define DS1302_D5 5
#define DS1302_D6 6
#define DS1302_D7 7
// Bit for reading (bit in address)
#define DS1302_READBIT DS1302_D0 // READBIT=1: read instruction
// Bit for clock (0) or ram (1) area,
// called R/C-bit (bit in address)
#define DS1302_RC DS1302_D6
// Seconds Register
#define DS1302_CH DS1302_D7 // 1 = Clock Halt, 0 = start
// Hour Register
#define DS1302_AM_PM DS1302_D5 // 0 = AM, 1 = PM
#define DS1302_12_24 DS1302 D7 // 0 = 24 hour, 1 = 12 hour
// Enable Register
#define DS1302_WP DS1302_D7 // 1 = Write Protect, 0 = enabled
// Trickle Register
#define DS1302_ROUT0 DS1302_D0
#define DS1302_ROUT1 DS1302_D1
#define DS1302_DS0 DS1302_D2
#define DS1302_DS1 DS1302_D2
#define DS1302_TCS0 DS1302_D4
#define DS1302_TCS1 DS1302_D5
#define DS1302_TCS2 DS1302_D6
#define DS1302_TCS3 DS1302_D7
// Structure for the first 8 registers.
// These 8 bytes can be read at once with
// the 'clock burst' command.
// Note that this structure contains an anonymous union.
// It might cause a problem on other compilers.
typedef struct ds1302_struct
{
uint8_t Seconds:4; // low decimal digit 0-9
uint8_t Seconds10:3; // high decimal digit 0-5
uint8_t CH:1; // CH = Clock Halt
uint8_t Minutes:4;
uint8_t Minutes10:3;
uint8_t reserved1:1;
union
{
struct
{
uint8_t Hour:4;
uint8_t Hour10:2;
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 0 for 24 hour format
} h24;
struct
{
uint8_t Hour:4;
uint8_t Hour10:1;
uint8_t AM_PM:1; // 0 for AM, 1 for PM
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 1 for 12 hour format
} h12;
};
uint8_t Date:4; // Day of month, 1 = first day
uint8_t Date10:2;
uint8_t reserved3:2;
uint8_t Month:4; // Month, 1 = January
uint8_t Month10:1;
uint8_t reserved4:3;
uint8_t Day:3; // Day of week, 1 = first day (any day)
uint8_t reserved5:5;
uint8_t Year:4; // Year, 0 = year 2000
uint8_t Year10:4;
uint8_t reserved6:7;
uint8_t WP:1; // WP = Write Protect
};
void setup()
{
ds1302_struct rtc;
Serial.begin(9600);
Serial.println(F("DS1302 Real Time Clock"));
Serial.println(F("Version 2, March 2013"));
// Start by clearing the Write Protect bit
// Otherwise the clock data cannot be written
// The whole register is written,
// but the WP-bit is the only bit in that register.
DS1302_write (DS1302_ENABLE, 0);
// Disable Trickle Charger.
DS1302_write (DS1302_TRICKLE, 0x00);
// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE
// Fill these variables with the date and time.
int seconds, minutes, hours, dayofweek, dayofmonth, month, year;
// Example for april 15, 2013, 10:08, monday is 2nd day of Week.
// Set your own time and date in these variables.
seconds = 0;
minutes = 29;
hours = 19;
dayofweek = 2; // Day of week, any day can be first, counts 1...7
dayofmonth = 14; // Day of month, 1...31
month = 3; // month 1...12
year = 2013;
// Set a time and date
// This also clears the CH (Clock Halt) bit,
// to start the clock.
// Fill the structure with zeros to make
// any unused bits zero
memset ((char *) &rtc, 0, sizeof(rtc));
rtc.Seconds = bin2bcd_l( seconds);
rtc.Seconds10 = bin2bcd_h( seconds);
rtc.CH = 0; // 1 for Clock Halt, 0 to run;
rtc.Minutes = bin2bcd_l( minutes);
rtc.Minutes10 = bin2bcd_h( minutes);
// To use the 12 hour format,
// use it like these four lines:
// rtc.h12.Hour = bin2bcd_l( hours);
// rtc.h12.Hour10 = bin2bcd_h( hours);
// rtc.h12.AM_PM = 0; // AM = 0
// rtc.h12.hour_12_24 = 1; // 1 for 24 hour format
rtc.h24.Hour = bin2bcd_l( hours);
rtc.h24.Hour10 = bin2bcd_h( hours);
rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
rtc.Date = bin2bcd_l( dayofmonth);
rtc.Date10 = bin2bcd_h( dayofmonth);
rtc.Month = bin2bcd_l( month);
rtc.Month10 = bin2bcd_h( month);
rtc.Day = dayofweek;
rtc.Year = bin2bcd_l( year - 2000);
rtc.Year10 = bin2bcd_h( year - 2000);
rtc.WP = 0;
// Write all clock data at once (burst mode).
DS1302_clock_burst_write( (uint8_t *) &rtc);
#endif
}
void loop()
{
ds1302_struct rtc;
char buffer[80]; // the code uses 70 characters.
// Read all clock data at once (burst mode).
DS1302_clock_burst_read( (uint8_t *) &rtc);
sprintf( buffer, "Time = %02d:%02d:%02d, ", \
bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
bcd2bin( rtc.Minutes10, rtc.Minutes), \
bcd2bin( rtc.Seconds10, rtc.Seconds));
Serial.print(buffer);
sprintf(buffer, "Date(day of month) = %d, Month = %d, " \
"Day(day of week) = %d, Year = %d", \
bcd2bin( rtc.Date10, rtc.Date), \
bcd2bin( rtc.Month10, rtc.Month), \
rtc.Day, \
2000 + bcd2bin( rtc.Year10, rtc.Year));
Serial.println( buffer);
delay( 5000);
}
// --------------------------------------------------------
// DS1302_clock_burst_read
//
// This function reads 8 bytes clock data in burst mode
// from the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_read( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_READ command is issued
// the I/O-line is released for the data
_DS1302_togglewrite( DS1302_CLOCK_BURST_READ, true);
for( i=0; i<8; i++)
{
*p++ = _DS1302_toggleread();
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_clock_burst_write
//
// This function writes 8 bytes clock data in burst mode
// to the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_write( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_WRITE command is issued.
// the I/O-line is not released
_DS1302_togglewrite( DS1302_CLOCK_BURST_WRITE, false);
for( i=0; i<8; i++)
{
// the I/O-line is not released
_DS1302_togglewrite( *p++, false);
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_read
//
// This function reads a byte from the DS1302
// (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is set anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
uint8_t DS1302_read(int address)
{
uint8_t data;
// set lowest bit (read bit) in address
bitSet( address, DS1302_READBIT);
_DS1302_start();
// the I/O-line is released for the data
_DS1302_togglewrite( address, true);
data = _DS1302_toggleread();
_DS1302_stop();
return (data);
}
// --------------------------------------------------------
// DS1302_write
//
// This function writes a byte to the DS1302 (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is cleared anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_write( int address, uint8_t data)
{
// clear lowest bit (read bit) in address
bitClear( address, DS1302_READBIT);
_DS1302_start();
// don't release the I/O-line
_DS1302_togglewrite( address, false);
// don't release the I/O-line
_DS1302_togglewrite( data, false);
_DS1302_stop();
}
// --------------------------------------------------------
// _DS1302_start
//
// A helper function to setup the start condition.
//
// An 'init' function is not used.
// But now the pinMode is set every time.
// That's not a big deal, and it's valid.
// At startup, the pins of the Arduino are high impedance.
// Since the DS1302 has pull-down resistors,
// the signals are low (inactive) until the DS1302 is used.
void _DS1302_start( void)
{
digitalWrite( DS1302_CE_PIN, LOW); // default, not enabled
pinMode( DS1302_CE_PIN, OUTPUT);
digitalWrite( DS1302_SCLK_PIN, LOW); // default, clock low
pinMode( DS1302_SCLK_PIN, OUTPUT);
pinMode( DS1302_IO_PIN, OUTPUT);
digitalWrite( DS1302_CE_PIN, HIGH); // start the session
delayMicroseconds( 4); // tCC = 4us
}
// --------------------------------------------------------
// _DS1302_stop
//
// A helper function to finish the communication.
//
void _DS1302_stop(void)
{
// Set CE low
digitalWrite( DS1302_CE_PIN, LOW);
delayMicroseconds( 4); // tCWH = 4us
}
// --------------------------------------------------------
// _DS1302_toggleread
//
// A helper function for reading a byte with bit toggle
//
// This function assumes that the SCLK is still high.
//
uint8_t _DS1302_toggleread( void)
{
uint8_t i, data;
data = 0;
for( i = 0; i <= 7; i++)
{
// Issue a clock pulse for the next databit.
// If the 'togglewrite' function was used before
// this function, the SCLK is already high.
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1);
// Clock down, data is ready after some time.
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
// read bit, and set it in place in 'data' variable
bitWrite( data, i, digitalRead( DS1302_IO_PIN));
}
return( data);
}
// --------------------------------------------------------
// _DS1302_togglewrite
//
// A helper function for writing a byte with bit toggle
//
// The 'release' parameter is for a read after this write.
// It will release the I/O-line and will keep the SCLK high.
//
void _DS1302_togglewrite( uint8_t data, uint8_t release)
{
int i;
for( i = 0; i <= 7; i++)
{
// set a bit of the data on the I/O-line
digitalWrite( DS1302_IO_PIN, bitRead(data, i));
delayMicroseconds( 1); // tDC = 200ns
// clock up, data is read by DS1302
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1); // tCH = 1000ns, tCDH = 800ns
if( release && i == 7)
{
// If this write is followed by a read,
// the I/O-line should be released after
// the last bit, before the clock line is made low.
// This is according the datasheet.
// I have seen other programs that don't release
// the I/O-line at this moment,
// and that could cause a shortcut spike
// on the I/O-line.
pinMode( DS1302_IO_PIN, INPUT);
// For Arduino 1.0.3, removing the pull-up is no longer needed.
// Setting the pin as 'INPUT' will already remove the pull-up.
// digitalWrite (DS1302_IO, LOW); // remove any pull-up
}
else
{
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
}
}
}
Per supplire a questa funzione si puo' accoppiare un circiuto esterno di RTC (Real Time Clcok) basata sull'integrato DS1302.In commercio esistono delle schedine che integrano il DS1302 e le connessioni di base.
Si faccia presente che il nome dei piedini (ma non la funzione)puo' cambiare per cui le indicazioni presenti sulle foto possono non corrispondere a tutte le schede DS1302 (in particolare il pin Reset si puo' chiamare Chip Enable)
I collegamenti con la Arduino sono
SCLK_PIN 6 // Pin Digitale 6 Serial Clock
IO_PIN 7 // Pin Digitale 7 Data I/O
CE_PIN 8 // Pin Digitale 8 Chip Enable
in piu' si devono inserire i due cavi di alimentazione
-----------------------------------------------------------------------------
#include <Wire.h>
// DS1302 RTC
// ----------
//
// Open Source / Public Domain
//
// Version 1
// By arduino.cc user "Krodal".
// June 2012
// Using Arduino 1.0.1
// Version 2
// By arduino.cc user "Krodal"
// March 2013
// Using Arduino 1.0.3, 1.5.2
// The code is no longer compatible with older versions.
// Added bcd2bin, bin2bcd_h, bin2bcd_l
// A few minor changes.
//
//
// Documentation: datasheet
//
// The DS1302 uses a 3-wire interface:
// - bidirectional data.
// - clock
// - chip select
// It is not I2C, not OneWire, and not SPI.
// So the standard libraries can not be used.
// Even the shiftOut() function is not used, since it
// could be too fast (it might be slow enough,
// but that's not certain).
//
// I wrote my own interface code according to the datasheet.
// Any three pins of the Arduino can be used.
// See the first defines below this comment,
// to set your own pins.
//
// The "Chip Enable" pin was called "/Reset" before.
//
// The chip has internal pull-down registers.
// This keeps the chip disabled, even if the pins of
// the Arduino are floating.
//
//
// Range
// -----
// seconds : 00-59
// minutes : 00-59
// hour : 1-12 or 0-23
// date : 1-31
// month : 1-12
// day : 1-7
// year : 00-99
//
//
// Burst mode
// ----------
// In burst mode, all the clock data is read at once.
// This is to prevent a rollover of a digit during reading.
// The read data is from an internal buffer.
//
// The burst registers are commands, rather than addresses.
// Clock Data Read in Burst Mode
// Start by writing 0xBF (as the address),
// after that: read clock data
// Clock Data Write in Burst Mode
// Start by writing 0xBE (as the address),
// after that: write clock data
// Ram Data Read in Burst Mode
// Start by writing 0xFF (as the address),
// after that: read ram data
// Ram Data Write in Burst Mode
// Start by writing 0xFE (as the address),
// after that: write ram data
//
//
// Ram
// ---
// The DS1302 has 31 of ram, which can be used to store data.
// The contents will be lost if the Arduino is off,
// and the backup battery gets empty.
// It is better to store data in the EEPROM of the Arduino.
// The burst read or burst write for ram is not implemented
// in this code.
//
//
// Trickle charge
// --------------
// The DS1302 has a build-in trickle charger.
// That can be used for example with a lithium battery
// or a supercap.
// Using the trickle charger has not been implemented
// in this code.
//
// Set your own pins with these defines !
#define DS1302_SCLK_PIN 6 // Arduino pin for the Serial Clock
#define DS1302_IO_PIN 7 // Arduino pin for the Data I/O
#define DS1302_CE_PIN 8 // Arduino pin for the Chip Enable
// Macros to convert the bcd values of the registers to normal
// integer variables.
// The code uses seperate variables for the high byte and the low byte
// of the bcd, so these macros handle both bytes seperately.
#define bcd2bin(h,l) (((h)*10) + (l))
#define bin2bcd_h(x) ((x)/10)
#define bin2bcd_l(x) ((x)%10)
// Register names.
// Since the highest bit is always '1',
// the registers start at 0x80
// If the register is read, the lowest bit should be '1'.
#define DS1302_SECONDS 0x80
#define DS1302_MINUTES 0x82
#define DS1302_HOURS 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_ENABLE 0x8E
#define DS1302_TRICKLE 0x90
#define DS1302_CLOCK_BURST 0xBE
#define DS1302_CLOCK_BURST_WRITE 0xBE
#define DS1302_CLOCK_BURST_READ 0xBF
#define DS1302_RAMSTART 0xC0
#define DS1302_RAMEND 0xFC
#define DS1302_RAM_BURST 0xFE
#define DS1302_RAM_BURST_WRITE 0xFE
#define DS1302_RAM_BURST_READ 0xFF
// Defines for the bits, to be able to change
// between bit number and binary definition.
// By using the bit number, using the DS1302
// is like programming an AVR microcontroller.
// But instead of using "(1<<X)", or "_BV(X)",
// the Arduino "bit(X)" is used.
#define DS1302_D0 0
#define DS1302_D1 1
#define DS1302_D2 2
#define DS1302_D3 3
#define DS1302_D4 4
#define DS1302_D5 5
#define DS1302_D6 6
#define DS1302_D7 7
// Bit for reading (bit in address)
#define DS1302_READBIT DS1302_D0 // READBIT=1: read instruction
// Bit for clock (0) or ram (1) area,
// called R/C-bit (bit in address)
#define DS1302_RC DS1302_D6
// Seconds Register
#define DS1302_CH DS1302_D7 // 1 = Clock Halt, 0 = start
// Hour Register
#define DS1302_AM_PM DS1302_D5 // 0 = AM, 1 = PM
#define DS1302_12_24 DS1302 D7 // 0 = 24 hour, 1 = 12 hour
// Enable Register
#define DS1302_WP DS1302_D7 // 1 = Write Protect, 0 = enabled
// Trickle Register
#define DS1302_ROUT0 DS1302_D0
#define DS1302_ROUT1 DS1302_D1
#define DS1302_DS0 DS1302_D2
#define DS1302_DS1 DS1302_D2
#define DS1302_TCS0 DS1302_D4
#define DS1302_TCS1 DS1302_D5
#define DS1302_TCS2 DS1302_D6
#define DS1302_TCS3 DS1302_D7
// Structure for the first 8 registers.
// These 8 bytes can be read at once with
// the 'clock burst' command.
// Note that this structure contains an anonymous union.
// It might cause a problem on other compilers.
typedef struct ds1302_struct
{
uint8_t Seconds:4; // low decimal digit 0-9
uint8_t Seconds10:3; // high decimal digit 0-5
uint8_t CH:1; // CH = Clock Halt
uint8_t Minutes:4;
uint8_t Minutes10:3;
uint8_t reserved1:1;
union
{
struct
{
uint8_t Hour:4;
uint8_t Hour10:2;
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 0 for 24 hour format
} h24;
struct
{
uint8_t Hour:4;
uint8_t Hour10:1;
uint8_t AM_PM:1; // 0 for AM, 1 for PM
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 1 for 12 hour format
} h12;
};
uint8_t Date:4; // Day of month, 1 = first day
uint8_t Date10:2;
uint8_t reserved3:2;
uint8_t Month:4; // Month, 1 = January
uint8_t Month10:1;
uint8_t reserved4:3;
uint8_t Day:3; // Day of week, 1 = first day (any day)
uint8_t reserved5:5;
uint8_t Year:4; // Year, 0 = year 2000
uint8_t Year10:4;
uint8_t reserved6:7;
uint8_t WP:1; // WP = Write Protect
};
void setup()
{
ds1302_struct rtc;
Serial.begin(9600);
Serial.println(F("DS1302 Real Time Clock"));
Serial.println(F("Version 2, March 2013"));
// Start by clearing the Write Protect bit
// Otherwise the clock data cannot be written
// The whole register is written,
// but the WP-bit is the only bit in that register.
DS1302_write (DS1302_ENABLE, 0);
// Disable Trickle Charger.
DS1302_write (DS1302_TRICKLE, 0x00);
// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE
// Fill these variables with the date and time.
int seconds, minutes, hours, dayofweek, dayofmonth, month, year;
// Example for april 15, 2013, 10:08, monday is 2nd day of Week.
// Set your own time and date in these variables.
seconds = 0;
minutes = 29;
hours = 19;
dayofweek = 2; // Day of week, any day can be first, counts 1...7
dayofmonth = 14; // Day of month, 1...31
month = 3; // month 1...12
year = 2013;
// Set a time and date
// This also clears the CH (Clock Halt) bit,
// to start the clock.
// Fill the structure with zeros to make
// any unused bits zero
memset ((char *) &rtc, 0, sizeof(rtc));
rtc.Seconds = bin2bcd_l( seconds);
rtc.Seconds10 = bin2bcd_h( seconds);
rtc.CH = 0; // 1 for Clock Halt, 0 to run;
rtc.Minutes = bin2bcd_l( minutes);
rtc.Minutes10 = bin2bcd_h( minutes);
// To use the 12 hour format,
// use it like these four lines:
// rtc.h12.Hour = bin2bcd_l( hours);
// rtc.h12.Hour10 = bin2bcd_h( hours);
// rtc.h12.AM_PM = 0; // AM = 0
// rtc.h12.hour_12_24 = 1; // 1 for 24 hour format
rtc.h24.Hour = bin2bcd_l( hours);
rtc.h24.Hour10 = bin2bcd_h( hours);
rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
rtc.Date = bin2bcd_l( dayofmonth);
rtc.Date10 = bin2bcd_h( dayofmonth);
rtc.Month = bin2bcd_l( month);
rtc.Month10 = bin2bcd_h( month);
rtc.Day = dayofweek;
rtc.Year = bin2bcd_l( year - 2000);
rtc.Year10 = bin2bcd_h( year - 2000);
rtc.WP = 0;
// Write all clock data at once (burst mode).
DS1302_clock_burst_write( (uint8_t *) &rtc);
#endif
}
void loop()
{
ds1302_struct rtc;
char buffer[80]; // the code uses 70 characters.
// Read all clock data at once (burst mode).
DS1302_clock_burst_read( (uint8_t *) &rtc);
sprintf( buffer, "Time = %02d:%02d:%02d, ", \
bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
bcd2bin( rtc.Minutes10, rtc.Minutes), \
bcd2bin( rtc.Seconds10, rtc.Seconds));
Serial.print(buffer);
sprintf(buffer, "Date(day of month) = %d, Month = %d, " \
"Day(day of week) = %d, Year = %d", \
bcd2bin( rtc.Date10, rtc.Date), \
bcd2bin( rtc.Month10, rtc.Month), \
rtc.Day, \
2000 + bcd2bin( rtc.Year10, rtc.Year));
Serial.println( buffer);
delay( 5000);
}
// --------------------------------------------------------
// DS1302_clock_burst_read
//
// This function reads 8 bytes clock data in burst mode
// from the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_read( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_READ command is issued
// the I/O-line is released for the data
_DS1302_togglewrite( DS1302_CLOCK_BURST_READ, true);
for( i=0; i<8; i++)
{
*p++ = _DS1302_toggleread();
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_clock_burst_write
//
// This function writes 8 bytes clock data in burst mode
// to the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_write( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_WRITE command is issued.
// the I/O-line is not released
_DS1302_togglewrite( DS1302_CLOCK_BURST_WRITE, false);
for( i=0; i<8; i++)
{
// the I/O-line is not released
_DS1302_togglewrite( *p++, false);
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_read
//
// This function reads a byte from the DS1302
// (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is set anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
uint8_t DS1302_read(int address)
{
uint8_t data;
// set lowest bit (read bit) in address
bitSet( address, DS1302_READBIT);
_DS1302_start();
// the I/O-line is released for the data
_DS1302_togglewrite( address, true);
data = _DS1302_toggleread();
_DS1302_stop();
return (data);
}
// --------------------------------------------------------
// DS1302_write
//
// This function writes a byte to the DS1302 (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is cleared anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_write( int address, uint8_t data)
{
// clear lowest bit (read bit) in address
bitClear( address, DS1302_READBIT);
_DS1302_start();
// don't release the I/O-line
_DS1302_togglewrite( address, false);
// don't release the I/O-line
_DS1302_togglewrite( data, false);
_DS1302_stop();
}
// --------------------------------------------------------
// _DS1302_start
//
// A helper function to setup the start condition.
//
// An 'init' function is not used.
// But now the pinMode is set every time.
// That's not a big deal, and it's valid.
// At startup, the pins of the Arduino are high impedance.
// Since the DS1302 has pull-down resistors,
// the signals are low (inactive) until the DS1302 is used.
void _DS1302_start( void)
{
digitalWrite( DS1302_CE_PIN, LOW); // default, not enabled
pinMode( DS1302_CE_PIN, OUTPUT);
digitalWrite( DS1302_SCLK_PIN, LOW); // default, clock low
pinMode( DS1302_SCLK_PIN, OUTPUT);
pinMode( DS1302_IO_PIN, OUTPUT);
digitalWrite( DS1302_CE_PIN, HIGH); // start the session
delayMicroseconds( 4); // tCC = 4us
}
// --------------------------------------------------------
// _DS1302_stop
//
// A helper function to finish the communication.
//
void _DS1302_stop(void)
{
// Set CE low
digitalWrite( DS1302_CE_PIN, LOW);
delayMicroseconds( 4); // tCWH = 4us
}
// --------------------------------------------------------
// _DS1302_toggleread
//
// A helper function for reading a byte with bit toggle
//
// This function assumes that the SCLK is still high.
//
uint8_t _DS1302_toggleread( void)
{
uint8_t i, data;
data = 0;
for( i = 0; i <= 7; i++)
{
// Issue a clock pulse for the next databit.
// If the 'togglewrite' function was used before
// this function, the SCLK is already high.
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1);
// Clock down, data is ready after some time.
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
// read bit, and set it in place in 'data' variable
bitWrite( data, i, digitalRead( DS1302_IO_PIN));
}
return( data);
}
// --------------------------------------------------------
// _DS1302_togglewrite
//
// A helper function for writing a byte with bit toggle
//
// The 'release' parameter is for a read after this write.
// It will release the I/O-line and will keep the SCLK high.
//
void _DS1302_togglewrite( uint8_t data, uint8_t release)
{
int i;
for( i = 0; i <= 7; i++)
{
// set a bit of the data on the I/O-line
digitalWrite( DS1302_IO_PIN, bitRead(data, i));
delayMicroseconds( 1); // tDC = 200ns
// clock up, data is read by DS1302
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1); // tCH = 1000ns, tCDH = 800ns
if( release && i == 7)
{
// If this write is followed by a read,
// the I/O-line should be released after
// the last bit, before the clock line is made low.
// This is according the datasheet.
// I have seen other programs that don't release
// the I/O-line at this moment,
// and that could cause a shortcut spike
// on the I/O-line.
pinMode( DS1302_IO_PIN, INPUT);
// For Arduino 1.0.3, removing the pull-up is no longer needed.
// Setting the pin as 'INPUT' will already remove the pull-up.
// digitalWrite (DS1302_IO, LOW); // remove any pull-up
}
else
{
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
}
}
}
giovedì 21 marzo 2013
Rele' su Arduino
Come indicato in un precedente post non e' banalissimo applicare un rele' direttamente ad una Arduino
In commercio esistono delle schedine con integrato un rele' che funzionano con Arduino ad un costo peraltro inferiore all'acquisto di un singolo rele'
Il programma per pilotare il rele' e' identico all'esempio Blink della IDE di Arduino
In pratica si deve connettere tre cavi: VCC, GND in modo ovvio mentre il cavo Signale si connette ad un pin digitale (nell'esempio al Pin Digitale 1)
---------------------------------------------------------------
void setup(){
pinMode(1,OUTPUT);
}
void loop(){
digitalWrite(1,HIGH);
delay(1000);
digitalWrite(1,LOW);
delay(1000);
}
In commercio esistono delle schedine con integrato un rele' che funzionano con Arduino ad un costo peraltro inferiore all'acquisto di un singolo rele'
Il programma per pilotare il rele' e' identico all'esempio Blink della IDE di Arduino
In pratica si deve connettere tre cavi: VCC, GND in modo ovvio mentre il cavo Signale si connette ad un pin digitale (nell'esempio al Pin Digitale 1)
---------------------------------------------------------------
void setup(){
pinMode(1,OUTPUT);
}
void loop(){
digitalWrite(1,HIGH);
delay(1000);
digitalWrite(1,LOW);
delay(1000);
}
LCD su Arduino
Per questa prova ho utilizzato un display LCD di 16 caratteri su due righe che ha connessione I2C
In realta' confrontando la foto in basso si osserva come il display LCD standard e quello I2C sono sostanzialmente uguali a meno della piccola schedina rossa che e' aggiunta nella versione I2C
La connessione del modello I2C avviene come al solito ai contatti SDA,SCL, VCC e GND (Pin 4, Pin5 rispettivamente per SDA ed SDC su Arduino Uno)
Per utilizzare questo componente con Arduino e' sufficiente utilizzare la libreria LiquidCrystal_I2C (attenzione ne esistono differenti versioni a seconda del controller I2C montato sul display, ho fatto diverse prove prima di trovare la versione giusta che per me e' stata questa, in caso di problemi con la libreria lo schermo lampeggia o mostra una sola riga di caratteri a blocco)
I comandi sono piuttosto limitati e semplici (per esempio SetCursor manda il cursore ad una determinata coordinata dello schermo)
Un difettto che ho potuto verificare e' il tempo di refresh piuttosto lungo del display (al di sotto dei 500 millisecondi i caratteri flickerano in modo vistoso e fastidioso)
----------------------------------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
lcd.init(); // initialize the lcd
/lcd.backlight();
lcd.print("Hello, Luca");
}
void loop()
{
}
In realta' confrontando la foto in basso si osserva come il display LCD standard e quello I2C sono sostanzialmente uguali a meno della piccola schedina rossa che e' aggiunta nella versione I2C
In alto display con connessione standard, in basso I2C |
La connessione del modello I2C avviene come al solito ai contatti SDA,SCL, VCC e GND (Pin 4, Pin5 rispettivamente per SDA ed SDC su Arduino Uno)
Per utilizzare questo componente con Arduino e' sufficiente utilizzare la libreria LiquidCrystal_I2C (attenzione ne esistono differenti versioni a seconda del controller I2C montato sul display, ho fatto diverse prove prima di trovare la versione giusta che per me e' stata questa, in caso di problemi con la libreria lo schermo lampeggia o mostra una sola riga di caratteri a blocco)
I comandi sono piuttosto limitati e semplici (per esempio SetCursor manda il cursore ad una determinata coordinata dello schermo)
Un difettto che ho potuto verificare e' il tempo di refresh piuttosto lungo del display (al di sotto dei 500 millisecondi i caratteri flickerano in modo vistoso e fastidioso)
----------------------------------------------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup()
{
lcd.init(); // initialize the lcd
/lcd.backlight();
lcd.print("Hello, Luca");
}
void loop()
{
}
Installare Arduino IDE su Debian
UPDATE
-------------------------------------------------------
Soluzione ultrarapida per Debian Testing
apt-get install arduino
al momento della scrittura il pacchetto corrisponde ad Arduino IDE 1.0.1 mentre sul sito
Arduino l'ultima stable e' 1.0.4
-------------------------------------------------------
Dato che era un po' di tempo che non giocavo piu' con Arduino ho dovuto reinstallare tutto il sistema di sviluppo sulla mia Debian Box
supponendo di avere gia' Java configurato e' sufficiente digitare
apt-get install openjdk-6-jre gcc-avr avr-libc avrdude
usermod -a -G dialout yourUserName
-------------------------------------------------------
Soluzione ultrarapida per Debian Testing
apt-get install arduino
al momento della scrittura il pacchetto corrisponde ad Arduino IDE 1.0.1 mentre sul sito
Arduino l'ultima stable e' 1.0.4
-------------------------------------------------------
Dato che era un po' di tempo che non giocavo piu' con Arduino ho dovuto reinstallare tutto il sistema di sviluppo sulla mia Debian Box
supponendo di avere gia' Java configurato e' sufficiente digitare
apt-get install openjdk-6-jre gcc-avr avr-libc avrdude
per poter compilare i programmi.
A questo punto si puo' scaricare e decomprimere il pacchetto della IDE di Arduino per iniziare a programmare.
Una accortezza: per problemi di permessi non e' possibile di default effettuare l'upload degli sketch sulla scheda perche' i permessi dell'utente normale non permettono di accedere alle porte seriali (virtuali o reali che siano)
Per operare con il proprio utente (e non come superuser) si dovranno modificare i permessi come segue
------------------------------------------------------
usermod -a -G tty yourUserNameusermod -a -G dialout yourUserName
Modulo rele' con Bluetooth
Questo modulo a 4 rele' viene normalmente associato ad Arduino ma in realta' ha ben poco da spartire le note schede opensource principalmente perche' in grado di vivere da solo senza l'appoggio a nessun altro apparato
Il sistema monta puo' essere interfacciato sia via cavo USB o via Bluetooth (in questo caso un modulo Bluetooth Bee rimuovibile che puo' essere sostituito anche da ZigBee); la selezione avviene mediante un microinterruttore a slitta parzialmente nascosto sotto il modulo Bluetooth
In entrambi i casi il sistema si interfaccia come una porta seriale a cui inviare dei caratteri che corrispondono all'apertura e chiusura dei circuiti dei rele' secondo lo schema della immagine seguente
La password per accoppiare il modulo Bluetooth e' 1234
L'alimentazione puo' derivare dalla porta microUSB oppure da una fonte esterna (jack sulla destra nella foto)
Il sistema monta puo' essere interfacciato sia via cavo USB o via Bluetooth (in questo caso un modulo Bluetooth Bee rimuovibile che puo' essere sostituito anche da ZigBee); la selezione avviene mediante un microinterruttore a slitta parzialmente nascosto sotto il modulo Bluetooth
In entrambi i casi il sistema si interfaccia come una porta seriale a cui inviare dei caratteri che corrispondono all'apertura e chiusura dei circuiti dei rele' secondo lo schema della immagine seguente
La password per accoppiare il modulo Bluetooth e' 1234
L'alimentazione puo' derivare dalla porta microUSB oppure da una fonte esterna (jack sulla destra nella foto)
In alto il microinterruttore a slitta |
Pulsante Done su EditText
Puo' essere comodo far sparire la tastiera e gestire l'evento una volta che e' stato premuto il tasto Done sulla tastiera virtuale di una Edit Text
Il trucco e' quello di attivare un OnEditorActionListener come nel breve listato che segue
---------------------------------------------------------------------------------
EditText test = (EditText) findViewById(R.id.editText1);
test.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
Log.d("test","Premuto il tasto Done");
}
return false;
}});
martedì 19 marzo 2013
Mantenere lo schermo acceso in Android
Per mantenere lo schermo acceso in una applicazione Android si puo' aggiungere la seguente riga nella funzione OnCreate
------------------------------------
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Wav file in Android
Per emettere suoni in un programma Android la prima cosa da fare e' trovare un file con il suono desiderato.
Una ottima fonte di suoni gratuiti e' Freesound.org
Una volta scaricato il file wav si clicca sulla cartella /res del progetto e si crea un nuovo folder denominato raw (si avra' quindi /res/raw) dove si copia il file del suono
a questo punto si puo' inserire questa funzione (copiata da qui) dove il suono in questo caso e' chiamato beep (da notare che si omette l'estensione)
-------------------------------------------------------------
private void playAlarm() {
MediaPlayer mp = MediaPlayer.create(this,R.raw.beep);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
Una ottima fonte di suoni gratuiti e' Freesound.org
Una volta scaricato il file wav si clicca sulla cartella /res del progetto e si crea un nuovo folder denominato raw (si avra' quindi /res/raw) dove si copia il file del suono
a questo punto si puo' inserire questa funzione (copiata da qui) dove il suono in questo caso e' chiamato beep (da notare che si omette l'estensione)
-------------------------------------------------------------
private void playAlarm() {
MediaPlayer mp = MediaPlayer.create(this,R.raw.beep);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
giovedì 14 marzo 2013
martedì 12 marzo 2013
Esempio di utilizzo di Itext in Java
Presento adesso un esempio reale dell'utilizzo della libreria IText per la creazione di pettorali per una corsa podistica.
La caratteristica dei pettorali era quella di dover contenere, oltre al numero, anche il relativo QrCode. Il pettorale e' quindi determinato dalla sovrapposizione di una immagine di base con i logo, il QrCode ed il numero. Il tutto e' gia' formattato per andare direttamente in tipografia (il foglio in formato Super A3 comprende 4 numeri che saranno successivamente tagliati)
Il codice per la generazione dei Pdf e' il seguente. Si deve precisare che le immagini dei QrCode erano gia' state create con il programma presentato in un precedente post e viene usato un font speciale (CITYB.ttf)
----------------------------------------------------------------------
package pettorale;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
/**
*
* @author l.innocenti
*/
public class Pettorale {
private static PdfWriter writer;
public static void main(String[] args) throws BadElementException, MalformedURLException, IOException {
//String numero = args[0];
String numero = "175";
int inizio = Integer.parseInt(numero);
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream (new FileOutputStream (new File ("Pettorale_"+numero+"_"+Integer.toString(inizio+3) +".pdf")));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//Definisce le dimensioni del foglio come SuperA3 (45x32 cm)
//Itext usa una unita' di misura in punti tipografici
//1 cm = 28.35 unita' per cui le dimesioni del foglio sono
//45 cm = 1285 u
//32 cm = 907 u
Rectangle pagina = new Rectangle(1275, 907);
Document doc = new Document (pagina,0,0,0,0);
try
{
writer = PdfWriter.getInstance (doc, out);
doc.open ();
PdfContentByte canvas = writer.getDirectContent();
//inserisce lo sfondo
Image pettorale = Image.getInstance("pettorale/vuoto.png");
pettorale.setAbsolutePosition(0f, 0f);
pettorale.scalePercent(24.5f);
doc.add(pettorale);
//inserisce il QrCode del numero del pettorale
Image qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio) +".png");
qrcode.setAbsolutePosition(475f, 620f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//2° numero
qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio+1) +".png");
qrcode.setAbsolutePosition(1125f, 620f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//3° numero
qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio+2) +".png");
qrcode.setAbsolutePosition(475f, 170f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//4° numero
qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio+3) +".png");
qrcode.setAbsolutePosition(1125f, 170f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//scrive il numero del pettorale alla giusta posizione
//1° numero
if (inizio <10) {
absText(Integer.toString(inizio),270,625);
}
if ((inizio >=10) && (inizio <= 99)) {
absText(Integer.toString(inizio),235,625);
}
if ((inizio >=100) && (inizio <= 999)) {
absText(Integer.toString(inizio),150,625);
}
//2°numero
if (inizio+1 <10) {
absText(Integer.toString(inizio+1),920,625);
}
if ((inizio+1 >=10) && (inizio+1 <= 99)) {
absText(Integer.toString(inizio+1),885,625);
}
if ((inizio+1 >=100) && (inizio+1 <= 999)) {
absText(Integer.toString(inizio+1),790,625);
}
//3°numero
if (inizio+2 <10) {
absText(Integer.toString(inizio+2),270,165);
}
if ((inizio+2 >=10) && (inizio+2 <= 99)) {
absText(Integer.toString(inizio+2),235,165);
}
if ((inizio+2 >=100) && (inizio+2 <= 999)) {
absText(Integer.toString(inizio+2),150,165);
}
//4°numero
if (inizio+3 <10) {
absText(Integer.toString(inizio+3),920,165);
}
if ((inizio+3 >=10) && (inizio+3 <= 99)) {
absText(Integer.toString(inizio+3),885,165);
}
if ((inizio+3 >=100) && (inizio+3 <= 999)) {
absText(Integer.toString(inizio+3),790,165);
}
}
catch (DocumentException e)
{
System.out.println ("Fatal PDF error: " + e);
}
doc.close ();
}
private static void absText(String text, int x, int y) {
try {
PdfContentByte cb = writer.getDirectContent();
BaseFont slam = BaseFont.createFont("CITYB.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
cb.saveState();
cb.beginText();
cb.moveText(x, y);
cb.setFontAndSize(slam, 200);
cb.showText(text);
cb.endText();
cb.restoreState();
} catch (DocumentException | IOException e) {
}
}
}
La caratteristica dei pettorali era quella di dover contenere, oltre al numero, anche il relativo QrCode. Il pettorale e' quindi determinato dalla sovrapposizione di una immagine di base con i logo, il QrCode ed il numero. Il tutto e' gia' formattato per andare direttamente in tipografia (il foglio in formato Super A3 comprende 4 numeri che saranno successivamente tagliati)
Immagine di fondo |
QrCode |
Il risultato finale |
Il codice per la generazione dei Pdf e' il seguente. Si deve precisare che le immagini dei QrCode erano gia' state create con il programma presentato in un precedente post e viene usato un font speciale (CITYB.ttf)
----------------------------------------------------------------------
package pettorale;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
/**
*
* @author l.innocenti
*/
public class Pettorale {
private static PdfWriter writer;
public static void main(String[] args) throws BadElementException, MalformedURLException, IOException {
//String numero = args[0];
String numero = "175";
int inizio = Integer.parseInt(numero);
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream (new FileOutputStream (new File ("Pettorale_"+numero+"_"+Integer.toString(inizio+3) +".pdf")));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//Definisce le dimensioni del foglio come SuperA3 (45x32 cm)
//Itext usa una unita' di misura in punti tipografici
//1 cm = 28.35 unita' per cui le dimesioni del foglio sono
//45 cm = 1285 u
//32 cm = 907 u
Rectangle pagina = new Rectangle(1275, 907);
Document doc = new Document (pagina,0,0,0,0);
try
{
writer = PdfWriter.getInstance (doc, out);
doc.open ();
PdfContentByte canvas = writer.getDirectContent();
//inserisce lo sfondo
Image pettorale = Image.getInstance("pettorale/vuoto.png");
pettorale.setAbsolutePosition(0f, 0f);
pettorale.scalePercent(24.5f);
doc.add(pettorale);
//inserisce il QrCode del numero del pettorale
Image qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio) +".png");
qrcode.setAbsolutePosition(475f, 620f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//2° numero
qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio+1) +".png");
qrcode.setAbsolutePosition(1125f, 620f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//3° numero
qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio+2) +".png");
qrcode.setAbsolutePosition(475f, 170f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//4° numero
qrcode = Image.getInstance("qrcode/"+Integer.toString(inizio+3) +".png");
qrcode.setAbsolutePosition(1125f, 170f);
qrcode.scalePercent(120f);
doc.add(qrcode);
//scrive il numero del pettorale alla giusta posizione
//1° numero
if (inizio <10) {
absText(Integer.toString(inizio),270,625);
}
if ((inizio >=10) && (inizio <= 99)) {
absText(Integer.toString(inizio),235,625);
}
if ((inizio >=100) && (inizio <= 999)) {
absText(Integer.toString(inizio),150,625);
}
//2°numero
if (inizio+1 <10) {
absText(Integer.toString(inizio+1),920,625);
}
if ((inizio+1 >=10) && (inizio+1 <= 99)) {
absText(Integer.toString(inizio+1),885,625);
}
if ((inizio+1 >=100) && (inizio+1 <= 999)) {
absText(Integer.toString(inizio+1),790,625);
}
//3°numero
if (inizio+2 <10) {
absText(Integer.toString(inizio+2),270,165);
}
if ((inizio+2 >=10) && (inizio+2 <= 99)) {
absText(Integer.toString(inizio+2),235,165);
}
if ((inizio+2 >=100) && (inizio+2 <= 999)) {
absText(Integer.toString(inizio+2),150,165);
}
//4°numero
if (inizio+3 <10) {
absText(Integer.toString(inizio+3),920,165);
}
if ((inizio+3 >=10) && (inizio+3 <= 99)) {
absText(Integer.toString(inizio+3),885,165);
}
if ((inizio+3 >=100) && (inizio+3 <= 999)) {
absText(Integer.toString(inizio+3),790,165);
}
}
catch (DocumentException e)
{
System.out.println ("Fatal PDF error: " + e);
}
doc.close ();
}
private static void absText(String text, int x, int y) {
try {
PdfContentByte cb = writer.getDirectContent();
BaseFont slam = BaseFont.createFont("CITYB.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
cb.saveState();
cb.beginText();
cb.moveText(x, y);
cb.setFontAndSize(slam, 200);
cb.showText(text);
cb.endText();
cb.restoreState();
} catch (DocumentException | IOException e) {
}
}
}
----------------------------------------------------------------------
Iscriviti a:
Post (Atom)
Debugger integrato ESP32S3
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...