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 :
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 :
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 :