Projet à microcontrôleur PIC
16F628A
Thermomètre numérique à capteur numérique DS1620
Il s'agit d'un thermomètre électronique avec affichage de la température sur un module LCD alphanumérique.
La température ambiante est mesurée toutes les 840 ms avec un capteur numérique DS1620, de la société Analog devices (à l'origine Dallas Semiconductor).
Un bouton poussoir permet de passer à un deuxième écran qui indique les températures maximale et minimale :
Ecran n°1 :
Ecran n°2 :
Un second bouton poussoir réinitialise la fonction température min/max.
En option, on peut connecter la carte sur un ordinateur (via une liaison RS232).
La température est transférée vers l'ordinateur (c'est un microcontrôleur 16F628A qui gère les communications côté carte).
Une application Windows affiche la température en temps réel et fournit un graphe déroulant de la température.
D'autre part, l'application Windows permet de programmer les deux températures de seuil de la fonction thermostat du DS1620.
Version n°1 : sans liaison RS232
Version n°2 : avec l'option liaison RS232
N.B. Le code source du microcontrôleur est le même, avec ou sans liaison RS232.
5-1- Sans liaison RS232
A la mise sous tension, le microcontrôleur 16F628A configure le capteur de température DS1620 (instruction Write Config avec CPU = 1 et 1SHOT = 0, puis instruction Start Convert T) et configure le module LCD alphanumérique (instruction Set Function pour une utilisation en mode d'interface 4 bits).
Le module Timer1 (16 bits) du microcontrôleur 16F628A est activé, ce qui donne lieu à une interruption toutes les 105 ms environ.
A chaque interruption du Timer1, l'état du bouton poussoir SELECTION ECRAN et du bouton poussoir RESET MIN/MAX est testé.
Toutes les 8 interruptions du Timer1 (soit environ 840 ms), une lecture de la température est effectuée, et l'affichage du module LCD alphanumérique est mis à jour :
Ecran n°1 :
Ecran n°2 :
5-2- Avec liaison RS232
Par rapport au fonctionnement sans liaison RS232, deux interruptions s'ajoutent :
- L'interruption de réception de l'UART (qui signale au microcontrôleur 16F628A qu'il a reçu des données de l'ordinateur via la liaison RS232)
- L'interruption d'émission de l'UART (qui signale au microcontrôleur 16F628A que l'UART est prêt à émettre des données vers l'ordinateur)
Il faut bien sûr un ordinateur qui possède un port COM, reconnaissable par son connecteur SubD 9 broches mâle.
Il faut brancher un câble "null-modem" (câble croisé) entre l'ordinateur et la carte.
Si vous n'en avez pas, vous pouvez facilement en faire un (il faut 3 fils et 2 connecteurs SubD 9 broches femelle).
Seul l'ordinateur prend la parole. Le microcontrôleur PIC 16F628A se contente de répondre.
L'ordinateur envoie 3 octets (via la liaison RS232) :
Instruction DS1620 |
1er octet (code instruction)
|
2ème octet (données)
|
3ème octet (données)
|
Read Temperature (toutes
les 1000 ms)
|
0xAA
|
0x00 (non
utilisé)
|
0x00 (non
utilisé)
|
Read TH (lecture de la
température haute du thermostat)
|
0xA1
|
0x00 (non
utilisé)
|
0x00 (non
utilisé)
|
Read TL (lecture de la
température basse du thermostat)
|
0xA2
|
0x00 (non
utilisé)
|
0x00 (non
utilisé)
|
Write TH (écriture de
la température haute du thermostat)
|
0x01
|
(0000000 D8)
|
(D7 ... D0)
|
Write TL (écriture de
la température basse du thermostat)
|
0x02
|
(0000000 D8)
|
(D7 ... D0)
|
Une fois reçus, le PIC transmet l'instruction vers le DS1620 (via les 3 fils du port série synchrone).
Dans le cas d'une instruction de lecture (Read Temperature, Read TH, Read TL) le thermomètre DS1620 renvoie les données vers le PIC (température sous la forme d'un nombre binaire 9 bits, codé en complément à 2).
Ce nombre est envoyé tel quel vers l'ordinateur sous la forme de 2 octets :
D0 = bit de poids faible
Pour les autres instructions, le PIC envoie deux octets 0x00 à l'ordinateur (via la liaison RS232).
Instruction
DS1620
1er octet (données) 2ème octet (données) Read Temperature (toutes les 1000 ms) (0000000 D8) (D7 ... D0) Read TH (lecture de la température haute du thermostat) (0000000 D8) (D7 ... D0) Read TL (lecture de la température basse du thermostat) (0000000 D8) (D7 ... D0) Write TH (écriture de la température haute du thermostat) 0x00 (non utilisé) 0x00 (non utilisé) Write TL (écriture de la température basse du thermostat) 0x00 (non utilisé) 0x00 (non utilisé)
- Exemple d'oscillogrammes : instruction Read Temperature
- Communication entre l'ordinateur et le PIC (liaison RS232) :
0xAA = code de l'instruction Read Temperature
0x00 0x2D = 0 0010 1101 = 45 = +22,5 °C
- Communication entre le PIC et le DS1620 (port série synchrone) :
10101010 = 0xAA = code de l'instruction Read Temperature
0 00101101 = 0x2D = 45 = +22,5 °C
Procédure d'utilisation
-> Brancher le câble "null-modem" entre l'ordinateur et la carte (hors tension)
Attention : l'utilisation d'un adaptateur USB <-> port COM semble poser problème !
-> Mettre la carte sous tension
-> Ouvrir l'application DS1620_104.exe
-> Configurer les paramètres de la liaison RS232C :
- 9600 bauds
- 8 bits de données
- Pas de bit de parité
- 1 bit de STOP
- Pas de contrôle de flux
-> Ouvrir le port
La température actuelle doit s'afficher (avec une mise à jour toutes les 1000 ms).
Il y a la possibilité de sauvegarder les données dans un fichier texte :
Ce fichier peut ensuite être exploité avec un tableur...
Code source de l'application
Cette application a été écrite en C++ avec l'environnement de développement Borland Builder 5.
L'application fonctionne sous Windows XP (au moment de l'écriture du code), et plus récemment sous Windows 10.
N.B. Borland Builder 5 nécessite l'installation du composant TComPort (la version 2.64 est suffisante) pour la gestion de la liaison RS232 :
Voici deux VI que j'ai écrit avec LabVIEW 5 :
Notez que ces VI fonctionnent également avec la version 6 de LabVIEW.
# (C) Fabrice Sincere
# python 2.7
# communication RS232 avec un thermomètre numérique à capteur numérique DS1620
# http://fabrice.sincere.free.fr/cm_electronique/projet_pic/thermometreLCD_DS1620htm/thermometreLCD_DS1620.htm
# test : OK (linux/ubuntu + winXP)
import time
import serial # librairie externe pyserial
print 'Communication avec le port COM'
filename = 'temperature.txt'
print '\nFichier de sauvegarde : '+filename
Fichier = open(filename,'a')
# biblio pyserial :
# http://pyserial.sourceforge.net/shortintro.html
# http://pyserial.sourceforge.net/pyserial_api.html
Port = serial.Serial()
Port.baudrate = 9600
Port.bytesize=8
Port.parities=0
Port.stopbits=1
Port.xonxoff=0
Port.rtscts=0
Port.timeout=0.1 # en seconde
print """
# Sous Windows :
# COM1 -> 0 (ou COM1)
# COM2 -> 1 (ou COM2)
# Sous Linux :
# COM1 -> 0 (ou /dev/ttyS0)
# COM2 -> 1 (ou /dev/ttyS1)
"""
nomport = raw_input('Nom du port COM ? ')
try:
int(nomport)
Port.port = int(nomport)
except:
Port.port = nomport
print 'Port ->',Port.portstr,'\n'
Port.open()
try:
while True:
# écriture
Port.write('\xAA\x00\x00')
# lecture
MSB = Port.read() # octet de poids fort
LSB = Port.read() # octet de poids faible
if (MSB !='' and LSB != ''):
temperature = ord(LSB) + 256* ord(MSB)
if temperature >= 256:
temperature = temperature - 512
temperature *= 0.5
affichage = time.strftime('%H:%M:%S',time.localtime()) + ' '+ str(temperature) +' °C'
print affichage
Fichier.write(affichage+'\n')
# pause 1 seconde
time.sleep(1.0)
except KeyboardInterrupt:
# CTRL + C
print "\nCTRL+C\nFermeture du port",Port.portstr
Port.close()
Fichier.close()
>>>
Communication avec le port COM
Fichier de sauvegarde : temperature.txt
# Sous Windows :
# COM1 -> 0 (ou COM1)
# COM2 -> 1 (ou COM2)
# Sous Linux :
# COM1 -> 0 (ou /dev/ttyS0)
# COM2 -> 1 (ou /dev/ttyS1)
Nom du port COM ? 0
Port -> COM1
09:15:28 19.5 °C
09:15:29 19.5 °C
09:15:30 19.5 °C
09:15:31 19.5 °C
09:15:32 19.5 °C
09:15:33 19.5 °C
09:15:34 20.0 °C
09:15:35 20.0 °C
09:15:36 20.0 °C
09:15:37 20.0 °C
09:15:38 20.0 °C
09:15:39 20.0 °C
CTRL+C
Fermeture du port COM1
>>>
Télécharger le script Python 2.7
Télécharger le script Python 3
Testé chez moi avec Linux/Ubuntu derrière une Livebox, avec les paramètres réseaux suivants :
IP privée : 192.168.1.10
IP publique : 90.14.148.96
Installations :
En plus de Python 2.7 et du package pyserial, il faut installer sur votre machine un serveur Web Apache (ici avec XAMPP).
Les scripts Python cgi_lecture_temperature.py
, cgi_formulaire_consigne.py
et cgi_traitement_formulaire_consigne.py
doivent être placés dans le répertoire /opt/lampp/cgi-bin/
Attention aux droits : Propriétés -> Permissions -> autoriser l'exécution du fichier comme un programme
A propos des scripts CGI en Python :
La première ligne des scripts doit être :
#! /usr/bin/python
La première sortie doit être (header) :
print "Content-Type: text/html\n\n"
Configuration de la Livebox :
Routeur-NAT -> Ajouter un service HTTP (protocole TCP, port 80, adresse IP du serveur 192.168.1.10)
Configuration du pare-feu :
autoriser les connexions entrantes sur le port 80 (protocole TCP)
Démarrage du serveur Web :
Dans la console Linux, taper la commande :
sudo /opt/lampp/lampp start
Si le script cgi_lecture_temperature.py
donne une erreur du type :
Permission denied: '/dev/ttyS0'
alors dans la console Linux, taper la commande :
sudo chmod 666 /dev/ttyS0
Ces scripts fonctionnent également sous Windows (testé avec XP et Wampserver).
#! /usr/bin/python
#-*- coding:utf-8 -*-
# script cgi_lecture_temperature.py
# (C) Fabrice Sincere
# python 2.7
# script cgi
# communication RS232 avec un thermomètre numérique à capteur numérique DS1620
# http://fabrice.sincere.free.fr/cm_electronique/projet_pic/thermometreLCD_DS1620htm/thermometreLCD_DS1620.htm
# test : OK (linux/ubuntu 11.10 + xampp 1.7.7)
import cgitb # débogage cgi
cgitb.enable()
import serial # librairie externe pyserial
# biblio pyserial :
# http://pyserial.sourceforge.net/shortintro.html
# http://pyserial.sourceforge.net/pyserial_api.html
import time
print "Content-Type: text/html\n\n"
print """<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Mesure de température</title>
<meta http-equiv="Refresh" content="10"/>
<meta name="Author" content="Fabrice Sincère"/>
</head>
<body>"""
print '<p>Communication avec le port COM</p>'
# au préalable, il faut créer le répertoire /opt/lampp/htdocs/temperature
filename = '/opt/lampp/htdocs/temperature/temperature.txt'
filename0 = '../temperature/temperature.txt'
print "<p><a href='"+filename0+"'>Fichier de sauvegarde</a></p>"
Fichier = open(filename,'a')
Port = serial.Serial()
Port.baudrate = 9600
Port.bytesize=8
Port.parities=0
Port.stopbits=1
Port.xonxoff=0
Port.rtscts=0
Port.timeout=0.1 # en seconde
# Sous Windows :
# COM1 -> 0 (ou COM1)
# COM2 -> 1 (ou COM2)
# Sous Linux :
# attention : permission 666
# > sudo chmod 666 /dev/ttyS0
# COM1 -> 0 (ou /dev/ttyS0)
# COM2 -> 1 (ou /dev/ttyS1)
nomport = 0
try:
int(nomport)
Port.port = int(nomport)
except:
Port.port = nomport
print '<p>Ouverture du port ',Port.portstr,'</p>'
Port.open()
# lecture de la température
Port.write('\xAA\x00\x00')
# lecture
MSB = Port.read() # octet de poids fort
LSB = Port.read() # octet de poids faible
if (MSB !='' and LSB != ''):
temperature = ord(LSB) + 256* ord(MSB)
if temperature >= 256:
temperature = temperature - 512
temperature *= 0.5
affichage = time.strftime('%H:%M:%S',time.localtime()) + ' ----> '+ str(temperature) +' °C'
print '<p>'+affichage+'</p>'
Fichier.write(affichage+'\n')
else:
print '<p style="color:red;">La carte n\'est pas branchée !</p>'
# lecture de la température basse du thermostat
Port.write('\xA2\x00\x00')
MSB = Port.read() # octet de poids fort
LSB = Port.read() # octet de poids faible
if (MSB !='' and LSB != ''):
temperature = ord(LSB) + 256* ord(MSB)
if temperature >= 256:
temperature = temperature - 512
temperature *= 0.5
affichage = str(temperature) +' °C'
print '<p>'+'Thermostat : TLow -->'+ affichage+'</p>'
# lecture de la température haute du thermostat
Port.write('\xA1\x00\x00')
MSB = Port.read() # octet de poids fort
LSB = Port.read() # octet de poids faible
if (MSB !='' and LSB != ''):
temperature = ord(LSB) + 256* ord(MSB)
if temperature >= 256:
temperature = temperature - 512
temperature *= 0.5
affichage = str(temperature) +' °C'
print '<p>'+'Thermostat : Thigh -->'+ affichage+'</p>'
print "<p>Fermeture du port",Port.portstr,'</p>'
Port.close()
Fichier.close()
print "</body></html>"
Lecture de la température (mis à jour toutes les 10 secondes) :
Fichier de sauvegarde :
#! /usr/bin/python
# -*- coding: utf-8 -*-
# script cgi_formulaire_consigne.py
# Affichage d'un formulaire HTML
print "Content-Type: text/html\n\n"
print """<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Mesure de température</title>
<meta name="Author" content="Fabrice Sincère"/>
</head>
<body>
<p>Température de consigne (en °C) du thermostat :</p>
<p>Par exemple : 54.5</p>
<form action="cgi_traitement_formulaire_consigne.py" method="post">
<p>
Tlow : <input type="text" name="tlow" /><br/><br/>
Thigh : <input type="text" name="thigh" /><br/><br/>
<input value="ENREGISTER" type="submit" name="envoyer"/>
</p>
</form>
</body>
</html>"""
#! /usr/bin/python
# -*- coding: utf-8 -*-
# (C) Fabrice Sincère
# script cgi_traitement_formulaire_consigne.py
# Traitement des données transmises par le formulaire HTML
import serial
import cgi
form = cgi.FieldStorage()
def octets(temperature):
temperature =int(temperature*2)
if temperature < 0:
temperature += 256
MSB = 1
LSB = temperature
else:
MSB = 0
LSB = temperature
return [MSB,LSB]
print "Content-Type: text/html\n\n"
print """<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Mesure de température</title>
<meta name="Author" content="Fabrice Sincère"/>
</head>
<body>"""
Port = serial.Serial()
Port.baudrate = 9600
Port.bytesize=8
Port.parities=0
Port.stopbits=1
Port.xonxoff=0
Port.rtscts=0
Port.timeout=0.1 # en seconde
# Sous Windows :
# COM1 -> 0 (ou COM1)
# COM2 -> 1 (ou COM2)
# Sous Linux :
# attention : permission 666
# > chmod 666 /dev/ttyS0
# COM1 -> 0 (ou /dev/ttyS0)
# COM2 -> 1 (ou /dev/ttyS1)
nomport = 0
try:
int(nomport)
Port.port = int(nomport)
except:
Port.port = nomport
print '<p>Ouverture du port ',Port.portstr,'</p>'
Port.open()
if form.has_key("tlow"):
Tlow = form["tlow"].value
try:
Tlow = float(Tlow)
Port.write('\x02'+chr(octets(Tlow)[0])+chr(octets(Tlow)[1]))
Port.read()
Port.read()
print '<p>Tlow : valeur enregistrée</p>'
except:
print '<p>Tlow : Valeur non valide</p>'
if form.has_key("thigh"):
Thigh = form["thigh"].value
try:
Thigh = float(Thigh)
Port.write('\x01'+chr(octets(Thigh)[0])+chr(octets(Thigh)[1]))
Port.read()
Port.read()
print '<p>Thigh : valeur enregistrée</p>'
except:
print '<p>Thigh : Valeur non valide</p>'
print "<p>Fermeture du port",Port.portstr,'</p>'
Port.close()
print "</body></html>"
- CREATE TABLE IF NOT EXISTS web_temperature1 (ID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,date DATE NOT NULL,time TIME NOT NULL,temperature varchar(20) collate latin1_general_ci NOT NULL) ENGINE = MYISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
- INSERT INTO web_temperature1(ID,date,time,temperature) VALUES (NULL,CURDATE(), CURTIME(), '21,5')
- SELECT date,time,temperature FROM web_temperature1 ORDER BY ID DESC LIMIT 0,1
Télécharger web_temperature.exe (263 ko)
Télécharger libmysql.dll (1,0 Mo)
Cette application a été écrite avec C++ Borland Builder 5.
N.B. La communication avec le port COM (RS232)
nécessite l'installation du composant TComPort (dont j'ai déjà
parlé ci-dessus).
La communication avec la base de données MySQL
nécessite la librairie C libmysql, que vous pouvez
télécharger librement sur le site officiel www.mysql.com :
Rubrique : Downloads
-> mysql-connector-c-noinstall-6.0.2-win32.zip
Pour utiliser cette librairie avec C++ Borland Builder 5, voici un lien externe :
Tutorial : Utilisation de l'API MySQL avec Borland C++ Builder
Un petit oubli dans ce tutorial : il faudra ajouter libmysql.lib au projet (Projet -> Ajouter au projet -> libmysql.lib)
Lien utile : http://fabrice.sincere.free.fr/application_builder5/client_mysql/mysql_client_builder.html
Télécharger le code source du script PHP
Télécharger web_temperature_ftp.exe (292 ko)
Cette application a été écrite avec C++ Borland
Builder 5.
Télécharger le code source (15 ko)
http://monsiteweb.fr/web_temperature.txt
Sans liaison RS232 :
Avec liaison RS232 : composants supplémentaires
- 1 circuit intégré MAX233A (interface RS232C <-> TTL/CMOS)
- 1 connecteur SubD 9 broches mâle
- 1 condensateur électrochimique de 1 µF (filtrage)
- 1 câble null-modem (femelle/femelle)
- 1 ordinateur avec port COM. Attention : l'utilisation d'un adaptateur USB <-> port COM semble poser problème !
Dimension : 62 x 100 mm
Simple face.
Remarque :
On n'oubliera pas les 9 straps (à souder en premier).
Le code source a été écrit en langage assembleur avec l'environnement de développement gratuit MPLAB IDE de Microchip.
© Fabrice Sincère ; révision 2.4.12
Contenu sous licence CC BY-NC-SA 3.0