Carte DataLogger
Carte DataLogger
1 But du projet
Le but de ce projet est de réunir sur une même carte un PIC16F876, une horloge temps réel I2C PCF8583,
une EEPROM I2C 24LCXX (XX pouvant varier en fonction de la capacité de celle-ci), un afficheur
alphanumérique LCD 2x16 caractères, deux boutons poussoirs et un buzzer. De plus il faut pouvoir
numériser 5 tensions analogiques et dialoguer/recevoir des informations par la voie série du PIC.
Ainsi nous pourrons numériser cinq capteurs analogiques, stocker les valeurs obtenues dans l'EEPROM pour
pouvoir les restituer par la suite vers un PC par le biais de la voie série. L'afficheur LCD permet un dialogue
direct avec l'utilisateur : le système est donc complétement autonome. En l'abscence de dialogue avec un PC
la voie série sera reliée à un module radio 433MHz pour pouvoir recevoir des informations d'un capteur
éloigné ou des ordres d'une télécommande radio.
L'horloge temps réel permet de dater chaque évenement et donc ainsi de suivre l'évolution dans le temps des
5 tensions analogiques (6 en comptant la voie série) que peut numériser le PIC.
Le choix du délai entre deux mesures, le nombre d'entrées à numériser, le réglage de l'heure de l'horloge
temps réel, la communication avec un PC se feront à l'aide des deux boutons disponibles sur la carte avec un
dialogue avec l'utilisateur par le biais de l'afficheur LCD.
L'horloge temps réel aura une alimentation de secours sur piles ce qui permet même lorsque le PIC n'est plus
alimenté de ne pas perdre l'heure et donc de ne pas avoir à la régler à chaque extinction.
Chaque entrée analogique dispose d'un connecteur 3 points avec le +5V, la donnée a numériser et la masse
pour pouvoir connecter facilement des platines externes.
Ce type de montage porte aussi très souvent le nom de DATALOGGER en anglais.
On peut très bien imaginer d'autres fonctions...toutes les fonctions précédemment énoncées ne sont pas toutes
implantées dans le firmware du PIC. Elles le seront à terme mais pour l'instant cette carte est un peu la base
commune à d'autres montages puisqu'elle est très polyvalente.
Le schéma structurel, l'implantation des composants, le typon (double face), la nomenclature et des exemples
de programmes sont donnés dans les pages suivantes. Et comme une photo vaut mieux qu'un long discours,
un cliché du prototype (qui diverge en certains points du schéma final (par exemple les connecteurs des
entrées analogiques) mais qui a exactement les mêmes fonctions) :
Alimentation
principale (9V)
LCD 2x16
caractères
Buzzer
4 entrées
Voie série pour:
analogiques pour
- envoyer des données vers un PC
capteur (modifié
- recevoir des données d'un capteur
sur le typon final) 5ème entrée
externe (par exemple issu d'une
analogique avec
transmission radio)
+5V et masse
- programmer le PIC avec le logiciel
TinyBootLoader
Carte externe pour
amplification
tension capteur de
température
U2 VDD
7805 16
K6 K
Olivier DARTOIS
1 3
1 VI VO 15
A
GND
R5 R2
VSS
VDD
VEE
RS
RW
E
D0
D1
D2
D3
D4
D5
D6
D7
C4 C5 C6 220
2
2 100 +5V
0.22µF 47µF 0.1µF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
BORVI2
VSS
K3 +Vbatt D2 LS1
LED
1 +5V +5V R3
PB1
PB2
PB0
PB4
PB5
PB6
PB7
D1 4.7K
2 D3 BUZ
1N4148
+5V
ALIM_PILE P1
+5V
1N4148 10K +5V +Vbatt
U3 R4 Q1
FREQ=32.768KHz PC0 BC337
1 8 Condo découplage CMS
OSC1 VCC 4.7K
X2 2 7
OSC2 INT
C2 (RTC)
3 6
C1 A0 SCL SCL
4 5 C3 C7 C8
22pF 22pF GND SDA SDA +5V
+5V
C1206 C1206 C1206
X1 PCF8583
U1
4MHz
2 Schéma structurel du DataLogger
9 21
OSC1/CLKIN RB0/INT PB0
10 22 +5V
OSC2/CLKOUT RB1 PB1 R8 R9
1 23 +5V +5V
MCLR/Vpp/THV RB2 PB2 U4 2.2K 2.2k
24 J2
RB3/PGM
2 25 1 8
AN0 RA0/AN0 RB4 PB4 A0 VCC
3 26 2 7
AN1 RA1/AN1 RB5 PB5 3 A1 WP
4 27 AN0 3
AN2 RA2/AN2/VREF- RB6/PGC PB6 2 A2
I2C
5 28 6
Mémoire
AN3 RA3/AN3/VREF+ RB7/PGD PB7 1 SCL SCL R6 R7
6 4 5
RA4/T0CKI EMBASE-3PT GND SDA SDA 10k 10k
7 11
AN4 RA5/AN4/SS RC0/T1OSO/T1CKI PC0
12 24LCXX
RC1/T1OSI/CCP2 PC1
13
RC2/CCP1 PC2 Capteur Temp
14
RC3/SCK/SCL SCL
15 +5V +5V PC1 PC2
RC4/SDI/SDA SDA
16
R13 R14 RC5/SDO +5V
17 J3 J5
10k 10k RC6/TX/CK
18
RC7/RX/DT J1
+5V K1 K2
3 3
PIC16F876A 1 AN1 AN3 BPT BPT
2 2
2
1 1
3
EMBASE-3PT EMBASE-3PT
4
5 +5V +5V
R1 6
10K 7 J4 J6
8
9
3 3
10 AN2 AN4
2 2 DataLogger
1 1
HE10-10
EMBASE-3PT EMBASE-3PT Olivier DARTOIS ELN2007
turgot serie
Eln 2007
Page 2/13
DataLogger Eln 2007
3 Documents de fabrication
Implantation (échelle 1):
Attention:
● C3, C7 et C8 sont des condensateurs CMS 1206 implantés coté cuivre.
● L'afficheur LCD recouvre U1 (PIC), U3 (RTC) et U4 (EEPROM).
Nomenclature:
Capacitors
----------
2 C1,C2 22pF
3 C3,C7,C8 C1206 (CMS) 100nF
1 C4 0.22µF
1 C5 47µF
1 C6 0.1µF
Integrated Circuits
-------------------
1 U1 PIC16F876A
1 U2 7805
1 U3 PCF8583
1 U4 24LCXX
Transistors
-----------
1 Q1 BC337
Diodes
------
2 D1,D3 1N4148
1 D2 LED
Miscellaneous
-------------
1 J1 HE10-10
5 J2-J6 EMBASE-3PT
2 K1,K2 BPT
1 K3 BORVI2 - ALIM_PILE
1 K6 BORVI2
1 LCD1 LCD2X16CBL
1 LS1 BUZ
1 P1 10K
1 X1 4MHz
1 X2 CRYSTAL
4 Programmes
J'utilise le compilateur C pour PIC de CCS. Le pilote pour l'horloge temps réel a été trouvé sur les forums du
site de CCS. Il fonctionne correctement mais il n'est pas complet, par exemple il manque tout ce qui est
gestion de l'alarme de l'horloge temps réel. La programmation du PIC s'effectue par le biais de la voie série et
du logiciel TinyBootLoader (un bootloader est donc programmé en mémoire haute du PIC auparavant).
Le programme suivant permet de régler l'heure de l'horloge temps réel puis une numérisation du capteur de
température est faite toutes les dix secondes puis affichée sur l'afficheur LCD avec la date et l'heure.
Remarque : pour la numérisation de la température j'ai fait une petite platine externe avec un ampli-op
CA3140 (pas de tension de déchet basse) qui amplifie de 5 la tension issu du capteur. Le schéma et le typon
de cette platine sont données en annexe et visible sur la photo de la première page.
Des petits programmes de test sont aussi donnés. Ils servent juste à valider différentes parties du montage.
#include <16F876.H>
#device ICD=TRUE, ADC=10
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(stream=PC, baud=19200, xmit=PIN_C6, rcv=PIN_C7, PARITY=N)
#INT_RDA // l'interruption voie série est utilisé dans la phase de test pour la programmation
// du pic via TinyBootLoader. Si la sequence suivante, envoyée par TinyBootLoader,
// est bien recue par le PIC celui-ci fera un reset ce qui permettra de dialoguer
// avec le bootloader au démarrage
void serial_isr()
{
int8 uReceive;
disable_interrupts(GLOBAL);
uReceive = fgetc(PC);
switch (uReceive) {
case 0x12: {
if (fgetc(PC) == 0x34 & fgetc(PC) == 0x56 & fgetc(PC) == 0x78 & fgetc(PC) == 0x90) reset_cpu();
}
break;
}
//=================================
void main()
{
char weekday[10];
date_time_t dt;
int8 Etape=ReglageNomJour, cpt=0;
int1 initialisation=true;
int16 res;
float volt;
float const Quanta=5.0/1024.0; // Vcc=5V et résolution 10 bit du CAN
setup_adc_ports(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
lcd_init();
delay_ms(1000);
// Machine à état pour le réglage de l'horloge (pas sur que ce soit la meilleur méthode
while(initialisation==true)
{
switch (Etape)
{
case ReglageNomJour:
cpt=0;
printf(lcd_putc,"\fJour semaine:\n%s",weekday_names[cpt]);
do
{
if (input(BP_CHOIX)==0)
{
cpt++;
delay_ms(200);
if (cpt==7) cpt=0;
printf(lcd_putc,"\fJour semaine:\n%s",weekday_names[cpt]);
}
}
while (input(BP_VALID)==1);
while (input(BP_VALID)==0);
[Link]=cpt;
lcd_putc("\fJour semaine\nVALIDE");
delay_ms(1000);
Etape=ReglageNumJour;
break;
case ReglageNumJour:
cpt=1;
printf(lcd_putc,"\fJour du mois:\n%02u",cpt);
do
{
if (input(BP_CHOIX)==0)
{
cpt++;
delay_ms(200);
if (cpt==32) cpt=1;
printf(lcd_putc,"\fJour du mois:\n%02u",cpt);
}
}
while (input(BP_VALID)==1);
while (input(BP_VALID)==0);
[Link]=cpt;
lcd_putc("\fJour du mois\nVALIDE");
delay_ms(1000);
Etape=ReglageMois;
break;
case ReglageMois:
cpt=1;
printf(lcd_putc,"\fMois:\n%02u",cpt);
do
{
if (input(BP_CHOIX)==0)
{
cpt++;
delay_ms(200);
if (cpt==13) cpt=1;
printf(lcd_putc,"\fMois:\n%02u",cpt);
}
}
while (input(BP_VALID)==1);
while (input(BP_VALID)==0);
[Link]=cpt;
lcd_putc("\fMois\nVALIDE");
delay_ms(1000);
Etape=ReglageAnnee;
break;
case ReglageAnnee:
cpt=0;
printf(lcd_putc,"\fAnnee:\n%02u",cpt);
do
{
if (input(BP_CHOIX)==0)
{
cpt++;
delay_ms(200);
if (cpt==100) cpt=0;
printf(lcd_putc,"\fAnnee:\n%02u",cpt);
}
}
while (input(BP_VALID)==1);
while (input(BP_VALID)==0);
[Link]=cpt;
lcd_putc("\fAnnee\nVALIDE");
delay_ms(1000);
Etape=ReglageHeure;
break;
case ReglageHeure:
cpt=0;
printf(lcd_putc,"\fHeure:\n%02u",cpt);
do
{
if (input(BP_CHOIX)==0)
{
cpt++;
delay_ms(200);
if (cpt==24) cpt=0;
printf(lcd_putc,"\fHeure:\n%02u",cpt);
}
}
while (input(BP_VALID)==1);
while (input(BP_VALID)==0);
[Link]=cpt;
lcd_putc("\fHeure\nVALIDE");
delay_ms(1000);
Etape=ReglageMin;
break;
case ReglageMin:
cpt=0;
printf(lcd_putc,"\fMinutes:\n%02u",cpt);
do
{
if (input(BP_CHOIX)==0)
{
cpt++;
delay_ms(200);
if (cpt==60) cpt=0;
printf(lcd_putc,"\fMinutes:\n%02u",cpt);
}
}
while (input(BP_VALID)==1);
while (input(BP_VALID)==0);
[Link]=cpt;
lcd_putc("\fMinutes\nVALIDE");
delay_ms(1000);
Etape=Validation;
break;
case Validation:
lcd_putc("\fVos reglages:");
printf(lcd_putc,"\n%02u/%02u/%02u %02u:%02u",
[Link], [Link], [Link],
[Link], [Link]);
delay_ms(5000);
lcd_putc("\fHorloge correct?\nV=Oui C=Non");
while (1)
{
if (input(BP_CHOIX)==0) { lcd_putc("\fRéglage horloge"); delay_ms(1500); Etape=ReglageNomJour;
break;}
if (input(BP_VALID)==0) {
[Link]=0;
PCF8583_set_datetime(&dt);
lcd_putc("\fHorloge OK");
initialisation=false;
break;
}
}
break;
}
}
set_adc_channel(0);
delay_ms(1);
cpt=0;
while(1)
{
delay_ms(1000);
cpt++;
if (cpt==10)
{
res = READ_ADC();
volt = res * Quanta;
volt = (volt/4.9159)*100; // le 4.91 vient de l'amplification extérieur avec la platine externe
PCF8583_read_datetime(&dt);
strcpy(weekday, weekday_names[[Link]]);
printf(lcd_putc,"\f%s %02u/%02u/%02u\n%02u:%02u:%02u T:%2.1fC",
weekday, [Link], [Link], [Link],
[Link], [Link], [Link],volt);
cpt=0;
}
}
#ifndef PCF8583_SDA
#define PCF8583_SDA PIN_C4
#define PCF8583_SCL PIN_C3
#endif
#ifndef PCF8583_WRITE_ADDRESS
//#define PCF8583_WRITE_ADDRESS 0xA0
#define PCF8583_WRITE_ADDRESS 0xA2
//#define PCF8583_READ_ADDRESS 0xA1
#define PCF8583_READ_ADDRESS 0xA3
#endif
// Register addresses
#define PCF8583_CTRL_STATUS_REG 0x00
#define PCF8583_100S_REG 0x01
#define PCF8583_SECONDS_REG 0x02
#define PCF8583_MINUTES_REG 0x03
#define PCF8583_HOURS_REG 0x04
#define PCF8583_DATE_REG 0x05
#define PCF8583_MONTHS_REG 0x06
#define PCF8583_TIMER_REG 0x07
//----------------------------------------------
void PCF8583_write_byte(int8 address, int8 data)
{
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8583_WRITE_ADDRESS);
i2c_write(address);
i2c_write(data);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------
int8 PCF8583_read_byte(int8 address)
{
int8 retval;
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(PCF8583_WRITE_ADDRESS);
i2c_write(address);
i2c_start();
i2c_write(PCF8583_READ_ADDRESS);
retval = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
return(retval);
}
void PCF8583_init(void)
{
PCF8583_write_byte(PCF8583_CTRL_STATUS_REG,
PCF8583_START_COUNTING);
}
//----------------------------------------------
// This function converts an 8 bit binary value
// to an 8 bit BCD value.
// The input range must be from 0 to 99.
retval = 0;
while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(value >= 10)
{
value -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += value;
break;
}
}
return(retval);
}
//----------------------------------------------
// This function converts an 8 bit BCD value to
// an 8 bit binary value.
// The input range must be from 00 to 99.
temp = bcd_value;
//----------------------------------------------
void PCF8583_set_datetime(date_time_t *dt)
{
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_mon;
//----------------------------------------------
// Read the Date and Time from the hardware registers
// in the PCF8583. We don't have to disable counting
// during read operations, because according to the data
// sheet, if any of the lower registers (1 to 7) is read,
// all of them are loaded into "capture" registers.
// All further reading within that cycle is done from
// those registers.
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_mon;
bcd_sec = i2c_read();
bcd_min = i2c_read();
bcd_hrs = i2c_read();
bcd_day = i2c_read();
bcd_mon = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
dt->year = year;
#include <ctype.h>
#include <PCF8583.c>
#include <2464.C>
date_time_t dt;
char weekday[10];
lcd_init();
while(1)
{
lcd_putc("\fEcriture\naddr:00 Val:03");
delay_ms(2000);
adresse=0; valeur=3;
WRITE_EXT_EEPROM( adresse, valeur );
lcd_putc("\fEcriture\naddr:01 Val:04");
delay_ms(2000);
adresse=1; valeur=4;
WRITE_EXT_EEPROM( adresse, valeur );
lcd_putc("\fPause 5s");
delay_ms(5000);
lcd_putc("\fLecture\naddr:00 Val:");
printf(lcd_putc,"%X",READ_EXT_EEPROM(0x0000));
delay_ms(2500);
lcd_putc("\fLecture\naddr:01 Val:");
printf(lcd_putc,"%X",READ_EXT_EEPROM(0x0001));
delay_ms(2500);
lcd_putc("\fPause 5s");
delay_ms(5000);
PCF8583_read_datetime(&dt);
strcpy(weekday, weekday_names[[Link]]);
printf(lcd_putc,"\f%s %02u/%02u/%02u\n%02u:%02u:%02u",
weekday, [Link], [Link], [Link],
[Link], [Link], [Link]);
delay_ms(5000);
}
5 Annexes
Le schéma et le typon de la carte externe pour amplification de la tension issue du capteur de température
LM35DZ. L'amplification choisie est de 5 sachant que la capteur augmente de 10mV/°C.
P1
150K R2 R1
10K 10K
U1 J2
J1
7
3 3
3 6 2
2 2 1
1 C1 C2 EMBASE-3PT
EMBASE-3PT 100nF 100nF
5
1
4
Capteur Température
CA3140
Vers Data Logger
Connecteur
Afficheur LCD
EEPROM 24LC64
Horloge temps
PIC16F876
réel (RTC : Real
Time Clock)
PCF8583
Quartz 4 MHz