First commit
This commit is contained in:
commit
e52bf4d0af
BIN
1 - Découverte du langage Python/._Découverte_Python.pdf
Normal file
BIN
1 - Découverte du langage Python/._Découverte_Python.pdf
Normal file
Binary file not shown.
BIN
1 - Découverte du langage Python/Découverte_Python.pdf
Normal file
BIN
1 - Découverte du langage Python/Découverte_Python.pdf
Normal file
Binary file not shown.
BIN
1 - Découverte du langage Python/Memento_Python.pdf
Normal file
BIN
1 - Découverte du langage Python/Memento_Python.pdf
Normal file
Binary file not shown.
BIN
1 - Découverte du langage Python/Pierre_feuilles_ciseaux.pdf
Normal file
BIN
1 - Découverte du langage Python/Pierre_feuilles_ciseaux.pdf
Normal file
Binary file not shown.
BIN
10- Fonctions booléennes/Fonctions_Booléennes.pdf
Normal file
BIN
10- Fonctions booléennes/Fonctions_Booléennes.pdf
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
11300
10-Type-construit/Types construits/pdf/Types construits.html
Normal file
11300
10-Type-construit/Types construits/pdf/Types construits.html
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
BIN
11- Fonctions booléennes/Fonctions_Booléennes.pdf
Normal file
BIN
11- Fonctions booléennes/Fonctions_Booléennes.pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
12 - Découverte Rapsberry PICO/Découverte_Raspberry_PICO.pdf
Normal file
BIN
12 - Découverte Rapsberry PICO/Découverte_Raspberry_PICO.pdf
Normal file
Binary file not shown.
Binary file not shown.
41
12 - Découverte Rapsberry PICO/mission6.py
Normal file
41
12 - Découverte Rapsberry PICO/mission6.py
Normal file
@ -0,0 +1,41 @@
|
||||
from machine import Pin, PWM
|
||||
import time
|
||||
pin_led = PWM(Pin(16, mode=Pin.OUT))
|
||||
pin_bpblue = Pin(20, mode=Pin.IN)
|
||||
pin_bpred = Pin(21, mode=Pin.IN)
|
||||
led=0
|
||||
gyro = 0
|
||||
|
||||
while True:
|
||||
etat_BPblue = pin_bpblue.value()
|
||||
etat_BPred = pin_bpred.value()
|
||||
if (etat_BPred == False) and (etat_BPblue == False):
|
||||
print('Nous avons besoin de votre aide')
|
||||
elif (etat_BPblue == False):
|
||||
print('Bonjour habitants de la planète Algoréa')
|
||||
while gyro <= 10:
|
||||
pin_led.value(True)
|
||||
time.sleep(0.1)
|
||||
pin_led.value(False)
|
||||
time.sleep(0.1)
|
||||
gyro = gyro +1
|
||||
elif (etat_BPred == False):
|
||||
print('Nous venons de la planète Terre')
|
||||
if led == 0:
|
||||
pin_led.value(True)
|
||||
led = 1
|
||||
elif led == 1:
|
||||
pin_led.value(False)
|
||||
led = 0
|
||||
|
||||
else:
|
||||
print('Released')
|
||||
|
||||
time.sleep(0.5)
|
||||
gyro = 0
|
||||
'''
|
||||
pin_led.value(True)
|
||||
time.sleep(1)
|
||||
pin_led.value(False)
|
||||
time.sleep(1)
|
||||
'''
|
||||
35
12 - Découverte Rapsberry PICO/pwm.py
Normal file
35
12 - Découverte Rapsberry PICO/pwm.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Import all libs
|
||||
from machine import PWM, Pin, ADC
|
||||
import time
|
||||
# Value definitions
|
||||
pwm_const = 65535
|
||||
pwm_percentage = 0.80
|
||||
|
||||
# Make calculations on the cont to use it later
|
||||
cycle = int(pwm_const*pwm_percentage)
|
||||
|
||||
# Define pins to use
|
||||
led_pwm = PWM(Pin(16, mode=Pin.OUT))
|
||||
adc_pin = Pin(26, mode=Pin.IN)
|
||||
pin_bpblue = Pin(20, mode=Pin.IN)
|
||||
pin_bpred = Pin(21, mode=Pin.IN)
|
||||
|
||||
# Define parameters
|
||||
led_pwm.freq(50)
|
||||
adc = ADC(adc_pin)
|
||||
|
||||
# Main loop
|
||||
led_pwm.duty_u16(cycle)
|
||||
while True :
|
||||
etat_BPblue = pin_bpblue.value()
|
||||
etat_BPred = pin_bpred.value()
|
||||
N = adc.read_u16();
|
||||
led_pwm.duty_u16(N)
|
||||
if (etat_BPred == False) and (etat_BPblue == False):
|
||||
time.sleep(5)
|
||||
print(N)
|
||||
time.sleep(0.01)
|
||||
'''
|
||||
pin_led.value(True)
|
||||
|
||||
'''
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
13 - Découverte Rapsberry PICO/Découverte_Raspberry_PICO.pdf
Normal file
BIN
13 - Découverte Rapsberry PICO/Découverte_Raspberry_PICO.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
13 - Mini Projets/2 - Station Météo/Compte Rendu.7z
Normal file
BIN
13 - Mini Projets/2 - Station Météo/Compte Rendu.7z
Normal file
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,218 @@
|
||||
# Sommaire :
|
||||
- Cahier de charges
|
||||
- Le matériel utilisé
|
||||
- Les parties importantes du code
|
||||
- Le code
|
||||
- Le schéma de l’algorithme
|
||||
- Captures d'écrans (page bluetooth et comment ça fonctionne + page HTML)
|
||||
|
||||
## Le Cahier de Charges
|
||||
*Problématique:* Comment récupérer les mesures du monde réel grâce a des capteurs pour les rendre accessibles ?
|
||||
|
||||
*Objectif du projet:* Nous voulions créer une station météo portative sur laquelle on peut connaitre différentes mesures de notre environnement (Taux de CO2, Température, Humidité et Pression Atmosphérique). Pour voir ces mesures, on peut utiliser l'écran LCD intégré, une application reliée en Bluetooth, ou une page internet, par Wi-Fi.
|
||||
|
||||
*Périmètre du projet:* Nous nous concentrons sur des personnes désignées.
|
||||
|
||||
*Description fonctionnelle de besoin:* L'application doit être en capacité de renvoyer sur l'écran, les valeurs mesurées par les capteurs tout en renouvelant ces données toutes les 10 secondes pour des valeurs presque en temps réel.
|
||||
|
||||
*Contraintes:* être capable d'avoir des valeurs précises et cohérentes.
|
||||
|
||||
*Délais*: le projet a commencé le 18/12/2024 et on aura terminer vers le 24/01/2025 avec quelques jours de délais pour finaliser le compte rendu.
|
||||
|
||||
## Le matériel utilisé
|
||||
Pour réaliser ce projet, nous avions eu besoin de quelques éléments matériels :
|
||||
- Une carte Raspberry Pi PICO: elle sert a contrôler les différents capteurs et l'écran
|
||||
- Un capteur SGP30 (Gaz)
|
||||
- Un capteur BME280 (Température, pression atmoshérique et humidité)
|
||||
- Afficheur LCD I2C Grove
|
||||
## Le code
|
||||
````
|
||||
# Importe tout les modules requis
|
||||
|
||||
from machine import Pin, I2C, UART
|
||||
|
||||
import uSGP30
|
||||
|
||||
import uBME280
|
||||
|
||||
from i2c_lcd import lcd
|
||||
|
||||
import time
|
||||
|
||||
|
||||
|
||||
# Défini l'interface du protocole I2C
|
||||
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 1024)
|
||||
|
||||
|
||||
|
||||
# Défini l'interface UART utilisée pour le Bluetooth
|
||||
|
||||
BT = UART(1, baudrate = 9600, tx = Pin(4), rx = Pin(5))
|
||||
|
||||
|
||||
|
||||
# Défuini les adresses I2C requis pour les capteurs
|
||||
|
||||
BME_addr = 0x76;
|
||||
|
||||
SGP30_adrr = 0x58;
|
||||
|
||||
|
||||
|
||||
# Déclare les paramètres des capteurs
|
||||
|
||||
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
|
||||
|
||||
# Le BME280 prends comme argument : le mode du capteur, l'adresse i2c du capteur et l'interface du protocole i2c
|
||||
|
||||
sgp30 = uSGP30.SGP30(i2c, SGP30_adrr)
|
||||
|
||||
# Le SGP30 prends comme argument : l'interface du protocole i2c et l'adresse i2c du capteur
|
||||
|
||||
display = lcd(i2c)
|
||||
|
||||
|
||||
|
||||
# Crée les variables contenants les valeurs extérieures
|
||||
|
||||
t = str(bme280.read_temperature()/100)
|
||||
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
|
||||
# Les valeurs ci dessus doivent être converties en texte car l'écran requiers des valeurs car sinon le programe renvoie une "TypeError: object with buffer protocol required"
|
||||
|
||||
# De plus, les valeurs doivent êtres divisés par 100 ou par 1000 car elles ne sont pas dans la bonne unitée (capteur en pascal, valeur attendue en kPascal)
|
||||
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
|
||||
co2 = str(t_CO2)
|
||||
|
||||
|
||||
|
||||
# Crée la fonction qui permet de récupérer les valeurs
|
||||
|
||||
def Update_Valeurs():
|
||||
|
||||
t = str(bme280.read_temperature()/100)
|
||||
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
|
||||
co2 = str(t_CO2)
|
||||
|
||||
|
||||
|
||||
# Crée la fonction qui permet d'afficher le "premier écran"
|
||||
|
||||
def First_Screen():
|
||||
|
||||
# Affiche le premier "écran" (Température + Humidité)
|
||||
|
||||
display.home()
|
||||
|
||||
display.write("Temp = ")
|
||||
|
||||
display.write(t)
|
||||
|
||||
display.write(" °C")
|
||||
|
||||
display.setCursor(0,1)
|
||||
|
||||
display.write("THum = ")
|
||||
|
||||
display.write(h)
|
||||
|
||||
display.write(" %")
|
||||
|
||||
|
||||
|
||||
# Crée la fonction qui permet d'afficher le "deuxième écran"
|
||||
|
||||
def Second_Screen():
|
||||
|
||||
# Affiche le deuxième "écran" (Pression + CO2)
|
||||
|
||||
display.clear()
|
||||
|
||||
display.home()
|
||||
|
||||
display.write("P = ")
|
||||
|
||||
display.write(p)
|
||||
|
||||
display.write(" Pa")
|
||||
|
||||
display.setCursor(0,1)
|
||||
|
||||
display.write("TCO2 = ")
|
||||
|
||||
display.write(co2)
|
||||
|
||||
display.write(" ppm")
|
||||
|
||||
|
||||
|
||||
# Crée la fonction qui permet d'afficher les valeurs
|
||||
|
||||
def Update_Screen():
|
||||
|
||||
# Affiche le premier "écran"
|
||||
|
||||
First_Screen()
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
Second_Screen()
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
display.clear()
|
||||
|
||||
|
||||
|
||||
# Crée la fonction qui permet d'envoyer les valeurs en bluetooth
|
||||
|
||||
def Send_Datas(a, b, c, d):
|
||||
|
||||
BT.write(a)
|
||||
|
||||
BT.write(b)
|
||||
|
||||
BT.write(c)
|
||||
|
||||
BT.write(d)
|
||||
|
||||
# Lance le programme indéfiniment
|
||||
|
||||
while True:
|
||||
|
||||
Update_Valeurs()
|
||||
|
||||
Send_Datas(t, h, p, co2)
|
||||
|
||||
Update_Screen()
|
||||
````
|
||||
|
||||
## Les parties importantes du code
|
||||
### La fonction Update_Values() qui permet de récupérer les valeurs des différents capteurs
|
||||
`def Update_Values():` Crée la fonction avec le mot-clé "def"
|
||||
`t = str(bme280.read_temperature()/100)` Récupère la température depuis le BME280, la transforme en "str" pour que l'écran puisse l'afficher et divise par 100 pour adapter à la bonne unité
|
||||
`p = str(bme280.read_pressure()/1000)` Récupère la pression atmosphérique depuis le BME280, la transforme en "str" pour que l'écran puisse l'afficher et divise par 1000 pour adapter à la bonne unité
|
||||
`h = str(bme280.read_humidity()/1000)` Récupère l'humidité depuis le BME280, la transforme en "str" pour que l'écran puisse l'afficher et divise par 1000 pour adapter à la bonne unité
|
||||
`t_CO2, t_COV = sgp30.measure_iaq()` Récupère le taux de CO2 depuis le SGP30
|
||||
`co2 = str(t_CO2)` Converti le taux de CO2 en "str" pour pouvoir l'afficher sur l'écran
|
||||
|
||||
## Schéma de l’algorithme
|
||||
[[Schéma de l'algorithme.canvas|Schéma de l'algorithme]]
|
||||
![[Algorigramme.png]]
|
||||
|
||||
## Captures d'écran
|
||||
Capture d'écran de la page Web de la station, avec des éléments de template
|
||||
![[capture station.PNG]]
|
||||
Binary file not shown.
@ -0,0 +1,135 @@
|
||||
from machine import I2C
|
||||
import time
|
||||
|
||||
_I2CADDR = const(0x3E)
|
||||
|
||||
# commands
|
||||
_LCD_CLEARDISPLAY = const(0x01)
|
||||
_LCD_RETURNHOME = const(0x02)
|
||||
_LCD_ENTRYMODESET = const(0x04)
|
||||
_LCD_DISPLAYCONTROL = const(0x08)
|
||||
_LCD_CURSORSHIFT = const(0x10)
|
||||
_LCD_FUNCTIONSET = const(0x20)
|
||||
_LCD_SETCGRAMADDR = const(0x40)
|
||||
_LCD_SETDDRAMADDR = const(0x80)
|
||||
|
||||
# flags for display entry mode
|
||||
_LCD_ENTRYRIGHT = const(0x00)
|
||||
_LCD_ENTRYLEFT = const(0x02)
|
||||
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
|
||||
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
|
||||
|
||||
# flags for display on/off control
|
||||
_LCD_DISPLAYON = const(0x04)
|
||||
_LCD_DISPLAYOFF = const(0x00)
|
||||
_LCD_CURSORON = const(0x02)
|
||||
_LCD_CURSOROFF = const(0x00)
|
||||
_LCD_BLINKON = const(0x01)
|
||||
_LCD_BLINKOFF = const(0x00)
|
||||
|
||||
# flags for display/cursor shift
|
||||
_LCD_DISPLAYMOVE = const(0x08)
|
||||
_LCD_CURSORMOVE = const(0x00)
|
||||
_LCD_MOVERIGHT = const(0x04)
|
||||
_LCD_MOVELEFT = const(0x00)
|
||||
|
||||
# flags for function set
|
||||
_LCD_8BITMODE = const(0x10)
|
||||
_LCD_4BITMODE = const(0x00)
|
||||
_LCD_2LINE = const(0x08)
|
||||
_LCD_1LINE = const(0x00)
|
||||
_LCD_5x10DOTS = const(0x04)
|
||||
_LCD_5x8DOTS = const(0x00)
|
||||
|
||||
class lcd:
|
||||
|
||||
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
|
||||
self.i2c = i2c
|
||||
self.i2c.scan()
|
||||
self.address = address
|
||||
self.disp_func = _LCD_DISPLAYON
|
||||
if not oneline:
|
||||
self.disp_func |= _LCD_2LINE
|
||||
elif charsize != 0:
|
||||
# for 1-line displays you can choose another dotsize
|
||||
self.disp_func |= _LCD_5x10DOTS
|
||||
|
||||
# wait for display init after power-on
|
||||
time.sleep_ms(50) # 50ms
|
||||
|
||||
# send function set
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
|
||||
# turn on the display
|
||||
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
|
||||
self.display(True)
|
||||
|
||||
# clear it
|
||||
self.clear()
|
||||
|
||||
# set default text direction (left-to-right)
|
||||
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
|
||||
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
|
||||
|
||||
def cmd(self, command):
|
||||
assert command >= 0 and command < 256
|
||||
command = bytearray([command])
|
||||
self.i2c.writeto_mem(self.address, 0x80, command)
|
||||
|
||||
def write_char(self, c):
|
||||
assert c >= 0 and c < 256
|
||||
c = bytearray([c])
|
||||
self.i2c.writeto_mem(self.address, 0x40, c)
|
||||
|
||||
def write(self, text):
|
||||
for char in text:
|
||||
self.write_char(ord(char))
|
||||
|
||||
def cursor(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def setCursor(self, col, row):
|
||||
col = (col | 0x80) if row == 0 else (col | 0xc0)
|
||||
self.cmd(col)
|
||||
|
||||
def autoscroll(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def blink(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def display(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def clear(self):
|
||||
self.cmd(_LCD_CLEARDISPLAY)
|
||||
time.sleep_ms(2) # 2ms
|
||||
|
||||
def home(self):
|
||||
self.cmd(_LCD_RETURNHOME)
|
||||
time.sleep_ms(2) # 2m
|
||||
@ -0,0 +1,284 @@
|
||||
from machine import I2C
|
||||
import time
|
||||
|
||||
# BME280 default address.
|
||||
BME280_I2CADDR = 0x76
|
||||
|
||||
# Operating Modes
|
||||
BME280_OSAMPLE_1 = 1
|
||||
BME280_OSAMPLE_2 = 2
|
||||
BME280_OSAMPLE_4 = 3
|
||||
BME280_OSAMPLE_8 = 4
|
||||
BME280_OSAMPLE_16 = 5
|
||||
|
||||
# BME280 Registers
|
||||
|
||||
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
|
||||
BME280_REGISTER_DIG_T2 = 0x8A
|
||||
BME280_REGISTER_DIG_T3 = 0x8C
|
||||
|
||||
BME280_REGISTER_DIG_P1 = 0x8E
|
||||
BME280_REGISTER_DIG_P2 = 0x90
|
||||
BME280_REGISTER_DIG_P3 = 0x92
|
||||
BME280_REGISTER_DIG_P4 = 0x94
|
||||
BME280_REGISTER_DIG_P5 = 0x96
|
||||
BME280_REGISTER_DIG_P6 = 0x98
|
||||
BME280_REGISTER_DIG_P7 = 0x9A
|
||||
BME280_REGISTER_DIG_P8 = 0x9C
|
||||
BME280_REGISTER_DIG_P9 = 0x9E
|
||||
|
||||
BME280_REGISTER_DIG_H1 = 0xA1
|
||||
BME280_REGISTER_DIG_H2 = 0xE1
|
||||
BME280_REGISTER_DIG_H3 = 0xE3
|
||||
BME280_REGISTER_DIG_H4 = 0xE4
|
||||
BME280_REGISTER_DIG_H5 = 0xE5
|
||||
BME280_REGISTER_DIG_H6 = 0xE6
|
||||
BME280_REGISTER_DIG_H7 = 0xE7
|
||||
|
||||
BME280_REGISTER_CHIPID = 0xD0
|
||||
BME280_REGISTER_VERSION = 0xD1
|
||||
BME280_REGISTER_SOFTRESET = 0xE0
|
||||
|
||||
BME280_REGISTER_CONTROL_HUM = 0xF2
|
||||
BME280_REGISTER_CONTROL = 0xF4
|
||||
BME280_REGISTER_CONFIG = 0xF5
|
||||
BME280_REGISTER_PRESSURE_DATA = 0xF7
|
||||
BME280_REGISTER_TEMP_DATA = 0xFA
|
||||
BME280_REGISTER_HUMIDITY_DATA = 0xFD
|
||||
|
||||
|
||||
class Device:
|
||||
"""Class for communicating with an I2C device.
|
||||
Allows reading and writing 8-bit, 16-bit, and byte array values to
|
||||
registers on the device."""
|
||||
|
||||
def __init__(self, address, i2c):
|
||||
"""Create an instance of the I2C device at the specified address using
|
||||
the specified I2C interface object."""
|
||||
self._address = address
|
||||
self._i2c = i2c
|
||||
|
||||
def writeRaw8(self, value):
|
||||
"""Write an 8-bit value on the bus (without register)."""
|
||||
value = value & 0xFF
|
||||
self._i2c.writeto(self._address, value)
|
||||
|
||||
def write8(self, register, value):
|
||||
"""Write an 8-bit value to the specified register."""
|
||||
b=bytearray(1)
|
||||
b[0]=value & 0xFF
|
||||
self._i2c.writeto_mem(self._address, register, b)
|
||||
|
||||
def write16(self, register, value):
|
||||
"""Write a 16-bit value to the specified register."""
|
||||
value = value & 0xFFFF
|
||||
b=bytearray(2)
|
||||
b[0]= value & 0xFF
|
||||
b[1]= (value>>8) & 0xFF
|
||||
self.i2c.writeto_mem(self._address, register, value)
|
||||
|
||||
def readRaw8(self):
|
||||
"""Read an 8-bit value on the bus (without register)."""
|
||||
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
|
||||
|
||||
def readU8(self, register):
|
||||
"""Read an unsigned byte from the specified register."""
|
||||
return int.from_bytes(
|
||||
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
|
||||
|
||||
def readS8(self, register):
|
||||
"""Read a signed byte from the specified register."""
|
||||
result = self.readU8(register)
|
||||
if result > 127:
|
||||
result -= 256
|
||||
return result
|
||||
|
||||
def readU16(self, register, little_endian=True):
|
||||
"""Read an unsigned 16-bit value from the specified register, with the
|
||||
specified endianness (default little endian, or least significant byte
|
||||
first)."""
|
||||
result = int.from_bytes(
|
||||
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
|
||||
if not little_endian:
|
||||
result = ((result << 8) & 0xFF00) + (result >> 8)
|
||||
return result
|
||||
|
||||
def readS16(self, register, little_endian=True):
|
||||
"""Read a signed 16-bit value from the specified register, with the
|
||||
specified endianness (default little endian, or least significant byte
|
||||
first)."""
|
||||
result = self.readU16(register, little_endian)
|
||||
if result > 32767:
|
||||
result -= 65536
|
||||
return result
|
||||
|
||||
def readU16LE(self, register):
|
||||
"""Read an unsigned 16-bit value from the specified register, in little
|
||||
endian byte order."""
|
||||
return self.readU16(register, little_endian=True)
|
||||
|
||||
def readU16BE(self, register):
|
||||
"""Read an unsigned 16-bit value from the specified register, in big
|
||||
endian byte order."""
|
||||
return self.readU16(register, little_endian=False)
|
||||
|
||||
def readS16LE(self, register):
|
||||
"""Read a signed 16-bit value from the specified register, in little
|
||||
endian byte order."""
|
||||
return self.readS16(register, little_endian=True)
|
||||
|
||||
def readS16BE(self, register):
|
||||
"""Read a signed 16-bit value from the specified register, in big
|
||||
endian byte order."""
|
||||
return self.readS16(register, little_endian=False)
|
||||
|
||||
|
||||
class BME280:
|
||||
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
|
||||
**kwargs):
|
||||
# Check that mode is valid.
|
||||
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
|
||||
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
|
||||
raise ValueError(
|
||||
'Unexpected mode value {0}. Set mode to one of '
|
||||
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
|
||||
'BME280_ULTRAHIGHRES'.format(mode))
|
||||
self._mode = mode
|
||||
# Create I2C device.
|
||||
if i2c is None:
|
||||
raise ValueError('An I2C object is required.')
|
||||
self._device = Device(address, i2c)
|
||||
# Load calibration values.
|
||||
self._load_calibration()
|
||||
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
|
||||
self.t_fine = 0
|
||||
|
||||
def _load_calibration(self):
|
||||
|
||||
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
|
||||
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
|
||||
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
|
||||
|
||||
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
|
||||
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
|
||||
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
|
||||
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
|
||||
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
|
||||
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
|
||||
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
|
||||
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
|
||||
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
|
||||
|
||||
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
|
||||
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
|
||||
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
|
||||
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
|
||||
|
||||
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
|
||||
h4 = (h4 << 24) >> 20
|
||||
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
|
||||
|
||||
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
|
||||
h5 = (h5 << 24) >> 20
|
||||
self.dig_H5 = h5 | (
|
||||
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
|
||||
|
||||
def read_raw_temp(self):
|
||||
"""Reads the raw (uncompensated) temperature from the sensor."""
|
||||
meas = self._mode
|
||||
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
|
||||
meas = self._mode << 5 | self._mode << 2 | 1
|
||||
self._device.write8(BME280_REGISTER_CONTROL, meas)
|
||||
sleep_time = 1250 + 2300 * (1 << self._mode)
|
||||
|
||||
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
|
||||
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
|
||||
time.sleep_us(sleep_time) # Wait the required time
|
||||
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
|
||||
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
|
||||
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
|
||||
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
return raw
|
||||
|
||||
def read_raw_pressure(self):
|
||||
"""Reads the raw (uncompensated) pressure level from the sensor."""
|
||||
"""Assumes that the temperature has already been read """
|
||||
"""i.e. that enough delay has been provided"""
|
||||
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
|
||||
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
|
||||
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
|
||||
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
return raw
|
||||
|
||||
def read_raw_humidity(self):
|
||||
"""Assumes that the temperature has already been read """
|
||||
"""i.e. that enough delay has been provided"""
|
||||
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
|
||||
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
|
||||
raw = (msb << 8) | lsb
|
||||
return raw
|
||||
|
||||
def read_temperature(self):
|
||||
"""Get the compensated temperature in 0.01 of a degree celsius."""
|
||||
adc = self.read_raw_temp()
|
||||
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
|
||||
var2 = ((
|
||||
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
|
||||
self.dig_T3) >> 14
|
||||
self.t_fine = var1 + var2
|
||||
return (self.t_fine * 5 + 128) >> 8
|
||||
|
||||
def read_pressure(self):
|
||||
"""Gets the compensated pressure in Pascals."""
|
||||
adc = self.read_raw_pressure()
|
||||
var1 = self.t_fine - 128000
|
||||
var2 = var1 * var1 * self.dig_P6
|
||||
var2 = var2 + ((var1 * self.dig_P5) << 17)
|
||||
var2 = var2 + (self.dig_P4 << 35)
|
||||
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
|
||||
((var1 * self.dig_P2) >> 12))
|
||||
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
|
||||
if var1 == 0:
|
||||
return 0
|
||||
p = 1048576 - adc
|
||||
p = (((p << 31) - var2) * 3125) // var1
|
||||
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
|
||||
var2 = (self.dig_P8 * p) >> 19
|
||||
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
|
||||
|
||||
def read_humidity(self):
|
||||
adc = self.read_raw_humidity()
|
||||
# print 'Raw humidity = {0:d}'.format (adc)
|
||||
h = self.t_fine - 76800
|
||||
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
|
||||
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
|
||||
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
|
||||
self.dig_H2 + 8192) >> 14))
|
||||
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
|
||||
h = 0 if h < 0 else h
|
||||
h = 419430400 if h > 419430400 else h
|
||||
return h >> 12
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
"Return the temperature in degrees."
|
||||
t = self.read_temperature()
|
||||
ti = t // 100
|
||||
td = t - ti * 100
|
||||
return "{}.{:02d}C".format(ti, td)
|
||||
|
||||
@property
|
||||
def pressure(self):
|
||||
"Return the temperature in hPa."
|
||||
p = self.read_pressure() // 256
|
||||
pi = p // 100
|
||||
pd = p - pi * 100
|
||||
return "{}.{:02d}hPa".format(pi, pd)
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
"Return the humidity in percent."
|
||||
h = self.read_humidity()
|
||||
hi = h // 1024
|
||||
hd = h * 100 // 1024 - hi * 100
|
||||
return "{}.{:02d}%".format(hi, hd)
|
||||
@ -0,0 +1,300 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2017 ladyada for Adafruit Industries
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
"""
|
||||
`adafruit_sgp30`
|
||||
====================================================
|
||||
|
||||
I2C driver for SGP30 Sensirion VoC sensor
|
||||
|
||||
* Author(s): ladyada, Alexandre Marquet.
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
* Adafruit `SGP30 Air Quality Sensor Breakout - VOC and eCO2
|
||||
<https://www.adafruit.com/product/3709>`_ (Product ID: 3709)
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* MicroPython:
|
||||
https://github.com/micropython/micropython
|
||||
|
||||
* Modified by Alan Peaty for MicroPython port.
|
||||
"""
|
||||
|
||||
from math import exp
|
||||
from utime import sleep_ms
|
||||
from micropython import const
|
||||
|
||||
# General SGP30 settings
|
||||
SGP30_DEFAULT_I2C_ADDR = const(0x58)
|
||||
SGP30_WORD_LEN = const(2)
|
||||
SGP30_CRC8_POLYNOMIAL = const(0x31)
|
||||
SGP30_CRC8_INIT = const(0xFF)
|
||||
SGP30_CRC8_FINAL_XOR = const(0xFF)
|
||||
SGP30_MEASURE_TEST_PASS = const(0xD400)
|
||||
|
||||
# SGP30 feature set measurement commands (Hex Codes)
|
||||
# From datasheet section 6.3
|
||||
SGP30_CMD_IAQ_INIT_HEX = [0x20, 0x03]
|
||||
SGP30_CMD_IAQ_INIT_WORDS = const(0)
|
||||
SGP30_CMD_IAQ_INIT_MAX_MS = const(10)
|
||||
SGP30_CMD_MEASURE_IAQ_HEX = [0x20, 0x08]
|
||||
SGP30_CMD_MEASURE_IAQ_WORDS = const(2)
|
||||
SGP30_CMD_MEASURE_IAQ_MS = const(12)
|
||||
SGP30_CMD_GET_IAQ_BASELINE_HEX = [0x20, 0x15]
|
||||
SGP30_CMD_GET_IAQ_BASELINE_WORDS = const(2)
|
||||
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS = const(10)
|
||||
SGP30_CMD_SET_IAQ_BASELINE_HEX = [0x20, 0x1E]
|
||||
SGP30_CMD_SET_IAQ_BASELINE_WORDS = const(0)
|
||||
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS = const(10)
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX = [0x20, 0x61]
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS = const(0)
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS = const(10)
|
||||
SGP30_CMD_MEASURE_TEST_HEX = [0x20, 0x32]
|
||||
SGP30_CMD_MEASURE_TEST_WORDS = const(1)
|
||||
SGP30_CMD_MEASURE_TEST_MAX_MS = const(220)
|
||||
SGP30_CMD_GET_FEATURE_SET_HEX = [0x20, 0x2F]
|
||||
SGP30_CMD_GET_FEATURE_SET_WORDS = const(1)
|
||||
SGP30_CMD_GET_FEATURE_SET_MAX_MS = const(10)
|
||||
SGP30_CMD_MEASURE_RAW_HEX = [0x20, 0x50]
|
||||
SGP30_CMD_MEASURE_RAW_WORDS = const(2)
|
||||
SGP30_CMD_MEASURE_RAW_MAX_MS = const(25)
|
||||
SGP30_CMD_GET_TVOC_INCEPTIVE_HEX = [0x20, 0xB3]
|
||||
SGP30_CMD_GET_TVOC_INCEPTIVE_WORDS = const(1)
|
||||
SGP30_CMD_GET_TVOC_INCEPTIVE_MAX_MS = const(10)
|
||||
SGP30_CMD_SET_TVOC_BASELINE_HEX = [0x20, 0x77]
|
||||
SGP30_CMD_SET_TVOC_BASELINE_WORDS = const(0)
|
||||
SGP30_CMD_SET_TVOC_BASELINE_MAX_MS = const(10)
|
||||
|
||||
# TODO: Soft Reset (datasheet section 6.4)
|
||||
|
||||
# Obtaining Serial ID (datasheet section 6.5)
|
||||
SGP30_CMD_GET_SERIAL_ID_HEX = [0x36, 0x82]
|
||||
SGP30_CMD_GET_SERIAL_ID_WORDS = const(3)
|
||||
SGP30_CMD_GET_SERIAL_ID_MAX_MS = const(10)
|
||||
|
||||
|
||||
class SGP30:
|
||||
"""
|
||||
A driver for the SGP30 gas sensor.
|
||||
|
||||
:param i2c: The "I2C" object to use. This is the only required parameter.
|
||||
:param int address: (optional) The I2C address of the device.
|
||||
:param boolean measure_test: (optional) Whether to run on-chip test during initialisation.
|
||||
:param boolean iaq_init: (optional) Whether to initialise SGP30 algorithm / baseline.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, i2c, addr=SGP30_DEFAULT_I2C_ADDR, measure_test=False, iaq_init=True
|
||||
):
|
||||
""" Initialises the sensor and display stats """
|
||||
self._i2c = i2c
|
||||
if addr not in self._i2c.scan():
|
||||
raise IOError("No SGP30 device found on I2C bus")
|
||||
self.addr = addr
|
||||
self.serial = self.get_serial()
|
||||
self.feature_set = self.get_feature_set()
|
||||
if measure_test:
|
||||
if SGP30_MEASURE_TEST_PASS != self.measure_test():
|
||||
raise RuntimeError("Device failed the on-chip test")
|
||||
print(
|
||||
"SGP30 device discovered...\n"
|
||||
+ "I2C address: "
|
||||
+ str(self.addr)
|
||||
+ "\n"
|
||||
+ "Serial ID: "
|
||||
+ str(self.serial)
|
||||
+ "\n"
|
||||
+ "Feature set: "
|
||||
+ str(self.feature_set)
|
||||
+ "\n"
|
||||
+ "Initialise algo: "
|
||||
+ str(iaq_init)
|
||||
)
|
||||
if iaq_init:
|
||||
self.iaq_init()
|
||||
|
||||
def iaq_init(self):
|
||||
""" Initialises the IAQ algorithm """
|
||||
self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_IAQ_INIT_HEX, SGP30_CMD_IAQ_INIT_MAX_MS, SGP30_CMD_IAQ_INIT_WORDS
|
||||
)
|
||||
|
||||
def measure_iaq(self):
|
||||
""" Measures the CO2eq and TVOC """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_MEASURE_IAQ_HEX,
|
||||
SGP30_CMD_MEASURE_IAQ_MS,
|
||||
SGP30_CMD_MEASURE_IAQ_WORDS,
|
||||
)
|
||||
|
||||
def get_iaq_baseline(self):
|
||||
""" Retreives the IAQ algorithm baseline for CO2eq and TVOC """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_GET_IAQ_BASELINE_HEX,
|
||||
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS,
|
||||
SGP30_CMD_GET_IAQ_BASELINE_WORDS,
|
||||
)
|
||||
|
||||
def set_iaq_baseline(self, co2eq, tvoc):
|
||||
""" Sets the previously recorded IAQ algorithm baseline for CO2eq and TVOC """
|
||||
if co2eq == 0 and tvoc == 0:
|
||||
raise ValueError("Invalid baseline values used")
|
||||
buffer = []
|
||||
for value in [tvoc, co2eq]:
|
||||
arr = [value >> 8, value & 0xFF]
|
||||
arr.append(generate_crc(arr))
|
||||
buffer += arr
|
||||
self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_SET_IAQ_BASELINE_HEX + buffer,
|
||||
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS,
|
||||
SGP30_CMD_SET_IAQ_BASELINE_WORDS,
|
||||
)
|
||||
|
||||
def set_absolute_humidity(self, absolute_humidity):
|
||||
""" Sets absolute humidity compensation. To disable,
|
||||
set 0. """
|
||||
buffer = []
|
||||
arr = [absolute_humidity >> 8, absolute_humidity & 0xFF]
|
||||
arr.append(generate_crc(arr))
|
||||
buffer += arr
|
||||
self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX + buffer,
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS,
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS,
|
||||
)
|
||||
|
||||
def measure_test(self):
|
||||
""" Runs on-chip self test """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_MEASURE_TEST_HEX,
|
||||
SGP30_CMD_MEASURE_TEST_MAX_MS,
|
||||
SGP30_CMD_MEASURE_TEST_WORDS,
|
||||
)[0]
|
||||
|
||||
def get_feature_set(self):
|
||||
""" Retrieves feature set of sensor """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_GET_FEATURE_SET_HEX,
|
||||
SGP30_CMD_GET_FEATURE_SET_MAX_MS,
|
||||
SGP30_CMD_GET_FEATURE_SET_WORDS,
|
||||
)[0]
|
||||
|
||||
def measure_raw(self):
|
||||
""" Returns raw H2 and Ethanol signals, used for part verification and testing """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_MEASURE_RAW_HEX,
|
||||
SGP30_CMD_MEASURE_RAW_MAX_MS,
|
||||
SGP30_CMD_MEASURE_RAW_WORDS,
|
||||
)
|
||||
|
||||
# TODO: Get TVOC inceptive baseline
|
||||
# TODO: Set TVOC baseline
|
||||
# TODO: Soft Reset (datasheet section 6.4)
|
||||
|
||||
def get_serial(self):
|
||||
""" Retrieves sensor serial """
|
||||
serial = self.serial = self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_GET_SERIAL_ID_HEX,
|
||||
SGP30_CMD_GET_SERIAL_ID_MAX_MS,
|
||||
SGP30_CMD_GET_SERIAL_ID_WORDS,
|
||||
)
|
||||
return hex(int.from_bytes(bytearray(serial), "large"))
|
||||
|
||||
@property
|
||||
def co2eq(self):
|
||||
""" Carbon Dioxide Equivalent in parts per million (ppm) """
|
||||
return self.measure_iaq()[0]
|
||||
|
||||
@property
|
||||
def baseline_co2eq(self):
|
||||
""" Carbon Dioxide Equivalent baseline value """
|
||||
return self.get_iaq_baseline()[0]
|
||||
|
||||
@property
|
||||
def tvoc(self):
|
||||
""" Total Volatile Organic Compound in parts per billion (ppb) """
|
||||
return self.measure_iaq()[1]
|
||||
|
||||
@property
|
||||
def baseline_tvoc(self):
|
||||
""" Total Volatile Organic Compound baseline value """
|
||||
return self.get_iaq_baseline()[1]
|
||||
|
||||
@property
|
||||
def raw_h2(self):
|
||||
""" Raw H2 signal """
|
||||
return self.measure_raw()[0]
|
||||
|
||||
@property
|
||||
def raw_ethanol(self):
|
||||
""" Raw Ethanol signal """
|
||||
return self.measure_raw()[1]
|
||||
|
||||
def _i2c_read_words_from_cmd(self, command, delay, reply_size):
|
||||
""" Runs an SGP command query, gets a reply and CRC results if necessary """
|
||||
self._i2c.writeto(self.addr, bytes(command))
|
||||
sleep_ms(delay)
|
||||
if not reply_size:
|
||||
return None
|
||||
crc_result = bytearray(reply_size * (SGP30_WORD_LEN + 1))
|
||||
self._i2c.readfrom_into(self.addr, crc_result)
|
||||
result = []
|
||||
for i in range(reply_size):
|
||||
word = [crc_result[3 * i], crc_result[3 * i + 1]]
|
||||
crc = crc_result[3 * i + 2]
|
||||
if generate_crc(word) != crc:
|
||||
raise RuntimeError("CRC Error")
|
||||
result.append(word[0] << 8 | word[1])
|
||||
return result
|
||||
|
||||
|
||||
def generate_crc(data):
|
||||
""" 8-bit CRC algorithm for checking data.
|
||||
Calculation described in section 6.6 of SGP30 datasheet """
|
||||
crc = SGP30_CRC8_INIT
|
||||
# Calculates 8-Bit CRC checksum with given polynomial
|
||||
for byte in data:
|
||||
crc ^= byte
|
||||
for _ in range(8):
|
||||
if crc & 0x80:
|
||||
crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL
|
||||
else:
|
||||
crc <<= 1
|
||||
return crc & 0xFF
|
||||
|
||||
|
||||
def convert_r_to_a_humidity(temp_c, r_humidity_perc, fixed_point=True):
|
||||
""" Converts relative to absolute humidity as per the equation
|
||||
found in datasheet """
|
||||
a_humidity_gm3 = 216.7 * (
|
||||
(r_humidity_perc / 100 * 6.112 * exp(17.62 * temp_c / (243.12 + temp_c)))
|
||||
/ (273.15 + temp_c)
|
||||
)
|
||||
# Return in 8.8 bit fixed point format (for setting humidity compensation), if not
|
||||
# simply return the calculated value in g/m^3
|
||||
if fixed_point:
|
||||
a_humidity_gm3 = (int(a_humidity_gm3) << 8) + (int(a_humidity_gm3 % 1 * 256))
|
||||
return a_humidity_gm3
|
||||
86
13 - Mini Projets/2 - Station Météo/Compte Rendu/Rewrite.py
Normal file
86
13 - Mini Projets/2 - Station Météo/Compte Rendu/Rewrite.py
Normal file
@ -0,0 +1,86 @@
|
||||
# Importe tout les modules requis
|
||||
from machine import Pin, I2C, UART
|
||||
import uSGP30
|
||||
import uBME280
|
||||
from i2c_lcd import lcd
|
||||
import time
|
||||
|
||||
# Défini l'interface du protocole I2C
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 1024)
|
||||
|
||||
# Défini l'interface UART utilisée pour le Bluetooth
|
||||
BT = UART(1, baudrate = 9600, tx = Pin(4), rx = Pin(5))
|
||||
|
||||
# Défuini les adresses I2C requis pour les capteurs
|
||||
BME_addr = 0x76;
|
||||
SGP30_adrr = 0x58;
|
||||
|
||||
# Déclare les paramètres des capteurs
|
||||
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
|
||||
# Le BME280 prends comme argument : le mode du capteur, l'adresse i2c du capteur et l'interface du protocole i2c
|
||||
sgp30 = uSGP30.SGP30(i2c, SGP30_adrr)
|
||||
# Le SGP30 prends comme argument : l'interface du protocole i2c et l'adresse i2c du capteur
|
||||
display = lcd(i2c)
|
||||
|
||||
# Crée les variables contenants les valeurs extérieures
|
||||
t = str(bme280.read_temperature()/100)
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
# Les valeurs ci dessus doivent être converties en texte car l'écran requiers des valeurs car sinon le programe renvoie une "TypeError: object with buffer protocol required"
|
||||
# De plus, les valeurs doivent êtres divisés par 100 ou par 1000 car elles ne sont pas dans la bonne unitée (capteur en pascal, valeur attendue en kPascal)
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
co2 = str(t_CO2)
|
||||
|
||||
# Crée la fonction qui permet de récupérer les valeurs
|
||||
def Update_Valeurs():
|
||||
t = str(bme280.read_temperature()/100)
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
co2 = str(t_CO2)
|
||||
|
||||
# Crée la fonction qui permet d'afficher le "premier écran"
|
||||
def First_Screen():
|
||||
# Affiche le premier "écran" (Température + Humidité)
|
||||
display.home()
|
||||
display.write("Temp = ")
|
||||
display.write(t)
|
||||
display.write(" °C")
|
||||
display.setCursor(0,1)
|
||||
display.write("THum = ")
|
||||
display.write(h)
|
||||
display.write(" %")
|
||||
|
||||
# Crée la fonction qui permet d'afficher le "deuxième écran"
|
||||
def Second_Screen():
|
||||
# Affiche le deuxième "écran" (Pression + CO2)
|
||||
display.clear()
|
||||
display.home()
|
||||
display.write("P = ")
|
||||
display.write(p)
|
||||
display.write(" Pa")
|
||||
display.setCursor(0,1)
|
||||
display.write("TCO2 = ")
|
||||
display.write(co2)
|
||||
display.write(" ppm")
|
||||
|
||||
# Crée la fonction qui permet d'afficher les valeurs
|
||||
def Update_Screen():
|
||||
# Affiche le premier "écran"
|
||||
First_Screen()
|
||||
time.sleep(5)
|
||||
Second_Screen()
|
||||
time.sleep(5)
|
||||
display.clear()
|
||||
|
||||
# Crée la fonction qui permet d'envoyer les valeurs en bluetooth
|
||||
def Send_Datas(a, b, c, d):
|
||||
BT.write(a)
|
||||
BT.write(b)
|
||||
BT.write(c)
|
||||
BT.write(d)
|
||||
# Lance le programme indéfiniment
|
||||
while True:
|
||||
Update_Valeurs()
|
||||
Send_Datas(t, h, p, co2)
|
||||
Update_Screen()
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"nodes":[
|
||||
{"id":"ef10e0e9de432d66","type":"text","text":"Carte raspberry PICO\n","x":-210,"y":-196,"width":250,"height":50,"color":"1"},
|
||||
{"id":"078d5b19fbbc6b3e","type":"text","text":"Début ou fin","x":640,"y":-420,"width":250,"height":50,"color":"1"},
|
||||
{"id":"781a281c217a87e4","type":"text","text":"Traitement","x":640,"y":-340,"width":250,"height":50,"color":"3"},
|
||||
{"id":"b154f88c8da852f4","type":"text","text":"Entrée/sortie","x":640,"y":-251,"width":250,"height":55,"color":"6"},
|
||||
{"id":"fa87106ca6ca9685","x":-210,"y":-39,"width":250,"height":60,"color":"3","type":"text","text":"Update_Values()"},
|
||||
{"id":"59f59b8b9806b549","x":-210,"y":420,"width":250,"height":60,"color":"3","type":"text","text":"Conversion des valeurs brutes"},
|
||||
{"id":"c08d9840e4f49bf2","x":-210,"y":650,"width":250,"height":60,"color":"3","type":"text","text":"Affichage des valeurs"},
|
||||
{"id":"25b4fe07f6d1c2a6","x":-210,"y":200,"width":250,"height":60,"color":"6","type":"text","text":"BME280"},
|
||||
{"id":"f9be99f4a13e5d26","x":80,"y":200,"width":234,"height":60,"color":"6","type":"text","text":"SGP30"},
|
||||
{"id":"928adab9542314a4","x":189,"y":655,"width":250,"height":50,"color":"6","type":"text","text":"Ecran LCD"}
|
||||
],
|
||||
"edges":[
|
||||
{"id":"bec9ba33e0fdedcc","fromNode":"ef10e0e9de432d66","fromSide":"bottom","toNode":"fa87106ca6ca9685","toSide":"top"},
|
||||
{"id":"7f8ddcc682e8421c","fromNode":"fa87106ca6ca9685","fromSide":"bottom","toNode":"25b4fe07f6d1c2a6","toSide":"top"},
|
||||
{"id":"8a56bb625d58db96","fromNode":"fa87106ca6ca9685","fromSide":"bottom","toNode":"f9be99f4a13e5d26","toSide":"top"},
|
||||
{"id":"f340551ea5272ac2","fromNode":"25b4fe07f6d1c2a6","fromSide":"bottom","toNode":"59f59b8b9806b549","toSide":"top"},
|
||||
{"id":"315d366bc4490e22","fromNode":"f9be99f4a13e5d26","fromSide":"bottom","toNode":"59f59b8b9806b549","toSide":"top"},
|
||||
{"id":"176c34e7ba2b699e","fromNode":"59f59b8b9806b549","fromSide":"bottom","toNode":"c08d9840e4f49bf2","toSide":"top"},
|
||||
{"id":"b0b97834bda7aa82","fromNode":"c08d9840e4f49bf2","fromSide":"right","toNode":"928adab9542314a4","toSide":"left"},
|
||||
{"id":"6414806d66e6db2a","fromNode":"c08d9840e4f49bf2","fromSide":"left","toNode":"fa87106ca6ca9685","toSide":"left"}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
from machine import Pin, UART
|
||||
import time
|
||||
|
||||
BT = UART(1, baudrate = 9600, tx = Pin(4), rx = Pin(5))
|
||||
"""
|
||||
compteur = 0
|
||||
|
||||
BT = UART(1, 9600)
|
||||
BT.init(baudrate=9600, tx = Pin(4), rx = Pin(5))
|
||||
"""
|
||||
toto=("hello")
|
||||
|
||||
while True:
|
||||
BT.write(toto+'\n')
|
||||
time.sleep(1)
|
||||
@ -0,0 +1,17 @@
|
||||
from machine import Pin, I2C
|
||||
import uBME280
|
||||
import time
|
||||
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
|
||||
|
||||
BME_addr = 0x76;
|
||||
|
||||
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
|
||||
|
||||
while True:
|
||||
t = str(bme280.read_temperature()/100)
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
time.sleep(1)
|
||||
|
||||
print(t, p, h)
|
||||
@ -0,0 +1,9 @@
|
||||
from machine import Pin, I2C
|
||||
from i2c_lcd import lcd
|
||||
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
|
||||
|
||||
display = lcd(i2c)
|
||||
|
||||
display.home()
|
||||
display.write("Temp = ")
|
||||
@ -0,0 +1,14 @@
|
||||
from machine import Pin, I2C
|
||||
import uSGP30
|
||||
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
|
||||
|
||||
SGP30_addr = 0x58;
|
||||
|
||||
# sgp30 = uSGP30.SGP30(i2c, SGP30_addr);
|
||||
|
||||
sgp30 = uSGP30.SGP30(i2c)
|
||||
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
|
||||
print(t_CO2)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26
13 - Mini Projets/2 - Station Météo/SGP Test.py
Normal file
26
13 - Mini Projets/2 - Station Météo/SGP Test.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Importe tout les modules requis
|
||||
from machine import Pin, I2C
|
||||
import uSGP30
|
||||
import uBME280
|
||||
from i2c_lcd import lcd
|
||||
import time
|
||||
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
|
||||
BME_addr = 0x76;
|
||||
ptr_registre = 0
|
||||
|
||||
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
|
||||
display = lcd(i2c)
|
||||
|
||||
while True:
|
||||
t = bme280.read_temperature()/100
|
||||
p = bme280.read_pressure()/1000
|
||||
h = bme280.read_humidity()/1000
|
||||
|
||||
print(t, "°C")
|
||||
# print(p, "hPascals")
|
||||
print(h, "%")
|
||||
display.write('Bouh')
|
||||
display.cursor(1)
|
||||
time.sleep(1)
|
||||
display.clear()
|
||||
BIN
13 - Mini Projets/2 - Station Météo/Station_Météo.pdf
Normal file
BIN
13 - Mini Projets/2 - Station Météo/Station_Météo.pdf
Normal file
Binary file not shown.
68
13 - Mini Projets/2 - Station Météo/Web/AP.py
Normal file
68
13 - Mini Projets/2 - Station Météo/Web/AP.py
Normal file
@ -0,0 +1,68 @@
|
||||
import network
|
||||
import time
|
||||
import socket
|
||||
|
||||
|
||||
def web_page():
|
||||
html = """<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
<!-- Begin
|
||||
function reFresh() {
|
||||
location.reload(true)
|
||||
}
|
||||
/* Definir le temp de refraichir le nombre en in milliseconds, 1 minute = 60000 milliseconds. */
|
||||
window.setInterval("reFresh()",500);
|
||||
// End -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Weather Station</h1>
|
||||
<p>Temperature : {t}</p>
|
||||
<p>Pression Atmoshérique : {p}</p>
|
||||
<p>Humiditée : {h}</p>
|
||||
<p>Taux de CO2 : {co2}</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return html
|
||||
|
||||
# if you do not see the network you may have to power cycle
|
||||
# unplug your pico w for 10 seconds and plug it in again
|
||||
def ap_mode(ssid, password):
|
||||
"""
|
||||
Description: This is a function to activate AP mode
|
||||
|
||||
Parameters:
|
||||
|
||||
ssid[str]: The name of your internet connection
|
||||
password[str]: Password for your internet connection
|
||||
|
||||
Returns: Nada
|
||||
"""
|
||||
# Just making our internet connection
|
||||
ap = network.WLAN(network.AP_IF)
|
||||
ap.config(essid=ssid, password=password)
|
||||
ap.active(True)
|
||||
|
||||
while ap.active() == False:
|
||||
pass
|
||||
print('AP Mode Is Active, You can Now Connect')
|
||||
print('IP Address To Connect to:: ' + ap.ifconfig()[0])
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object
|
||||
s.bind(('', 80))
|
||||
s.listen(5)
|
||||
|
||||
while True:
|
||||
conn, addr = s.accept()
|
||||
print('Got a connection from %s' % str(addr))
|
||||
request = conn.recv(1024)
|
||||
print('Content = %s' % str(request))
|
||||
response = web_page()
|
||||
conn.send(response)
|
||||
conn.close()
|
||||
|
||||
ap_mode('Weather Station',
|
||||
'Miam1234')
|
||||
0
13 - Mini Projets/2 - Station Météo/demofile1.txt
Normal file
0
13 - Mini Projets/2 - Station Météo/demofile1.txt
Normal file
21
13 - Mini Projets/2 - Station Météo/index.html
Normal file
21
13 - Mini Projets/2 - Station Météo/index.html
Normal file
@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
<!-- Begin
|
||||
function reFresh() {
|
||||
location.reload(true)
|
||||
}
|
||||
/* Definir le temp de refraichir le nombre en in milliseconds, 1 minute = 60000 milliseconds. */
|
||||
window.setInterval("reFresh()",500);
|
||||
// End -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Weather Station</h1>
|
||||
<p>Temperature : {t}</p>
|
||||
<p>Pression Atmoshérique : {p}</p>
|
||||
<p>Humiditée : {h}</p>
|
||||
<p>Taux de CO2 : {co2}</p>
|
||||
</body>
|
||||
</html>
|
||||
56
13 - Mini Projets/2 - Station Météo/main.py
Normal file
56
13 - Mini Projets/2 - Station Météo/main.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Importe tout les modules requis
|
||||
from machine import Pin, I2C
|
||||
import uSGP30
|
||||
import uBME280
|
||||
from i2c_lcd import lcd
|
||||
import time
|
||||
import network
|
||||
import socket
|
||||
# Défini l'interface du protocole I2C
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 1024)
|
||||
|
||||
# Défini l'adresse I2C requis pour les capteurs
|
||||
BME_addr = 0x76;
|
||||
SGP30_addr = 0x58;
|
||||
|
||||
# Déclare les paramètres dans des variables
|
||||
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
|
||||
sgp30 = uSGP30.SGP30(i2c, SGP30_addr);
|
||||
display = lcd(i2c)
|
||||
|
||||
def Update():
|
||||
# Récupère toutes les données du capteur BME280
|
||||
t = str(bme280.read_temperature()/100)
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
co2 = str(t_CO2)
|
||||
|
||||
|
||||
# Affiche la première image (Température + Humidité)
|
||||
display.home()
|
||||
display.write("Temp = ")
|
||||
display.write(t)
|
||||
display.write(" °C")
|
||||
display.setCursor(0,1)
|
||||
display.write("Hum = ")
|
||||
display.write(h)
|
||||
display.write(" %")
|
||||
time.sleep(5)
|
||||
# Affiche la deuxième image (Pression + CO2)
|
||||
display.clear()
|
||||
display.home()
|
||||
display.write("P = ")
|
||||
display.write(p)
|
||||
display.write(" Pa")
|
||||
display.setCursor(0,1)
|
||||
display.write("TCO2 = ")
|
||||
display.write(co2)
|
||||
display.write(" ppm")
|
||||
f = open("demofile1.txt", "w")
|
||||
f.write(t)
|
||||
f.close()
|
||||
time.sleep(5)
|
||||
display.clear()
|
||||
while True:
|
||||
Update()
|
||||
5
13 - Mini Projets/2 - Station Météo/test.py
Normal file
5
13 - Mini Projets/2 - Station Météo/test.py
Normal file
@ -0,0 +1,5 @@
|
||||
from machine import SoftI2C, Pin
|
||||
i2c=SoftI2C(sda=Pin(20), scl=Pin(21), freq=400000)
|
||||
scan = i2c.scan()
|
||||
print(scan)
|
||||
print(i2c.readfrom_mem(0x76, 0xd0, 1)[0])
|
||||
3
13 - Mini Projets/2 - Station Météo/tests/bme2.py
Normal file
3
13 - Mini Projets/2 - Station Météo/tests/bme2.py
Normal file
@ -0,0 +1,3 @@
|
||||
from machine import SoftI2C, Pin
|
||||
i2c=SoftI2C(sda=Pin(20), scl=Pin(21), freq=400000)
|
||||
print(i2c.readfrom_mem(0x76, 0xd0, 1)[0])
|
||||
14
13 - Mini Projets/2 - Station Météo/tests/bt.py
Normal file
14
13 - Mini Projets/2 - Station Météo/tests/bt.py
Normal file
@ -0,0 +1,14 @@
|
||||
from machine import Pin,UART
|
||||
uart = UART(0,9600)
|
||||
LedGPIO = 16
|
||||
led = Pin(LedGPIO, Pin.OUT)
|
||||
while True:
|
||||
if uart.any():
|
||||
command = uart.readline()
|
||||
print(command) # uncomment this line to see the recieved data
|
||||
if command==b'\xd0':
|
||||
led.high()
|
||||
print("ON")
|
||||
elif command==b'\xd5':
|
||||
led.low()
|
||||
print("OFF")
|
||||
123
13 - Mini Projets/2 - Station Météo/tests/maintest.py
Normal file
123
13 - Mini Projets/2 - Station Météo/tests/maintest.py
Normal file
@ -0,0 +1,123 @@
|
||||
# Importe tout les modules requis
|
||||
from machine import Pin, I2C
|
||||
import uSGP30
|
||||
import uBME280
|
||||
from i2c_lcd import lcd
|
||||
import time
|
||||
import network
|
||||
import socket
|
||||
|
||||
# Défini l'interface du protocole I2C
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
|
||||
|
||||
# Défini l'adresse I2C requis pour les capteurs
|
||||
BME_addr = 0x76;
|
||||
SGP30_addr = 0x58;
|
||||
|
||||
# Déclare les paramètres dans des variables
|
||||
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
|
||||
sgp30 = uSGP30.SGP30(i2c, SGP30_addr);
|
||||
display = lcd(i2c)
|
||||
|
||||
t = str(bme280.read_temperature()/100)
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
co2 = str(t_CO2)
|
||||
|
||||
def Update():
|
||||
# Récupère toutes les données du capteur BME280
|
||||
t = str(bme280.read_temperature()/100)
|
||||
p = str(bme280.read_pressure()/1000)
|
||||
h = str(bme280.read_humidity()/1000)
|
||||
t_CO2, t_COV = sgp30.measure_iaq()
|
||||
co2 = str(t_CO2)
|
||||
|
||||
|
||||
# Affiche la première image (Température + Humidité)
|
||||
display.home()
|
||||
display.write("Temp = ")
|
||||
display.write(t)
|
||||
display.write(" °C")
|
||||
display.setCursor(0,1)
|
||||
display.write("THum = ")
|
||||
display.write(h)
|
||||
display.write(" %")
|
||||
time.sleep(1.5)
|
||||
# Affiche la deuxième image (Pression + CO2)
|
||||
display.clear()
|
||||
display.home()
|
||||
display.write("P = ")
|
||||
display.write(p)
|
||||
display.write(" Pa")
|
||||
display.setCursor(0,1)
|
||||
display.write("TCO2 = ")
|
||||
display.write(co2)
|
||||
display.write(" ppm")
|
||||
time.sleep(1.5)
|
||||
display.clear()
|
||||
|
||||
def web_page():
|
||||
html = """<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
<!-- Begin
|
||||
function reFresh() {
|
||||
location.reload(true)
|
||||
}
|
||||
/* Definir le temp de refraichir le nombre en in milliseconds, 1 minute = 60000 milliseconds. */
|
||||
window.setInterval("reFresh()",500);
|
||||
// End -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Weather Station</h1>
|
||||
<p>Temperature : {t}</p>
|
||||
<p>Pression Atmoshérique : {p}</p>
|
||||
<p>Humiditée : {h}</p>
|
||||
<p>Taux de CO2 : {co2}</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return html
|
||||
|
||||
# if you do not see the network you may have to power cycle
|
||||
# unplug your pico w for 10 seconds and plug it in again
|
||||
def ap_mode(ssid, password):
|
||||
"""
|
||||
Description: This is a function to activate AP mode
|
||||
|
||||
Parameters:
|
||||
|
||||
ssid[str]: The name of your internet connection
|
||||
password[str]: Password for your internet connection
|
||||
|
||||
Returns: Nada
|
||||
"""
|
||||
# Just making our internet connection
|
||||
ap = network.WLAN(network.AP_IF)
|
||||
ap.config(essid=ssid, password=password)
|
||||
ap.active(True)
|
||||
|
||||
while ap.active() == False:
|
||||
pass
|
||||
print('AP Mode Is Active, You can Now Connect')
|
||||
print('IP Address To Connect to:: ' + ap.ifconfig()[0])
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object
|
||||
s.bind(('', 80))
|
||||
s.listen(5)
|
||||
|
||||
while True:
|
||||
conn, addr = s.accept()
|
||||
print('Got a connection from %s' % str(addr))
|
||||
request = conn.recv(1024)
|
||||
print('Content = %s' % str(request))
|
||||
Update()
|
||||
response = web_page()
|
||||
conn.send(response)
|
||||
conn.close()
|
||||
|
||||
ap_mode('Weather Station',
|
||||
'Miam1234')
|
||||
58
13 - Mini Projets/2 - Station Météo/tests/thread.py
Normal file
58
13 - Mini Projets/2 - Station Météo/tests/thread.py
Normal file
@ -0,0 +1,58 @@
|
||||
import machine, time, _thread
|
||||
from machine import Timer
|
||||
from machine import Pin, I2C
|
||||
from i2c_lcd import lcd
|
||||
|
||||
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
|
||||
|
||||
display = lcd(i2c)
|
||||
|
||||
#led interne du raspberry pico
|
||||
pico_led = machine.Pin(25, machine.Pin.OUT)
|
||||
|
||||
# Objet compte à rebours
|
||||
class CptRebours():
|
||||
#constructeur, initialise timeleft
|
||||
def __init__(self, t=0):
|
||||
self.timeleft = t
|
||||
# fct callbackappelée par le timer
|
||||
def countdown(self, tm):
|
||||
if self.timeleft > 0 :
|
||||
self.timeleft -= 1
|
||||
|
||||
# Fonction exécutée dans le second thread
|
||||
# gère le clignotement de la led
|
||||
def thread_anim():
|
||||
while True:
|
||||
if (cptr.timeleft>0):
|
||||
# fait clignoter la led interne
|
||||
pico_led.toggle()
|
||||
display.home()
|
||||
display.write("Temp = ")
|
||||
# attente supplémentaire s'il reste plus de 5s
|
||||
if cptr.timeleft>5:
|
||||
time.sleep(0.18)
|
||||
else:
|
||||
# extinction de la led interne
|
||||
pico_led.value(0)
|
||||
# temps d'attente clignotement
|
||||
time.sleep(0.18)
|
||||
|
||||
#initialisation d'un compte à rebours
|
||||
cptr = CptRebours()
|
||||
|
||||
#démarrage du thread d'animation
|
||||
_thread.start_new_thread(thread_anim, ())
|
||||
|
||||
#boucle du thread principal
|
||||
while True:
|
||||
cptr = CptRebours(int(input("Compte à rebours en secondes: ")))
|
||||
print('Démarrage compte à rebours ...')
|
||||
tim = Timer(period=1000, callback=cptr.countdown)
|
||||
|
||||
while (cptr.timeleft > 0 ):
|
||||
print('temps restant:', cptr.timeleft, ' secondes')
|
||||
time.sleep(1)
|
||||
|
||||
print("BIP BIP BIP compte à rebours terminé !")
|
||||
tim.deinit() #stoppe et libère le timer
|
||||
BIN
13 - Mini Projets/capture station.PNG
Normal file
BIN
13 - Mini Projets/capture station.PNG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,135 @@
|
||||
from machine import I2C
|
||||
import time
|
||||
|
||||
_I2CADDR = const(0x3E)
|
||||
|
||||
# commands
|
||||
_LCD_CLEARDISPLAY = const(0x01)
|
||||
_LCD_RETURNHOME = const(0x02)
|
||||
_LCD_ENTRYMODESET = const(0x04)
|
||||
_LCD_DISPLAYCONTROL = const(0x08)
|
||||
_LCD_CURSORSHIFT = const(0x10)
|
||||
_LCD_FUNCTIONSET = const(0x20)
|
||||
_LCD_SETCGRAMADDR = const(0x40)
|
||||
_LCD_SETDDRAMADDR = const(0x80)
|
||||
|
||||
# flags for display entry mode
|
||||
_LCD_ENTRYRIGHT = const(0x00)
|
||||
_LCD_ENTRYLEFT = const(0x02)
|
||||
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
|
||||
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
|
||||
|
||||
# flags for display on/off control
|
||||
_LCD_DISPLAYON = const(0x04)
|
||||
_LCD_DISPLAYOFF = const(0x00)
|
||||
_LCD_CURSORON = const(0x02)
|
||||
_LCD_CURSOROFF = const(0x00)
|
||||
_LCD_BLINKON = const(0x01)
|
||||
_LCD_BLINKOFF = const(0x00)
|
||||
|
||||
# flags for display/cursor shift
|
||||
_LCD_DISPLAYMOVE = const(0x08)
|
||||
_LCD_CURSORMOVE = const(0x00)
|
||||
_LCD_MOVERIGHT = const(0x04)
|
||||
_LCD_MOVELEFT = const(0x00)
|
||||
|
||||
# flags for function set
|
||||
_LCD_8BITMODE = const(0x10)
|
||||
_LCD_4BITMODE = const(0x00)
|
||||
_LCD_2LINE = const(0x08)
|
||||
_LCD_1LINE = const(0x00)
|
||||
_LCD_5x10DOTS = const(0x04)
|
||||
_LCD_5x8DOTS = const(0x00)
|
||||
|
||||
class lcd:
|
||||
|
||||
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
|
||||
self.i2c = i2c
|
||||
self.i2c.scan()
|
||||
self.address = address
|
||||
self.disp_func = _LCD_DISPLAYON
|
||||
if not oneline:
|
||||
self.disp_func |= _LCD_2LINE
|
||||
elif charsize != 0:
|
||||
# for 1-line displays you can choose another dotsize
|
||||
self.disp_func |= _LCD_5x10DOTS
|
||||
|
||||
# wait for display init after power-on
|
||||
time.sleep_ms(50) # 50ms
|
||||
|
||||
# send function set
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
|
||||
# turn on the display
|
||||
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
|
||||
self.display(True)
|
||||
|
||||
# clear it
|
||||
self.clear()
|
||||
|
||||
# set default text direction (left-to-right)
|
||||
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
|
||||
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
|
||||
|
||||
def cmd(self, command):
|
||||
assert command >= 0 and command < 256
|
||||
command = bytearray([command])
|
||||
self.i2c.writeto_mem(self.address, 0x80, command)
|
||||
|
||||
def write_char(self, c):
|
||||
assert c >= 0 and c < 256
|
||||
c = bytearray([c])
|
||||
self.i2c.writeto_mem(self.address, 0x40, c)
|
||||
|
||||
def write(self, text):
|
||||
for char in text:
|
||||
self.write_char(ord(char))
|
||||
|
||||
def cursor(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def setCursor(self, col, row):
|
||||
col = (col | 0x80) if row == 0 else (col | 0xc0)
|
||||
self.cmd(col)
|
||||
|
||||
def autoscroll(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def blink(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def display(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def clear(self):
|
||||
self.cmd(_LCD_CLEARDISPLAY)
|
||||
time.sleep_ms(2) # 2ms
|
||||
|
||||
def home(self):
|
||||
self.cmd(_LCD_RETURNHOME)
|
||||
time.sleep_ms(2) # 2m
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
135
13 - Mini-projets/2 - Station Météo/Programme/i2c_lcd.py
Normal file
135
13 - Mini-projets/2 - Station Météo/Programme/i2c_lcd.py
Normal file
@ -0,0 +1,135 @@
|
||||
from machine import I2C
|
||||
import time
|
||||
|
||||
_I2CADDR = const(0x3E)
|
||||
|
||||
# commands
|
||||
_LCD_CLEARDISPLAY = const(0x01)
|
||||
_LCD_RETURNHOME = const(0x02)
|
||||
_LCD_ENTRYMODESET = const(0x04)
|
||||
_LCD_DISPLAYCONTROL = const(0x08)
|
||||
_LCD_CURSORSHIFT = const(0x10)
|
||||
_LCD_FUNCTIONSET = const(0x20)
|
||||
_LCD_SETCGRAMADDR = const(0x40)
|
||||
_LCD_SETDDRAMADDR = const(0x80)
|
||||
|
||||
# flags for display entry mode
|
||||
_LCD_ENTRYRIGHT = const(0x00)
|
||||
_LCD_ENTRYLEFT = const(0x02)
|
||||
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
|
||||
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
|
||||
|
||||
# flags for display on/off control
|
||||
_LCD_DISPLAYON = const(0x04)
|
||||
_LCD_DISPLAYOFF = const(0x00)
|
||||
_LCD_CURSORON = const(0x02)
|
||||
_LCD_CURSOROFF = const(0x00)
|
||||
_LCD_BLINKON = const(0x01)
|
||||
_LCD_BLINKOFF = const(0x00)
|
||||
|
||||
# flags for display/cursor shift
|
||||
_LCD_DISPLAYMOVE = const(0x08)
|
||||
_LCD_CURSORMOVE = const(0x00)
|
||||
_LCD_MOVERIGHT = const(0x04)
|
||||
_LCD_MOVELEFT = const(0x00)
|
||||
|
||||
# flags for function set
|
||||
_LCD_8BITMODE = const(0x10)
|
||||
_LCD_4BITMODE = const(0x00)
|
||||
_LCD_2LINE = const(0x08)
|
||||
_LCD_1LINE = const(0x00)
|
||||
_LCD_5x10DOTS = const(0x04)
|
||||
_LCD_5x8DOTS = const(0x00)
|
||||
|
||||
class lcd:
|
||||
|
||||
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
|
||||
self.i2c = i2c
|
||||
self.i2c.scan()
|
||||
self.address = address
|
||||
self.disp_func = _LCD_DISPLAYON
|
||||
if not oneline:
|
||||
self.disp_func |= _LCD_2LINE
|
||||
elif charsize != 0:
|
||||
# for 1-line displays you can choose another dotsize
|
||||
self.disp_func |= _LCD_5x10DOTS
|
||||
|
||||
# wait for display init after power-on
|
||||
time.sleep_ms(50) # 50ms
|
||||
|
||||
# send function set
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
|
||||
# turn on the display
|
||||
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
|
||||
self.display(True)
|
||||
|
||||
# clear it
|
||||
self.clear()
|
||||
|
||||
# set default text direction (left-to-right)
|
||||
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
|
||||
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
|
||||
|
||||
def cmd(self, command):
|
||||
assert command >= 0 and command < 256
|
||||
command = bytearray([command])
|
||||
self.i2c.writeto_mem(self.address, 0x80, command)
|
||||
|
||||
def write_char(self, c):
|
||||
assert c >= 0 and c < 256
|
||||
c = bytearray([c])
|
||||
self.i2c.writeto_mem(self.address, 0x40, c)
|
||||
|
||||
def write(self, text):
|
||||
for char in text:
|
||||
self.write_char(ord(char))
|
||||
|
||||
def cursor(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def setCursor(self, col, row):
|
||||
col = (col | 0x80) if row == 0 else (col | 0xc0)
|
||||
self.cmd(col)
|
||||
|
||||
def autoscroll(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def blink(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def display(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def clear(self):
|
||||
self.cmd(_LCD_CLEARDISPLAY)
|
||||
time.sleep_ms(2) # 2ms
|
||||
|
||||
def home(self):
|
||||
self.cmd(_LCD_RETURNHOME)
|
||||
time.sleep_ms(2) # 2m
|
||||
284
13 - Mini-projets/2 - Station Météo/Programme/uBME280.py
Normal file
284
13 - Mini-projets/2 - Station Météo/Programme/uBME280.py
Normal file
@ -0,0 +1,284 @@
|
||||
from machine import I2C
|
||||
import time
|
||||
|
||||
# BME280 default address.
|
||||
BME280_I2CADDR = 0x76
|
||||
|
||||
# Operating Modes
|
||||
BME280_OSAMPLE_1 = 1
|
||||
BME280_OSAMPLE_2 = 2
|
||||
BME280_OSAMPLE_4 = 3
|
||||
BME280_OSAMPLE_8 = 4
|
||||
BME280_OSAMPLE_16 = 5
|
||||
|
||||
# BME280 Registers
|
||||
|
||||
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
|
||||
BME280_REGISTER_DIG_T2 = 0x8A
|
||||
BME280_REGISTER_DIG_T3 = 0x8C
|
||||
|
||||
BME280_REGISTER_DIG_P1 = 0x8E
|
||||
BME280_REGISTER_DIG_P2 = 0x90
|
||||
BME280_REGISTER_DIG_P3 = 0x92
|
||||
BME280_REGISTER_DIG_P4 = 0x94
|
||||
BME280_REGISTER_DIG_P5 = 0x96
|
||||
BME280_REGISTER_DIG_P6 = 0x98
|
||||
BME280_REGISTER_DIG_P7 = 0x9A
|
||||
BME280_REGISTER_DIG_P8 = 0x9C
|
||||
BME280_REGISTER_DIG_P9 = 0x9E
|
||||
|
||||
BME280_REGISTER_DIG_H1 = 0xA1
|
||||
BME280_REGISTER_DIG_H2 = 0xE1
|
||||
BME280_REGISTER_DIG_H3 = 0xE3
|
||||
BME280_REGISTER_DIG_H4 = 0xE4
|
||||
BME280_REGISTER_DIG_H5 = 0xE5
|
||||
BME280_REGISTER_DIG_H6 = 0xE6
|
||||
BME280_REGISTER_DIG_H7 = 0xE7
|
||||
|
||||
BME280_REGISTER_CHIPID = 0xD0
|
||||
BME280_REGISTER_VERSION = 0xD1
|
||||
BME280_REGISTER_SOFTRESET = 0xE0
|
||||
|
||||
BME280_REGISTER_CONTROL_HUM = 0xF2
|
||||
BME280_REGISTER_CONTROL = 0xF4
|
||||
BME280_REGISTER_CONFIG = 0xF5
|
||||
BME280_REGISTER_PRESSURE_DATA = 0xF7
|
||||
BME280_REGISTER_TEMP_DATA = 0xFA
|
||||
BME280_REGISTER_HUMIDITY_DATA = 0xFD
|
||||
|
||||
|
||||
class Device:
|
||||
"""Class for communicating with an I2C device.
|
||||
Allows reading and writing 8-bit, 16-bit, and byte array values to
|
||||
registers on the device."""
|
||||
|
||||
def __init__(self, address, i2c):
|
||||
"""Create an instance of the I2C device at the specified address using
|
||||
the specified I2C interface object."""
|
||||
self._address = address
|
||||
self._i2c = i2c
|
||||
|
||||
def writeRaw8(self, value):
|
||||
"""Write an 8-bit value on the bus (without register)."""
|
||||
value = value & 0xFF
|
||||
self._i2c.writeto(self._address, value)
|
||||
|
||||
def write8(self, register, value):
|
||||
"""Write an 8-bit value to the specified register."""
|
||||
b=bytearray(1)
|
||||
b[0]=value & 0xFF
|
||||
self._i2c.writeto_mem(self._address, register, b)
|
||||
|
||||
def write16(self, register, value):
|
||||
"""Write a 16-bit value to the specified register."""
|
||||
value = value & 0xFFFF
|
||||
b=bytearray(2)
|
||||
b[0]= value & 0xFF
|
||||
b[1]= (value>>8) & 0xFF
|
||||
self.i2c.writeto_mem(self._address, register, value)
|
||||
|
||||
def readRaw8(self):
|
||||
"""Read an 8-bit value on the bus (without register)."""
|
||||
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
|
||||
|
||||
def readU8(self, register):
|
||||
"""Read an unsigned byte from the specified register."""
|
||||
return int.from_bytes(
|
||||
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
|
||||
|
||||
def readS8(self, register):
|
||||
"""Read a signed byte from the specified register."""
|
||||
result = self.readU8(register)
|
||||
if result > 127:
|
||||
result -= 256
|
||||
return result
|
||||
|
||||
def readU16(self, register, little_endian=True):
|
||||
"""Read an unsigned 16-bit value from the specified register, with the
|
||||
specified endianness (default little endian, or least significant byte
|
||||
first)."""
|
||||
result = int.from_bytes(
|
||||
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
|
||||
if not little_endian:
|
||||
result = ((result << 8) & 0xFF00) + (result >> 8)
|
||||
return result
|
||||
|
||||
def readS16(self, register, little_endian=True):
|
||||
"""Read a signed 16-bit value from the specified register, with the
|
||||
specified endianness (default little endian, or least significant byte
|
||||
first)."""
|
||||
result = self.readU16(register, little_endian)
|
||||
if result > 32767:
|
||||
result -= 65536
|
||||
return result
|
||||
|
||||
def readU16LE(self, register):
|
||||
"""Read an unsigned 16-bit value from the specified register, in little
|
||||
endian byte order."""
|
||||
return self.readU16(register, little_endian=True)
|
||||
|
||||
def readU16BE(self, register):
|
||||
"""Read an unsigned 16-bit value from the specified register, in big
|
||||
endian byte order."""
|
||||
return self.readU16(register, little_endian=False)
|
||||
|
||||
def readS16LE(self, register):
|
||||
"""Read a signed 16-bit value from the specified register, in little
|
||||
endian byte order."""
|
||||
return self.readS16(register, little_endian=True)
|
||||
|
||||
def readS16BE(self, register):
|
||||
"""Read a signed 16-bit value from the specified register, in big
|
||||
endian byte order."""
|
||||
return self.readS16(register, little_endian=False)
|
||||
|
||||
|
||||
class BME280:
|
||||
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
|
||||
**kwargs):
|
||||
# Check that mode is valid.
|
||||
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
|
||||
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
|
||||
raise ValueError(
|
||||
'Unexpected mode value {0}. Set mode to one of '
|
||||
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
|
||||
'BME280_ULTRAHIGHRES'.format(mode))
|
||||
self._mode = mode
|
||||
# Create I2C device.
|
||||
if i2c is None:
|
||||
raise ValueError('An I2C object is required.')
|
||||
self._device = Device(address, i2c)
|
||||
# Load calibration values.
|
||||
self._load_calibration()
|
||||
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
|
||||
self.t_fine = 0
|
||||
|
||||
def _load_calibration(self):
|
||||
|
||||
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
|
||||
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
|
||||
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
|
||||
|
||||
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
|
||||
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
|
||||
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
|
||||
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
|
||||
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
|
||||
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
|
||||
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
|
||||
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
|
||||
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
|
||||
|
||||
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
|
||||
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
|
||||
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
|
||||
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
|
||||
|
||||
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
|
||||
h4 = (h4 << 24) >> 20
|
||||
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
|
||||
|
||||
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
|
||||
h5 = (h5 << 24) >> 20
|
||||
self.dig_H5 = h5 | (
|
||||
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
|
||||
|
||||
def read_raw_temp(self):
|
||||
"""Reads the raw (uncompensated) temperature from the sensor."""
|
||||
meas = self._mode
|
||||
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
|
||||
meas = self._mode << 5 | self._mode << 2 | 1
|
||||
self._device.write8(BME280_REGISTER_CONTROL, meas)
|
||||
sleep_time = 1250 + 2300 * (1 << self._mode)
|
||||
|
||||
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
|
||||
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
|
||||
time.sleep_us(sleep_time) # Wait the required time
|
||||
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
|
||||
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
|
||||
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
|
||||
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
return raw
|
||||
|
||||
def read_raw_pressure(self):
|
||||
"""Reads the raw (uncompensated) pressure level from the sensor."""
|
||||
"""Assumes that the temperature has already been read """
|
||||
"""i.e. that enough delay has been provided"""
|
||||
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
|
||||
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
|
||||
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
|
||||
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
return raw
|
||||
|
||||
def read_raw_humidity(self):
|
||||
"""Assumes that the temperature has already been read """
|
||||
"""i.e. that enough delay has been provided"""
|
||||
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
|
||||
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
|
||||
raw = (msb << 8) | lsb
|
||||
return raw
|
||||
|
||||
def read_temperature(self):
|
||||
"""Get the compensated temperature in 0.01 of a degree celsius."""
|
||||
adc = self.read_raw_temp()
|
||||
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
|
||||
var2 = ((
|
||||
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
|
||||
self.dig_T3) >> 14
|
||||
self.t_fine = var1 + var2
|
||||
return (self.t_fine * 5 + 128) >> 8
|
||||
|
||||
def read_pressure(self):
|
||||
"""Gets the compensated pressure in Pascals."""
|
||||
adc = self.read_raw_pressure()
|
||||
var1 = self.t_fine - 128000
|
||||
var2 = var1 * var1 * self.dig_P6
|
||||
var2 = var2 + ((var1 * self.dig_P5) << 17)
|
||||
var2 = var2 + (self.dig_P4 << 35)
|
||||
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
|
||||
((var1 * self.dig_P2) >> 12))
|
||||
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
|
||||
if var1 == 0:
|
||||
return 0
|
||||
p = 1048576 - adc
|
||||
p = (((p << 31) - var2) * 3125) // var1
|
||||
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
|
||||
var2 = (self.dig_P8 * p) >> 19
|
||||
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
|
||||
|
||||
def read_humidity(self):
|
||||
adc = self.read_raw_humidity()
|
||||
# print 'Raw humidity = {0:d}'.format (adc)
|
||||
h = self.t_fine - 76800
|
||||
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
|
||||
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
|
||||
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
|
||||
self.dig_H2 + 8192) >> 14))
|
||||
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
|
||||
h = 0 if h < 0 else h
|
||||
h = 419430400 if h > 419430400 else h
|
||||
return h >> 12
|
||||
|
||||
@property
|
||||
def temperature(self):
|
||||
"Return the temperature in degrees."
|
||||
t = self.read_temperature()
|
||||
ti = t // 100
|
||||
td = t - ti * 100
|
||||
return "{}.{:02d}C".format(ti, td)
|
||||
|
||||
@property
|
||||
def pressure(self):
|
||||
"Return the temperature in hPa."
|
||||
p = self.read_pressure() // 256
|
||||
pi = p // 100
|
||||
pd = p - pi * 100
|
||||
return "{}.{:02d}hPa".format(pi, pd)
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
"Return the humidity in percent."
|
||||
h = self.read_humidity()
|
||||
hi = h // 1024
|
||||
hd = h * 100 // 1024 - hi * 100
|
||||
return "{}.{:02d}%".format(hi, hd)
|
||||
300
13 - Mini-projets/2 - Station Météo/Programme/uSGP30.py
Normal file
300
13 - Mini-projets/2 - Station Météo/Programme/uSGP30.py
Normal file
@ -0,0 +1,300 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2017 ladyada for Adafruit Industries
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
"""
|
||||
`adafruit_sgp30`
|
||||
====================================================
|
||||
|
||||
I2C driver for SGP30 Sensirion VoC sensor
|
||||
|
||||
* Author(s): ladyada, Alexandre Marquet.
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Hardware:**
|
||||
|
||||
* Adafruit `SGP30 Air Quality Sensor Breakout - VOC and eCO2
|
||||
<https://www.adafruit.com/product/3709>`_ (Product ID: 3709)
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* MicroPython:
|
||||
https://github.com/micropython/micropython
|
||||
|
||||
* Modified by Alan Peaty for MicroPython port.
|
||||
"""
|
||||
|
||||
from math import exp
|
||||
from utime import sleep_ms
|
||||
from micropython import const
|
||||
|
||||
# General SGP30 settings
|
||||
SGP30_DEFAULT_I2C_ADDR = const(0x58)
|
||||
SGP30_WORD_LEN = const(2)
|
||||
SGP30_CRC8_POLYNOMIAL = const(0x31)
|
||||
SGP30_CRC8_INIT = const(0xFF)
|
||||
SGP30_CRC8_FINAL_XOR = const(0xFF)
|
||||
SGP30_MEASURE_TEST_PASS = const(0xD400)
|
||||
|
||||
# SGP30 feature set measurement commands (Hex Codes)
|
||||
# From datasheet section 6.3
|
||||
SGP30_CMD_IAQ_INIT_HEX = [0x20, 0x03]
|
||||
SGP30_CMD_IAQ_INIT_WORDS = const(0)
|
||||
SGP30_CMD_IAQ_INIT_MAX_MS = const(10)
|
||||
SGP30_CMD_MEASURE_IAQ_HEX = [0x20, 0x08]
|
||||
SGP30_CMD_MEASURE_IAQ_WORDS = const(2)
|
||||
SGP30_CMD_MEASURE_IAQ_MS = const(12)
|
||||
SGP30_CMD_GET_IAQ_BASELINE_HEX = [0x20, 0x15]
|
||||
SGP30_CMD_GET_IAQ_BASELINE_WORDS = const(2)
|
||||
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS = const(10)
|
||||
SGP30_CMD_SET_IAQ_BASELINE_HEX = [0x20, 0x1E]
|
||||
SGP30_CMD_SET_IAQ_BASELINE_WORDS = const(0)
|
||||
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS = const(10)
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX = [0x20, 0x61]
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS = const(0)
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS = const(10)
|
||||
SGP30_CMD_MEASURE_TEST_HEX = [0x20, 0x32]
|
||||
SGP30_CMD_MEASURE_TEST_WORDS = const(1)
|
||||
SGP30_CMD_MEASURE_TEST_MAX_MS = const(220)
|
||||
SGP30_CMD_GET_FEATURE_SET_HEX = [0x20, 0x2F]
|
||||
SGP30_CMD_GET_FEATURE_SET_WORDS = const(1)
|
||||
SGP30_CMD_GET_FEATURE_SET_MAX_MS = const(10)
|
||||
SGP30_CMD_MEASURE_RAW_HEX = [0x20, 0x50]
|
||||
SGP30_CMD_MEASURE_RAW_WORDS = const(2)
|
||||
SGP30_CMD_MEASURE_RAW_MAX_MS = const(25)
|
||||
SGP30_CMD_GET_TVOC_INCEPTIVE_HEX = [0x20, 0xB3]
|
||||
SGP30_CMD_GET_TVOC_INCEPTIVE_WORDS = const(1)
|
||||
SGP30_CMD_GET_TVOC_INCEPTIVE_MAX_MS = const(10)
|
||||
SGP30_CMD_SET_TVOC_BASELINE_HEX = [0x20, 0x77]
|
||||
SGP30_CMD_SET_TVOC_BASELINE_WORDS = const(0)
|
||||
SGP30_CMD_SET_TVOC_BASELINE_MAX_MS = const(10)
|
||||
|
||||
# TODO: Soft Reset (datasheet section 6.4)
|
||||
|
||||
# Obtaining Serial ID (datasheet section 6.5)
|
||||
SGP30_CMD_GET_SERIAL_ID_HEX = [0x36, 0x82]
|
||||
SGP30_CMD_GET_SERIAL_ID_WORDS = const(3)
|
||||
SGP30_CMD_GET_SERIAL_ID_MAX_MS = const(10)
|
||||
|
||||
|
||||
class SGP30:
|
||||
"""
|
||||
A driver for the SGP30 gas sensor.
|
||||
|
||||
:param i2c: The "I2C" object to use. This is the only required parameter.
|
||||
:param int address: (optional) The I2C address of the device.
|
||||
:param boolean measure_test: (optional) Whether to run on-chip test during initialisation.
|
||||
:param boolean iaq_init: (optional) Whether to initialise SGP30 algorithm / baseline.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, i2c, addr=SGP30_DEFAULT_I2C_ADDR, measure_test=False, iaq_init=True
|
||||
):
|
||||
""" Initialises the sensor and display stats """
|
||||
self._i2c = i2c
|
||||
if addr not in self._i2c.scan():
|
||||
raise IOError("No SGP30 device found on I2C bus")
|
||||
self.addr = addr
|
||||
self.serial = self.get_serial()
|
||||
self.feature_set = self.get_feature_set()
|
||||
if measure_test:
|
||||
if SGP30_MEASURE_TEST_PASS != self.measure_test():
|
||||
raise RuntimeError("Device failed the on-chip test")
|
||||
print(
|
||||
"SGP30 device discovered...\n"
|
||||
+ "I2C address: "
|
||||
+ str(self.addr)
|
||||
+ "\n"
|
||||
+ "Serial ID: "
|
||||
+ str(self.serial)
|
||||
+ "\n"
|
||||
+ "Feature set: "
|
||||
+ str(self.feature_set)
|
||||
+ "\n"
|
||||
+ "Initialise algo: "
|
||||
+ str(iaq_init)
|
||||
)
|
||||
if iaq_init:
|
||||
self.iaq_init()
|
||||
|
||||
def iaq_init(self):
|
||||
""" Initialises the IAQ algorithm """
|
||||
self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_IAQ_INIT_HEX, SGP30_CMD_IAQ_INIT_MAX_MS, SGP30_CMD_IAQ_INIT_WORDS
|
||||
)
|
||||
|
||||
def measure_iaq(self):
|
||||
""" Measures the CO2eq and TVOC """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_MEASURE_IAQ_HEX,
|
||||
SGP30_CMD_MEASURE_IAQ_MS,
|
||||
SGP30_CMD_MEASURE_IAQ_WORDS,
|
||||
)
|
||||
|
||||
def get_iaq_baseline(self):
|
||||
""" Retreives the IAQ algorithm baseline for CO2eq and TVOC """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_GET_IAQ_BASELINE_HEX,
|
||||
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS,
|
||||
SGP30_CMD_GET_IAQ_BASELINE_WORDS,
|
||||
)
|
||||
|
||||
def set_iaq_baseline(self, co2eq, tvoc):
|
||||
""" Sets the previously recorded IAQ algorithm baseline for CO2eq and TVOC """
|
||||
if co2eq == 0 and tvoc == 0:
|
||||
raise ValueError("Invalid baseline values used")
|
||||
buffer = []
|
||||
for value in [tvoc, co2eq]:
|
||||
arr = [value >> 8, value & 0xFF]
|
||||
arr.append(generate_crc(arr))
|
||||
buffer += arr
|
||||
self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_SET_IAQ_BASELINE_HEX + buffer,
|
||||
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS,
|
||||
SGP30_CMD_SET_IAQ_BASELINE_WORDS,
|
||||
)
|
||||
|
||||
def set_absolute_humidity(self, absolute_humidity):
|
||||
""" Sets absolute humidity compensation. To disable,
|
||||
set 0. """
|
||||
buffer = []
|
||||
arr = [absolute_humidity >> 8, absolute_humidity & 0xFF]
|
||||
arr.append(generate_crc(arr))
|
||||
buffer += arr
|
||||
self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX + buffer,
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS,
|
||||
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS,
|
||||
)
|
||||
|
||||
def measure_test(self):
|
||||
""" Runs on-chip self test """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_MEASURE_TEST_HEX,
|
||||
SGP30_CMD_MEASURE_TEST_MAX_MS,
|
||||
SGP30_CMD_MEASURE_TEST_WORDS,
|
||||
)[0]
|
||||
|
||||
def get_feature_set(self):
|
||||
""" Retrieves feature set of sensor """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_GET_FEATURE_SET_HEX,
|
||||
SGP30_CMD_GET_FEATURE_SET_MAX_MS,
|
||||
SGP30_CMD_GET_FEATURE_SET_WORDS,
|
||||
)[0]
|
||||
|
||||
def measure_raw(self):
|
||||
""" Returns raw H2 and Ethanol signals, used for part verification and testing """
|
||||
return self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_MEASURE_RAW_HEX,
|
||||
SGP30_CMD_MEASURE_RAW_MAX_MS,
|
||||
SGP30_CMD_MEASURE_RAW_WORDS,
|
||||
)
|
||||
|
||||
# TODO: Get TVOC inceptive baseline
|
||||
# TODO: Set TVOC baseline
|
||||
# TODO: Soft Reset (datasheet section 6.4)
|
||||
|
||||
def get_serial(self):
|
||||
""" Retrieves sensor serial """
|
||||
serial = self.serial = self._i2c_read_words_from_cmd(
|
||||
SGP30_CMD_GET_SERIAL_ID_HEX,
|
||||
SGP30_CMD_GET_SERIAL_ID_MAX_MS,
|
||||
SGP30_CMD_GET_SERIAL_ID_WORDS,
|
||||
)
|
||||
return hex(int.from_bytes(bytearray(serial), "large"))
|
||||
|
||||
@property
|
||||
def co2eq(self):
|
||||
""" Carbon Dioxide Equivalent in parts per million (ppm) """
|
||||
return self.measure_iaq()[0]
|
||||
|
||||
@property
|
||||
def baseline_co2eq(self):
|
||||
""" Carbon Dioxide Equivalent baseline value """
|
||||
return self.get_iaq_baseline()[0]
|
||||
|
||||
@property
|
||||
def tvoc(self):
|
||||
""" Total Volatile Organic Compound in parts per billion (ppb) """
|
||||
return self.measure_iaq()[1]
|
||||
|
||||
@property
|
||||
def baseline_tvoc(self):
|
||||
""" Total Volatile Organic Compound baseline value """
|
||||
return self.get_iaq_baseline()[1]
|
||||
|
||||
@property
|
||||
def raw_h2(self):
|
||||
""" Raw H2 signal """
|
||||
return self.measure_raw()[0]
|
||||
|
||||
@property
|
||||
def raw_ethanol(self):
|
||||
""" Raw Ethanol signal """
|
||||
return self.measure_raw()[1]
|
||||
|
||||
def _i2c_read_words_from_cmd(self, command, delay, reply_size):
|
||||
""" Runs an SGP command query, gets a reply and CRC results if necessary """
|
||||
self._i2c.writeto(self.addr, bytes(command))
|
||||
sleep_ms(delay)
|
||||
if not reply_size:
|
||||
return None
|
||||
crc_result = bytearray(reply_size * (SGP30_WORD_LEN + 1))
|
||||
self._i2c.readfrom_into(self.addr, crc_result)
|
||||
result = []
|
||||
for i in range(reply_size):
|
||||
word = [crc_result[3 * i], crc_result[3 * i + 1]]
|
||||
crc = crc_result[3 * i + 2]
|
||||
if generate_crc(word) != crc:
|
||||
raise RuntimeError("CRC Error")
|
||||
result.append(word[0] << 8 | word[1])
|
||||
return result
|
||||
|
||||
|
||||
def generate_crc(data):
|
||||
""" 8-bit CRC algorithm for checking data.
|
||||
Calculation described in section 6.6 of SGP30 datasheet """
|
||||
crc = SGP30_CRC8_INIT
|
||||
# Calculates 8-Bit CRC checksum with given polynomial
|
||||
for byte in data:
|
||||
crc ^= byte
|
||||
for _ in range(8):
|
||||
if crc & 0x80:
|
||||
crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL
|
||||
else:
|
||||
crc <<= 1
|
||||
return crc & 0xFF
|
||||
|
||||
|
||||
def convert_r_to_a_humidity(temp_c, r_humidity_perc, fixed_point=True):
|
||||
""" Converts relative to absolute humidity as per the equation
|
||||
found in datasheet """
|
||||
a_humidity_gm3 = 216.7 * (
|
||||
(r_humidity_perc / 100 * 6.112 * exp(17.62 * temp_c / (243.12 + temp_c)))
|
||||
/ (273.15 + temp_c)
|
||||
)
|
||||
# Return in 8.8 bit fixed point format (for setting humidity compensation), if not
|
||||
# simply return the calculated value in g/m^3
|
||||
if fixed_point:
|
||||
a_humidity_gm3 = (int(a_humidity_gm3) << 8) + (int(a_humidity_gm3 % 1 * 256))
|
||||
return a_humidity_gm3
|
||||
BIN
13 - Mini-projets/2 - Station Météo/Station_Météo.pdf
Normal file
BIN
13 - Mini-projets/2 - Station Météo/Station_Météo.pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,135 @@
|
||||
from machine import I2C
|
||||
import time
|
||||
|
||||
_I2CADDR = const(0x3E)
|
||||
|
||||
# commands
|
||||
_LCD_CLEARDISPLAY = const(0x01)
|
||||
_LCD_RETURNHOME = const(0x02)
|
||||
_LCD_ENTRYMODESET = const(0x04)
|
||||
_LCD_DISPLAYCONTROL = const(0x08)
|
||||
_LCD_CURSORSHIFT = const(0x10)
|
||||
_LCD_FUNCTIONSET = const(0x20)
|
||||
_LCD_SETCGRAMADDR = const(0x40)
|
||||
_LCD_SETDDRAMADDR = const(0x80)
|
||||
|
||||
# flags for display entry mode
|
||||
_LCD_ENTRYRIGHT = const(0x00)
|
||||
_LCD_ENTRYLEFT = const(0x02)
|
||||
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
|
||||
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
|
||||
|
||||
# flags for display on/off control
|
||||
_LCD_DISPLAYON = const(0x04)
|
||||
_LCD_DISPLAYOFF = const(0x00)
|
||||
_LCD_CURSORON = const(0x02)
|
||||
_LCD_CURSOROFF = const(0x00)
|
||||
_LCD_BLINKON = const(0x01)
|
||||
_LCD_BLINKOFF = const(0x00)
|
||||
|
||||
# flags for display/cursor shift
|
||||
_LCD_DISPLAYMOVE = const(0x08)
|
||||
_LCD_CURSORMOVE = const(0x00)
|
||||
_LCD_MOVERIGHT = const(0x04)
|
||||
_LCD_MOVELEFT = const(0x00)
|
||||
|
||||
# flags for function set
|
||||
_LCD_8BITMODE = const(0x10)
|
||||
_LCD_4BITMODE = const(0x00)
|
||||
_LCD_2LINE = const(0x08)
|
||||
_LCD_1LINE = const(0x00)
|
||||
_LCD_5x10DOTS = const(0x04)
|
||||
_LCD_5x8DOTS = const(0x00)
|
||||
|
||||
class lcd:
|
||||
|
||||
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
|
||||
self.i2c = i2c
|
||||
self.i2c.scan()
|
||||
self.address = address
|
||||
self.disp_func = _LCD_DISPLAYON
|
||||
if not oneline:
|
||||
self.disp_func |= _LCD_2LINE
|
||||
elif charsize != 0:
|
||||
# for 1-line displays you can choose another dotsize
|
||||
self.disp_func |= _LCD_5x10DOTS
|
||||
|
||||
# wait for display init after power-on
|
||||
time.sleep_ms(50) # 50ms
|
||||
|
||||
# send function set
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
|
||||
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
|
||||
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
|
||||
|
||||
# turn on the display
|
||||
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
|
||||
self.display(True)
|
||||
|
||||
# clear it
|
||||
self.clear()
|
||||
|
||||
# set default text direction (left-to-right)
|
||||
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
|
||||
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
|
||||
|
||||
def cmd(self, command):
|
||||
assert command >= 0 and command < 256
|
||||
command = bytearray([command])
|
||||
self.i2c.writeto_mem(self.address, 0x80, command)
|
||||
|
||||
def write_char(self, c):
|
||||
assert c >= 0 and c < 256
|
||||
c = bytearray([c])
|
||||
self.i2c.writeto_mem(self.address, 0x40, c)
|
||||
|
||||
def write(self, text):
|
||||
for char in text:
|
||||
self.write_char(ord(char))
|
||||
|
||||
def cursor(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_CURSORON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def setCursor(self, col, row):
|
||||
col = (col | 0x80) if row == 0 else (col | 0xc0)
|
||||
self.cmd(col)
|
||||
|
||||
def autoscroll(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def blink(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_BLINKON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def display(self, state):
|
||||
if state:
|
||||
self.disp_ctrl |= _LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
else:
|
||||
self.disp_ctrl &= ~_LCD_DISPLAYON
|
||||
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
|
||||
|
||||
def clear(self):
|
||||
self.cmd(_LCD_CLEARDISPLAY)
|
||||
time.sleep_ms(2) # 2ms
|
||||
|
||||
def home(self):
|
||||
self.cmd(_LCD_RETURNHOME)
|
||||
time.sleep_ms(2) # 2m
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user