"L'USB pour tous" 

Vincent Le Mieux - ETSF

 

couverture.jpg                        couverture2.jpg   

(1ère édition - 2004)                    (2ème édition - 2007)

 

Historique

 

A partir de 1997 j'ai commencé à écrire des articles dans le magazine "Electronique Pratique" puis dans son Hors Série "Interfaces PC".  A cette époque, la communication entre le PC et du matériel externe se faisait essentiellement par le port série ou le port parallèle. (Une autre solution existait : celle d'utiliser un slot ISA libre sur la carte mère, mais cette possibilité était difficile à mettre en oeuvre au niveau amateur en raison des contraintes qui s'imposaient à la réalisation du circuit imprimé)

En 1996 parait la première version de l'USB. Seules les dernières versions de Windows 95 allaient supporter cette norme (encore fallait-il disposer d'un PC ayant des connecteurs USB !).

Le véritable envol de l'USB va se faire à partir de 1998 : sortie de la révision 1.1 de l'USB et du système d'exploitation Windows 98 qui supportera cette norme.

Si l'arrivée de l'USB va simplifier la vie de l'utilisateur (alimentation du matériel directement par l'USB, possibilité de brancher plusieurs matériels par l'ajout d'un "hub", pas de réglages à faire du genre choix de port COM1 ou 2 etc...) elle va par contre considérablement compliquer la tâche du concepteur : au delà de la difficulté de compréhension de la norme USB, réussir à trouver une embase USB à souder sur un circuit imprimé n'était pas une mince affaire !

Après quelques articles écrits dans Electronique Pratique, il s'est avéré nécessaire de rassembler ces premières études dans un ouvrage ayant une flèche directrice générale.

C'est ainsi qu'est apparue la première édition de "L'USB pour tous"

 

Voici des extraits de l'avant-propos en page IX du livre :

"L'USB (Universal Serial Bus) a pris son envol grand public avec l'arrivée de Windows 98. Les nouveaux périphériques qui apparaissent sur le marché sont le plus souvent de type USB et nos bon vieux ports séries et parallèles désertent progressivement les cartes mères.

Pour pouvoir continuer à piloter des montages par ordinateur, en tant qu'amateur, ou pour des nécessités commerciales, nous sommes donc nombreux à vouloir maîtriser cette nouvelle technologie.

Les passionnés d'électronique et d'informatique qui souhaitent ajouter une corde à leur arc de compétences auront à coeur de vouloir réaliser et même concevoir des montages USB. Cet ouvrage est fait pour eux. [...]

[...] le choix pédagogique de l'auteur a été de distiller tout au long de cet ouvrage les informations nécessaires à la maîtrise progressive de l'USB.[...]

Le but avoué de l'auteur est d'amener le lecteur à l'écriture complète d'une application USB : ceci se réalisera dans les derniers chapitres."

Lors de mes premièrs travaux sur l'USB, deux voies de travail s'ouvraient :

 - l'utilisation d'un circuit de conversion USB - RS232 tel que ceux lancés sur le marché par la société FTDI.

 - la mise en oeuvre d'un montage à partir d'un microcontrôleur disposant de ressources USB.

Chacune de ces possibilités ayant ses avantages et inconvénients, je n'ai pas voulu en délaisser une pour privilégier l'autre. On retrouvera donc ces deux techniques dans cet ouvrage.

 

Description

 

Les logiciels accompagnant l'ouvrage (sur un CD-ROM dans la première édition, en téléchargement sur le site de l'éditeur pour la deuxième) ont été écrits en Visual Basic pour le système d'exploitation Windows XP.

A cause de problèmes liés au driver utilisé, non supporté par les nouvelles versions de Windows,  plusieurs des montages décrits ne peuvent plus être utilisés au delà de la vesion Windows XP.

Microsoft ayant décidé de ne plus suivre la version XP, il était temps pour l'auteur de réagir !

Ayant abandonné depuis quelques années l'utilisation de ce système d'exploitation (sauf pour obligation professionnelle) au profit de GNU/Linux, l'auteur a décidé de réécrire les logiciels pour pouvoir utiliser les montages sous Linux.

Tous les logiciels proposés ont été vérifiés sous la distribution Debian.

L'auteur vous invite à oublier Microsoft et à vous tourner vers une distribution Linux !

Vous trouverez sur ce site le code source des logiciels nécessaire au fonctionnement des montages proposés dans le livre. Ils ont été écrits en Python.

Ce que vous ne trouverez pas :

- les schémas théoriques et pratiques des montages ainsi que leur description

- les codes sources des logiciels à implanter dans les microcontrôleurs utilisés dans les montages

Ces informations sont bien sûr présentes dans l'ouvrage "L'USB pour tous"

Conversion RS232-USB

 

Si l'on maitrise le protocole de communication RS232 entre un appareil et le PC, utiliser un module électronique de conversion USB - RS232 reste le moyen le plus simple pour accéder à la communication via USB.

On retrouve cependant les inconvénients du protocole série, à savoir l'adéquation nécessaire entre les réglages matériels et logiciels (vitesse de communication, parité ...)

L'ajout d'un tel module eprésente aussi un surcoût au niveau du montage.

 

Carte 4 jauges analogiques :

C'est le premier montage décrit dans la deuxième édition :

Carte_4Jauges_photo.png

Il permet la mesure de quatre tensions (ayant une masse commune) et comprises entre 0 et 3,3V.

Une communication de type RS232 est installée entre le microcontrôleur (qui intègre un convertisseur analogique-numérique 8 bits) et le PC par le biais d'un module de conversion USB-RS232.

Deux Leds permettent de visualiser les échanges de données entre la carte et le PC.

Le logiciel sous Linux :

Quatre_jauges.png

Chacune des voies est activable individuellement.

Télécharger le fichier Quatre_jauges.zip , puis le décompresser dans le dossier de son choix. (Voir également les explications similaires concernant le logiciel AL991S.)

Le logiciel pilotant l'alimentation AL991S et la carte Quatre Jauges (connectée aux trois sorties A,B et C de l'alimentation) fonctionnant simultanément. Troies voies de mesure sont utilisées sur la carte (E0,E1,E2) pour mesurer respectivement les tensions présentes sur les sorties A, B et C de l'alimentation AL991S :

AL991_4jauges.png

Ci-dessous le code du logiciel à faire trouner sur le PC :

#!/usr/bin/python
#-*- coding: iso-8859-15 -*-
from __future__ import division
from gi.repository import Gtk, GObject
import os, sys
import serial
import string
from time import sleep
import glob

class JAUGES:
	def __init__(self):

		self.builder = Gtk.Builder()
		self.builder.add_from_file("4jauges.glade")

		#recuperation des widgets utilises par le programme :
		self.lb0 = self.builder.get_object("lb0")
		self.lb1 = self.builder.get_object("lb1")
		self.lb2 = self.builder.get_object("lb2")
		self.lb3 = self.builder.get_object("lb3")

		self.pb0 = self.builder.get_object("pb0")
		self.pb1 = self.builder.get_object("pb1")
		self.pb2 = self.builder.get_object("pb2")
		self.pb3 = self.builder.get_object("pb3")

		self.sw0 = self.builder.get_object("sw0")
		self.sw1 = self.builder.get_object("sw1")
		self.sw2 = self.builder.get_object("sw2")
		self.sw3 = self.builder.get_object("sw3")

		self.cbAuto = self.builder.get_object("cbAuto")

		
		self.btOuvrir = self.builder.get_object("btOuvrir")
		self.btFermer = self.builder.get_object("btFermer")
		self.btQuitter = self.builder.get_object("btQuitter")
		self.btRafraichir = self.builder.get_object("btRafraichir")
		self.comboPort = self.builder.get_object("comboPort")
		self.textAide = self.builder.get_object("textAide")
		self.textAPropos = self.builder.get_object("textAPropos")
		
		self.buffer_aide = self.textAide.get_buffer()
		fichier_aide = open("Aide.txt", "r")
		if fichier_aide:
			texte_aide = fichier_aide.read()
			fichier_aide.close()
			self.buffer_aide.set_text(texte_aide)
			
		self.buffer_apropos = self.textAPropos.get_buffer()
		fichier_apropos = open("A_propos.txt", "r")
		if fichier_apropos:
			texte_apropos = fichier_apropos.read()
			fichier_apropos.close()	
			self.buffer_apropos.set_text(texte_apropos)

		self.builder.connect_signals(self)

		window = self.builder.get_object('window')
		window.show_all()

		self.lister_ports()

		#initialisations :
		self.sortie =""
		self.port_serie = " "
		self.port_choisi = " "
		self.data_format = " "
		self.debit = 9600
		self.parite = ""

		self.E0active = False
		self.E1active = False
		self.E2active = False
		self.E3active = False

		
		self.btFermer.set_sensitive(False)
		self.btQuitter.set_sensitive(False)

	def lister_ports(self) :
		  list_port =  glob.glob('/dev/ttyUSB*')
		  i = 0
		  while i < len(list_port):
			self.comboPort.append_text(list_port[i])
			i=i+1

	def on_sw0_button_press_event(self,widget,event):
		self.E0active = not self.E0active

	def on_sw1_button_press_event(self,widget,event):
		self.E1active = not self.E1active

	def on_sw2_button_press_event(self,widget,event):
		self.E2active = not self.E2active

	def on_sw3_button_press_event(self,widget,event):
		self.E3active = not self.E3active


	def lecture_voies(self) :
		try :
			#lecture de chacune des 3 voies et affichage :
			#vidage du port et tentative de contact avec l'alim :
			self.port_serie.flushInput()
			self.port_serie.write('M')
			#petit délai avant de lire le retour :
			sleep(0.2)
			data_deci = []

			n_data = self.port_serie.inWaiting()
			for i in range (n_data):
				data_deci.append(ord(self.port_serie.read(1)))

			if self.E0active :
				self.lb0.set_text(str("{:4.2f}".format(data_deci[0]*3.3/256)))
				self.pb0.set_fraction(data_deci[0]/256)
			else:
				self.lb0.set_text("X.XX")
				self.pb0.set_fraction(0)

			if self.E1active :
				self.lb1.set_text(str("{:4.2f}".format(data_deci[1]*3.3/256)))
				self.pb1.set_fraction(data_deci[1]/256)
			else:
				self.lb1.set_text("X.XX")
				self.pb1.set_fraction(0)

			if self.E2active :
				self.lb2.set_text(str("{:4.2f}".format(data_deci[2]*3.3/256)))
				self.pb2.set_fraction(data_deci[2]/256)
			else:
				self.lb2.set_text("X.XX")
				self.pb2.set_fraction(0)

			if self.E3active :
				self.lb3.set_text(str("{:4.2f}".format(data_deci[3]*3.3/256)))
				self.pb3.set_fraction(data_deci[3]/256)
			else:
				self.lb3.set_text("X.XX")
				self.pb3.set_fraction(0)

			return True
		except :
			self.lb0.set_text('X.XX')
			self.lb1.set_text('X.XX')
			self.lb2.set_text('X.XX')
			self.lb3.set_text('X.XX')
			return False
		
		self.lecture_voies()

	def on_btRafraichir_clicked(self,widget):
		#Rafraichir la liste des ports série disponibles
		self.comboPort.remove_all()
		self.lister_ports()

	def on_btOuvrir_clicked(self,widget):
		# recuperation des parametres choisis :
		self.port_choisi = self.comboPort.get_active_text()
		debit = 9600
		data_format = serial.EIGHTBITS
		stop = serial.STOPBITS_ONE
		parite = serial.PARITY_NONE
		try:
			# desactivation de widgets (ceux qui ne doivent pas
			# etre modifies une fois le port serie ouvert) :
			self.comboPort.set_sensitive(False)
			self.btRafraichir.set_sensitive(False)
			self.btQuitter.set_sensitive(True)
			

			#ouverture du port serie :
			self.port_serie = serial.Serial(
				port=self.port_choisi,
				baudrate = debit,
				bytesize = data_format,
				parity = parite,
				stopbits = stop,
				timeout=2
			)

			#activation/desactivation de widgets :
			self.btFermer.set_sensitive(True)
			self.btOuvrir.set_sensitive(False)
			
			GObject.timeout_add(500, self.lecture_voies)

		except :
			self.comboPort.set_sensitive(True)
			self.btOuvrir.set_sensitive(True)
			self.btRafraichir.set_sensitive(True)

			#self.bt_fermer.set_sensitive(False)
			self.ouvert = False
			msg = "Erreur lors de l'ouverture du port série : ce port n'est peut-être pas valide, ou bien vous n'avez pas les droits pour accéder aux ports série"
			dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg)
			# Montre le dialog
			dialog.run()
			# Destruction du dialog
			dialog.destroy()


	def on_btFermer_clicked(self,widget):
		#fermeture du port série ouvert
		try :
			if self.port_serie.isOpen() == True:
				self.port_serie.close()
				self.comboPort.set_sensitive(True)
				self.btOuvrir.set_sensitive(True)
				self.btRafraichir.set_sensitive(True)
				self.btFermer.set_sensitive(False)
		
		except :
			msgFermer = "Erreur lors de la fermeture du port série !"
			dlgFermer = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msgFermer)
			dlgFermer.run()
			dlgFermer.destroy()

	def on_btQuitter_clicked(self,widget):
		Gtk.main_quit()

	def destroy(window, self):
		Gtk.main_quit()

def main():
	app = JAUGES()
	Gtk.main()

if __name__ == "__main__":
	sys.exit(main())

Avec un microcontrôleur

 

Montages à base de 68HC908

Le 68HC908JB8 est un microcontrôleur du fabricant Freescale ( Motorola) disposant des ressources nécessaires pour faire de la communication USB. On réduit alors notablement le coût de la réalisation par rapport à l'utilisation d'un module de conversion USB-série. Peu de composants suffisent à son fonctionnement :

HC908.png

Présentation

 

Les logiciels (initialement en Visual Basic sous Windows) ont été réécrits en Python. Ils utilisent le module PyUSB, module lui-même basé sur la libusb (Bibliothèque pour programmer des applications USB sans connaissances des mécanismes internes du noyau Linux).

Oubliez la fastidieuse installation des drivers (pilotes) sous Windows : l'utilisation de cette bibliothèque rend la vie simple à l'utilisateur. Nous n'aurons que quatre choses à faire, une fois pour toutes (pour l'intégralité des montages) :

1- Installer la libusb

2- Installer le module Python s'appuyant sur cette bibliothèque

3- Enregistrer, sur le système, en une seule fois l'intégralité des VID/PID des différents montages USB utilisés.

4- Appartenir au groupe d'utilisateurs autorisés à utiliser ces montages USB connectés sur le système

1- Installation de la Libusb :

On va commencer par vérifier si cette bibliothèque est installée :

A l'aide du gestionnaire de paquets, vérifier la présence de la libusb-1 ; l'installer si ce n'est déjà fait. (Rque : la présence de la version précédente (version 0.1) n'est pas gênante.

On doit finir par obtenir ceci (ici avec le gestionnaire de paquets Synaptic) :

libusb.png

2- Installation du module python PyUSB :

On installera la dernière version de ce module.

Faire le téléchargement ( https://github.com/walac/pyusb )

Puis :

 - décompresser ce zip dans le dossier de votre choix

 - Ouvrir une fenêtre du Terminal et se déplacer dans ce dossier

 - taper la commande sudo python setup.py install :

3- Inscription des couples VID/PID :

L'inscription de tous ces couples VID/PID (Cf livre pages 22 et 34) se fait sous Linux à l'aide d'un fichier de "règles" à déposer dans etc/udev/rules.d

L'accès à ce dossier étant protégé, on pourra utiliser la technique suivante :

 - dans un Terminal, taper la commande gksudo nautilus

 - on se retrouve dans l'explorateur de fichiers Nautilus mais on dispose de droits pour modifier le contenu de tous les dossiers

 - Aller dans Système de Fichiers -> etc -> udev -> rules.d

 - Y copier le fichier 20-usb-pour-tous.rules

rules.png

Détail du fichier 20-usb-pour-tous.rules :

# USB pour Tous - V.Le Mieux - Editions Dunod
# ID 0c70:f0a1 Carte E/S numeriques
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f0a1", GROUP="dialout", MODE="0660"
# ID 0c70:f0a2 Dongle USB
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f0a2", GROUP="dialout", MODE="0660"
# ID 0c70:f0a3 carte_CAN 8 bits
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f0a3", GROUP="dialout", MODE="0660"
# ID 0c70:f0a4 carte_relais
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f0a4", GROUP="dialout", MODE="0660"
# ID 0c70:f0a5 carte_CAN 12 bits
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f0a5", GROUP="dialout", MODE="0660"
# ID 0c70:f0a6 Reference de tension
SUBSYSTEM=="usb", ATTRS{idVendor}=="0c70", ATTRS{idProduct}=="f0a6", GROUP="dialout", MODE="0660"

4- S'inscrire au groupe Dialout :

On remarquera que l'on a lié tous ces VID/PID au groupe "dialout".

Seuls les utilisateurs appartenant à ce groupe pourront donc utiliser les montages.

Pour savoir à quels groupes on appartient, entrer dans un terminal la commande :

groups

Un exemple de retour (réalisé sur une distribution Debian toute neuve dans une VirtualBox) :

groups.png

On voit que l'utilisateur "vincent" n'appartient pas au group "dialout"

Appartenir au groupe "dialout" :

Pour que cet utilisateur "vincent" puisse appartenir au groupe "dialout", entrer les commandes suivantes dans un Terminal :

su     ( il faudra ensuite entrer son mot de passe administrateur)

usermod -a -G dialout vincent  (remplacer bien sûr l'utilisateur "vincent" par le vôtre !)

Voici l'ensemble de la séquence (à remarquer : la commande groups réitérée après usermod ne montre pas l'appartenance de l'utilisateur "vincent" au groupe "dialout". Il faudra faire un redémarrage pour que cela soit pris en compte :

usermod_avant_redemarage.png

Après redémarrage :

usermod_apres_reem.png

Remarque : l'ensemble des groupes disponibles se trouve dans le fichier etc/group. On aurait pu le lire avec gedit par exemple, voire même le modifier directement (en mode superutilisateur ... mais attention à ne pas faire d'erreurs !) :

9ae9e333cf5b6cb07614ac6874be639c_f812.png

Référence de tension

L'USB pour tous (2ème édition) - logiciels sous Linux

Carte "Sources de tension programmable" (page 113)

Cette carte permet de disposer de deux références de tension programmables par l'USB.

Les deux tensions générées sont indépendantes l'une de l'autre mais ont néanmoins leur masse commune.

La carte réalisée :

carte_ref_tension.png

L'interface graphique du logiciel sous Linux :

Ref_tension.png

Le code (téléchargeable ici), écrit en Python utilise un module nommé "bitstring" qui simplifie le travail avec les données binaires.

Il faudra installer ce module :

- le télécharger (https://pypi.python.org/pypi/bitstring/)

- le décompresser dans le dossier de son choix (l'auteur l'a placé dans Documents/Ajouts_Debian/ )

- entrer dans le dossier bitstring(dans mon cas : cd Documents/Ajouts_Debian/bitstring-3.1.3 )

et l'installer par la commande sudo python setup.py install :

instal_bitstring.png

Le code source du logiciel :

#!/usr/bin/python
#-*- coding: iso-8859-15 -*-
from gi.repository import Gtk, GObject
import os, sys
from bitstring import BitArray  #ce module rend aisé le retournement de l'octet
import usb.core
import usb.util
 
class REF_TENSION:
	def __init__(self):
 
		self.builder = Gtk.Builder()
		self.builder.add_from_file("reference_tension.glade")
 
		#recuperation des widgets utilises par le programme :
 
		self.lbA = self.builder.get_object("lbA")
		self.lbB = self.builder.get_object("lbB")
		self.scaleA = self.builder.get_object("scaleA")
		self.scaleB = self.builder.get_object("scaleB")
 
		self.builder.connect_signals(self)
 
		window = self.builder.get_object('window')
		window.show_all()
 
		#initialisations :
 
		ref_tension = usb.core.find(idVendor=0x0C70, idProduct = 0xF0A6)
 
		if ref_tension is None:	
			msg = "Carte Référence de tension non détectée : vérifier qu'elle est bien branchée sur un port USB, et bien alimentée ! Ce programme va se refermer ..."
			dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg) 
			# Montre le dialog
			dialog.run()
			# Destruction du dialog
			dialog.destroy()	
 
		config = ref_tension.get_active_configuration()
		interface = config[(0,0)]
 
		self.ep_out = usb.util.find_descriptor(interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT)
 
		# mise à 0 des deux voies
		self.ep_out.write(chr(0) + chr(0))
 
	def on_scaleA_value_changed(self,widget):			
		self.lbA.set_text(str("{:.2f}".format(self.scaleA.get_value()*3.3/256)))
		codeA = BitArray(uint=int(self.scaleA.get_value()), length=8)
		codeA.reverse()
		codeB = BitArray(uint=int(self.scaleB.get_value()), length=8)
		codeB.reverse()
		data = codeA.bytes + codeB.bytes
		self.ep_out.write(data)
 
	def on_scaleB_value_changed(self,widget):		
		self.lbB.set_text(str("{:.2f}".format(self.scaleB.get_value()*3.3/256)))
		codeA = BitArray(uint=int(self.scaleA.get_value()), length=8)
		codeA.reverse()		# retournement de l'octet
		codeB = BitArray(uint=int(self.scaleB.get_value()), length=8)
		codeB.reverse()		# retournement de l'octet
		data = codeA.bytes + codeB.bytes
		self.ep_out.write(data)
 
	def on_bt_Quitter_clicked(self,widget):
		self.ep_out.write(chr(0) + chr(0))	#remise à 0 des deux voies
		Gtk.main_quit()
 
	def on_window_destroy(self,widget):
		self.ep_out.write(chr(0) + chr(0))   #remise à 0 des deux voies
		Gtk.main_quit()
 
	def destroy(window, self):
		Gtk.main_quit()
 
def main():
	app = REF_TENSION()
	Gtk.main()
 
if __name__ == "__main__":
 
	sys.exit(main())

 

Carte 8 relais

L'USB pour tous (2ème édition) - logiciels sous Linux

Carte "8 Relais" (page 95)

Cette carte permet de disposer de 8 relais activables par l'USB.

La carte réalisée :

Carte_relais.png

L'interface graphique du logiciel sous Linux :

A télécharger ici

logiciel_carte_relais.png

Le code source du logiciel :



    #!/usr/bin/python
    #-*- coding: iso-8859-15 -*-
    from gi.repository import Gtk, GObject
    import os, sys
     
    import usb.core
    import usb.util
     
     
    class RELAIS:
    	def __init__(self):
     
    		self.builder = Gtk.Builder()
    		self.builder.add_from_file("carte_relais.glade")
     
    		#recuperation des widgets utilises par le programme :
     
    		self.switch0 = self.builder.get_object("switch0")
    		self.switch1 = self.builder.get_object("switch1")
    		self.switch2 = self.builder.get_object("switch2")
    		self.switch3 = self.builder.get_object("switch3")
    		self.switch4 = self.builder.get_object("switch4")
    		self.switch5 = self.builder.get_object("switch5")
    		self.switch6 = self.builder.get_object("switch6")
    		self.switch7 = self.builder.get_object("switch7")
     
    		self.bt_raz = self.builder.get_object("bt_raz")
     
    		self.builder.connect_signals(self)
     
    		window = self.builder.get_object('window')
    		window.show_all()
     
    		#initialisations :
    		carte_relais = usb.core.find(idVendor=0x0C70, idProduct = 0xF0A4)
     
    		if carte_relais is None:	
    			msg = "Carte_relais non détectée : vérifier qu'elle est bien branchée sur un port USB, et bien alimentée ! Ce programme va se refermer ..."
    			dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg) 
    			# Montre le dialog
    			dialog.run()
    			# Destruction du dialog
    			dialog.destroy()
     
     
    		config = carte_relais.get_active_configuration()
    		interface = config[(0,0)]
     
    		self.ep_out = usb.util.find_descriptor(interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT)
     
    		self.r0 = 0
    		self.r1 = 0
    		self.r2 = 0
    		self.r3 = 0
    		self.r4 = 0
    		self.r5 = 0
    		self.r6 = 0
    		self.r7 = 0
    		self.r = 0
     
    		self.raz()
     
    	def on_switch0_button_press_event(self,widget,event):
    		if self.switch0.get_active():
    			self.r0 = 0
    		else:
    			self.r0 = 1
    		self.envoyer_ordre()
     
    	def on_switch1_button_press_event(self,widget,event):
    		if self.switch1.get_active():
    			self.r1 = 0
    		else:
    			self.r1 = 2
    		self.envoyer_ordre()
     
    	def on_switch2_button_press_event(self,widget,event):
    		if self.switch2.get_active():
    			self.r2 = 0
    		else:
    			self.r2 = 4
    		self.envoyer_ordre()
     
    	def on_switch3_button_press_event(self,widget,event):
    		if self.switch3.get_active():
    			self.r3 = 0
    		else:
    			self.r3 = 8
    		self.envoyer_ordre()
     
    	def on_switch4_button_press_event(self,widget,event):
    		if self.switch4.get_active():
    			self.r4 = 0
    		else:
    			self.r4 = 16
    		self.envoyer_ordre()
     
    	def on_switch5_button_press_event(self,widget,event):
     
    		if self.switch5.get_active():
    			self.r5 = 0
    		else:
    			self.r5 = 32
    		self.envoyer_ordre()
     
    	def on_switch6_button_press_event(self,widget,event):
    		if self.switch6.get_active():
    			self.r6 = 0
    		else:
    			self.r6 = 64
    		self.envoyer_ordre()
     
    	def on_switch7_button_press_event(self,widget,event): 
    		if self.switch7.get_active():
    			self.r7 = 0
    		else:
    			self.r7 = 128
    		self.envoyer_ordre()
     
    	def envoyer_ordre(self):
    		r = self.r0 + self.r1 + self.r2 + self.r3 + self.r4 + self.r5 + self.r6 + self.r7
    		self.ep_out.write(chr(r))	
     
    	def bt_raz_clicked(self,widget):
    		self.raz()
     
    	def raz(self):
    		#Reouverture de tous les relais
    		self.switch0.set_active(False)
    		self.switch1.set_active(False)
    		self.switch2.set_active(False)
    		self.switch3.set_active(False)
    		self.switch4.set_active(False)
    		self.switch5.set_active(False)
    		self.switch6.set_active(False)
    		self.switch7.set_active(False)
    		self.r0 = 0
    		self.r1 = 0
    		self.r2 = 0
    		self.r3 = 0
    		self.r4 = 0
    		self.r5 = 0
    		self.r6 = 0
    		self.r7 = 0
    		self.ep_out.write(chr(0))		
     
    	def on_bt_Quitter_clicked(self,widget):
    		self.raz()
    		Gtk.main_quit()
     
    	def on_window_destroy(self,widget):
    		self.raz()
    		Gtk.main_quit()
     
    	def destroy(window, self):
    		Gtk.main_quit()
     
    def main():
    	app = RELAIS()
    	Gtk.main()
     
    if __name__ == "__main__":
     
    	sys.exit(main())

  

 

Thermomètre

 

L'USB pour tous (2ème édition) - logiciels sous Linux

Carte "Thermomètre" (page 157)

Cette carte permet de faire des mesures de température et de les transmettre en temps réel via l'USB.

La carte réalisée :

Carte_thermo.png

L'interface graphique de la version simple du logiciel sous Linux :

thermo.png

...et celle de la version 2 :

Thermometre_V2.png

Cette deuxième version permet l'enregistrement des données et l'export vers un tableur.

Le téléchargement se fait ici

 

#!/usr/bin/python
#-*- coding: iso-8859-15 -*-
 
# Copyright 2014 Vincent LE MIEUX
 
# Contact : vlemieux@laboiteaphysique.fr
 
# La version la plus récente de ce programme se trouve
# sur le site de l'auteur : www.laboiteaphysique.fr
 
# Ce programme est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant 
# les termes de la GNU General Public License telle que publiée par la Free Software Foundation ;
# soit la version 3 de la licence, soit (à votre gré) toute version ultérieure.
 
# Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ;
# sans même la garantie tacite de QUALITÉ MARCHANDE ou d'ADÉQUATION à UN BUT PARTICULIER. 
# Consultez la GNU General Public License pour plus de détails.
 
# Vous devez avoir reçu une copie de la GNU General Public License en même temps que ce programme ; 
# si ce n'est pas le cas, consultez <http://www.gnu.org/licenses>.
 
from gi.repository import Gtk, GObject
 
import os, sys
from time import sleep
import usb.core
import usb.util
 
import xlwt
from xlwt import Workbook
 
 
class THERMOMETRE(Gtk.Window):
	def __init__(self):
 
		self.builder = Gtk.Builder()
		self.builder.add_from_file("thermometre2.glade")
 
		#recuperation des widgets utilises par le programme :
 
		self.lbA = self.builder.get_object("lbA")
		self.swAcq = self.builder.get_object("swAcq")
		self.bt_Quitter = self.builder.get_object("bt_Quitter")
		self.bt_Save = self.builder.get_object("bt_Save")
		self.bt_Effacer = self.builder.get_object("bt_Effacer")
		self.sb_timer = self.builder.get_object("sb_timer")	
		self.textview = self.builder.get_object("textview")	
		self.textbuffer = self.builder.get_object("textbuffer")
		self.scrolledwindow1 = self.builder.get_object("scrolledwindow1")
 
		self.filechooserdialog = self.builder.get_object("filechooserdialog")
		self.cb_Filtre = self.builder.get_object("cb_Filtre")
 
		self.builder.connect_signals(self)
 
		window = self.builder.get_object('window')
		window.show_all()
 
		#initialisations :
 
		self.delai = 1000
		self.i = 0
		self.texte = ""
		self.cb_Filtre.set_active(0)
 
		self.texte = 't(s)' + '\t' + 'T(' + u"°C" +')' + '\r' + '\n' 
		self.textbuffer.set_text("")
 
 
 
		#création d'un classeur pour le tableur :
		global classeur
		classeur = Workbook()
		self.feuille1 = classeur.add_sheet("Mesures", cell_overwrite_ok=True)
		self.feuille1.write(0,0,'t(s)',xlwt.easyxf("align: horiz center"))
		self.feuille1.write(0,1,'T(' + u"°C" +')',xlwt.easyxf("align: horiz center"))
 
		thermo = usb.core.find(idVendor=0x0C70, idProduct = 0xF0A3)
 
		if thermo is None:	
			msg = "Carte thermometre non détectée : vérifier qu'elle est bien branchée sur un port USB, et bien alimentée ! Ce programme va se refermer ..."
			dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg) 
			# Montre le dialog
			dialog.run()
			# Destruction du dialog
			dialog.destroy()		
 
		config = thermo.get_active_configuration()
		interface = config[(0,0)]
 
		self.ep_out = usb.util.find_descriptor(interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT)		
		self.ep_in = usb.util.find_descriptor(interface, custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)
 
		self.pour_rien()
		self.affiche()
		self.timer_afficheur = GObject.timeout_add(300, self.affiche)
 
	def pour_rien(self):
		self.ep_out.write('M')
		sleep(0.02)
		pour_rien = self.ep_in.read(1)
		sleep(0.02)
		self.ep_out.write('M')
		sleep(0.02)
		pour_rien = self.ep_in.read(1)	
 
 
	def affiche(self):
		self.ep_out.write('M')
		temp_affiche = self.ep_in.read(1)	
		self.lbA.set_text(str("{:.1f}".format ( temp_affiche[0]*0.5)) + u" °C")
		return True
 
	def mesure(self):
		if self.i < 65536 :
			self.ep_out.write('M')
			temperature = self.ep_in.read(1)	
			self.texte +=(str(self.i*self.delai/1000) + '\t' + str("{:.1f}".format (temperature[0]*0.5)).replace('.', ',') + '\r' + '\n' )
			self.textbuffer.set_text(self.texte)	
			adjustment = self.scrolledwindow1.get_vadjustment()
			adjustment.set_value(adjustment.get_upper())
 
			self.feuille1.write(self.i+1,0,self.i*self.delai/1000,xlwt.easyxf("align: horiz center"))
			self.feuille1.write(self.i+1,1,float(str("{:.1f}".format (temperature[0]*0.5))),xlwt.easyxf("align: horiz center"))
			self.i = self.i + 1
			return True		
 
	def on_sb_timer_value_changed(self,widget):
		self.delai = int(1000*self.sb_timer.get_value())
 
	def on_swAcq_button_press_event(self,widget,event):
		if widget.get_active()==False :
			self.pour_rien()
			self.effacer()
			self.mesure()
			self.timer_id = GObject.timeout_add(self.delai, self.mesure)
 
			self.bt_Quitter.set_sensitive(False)
			self.bt_Effacer.set_sensitive(False)
			self.bt_Save.set_sensitive(False)
			self.sb_timer.set_sensitive(False)
 
		else:
			GObject.source_remove(self.timer_id)
			self.bt_Quitter.set_sensitive(True)
			self.bt_Effacer.set_sensitive(True)
			self.bt_Save.set_sensitive(True)
			self.sb_timer.set_sensitive(True)
 
	def effacer(self):
		self.texte = ' '
		self.texte = 't(s)' + '\t' + 'T(' + u"°C" +')' + '\r' + '\n' 
		self.textbuffer.set_text(self.texte)
		for j in range (self.i) :
			self.feuille1.write(j+1,0,'')
			self.feuille1.write(j+1,1,'')
		self.i = 0
 
	def on_bt_Effacer_clicked(self,widget) :
		self.effacer()
 
	def on_bt_Save_clicked(self,widget):
		reponse = self.filechooserdialog.run()
		if reponse == 1:		
			nom = self.filechooserdialog.get_filename()
			# Enregistrement format Calc :
			if self.cb_Filtre.get_active() ==0 :			
				if not nom.endswith('.ods'):
					fichier_ods = nom + '.ods'	
				else :
					fichier_ods = nom			
				with open(fichier_ods, 'w') :
					classeur.save(fichier_ods)
 
			# Enregistrement au format Gnumeric :			
			if self.cb_Filtre.get_active() == 1 :		
				if not nom.endswith('.gnumeric'):
					fichier_gnum = nom + '.gnumeric'
				else :
					fichier_gnum = nom				
				with open(fichier_gnum, 'w') :
					classeur.save(fichier_gnum)
		self.filechooserdialog.hide()
 
	def on_bt_Quitter_clicked(self,widget):
		Gtk.main_quit()
 
	def on_window_destroy(self,widget):
		GObject.source_remove(self.timer_id)
		GObject.source_remove(self.timer_afficheur)
		Gtk.main_quit()
 
	def destroy(window, self):
		GObject.source_remove(self.timer_id)
		GObject.source_remove(self.timer_afficheur)
		Gtk.main_quit()
 
def main():
	app = THERMOMETRE()
	Gtk.main()
 
 
 
if __name__ == "__main__":
 
	sys.exit(main())

 

Baromètre

 

L'USB pour tous (2ème édition) - logiciels sous Linux

Carte "Baromètre" (page 175)

Cette carte permet de faire des mesures de pression et de les transmettre en temps réel via l'USB.

La carte réalisée :

Carte_baro1.png

Vue sur le capteur de pression :

Carte_baro2.png

Le capteur de pression peut être utilisé comme sur la photo, auquel cas c'est la pression de l'air ambiant qui est mesurée. La carte fonctionne alors comme un "baromètre".

Mais on peut aussi relier la canule du capteur de pression à un tuyau souple relié à une enceinte contenant un gaz pour en mesurer la pression, ou plongeant dans un liquide. La carte est alors utilisée en "pressiomètre".

Le logiciel, avec en fond d'écran un site donnant la pression atmosphérique en temps réel dans quelques grandes villes :

barometre_9Sept2014.png

Une deuxième application (téléchargeable ici) a été créée pour faire fonctionner simultanément la carte thermomètre et la carte baromètre avec enregistrement des données et export possible vers un tableur (Calc de LibreOffice ou Gnumeric) :

thermo_barometre.png

 

katuberling.pngTélécharger le module Python PyUSB ( téléchargement ) ainsi que le fichier : 20-usb-pour-tous.rules