DS18S20 : capteur de température

Voilà un petit exemple d'intégration d'un capteur de température au côté d'un 8051. Le microcontrôleur utilisé dans le cadre de ce projet est le DS89C450 de Maxim. Le choix du microcontrôleur importe peu. Le software présenté dans le cadre de ce projet est valable pour d'autres microcontrôleurs de la famille 8051. Le seul point délicat est la gestion des timings. En effet, le DS89C450 fait partie de la famille des Ultra High Speed ne nécessitant pour la plupart des instructions qu'un cycle d'horloge au lieu de 12 pour un 8051 classique .

Concernant le capteur de température en lui-même, le DS18S20 est un capteur de température pouvant travailler sur une plage allant de -55°C à +125°C avec une précision atteignant 0,5°C ( un algorythme est disponible pour améliorer la résolution ). Un des avantages de ce type de capteur est qu'il est connecté au microcontrôleur que par 1 seul fil. Pas besoin donc d'un convertisseur ADC pour récupérer l'information de température. L'interface 1-Wire de Maxim permet une grande simplification du circuit en général mais aussi, entre autres, de connecter plusieurs capteurs sur la même pin de notre microcontrôleur. En effet, chaque capteur possède un numéro d'identification unique en ROM.

Le schéma est repris ci-dessous :

Pour bien comprendre le programme que nous étudierons plus loin dans l'article, il faut se plonger un peu plus profondément dans le silicium et voir ce qui y est gravé... Le capteur comprend une ROM et ses fonctions de contrôle, une RAM, le capteur thermique ainsi que l'électronique nécessaire à l'interfacage inter blocs mais aussi avec le monde extérieur.

La ROM comprend 64 bits permettant d'identifier le capteur (family code 10bits), un numéro de série (48 bits) et un crc de 8 bits sur les 56 premiers bits. Pour débuter toute communication avec le capteur, le maître du bus 1-Wire doit tout d'abord vérifier la présence d'un ou plusieurs capteurs sur le bus. Il effectue pour ce faire un pulse de reset sur le bus auquel répondent les capteurs présents par un pulse de présence (voir plus loin pour les détails). Pour pouvoir utiliser plus avant le capteur,le maître du bus 1-wire doit faire appel à une des 5 fonctions de contrôle de la ROM :

  1. Read ROM [33h] - Utilisable si une seul capteur est présent sur le bus : permet de lire la ROM.
  2. Match ROM [55h] - Permet au Maître de s'adresser uniquement au capteur dont les 64 bits de ROM correspondent à la séquence de 64 bits envoyée.
  3. Skip ROM [CCh] - Permet au Maître d'utiliser le capteur s'il est seul sur le bus sans besoin donc d'identification via la ROM.
  4. Search ROM [F0h] - Permet au Maître de rechercher les 64 bits de ROM de tous les capteurs présents sur le bus.
  5. Alarm search [CEh] - Permet au Maitre de rechercher les capteurs pour lesquels une alarme s'est déclenchée.

Une fois que la séquence d'accès aux fonctions de contrôle de la ROM est terminée, les autres fonctions du DS18S20 sont disponibles. La mémoire du DS18S20 est constituée de deux parties : la RAM appelée "scratchpad" et une EERAM pour stocker les les seuils haut et bas des alarmes.

La mémoire scratchpad est constitué de 9 octets. Les deux premiers permettent le stockage des LSB et MSB de la température mesurée. Les deux octets suivant conservent les valeurs "volatiles" des seuils haut et bas des alarmes. Les octets 4 et 5 sont réservés. Les octets 6 et 7 sont des registres-compteurs qui permettent d'obtenir une meilleure résolution sur les températures mesurées. Le 9ieme et dernier octet contient le CRC des huits octets précédents

Les commandes à utiliser pour les accès à la mémoire sont les suivantes :

  1. Read Scratchpad [4Eh] - Lit les 9 octets consécutifs de la mémoire Scratchpad. Si les 9 octets ne doivent pas être lus, le maître peut envoyer un reset pour terminer la lecture.
  2. Write Scratchpad [BEh] - Ecrit les octets 2 et 3 de la mémoire Scratchpad
  3. Copy Scratchpad [48h] - Copie les octets 2 et 3 vers l'EERAM
  4. Recall EERAM [B8h] - Remplit les octets 2 et 3 de l'EERAM vers la mémoire Scratchpad.
  5. Read Power Supply [B4h] - Renvoie le mode d'alimentaion du capteur au maitre du bus
  6. Convert T [44h] - Initialise la conversion de temperature

Voilà pour une partie de la théorie, pour les détails électriques et les timings min/max, faites un tour des datasheets. On continue par une mise en pratique, un capteur branché sur le microcontrôleur.

La première chose nécessaire, c'est une fonction délai. En effet, les accès au capteur demandent un bon contrôle des timings. Un bon contrôle ne veut pas nécessairement dire précis. Faut-il utiliser un timer ? Cela dépend...Il faut garder à l'esprit, que dans certains programmes, les interruptions peuvent être utilisées et qu'on ne maitrise en aucun cas l'apparition d'un évènement lié. On imagine bien l'interruption se pointant en plein milieu du déroulement de notre fonction délai... Il faut donc gérer au cas par cas et ne pas hésiter à utiliser des timers et à jouer sur les priorités des interruptions.

// Fonction Delay
// Quartz utilisé : 11.0592 Mhz
// 8051 classique durée : appel fonction :24us + 16us par cycle ds boucle for
// DS89C450 : compter 9x plus de cycles
/////////////////////////////////////////////////////////////////////
void delay(int useconds)
{
int s;
for (s=0; s<useconds;s++);
}

Entrant dans le vif du sujet, il nous faut maintenant voir si le capteur est présent et l'initialiser. Pour initialiser le capteur, le maître du bus envoie un signal bas d'une longueur de minimum 48O µsec et relache le bus qui remonte au niveau haut grace à la présence de la résistance de pull-up de 4,7 Kohms. Le maître se met alors en mode RX et attend la réponse du capteur. Après la détection du front haut sur sa pin DQ, le capteur attend pendant une durée allant de 15 à 60 µsec et puis, seulement, indique sa présence par un signal bas d'une durée de 60 à 240 µsec. Si plusieurs capteurs sont présents sur le même bus, rien n'indique encore leur nombre...

Dans le code si dessous, une exemple de la fonction reset :

unsigned char ow_reset(void)
{
unsigned char presence;
DQ = 0; //le maître met le bus bas
delay(250); // on temporise 480µsec : mettre 29 pour 8051 classique
DQ = 1; // on relache le bus
delay(35); // on attend le reveil du capteur : mettre 3 pour 8051 classique
presence = DQ; // on regarde si on a une présence
delay(220); // on attend la fin du temps possible: mettre 26 pour 8051 classique
return(presence); // on retourne le signal de présence
} // 0=presence, 1 = pas de capteur

Il nous faut maintenant les routines permettant au maître de lire et écrire sur le bus. Deux fonctions sont utilisées pour l'émission/réception d'un bit. Ces deux fonctions étant utilisées pour l'écriture/lecture des octets.

//////////////////////////////////////////////////////////////////////////////
READ_BIT
//////////////////////////////////////////////////////////////////////////////
unsigned char read_bit(void)
{
// Lecture d'un bit
DQ = 0; // On met DQ bas pour démarrer la séquence
DQ = 1; // retour niveau haut
//attention ici, si un 8051 classique est utilisé,
//le delai est trop court pour utiliser la
//fonction Delay, il faut faire une temporisation
//à base de boucle FOR
delay(7); // delai de 15us depuis le début de la séquence
return(DQ); // On renvoie la valeur de DQ
}
//////////////////////////////////////////////////////////////////////////////
WRITTE_BIT
//////////////////////////////////////////////////////////////////////////////
void write_bit(char bitval)
{
//Ecriture d'un bit
DQ = 0; //On met DQ bas pour démarrer la séquence
if(bitval==1) DQ =1; // On met DQ au niveau Haut si la valeur à écrire est 1
delay(52); // On garde la valeur pour le reste de la séquence
//mettre delay(5) si on utilise un 8051 classique
DQ = 1;
}
//////////////////////////////////////////////////////////////////////////////
// READ_BYTE - Lit un Octet sur le bus
//////////////////////////////////////////////////////////////////////////////
//
unsigned char read_byte(void)
{
unsigned char i;
unsigned char value = 0;
for (i=0;i<8;i++)
{
if(read_bit()) value|=0x01<<i;
// On lit un bit à la fois puis on shifte le tout à gauche
delay(64); // on attend pour le reste de la séquence
// utilisation de delay(7) pour un 8051 classique }
return(value);
}
//////////////////////////////////////////////////////////////////////////////
// WRITE_BYTE - Ecrit un octet sur le bus.
//////////////////////////////////////////////////////////////////////////////
//
void write_byte(char val)
{
unsigned char i;
unsigned char temp;
for (i=0; i<8; i++) // Ecrit un octet, un bit à la fois
{
temp = val>>i; // on shifte val i foiis vers la droite
temp &= 0x01; // on copie le bit lsb dans temp
write_bit(temp); // on envoie ce bit sur le bus
}
delay(52);//on attend pour le reste de la séquence
//mettre delay(5) pour un 8051 classique
}

On possède maintenant tous les outils pour discuter avec le capteur. On va donc étudier l'accès au capteur pour récupérer la température mesurée. Nous allons utiliser l'algorythme proposé dans la datasheet du composant pour atteindre une meilleure résolution. Pour ce faire, nous avons besoin du contenu des octets 6 (COUNT_REMAIN) et 7 (COUNT_PER_C) de la mémoire scratchpad pour pouvoir les injecter dans la formule suivante :

TEMP_READ est obtenu en lisant l'octet de température ( octet 0 de la mémoire scratchpad) duquel on retranche le dernier bit. le dernier bit correspond à 2^-1 soit 0,5°C. TEMP_READ est donc la partie entière de la température.

//////////////////////////////////////////////////
//Read temperature
//////////////////////////////////////////////////
void Read_Temperature(void)
{
char get[10];//variable dans laquelle on va charger la memoire scratchpad
char temp_lsb,temp_msb;
char k;
float temp;
write_byte(0xCC); //commande skip ROM
write_byte(0x44); // commande Convert T
delay(52);// utiliser delay(5) pour 8051 classique
ow_reset();// reset capteur
write_byte(0xCC); // Commande Skip ROM
write_byte(0xBE); // Commande Read Scratch Pad
for (k=0;k<9;k++){get[k]=read_byte();}// lecture de la mémoire scratchpad
temp_msb = get[1]; // octet de signe
temp_lsb = get[0]; // donnée température avec avec demi degré si nécessaire

if (temp_msb < 0x80){temp_lsb = (temp_lsb/2);} //récupération valeur entière
temp_msb = temp_msb & 0x80; //récupération du signe
if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1; // calcul complément à deux pour valeur négatives
temp_lsb = (temp_lsb/2);}// récupération partie entière
temp=temp_lsb-0.25+((get[7]-get[6])/get[7]);//application de la formule

if (temp_msb >= 0x80) {temp=((-1)*temp);} // on ajoute le signe
printf( "\nTempC= %.2f degrees C\n", temp ); // on imprime la température sur RS232 par exemple
}

On peut maintenant lire la température en faisant appel à la fonction précédente de la maière suivante :

if (!(ow_reset())) Read_Temperature();

Réalisation : LaboElectronique.be