
Dans ce tutoriel on va voir comment envoyer un message de la carte ESP32 vers le smarthpone via bluetooth en utilisant le clavier matriciel. C’est pour cela, on va créer deux programmes: une application mobile avec App Inventor pour le smartphone et un programme pour la carte ESP32.
On connecte les 8 sorties du clavier aux 8 broches de la carte ESP32 suivant cet ordre: D2, D4, D5, D18, D19, D16, D15 et D23.
Voici les programmes qui permettent de connecter la carte ESP32 au smartphone et d’envoyer un message par bluetooth en utilisant le clavier matriciel 4×4.
boot.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
from machine import Pin from esp_ble_uart import * from time import sleep import utime import machine import time nom = 'ESP32-ble-uart-gcworks' UUID_UART = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E' UUID_TX = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E' UUID_RX = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E' val_rx = "12" uart = Bleuart(nom, UUID_UART, UUID_TX, UUID_RX) uart.close() WIDTH = 128 HEIGHT = 64 # CONSTANTS KEY_UP = const(0) KEY_DOWN = const(1) keys = [['1', '2', '3', 'A'], ['4', '5', '6', 'B'], ['7', '8', '9', 'C'], ['*', '0', '#', 'D']] # Pin names for Pico cols = [19,16,15,23] rows = [2,4,5,18] # set pins for rows as outputs row_pins = [Pin(pin_name, mode=Pin.OUT) for pin_name in rows] # set pins for cols as inputs col_pins = [Pin(pin_name, mode=Pin.IN, pull=Pin.PULL_DOWN) for pin_name in cols] def init(): for row in range(0,4): for col in range(0,4): row_pins[row].value(0) def scan(row, col): """ scan the keypad """ # set the current column to high row_pins[row].value(1) key = None # check for keypressed events if col_pins[col].value() == KEY_DOWN: key = KEY_DOWN if col_pins[col].value() == KEY_UP: key = KEY_UP row_pins[row].value(0) # return the key state return key print("starting") def rcp_rx(): global val_rx if uart.any(): while uart.any(): val_rx = uart.read().decode().strip() print('sur rx: ', val_rx) # Interruption : affichage donn闁肩厧宕榮 re闁煎墽鎯甧s def env_tx(val_tx): uart.write(str(val_tx) + '\n') print("tx", val_tx) # set all the columns to low init() message="" while True: uart.irq(handler=rcp_rx) for row in range(4): for col in range(4): key = scan(row, col) if key == KEY_DOWN: print("Key Pressed", keys[row][col]) message=message+keys[row][col] env_tx(message) # envoi du caractere associe à la touche presse au smartphone last_key_press = keys[row][col] time.sleep_ms(1000) |
esp_ble_uart.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
from micropython import const import struct import bluetooth # Advertising payloads are repeated packets of the following form: # 1 byte data length (N + 1) # 1 byte type (see constants below) # N bytes type-specific data _ADV_TYPE_FLAGS = const(0x01) _ADV_TYPE_NAME = const(0x09) _ADV_TYPE_UUID16_COMPLETE = const(0x3) _ADV_TYPE_UUID32_COMPLETE = const(0x5) _ADV_TYPE_UUID128_COMPLETE = const(0x7) _ADV_TYPE_UUID16_MORE = const(0x2) _ADV_TYPE_UUID32_MORE = const(0x4) _ADV_TYPE_UUID128_MORE = const(0x6) _ADV_TYPE_APPEARANCE = const(0x19) _IRQ_CENTRAL_CONNECT = const(1 << 0) _IRQ_CENTRAL_DISCONNECT = const(1 << 1) _IRQ_GATTS_WRITE = const(1 << 2) # org.bluetooth.characteristic.gap.appearance.xml _ADV_APPEARANCE_GENERIC_COMPUTER = const(128) # Generate a payload to be passed to gap_advertise(adv_data=...). def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0): payload = bytearray() def _append(adv_type, value): nonlocal payload payload += struct.pack('BB', len(value) + 1, adv_type) + value _append(_ADV_TYPE_FLAGS, struct.pack('B', (0x01 if limited_disc else 0x02) + (0x00 if br_edr else 0x04))) if name: _append(_ADV_TYPE_NAME, name) if services: for uuid in services: b = bytes(uuid) if len(b) == 2: _append(_ADV_TYPE_UUID16_COMPLETE, b) elif len(b) == 4: _append(_ADV_TYPE_UUID32_COMPLETE, b) elif len(b) == 16: _append(_ADV_TYPE_UUID128_COMPLETE, b) # See org.bluetooth.characteristic.gap.appearance.xml _append(_ADV_TYPE_APPEARANCE, struct.pack('<h', appearance)) return payload def decode_field(payload, adv_type): i = 0 result = [] while i + 1 < len(payload): if payload[i + 1] == adv_type: result.append(payload[i + 2:i + payload[i] + 1]) i += 1 + payload[i] return result def decode_name(payload): n = decode_field(payload, _ADV_TYPE_NAME) return str(n[0], 'utf-8') if n else '' def decode_services(payload): services = [] for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE): services.append(bluetooth.UUID(struct.unpack('<h', u)[0])) for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE): services.append(bluetooth.UUID(struct.unpack('<d', u)[0])) for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE): services.append(bluetooth.UUID(u)) return services class Bleuart: def __init__(self, name, UUID_UART, UUID_TX, UUID_RX, rxbuf=100): _UART_UUID = bluetooth.UUID(UUID_UART,) _UART_TX = (bluetooth.UUID(UUID_TX), bluetooth.FLAG_NOTIFY,) _UART_RX = (bluetooth.UUID(UUID_RX), bluetooth.FLAG_WRITE,) _UART_SERVICE = (_UART_UUID, (_UART_TX, _UART_RX,),) self._ble = bluetooth.BLE() self._ble.active(True) self._ble.irq(handler=self._irq) ((self._tx_handle, self._rx_handle,),) = self._ble.gatts_register_services((_UART_SERVICE,)) # Increase the size of the rx buffer and enable append mode. self._ble.gatts_set_buffer(self._rx_handle, rxbuf, True) self._connections = set() self._rx_buffer = bytearray() self._handler = None # Optionally add services=[_UART_UUID], but this is likely to make the payload too large. self._payload = advertising_payload(name=name, appearance=_ADV_APPEARANCE_GENERIC_COMPUTER) self._advertise() def irq(self, handler): self._handler = handler def _irq(self, event, data): # Track connections so we can send notifications. if event == _IRQ_CENTRAL_CONNECT: conn_handle, _, _, = data self._connections.add(conn_handle) elif event == _IRQ_CENTRAL_DISCONNECT: conn_handle, _, _, = data if conn_handle in self._connections: self._connections.remove(conn_handle) # Start advertising again to allow a new connection. self._advertise() elif event == _IRQ_GATTS_WRITE: conn_handle, value_handle, = data if conn_handle in self._connections and value_handle == self._rx_handle: self._rx_buffer += self._ble.gatts_read(self._rx_handle) if self._handler: self._handler() def any(self): return len(self._rx_buffer) def read(self, sz=None): if not sz: sz = len(self._rx_buffer) result = self._rx_buffer[0:sz] self._rx_buffer = self._rx_buffer[sz:] return result def write(self, data): for conn_handle in self._connections: self._ble.gatts_notify(conn_handle, self._tx_handle, data) def close(self): for conn_handle in self._connections: self._ble.gap_disconnect(conn_handle) self._connections.clear() def _advertise(self, interval_us=500000): self._ble.gap_advertise(interval_us, adv_data=self._payload) |
On va créer une application mobile nommée ‘esp32_clavier’ avec App Inventor qui permet de recevoir un message de la carte ESP32.
On vous propose donc de réaliser le design de l’application, avec le visuel suivant:
Pour programmer l’application, App Inventor nous propose d’utiliser L’espace Blocs qui permet de créer un programme sous forme de schéma bloc. Très simple d’utilisation mais nécessitant un peu de logique de programmation.
Voici le programme de l’application réalisée dans l’espace Blocs de l’App Inventor: