Ligne 1 : |
Ligne 1 : |
| {{RASP-PYGAME-GUI-NAV}} | | {{RASP-PYGAME-GUI-NAV}} |
| + | |
| + | == Entrée Analogique == |
| + | |
| + | {{ADFImage|RASP-PYGAME-GUI-Analogique-00.jpg}} |
| + | |
| + | Cet exemple utilise un potentiomètre de 10K pour fournir une tension variable. Pour la conversion analogique vers digital nous utilisons habituellement un [http://jeremyblythe.blogspot.co.uk/2012/09/raspberry-pi-hardware-spi-analog-inputs.html MCP3008 via SPI]. Mais cela n'est pas possible ici puisque le PiTFT utilise les deux canaux SPI disponibles sur le Pi. Par conséquant, nous optons pour un convertisseur ADC I2C: [http://www.adafruit.com/product/1085 ADC 16-Bit ADS1115 - 4 canaux avec un gain programmable]. |
| + | |
| + | Pour obtenir la bibliothèque Python Adafruit: |
| + | |
| + | <syntaxhighlight lang="bash"> |
| + | cd /home/pi |
| + | git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git |
| + | </syntaxhighlight> |
| + | |
| + | Vous aurez besoin d'activer [[Rasp-Hack-GPIO_Configurer_I2C|le support I2C en suivant ce guide]] |
| + | |
| + | {{ADFImage|RASP-PYGAME-GUI-Analogique-01.jpg}} |
| + | |
| + | == Démarrage == |
| + | Au tout début du script nous faisons quelques {{fname|import}} pour le support multitâche (''threading'') et la conversion ADC. |
| + | |
| + | Le gain et le taux d'échantillonnage sont configurés et le convertisseur ADC est initialisé. |
| + | |
| + | <syntaxhighlight lang="python"> |
| + | import sys |
| + | sys.path.append('/home/pi/Adafruit-Raspberry-Pi-Python-Code/Adafruit_ADS1x15') |
| + | |
| + | import pygame |
| + | import os |
| + | import pygameui as ui |
| + | import logging |
| + | import RPi.GPIO as GPIO |
| + | import signal |
| + | from Adafruit_ADS1x15 import ADS1x15 |
| + | import threading |
| + | import time |
| + | |
| + | ADS1015 = 0x00 # 12-bit ADC |
| + | ADS1115 = 0x01 # 16-bit ADC |
| + | |
| + | # Sélectionner le gain |
| + | # gain = 6144 # +/- 6.144V |
| + | gain = 4096 # +/- 4.096V |
| + | # gain = 2048 # +/- 2.048V |
| + | # gain = 1024 # +/- 1.024V |
| + | # gain = 512 # +/- 0.512V |
| + | # gain = 256 # +/- 0.256V |
| + | |
| + | # Sélectionner le taux d'échantillonnage |
| + | sps = 8 # 8 échantillons par seconde |
| + | # sps = 16 # 16 échantillons par seconde |
| + | # sps = 32 # 32 échantillons par seconde |
| + | # sps = 64 # 64 échantillons par seconde |
| + | # sps = 128 # 128 échantillons par seconde |
| + | # sps = 250 # 250 échantillons par seconde |
| + | # sps = 475 # 475 échantillons par seconde |
| + | # sps = 860 # 860 échantillons par seconde |
| + | |
| + | # Initialiser le convertisseur ADC en utilisant le mode par défaut (et adresse I2C par défaut) |
| + | # Utilisez ADS1015 ou ADS1115 en fonction de l'ADC que vous utilisez! |
| + | adc = ADS1x15(ic=ADS1115) |
| + | |
| + | # Configurer les GPIOs en sortie (OUTPUT) - seuls 4 et 17 sont disponibles |
| + | GPIO.setmode(GPIO.BCM) |
| + | GPIO.setup(4, GPIO.OUT) |
| + | GPIO.setup(17, GPIO.OUT) |
| + | |
| + | log_format = '%(asctime)-6s: %(name)s - %(levelname)s - %(message)s' |
| + | console_handler = logging.StreamHandler() |
| + | console_handler.setFormatter(logging.Formatter(log_format)) |
| + | logger = logging.getLogger() |
| + | logger.setLevel(logging.DEBUG) |
| + | logger.addHandler(console_handler) |
| + | |
| + | os.putenv('SDL_FBDEV', '/dev/fb1') |
| + | os.putenv('SDL_MOUSEDRV', 'TSLIB') |
| + | os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen') |
| + | |
| + | MARGIN = 20 |
| + | </syntaxhighlight> |
| + | |
| + | == Le thread du potentiomètre == |
| + | Un thread est utilisé pour lire continuellement la valeur du potentiomètre. Si l'on fait la lecture du potentiomètre dans la mise-à-jour de la Scene alors le taux de rafraîchissement de l'écran diminuera de façon importante. |
| + | |
| + | Ce thread séparé permet à l'écran d'être redessiné en même temps (en parallèle) que la lecture de la valeur depuis l'ADC. |
| + | |
| + | La classe est définie comme {{fname|callable}} appela - d'où la méthode {{fname|__call__}}. Il prend une référence vers la classe pitft de sorte qu'il est possible d'y mettre les valeurs à-jour. Il y a un schéma d'arrêt relativement simple basé sur la vérification d'un variable (un ''flag''/''drapeau'') à chaque tour de boucle. Nous verrons plus tard comment terminer proprement le programme en modifiant la variable ''flag''. |
| + | |
| + | Donc, nous lisons simplement la valeur depuis l'ADC et modifie la valeur du libellé et la position de la barre de progression (visible sur le pitft). |
| + | |
| + | <syntaxhighlight lang="python"> |
| + | class PotReader(): |
| + | def __init__(self, pitft): |
| + | self.pitft = pitft |
| + | self.terminated = False |
| + | |
| + | def terminate(self): |
| + | self.terminated = True |
| + | |
| + | def __call__(self): |
| + | while not self.terminated: |
| + | # Lecture du canal 0 en mode single-ended en utilisant la configuration ci-avant |
| + | volts = adc.readADCSingleEnded(0, gain, sps) / 1000 |
| + | self.pitft.set_volts_label(volts) |
| + | self.pitft.set_progress(volts / 3.3) |
| + | </syntaxhighlight> |
| + | |
| + | == Définition de l'interface utilisateur == |
| + | Nous avons ajouté quelques widget supplémentaires sur la Scene et modifié la taille des boutons (pour que tout se présente correctement). |
| + | |
| + | Nous allons afficher la tension sur un widget label (''libellé'') et un widget progress (''barre de progression''). |
| + | |
| + | Les méthodes {{fname|set_progress}} et {{fname|set_volts_label}} sont appelées depuis le thread PotReader pour faire la mise-à-jour des valeurs dans ces Widgets. |
| + | |
| + | <syntaxhighlight lang="python"> |
| + | class PiTft(ui.Scene): |
| + | def __init__(self): |
| + | ui.Scene.__init__(self) |
| + | |
| + | self.on17_button = ui.Button(ui.Rect(MARGIN, MARGIN, 130, 60), '17 on') |
| + | self.on17_button.on_clicked.connect(self.gpi_button) |
| + | self.add_child(self.on17_button) |
| + | |
| + | self.on4_button = ui.Button(ui.Rect(170, MARGIN, 130, 60), '4 on') |
| + | self.on4_button.on_clicked.connect(self.gpi_button) |
| + | self.add_child(self.on4_button) |
| + | |
| + | self.off17_button = ui.Button(ui.Rect(MARGIN, 100, 130, 60), '17 off') |
| + | self.off17_button.on_clicked.connect(self.gpi_button) |
| + | self.add_child(self.off17_button) |
| + | |
| + | self.off4_button = ui.Button(ui.Rect(170, 100, 130, 60), '4 off') |
| + | self.off4_button.on_clicked.connect(self.gpi_button) |
| + | self.add_child(self.off4_button) |
| + | |
| + | self.progress_view = ui.ProgressView(ui.Rect(MARGIN, 200, 280, 40)) |
| + | self.add_child(self.progress_view) |
| + | |
| + | self.volts_value = ui.Label(ui.Rect(135, 170, 50, 30), '') |
| + | self.add_child(self.volts_value) |
| + | |
| + | def gpi_button(self, btn, mbtn): |
| + | logger.info(btn.text) |
| + | |
| + | if btn.text == '17 on': |
| + | GPIO.output(17, False) |
| + | elif btn.text == '4 on': |
| + | GPIO.output(4, False) |
| + | elif btn.text == '17 off': |
| + | GPIO.output(17, True) |
| + | elif btn.text == '4 off': |
| + | GPIO.output(4, True) |
| + | |
| + | def set_progress(self, percent): |
| + | self.progress_view.progress = percent |
| + | |
| + | def set_volts_label(self, volts): |
| + | self.volts_value.text = '%.2f' % volts |
| + | |
| + | def update(self, dt): |
| + | ui.Scene.update(self, dt) |
| + | </syntaxhighlight> |
| + | |
| + | == Et pour finir... == |
| + | Pour démarrer le programme nous initialisons pygameui, construisons la classe pitft class et démarrons le thread potreader avec le pitft en référence. |
| + | |
| + | Puisque nous exécutons un thread supplémentaire, nous avons également besoin d'une '''méthode propre''' pour terminer le programme. |
| + | |
| + | Un gestionnaire de signal (''signal handler'') est utilisé pour capturer ctrl+c et terminer le thread PotReader avant d'appeler sys.exit - sinon le programme ne se fermera pas. |
| + | |
| + | <syntaxhighlight lang="python"> |
| + | ui.init('Raspberry Pi UI', (320, 240)) |
| + | pygame.mouse.set_visible(False) |
| + | |
| + | pitft = PiTft() |
| + | |
| + | # démarrer le thread exécutant le ''callable'' |
| + | potreader = PotReader(pitft) |
| + | threading.Thread(target=potreader).start() |
| + | |
| + | def signal_handler(signal, frame): |
| + | print 'Vous avez pressé Ctrl+C!' |
| + | potreader.terminate() |
| + | sys.exit(0) |
| + | |
| + | # Enregister le gesionnaire signal_handler pour le lignal SIGINT (interruption) |
| + | signal.signal(signal.SIGINT, signal_handler) |
| + | |
| + | ui.scene.push(pitft) |
| + | ui.run() |
| + | </syntaxhighlight> |
| + | |
| + | == Exécuter == |
| + | Vous pouvez exécuter cet exemple final depuis le projet pygamelcd: |
| + | |
| + | <syntaxhighlight lang="bash"> |
| + | sudo python test5.py |
| + | </syntaxhighlight> |
| + | |
| | | |
| {{RASP-PYGAME-GUI-TRAILER}} | | {{RASP-PYGAME-GUI-TRAILER}} |