La Robot Auto
module main
author unknown
version 1 0
description ''
variables _debug _QliiC_debug _QliiC_blocs _QliiC_bouton _QliiC_potentiometre _QliiC_LED
spec ' ' 'QliiC LED broche' 'QliiC LED broche _ [2,5,17,18,19,23] _' 'auto bool' '10' true
spec ' ' 'QliiC TEST Bouton, potentiometre, LED' 'Démo bouton, potentiometre, LED'
spec ' ' 'Démo senseurs I2C (MPU6050, TCS34725)' 'Démo senseurs I2C (MPU6050, TCS34725)'
spec ' ' 'Démo servomoteurs #26 et #27' 'Démo servomoteurs #26 et #27'
spec ' ' 'QliiC Menu' 'QliiC Menu'
spec ' ' 'Test HC-SR04' 'Tester HC-SR04 trigger _ echo _' 'auto auto' '10' '10'
spec ' ' 'Tester Couleur' 'Tester Couleur'
spec ' ' 'Tester IR' 'Tester IR _ _' 'auto auto' 10 '10'
spec ' ' 'Tester LED' 'Tester LED _' 'auto' '10'
spec ' ' 'Tester Potentiometre' 'Tester Potentiometre _' 'auto' '10'
spec ' ' 'Tester Servo' 'Tester Servo _ _' 'auto auto' '10' '10'
spec ' ' 'Tester actions' 'Tester bloc _ broche _' 'auto auto' 10 '10'
spec ' ' 'Ascii table' 'QliiC saisir text'
spec ' ' 'Tester Bouton' 'Tester Bouton _' 'auto' '10'
spec ' ' 'Qliic' 'QliiC Configurer _ broche _' 'str str' '10' '10'
spec ' ' 'Tester Buzzer' 'Tester Buzzer'
spec ' ' 'QliiC Initialiser' 'QliiC Initialiser bouton _ potentiometre _ LED _' 'num num auto' 10 10 '10'
spec ' ' 'Robot Auto' 'Robot Auto'
to 'Ascii table' {
local 'text' ('[data:makeList]' '')
local 'menu' ('[data:makeList]' 'ESC')
'[data:addLast]' 'DEL' menu
for i ('[data:range]' 32 126) {
'[data:addLast]' ('[data:unicodeString]' i) menu
}
local 'pot' 0
local 'menuLong' (1023 / (size menu))
local 'menuAction' 'NIL'
local 'menuActionPrecedant' 'NIL'
local 'menuItem' 0
forever {
pot = ('QliiC Potentiomètre' 36)
menuItem = (pot / menuLong)
menuItem = (ifExpression (menuItem == 0) 1 menuItem)
menuItem = (ifExpression (menuItem > 97) 97 menuItem)
menuAction = (at menuItem menu)
if (menuAction != menuActionPrecedant) {
local 'menuActionPrecedant' menuAction
'QliiC OLED effacer'
OLEDwrite menuAction 0 0 false 4
OLEDwrite ('[data:joinStrings]' text) 0 48 false 2
}
if ('QliiC Bouton' _QliiC_bouton) {
menuActionPrecedant = 'NIL'
if (menuAction == 'DEL') {
'[data:delete]' 'last' text
} (menuAction == 'ESC') {
exitLoop
} else {
'[data:addLast]' menuAction text
}
waitMillis 500
}
}
}
to 'Démo senseurs I2C (MPU6050, TCS34725)' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Demo senseurs I2C TCS34725 MPU6050' 1
'QliiC Couleur inistialiser TCS34725 sur I2C'
'QliiC Accéléromètre initialiser MPU6050 sur I2C'
'QliiC LED RGB initialiser sur #12'
forever {
'QliiC LOG' ('[data:join]' 'C:' ('QliiC Couleur') '
X:' ('QliiC Accéleration X') '
Y:' ('QliiC Accéleration Y') '
Z:' ('QliiC Accéleration Z') ' ')
if (('QliiC Couleur') == 'Red') {
'QliiC LED RGB couleur' (colorSwatch 190 7 38 255)
} (('QliiC Couleur') == 'Yellow') {
'QliiC LED RGB couleur' (colorSwatch 178 190 20 255)
} (('QliiC Couleur') == 'Blue') {
'QliiC LED RGB couleur' (colorSwatch 9 2 190 255)
} (('QliiC Couleur') == 'Green') {
'QliiC LED RGB couleur' (colorSwatch 4 190 20 255)
} else {
'QliiC LED RGB couleur' (colorSwatch 0 0 0 255)
}
graphIt ('QliiC Accéleration X') ('QliiC Accéleration Y') ('QliiC Accéleration Z')
}
}
to 'Démo servomoteurs #26 et #27' {
local 'pot' 0
local 'servo 26' 0
local 'servo 27' 0
repeat 2 {
'QliiC LOG' '0 degre '
'QliiC Servo broche' 26 0
'QliiC Servo broche' 27 0
waitMillis 1000
'QliiC LOG' '90 degre '
'QliiC Servo broche' 26 90
'QliiC Servo broche' 27 90
waitMillis 1000
'QliiC LOG' '0 degre '
'QliiC Servo broche' 26 0
'QliiC Servo broche' 27 0
waitMillis 1000
'QliiC LOG' '-90 degre'
'QliiC Servo broche' 26 -90
'QliiC Servo broche' 27 -90
waitMillis 1000
}
}
to 'QliiC Initialiser' broche_bouton broche_potentiometre broche_led {
_QliiC_bouton = broche_bouton
_QliiC_potentiometre = broche_potentiometre
_QliiC_LED = broche_led
_QliiC_debug = (booleanConstant false)
_QliiC_blocs = ('[data:makeList]' '')
'[data:delete]' 1 _QliiC_blocs
if _QliiC_debug {
sayIt ('[data:join]' 'Bouton broche:' _QliiC_bouton ' ' 'Potentiometre broche:' _QliiC_potentiometre)
}
}
to 'QliiC LED broche' broche etat {
digitalWriteOp broche etat
}
to 'QliiC Menu' {
local 'pot' 0
local 'menu' _QliiC_blocs
local 'menuLong' (1023 / (size menu))
local 'menuAction' 'NIL'
local 'menuActionPrecedant' 'NIL'
local 'menuItem' 0
forever {
pot = ('QliiC Potentiomètre' _QliiC_potentiometre)
if _QliiC_debug {
sayIt 'potentiometre ' pot
}
menuItem = (pot / menuLong)
menuItem = (ifExpression (menuItem == 0) 1 menuItem)
menuAction = ('[data:join]' (at menuItem menu) '')
if (menuAction != menuActionPrecedant) {
local 'bloc' (at 1 ('[data:split]' menuAction ','))
local 'pin' (at 2 ('[data:split]' menuAction ','))
local 'menuActionPrecedant' menuAction
'QliiC OLED effacer'
'QliiC LOG' ('[data:join]' bloc '
pin ' pin)
}
if ('QliiC Bouton' _QliiC_bouton) {
'Tester actions' bloc pin
menuActionPrecedant = 'NIL'
}
}
}
to 'QliiC TEST Bouton, potentiometre, LED' {
local 'pot' 0
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Demo bouton, potentiometre, LED' 1
'QliiC Initialiser Bouton' 'A'
'QliiC Initialiser potentiomètre' 34
'QliiC LED initialiser sur' 2
forever {
pot = ('QliiC Potentiomètre' 34)
'QliiC LOG' ('[data:join]' 'A:' ('QliiC Bouton' 'A') '
P34:' pot '
IR35:' ('QliiC Bouton' 35))
if ('QliiC Bouton' 'A') {
waitMillis pot
'QliiC LED broche' 2 true
waitMillis pot
'QliiC LED broche' 2 false
}
}
}
to Qliic bloc pin_list {
'[data:addLast]' ('[data:join]' bloc ',' pin_list) _QliiC_blocs
if (bloc == 'OLED') {
waitMillis 500
'QliiC Initialiser Écran OLED'
} (bloc == 'Couleur') {
if (not ('TCS34725 connected')) {sayIt 'TCS34725 absent du bus I2C'}
} (bloc == 'Buzzer') {
'attach buzzer to pin' pin_list
} (bloc == 'RGB') {
neoPixelAttach 7 pin_list
}
}
to 'Robot Auto' {
'QliiC Initialiser' 15 36 2
Qliic 'OLED' 'i2c'
Qliic 'Bouton' '15'
Qliic 'Bouton' '13'
Qliic 'Potentiometre' '36'
Qliic 'LED' '2'
Qliic 'Servo' '26'
Qliic 'Servo' '27'
Qliic 'Distance' '12-14'
Qliic 'IR' '33-32'
Qliic 'Demo servo' '26-27'
'QliiC Projet' 'Robot Auto' '4.0'
'QliiC Menu'
}
to 'Test HC-SR04' trigger echo {
forever {
'QliiC LOG' ('[data:join]' 'Distance
CM ' ('distance (cm)' trigger echo) ' ')
if ('QliiC Bouton' _QliiC_bouton) {
exitLoop
}
}
}
to 'Tester Bouton' broche {
forever {
if ('QliiC Bouton' broche) {
'QliiC LOG' ('[data:join]' 'Bouton ' broche '
ON ')
'QliiC LED broche' _QliiC_LED true
} else {
'QliiC LOG' ('[data:join]' 'Bouton ' broche '
OFF')
'QliiC LED broche' _QliiC_LED false
}
if ('QliiC Bouton' _QliiC_bouton) {
exitLoop
}
}
}
to 'Tester Buzzer' {
'attach buzzer to pin' 13
'QliiC LOG' ('[data:join]' 'Bouton B
pour jouer' '')
forever {
milliseconde = ('QliiC Potentiomètre' 36)
if ('QliiC Bouton' 'B') {
'play tone' 'nt;a' 0 500
}
if ('QliiC Bouton' 'A') {
exitLoop
}
}
}
to 'Tester Couleur' {
forever {
'QliiC LOG' ('[data:join]' 'COULEUR:' '
' ('QliiC Couleur') ' ')
if ('QliiC Bouton' 'A') {
exitLoop
}
}
}
to 'Tester IR' numerique analogique {
forever {
'QliiC LOG' ('[data:join]' 'IR_N:' (not (digitalReadOp 32 'up')) '
IR_A:' (analogReadOp 33) ' ')
if ('QliiC Bouton' _QliiC_bouton) {
exitLoop
}
}
}
to 'Tester LED' broche {
local 'pwm' 0
forever {
pwm = ('QliiC Potentiomètre' _QliiC_potentiometre)
'QliiC LOG' ('[data:join]' 'LED ' broche '
PWM ' pwm ' ')
analogWriteOp broche pwm
if ('QliiC Bouton' _QliiC_bouton) {
exitLoop
}
}
}
to 'Tester Potentiometre' broche {
forever {
'QliiC LOG' ('[data:join]' 'Potentiometre ' broche '
' ('QliiC Potentiomètre' broche) ' ')
if ('QliiC Bouton' _QliiC_bouton) {
exitLoop
}
}
}
to 'Tester Servo' pot servo {
local 'servo_degre' 0
forever {
servo_degre = ('[misc:rescale]' ('QliiC Potentiomètre' pot) 0 1023 -90 90)
'QliiC LOG' ('[data:join]' 'Servo ' servo '
' servo_degre ' ')
'QliiC Servo broche' servo servo_degre
if ('QliiC Bouton' _QliiC_bouton) {
exitLoop
}
}
}
to 'Tester actions' bloc broche {
waitMillis 250
'QliiC LED broche' _QliiC_LED true
waitMillis 250
'QliiC LED broche' _QliiC_LED false
if _QliiC_debug {
'QliiC LOG' ('[data:join]' 'Tester ' action)
waitMillis 1000
}
'QliiC OLED effacer'
if (bloc == 'Distance') {
sayIt ('[data:convertType]' (at 1 ('[data:split]' broche '-')) 'number') ('[data:convertType]' (at 2 ('[data:split]' broche '-')) 'number')
waitMillis 1000
'Test HC-SR04' ('[data:convertType]' (at 1 ('[data:split]' broche '-')) 'number') ('[data:convertType]' (at 2 ('[data:split]' broche '-')) 'number')
} (bloc == 'Potentiometre') {
'Tester Potentiometre' ('[data:convertType]' broche 'number')
} (bloc == 'IR') {
'Tester IR' 10 10
} (bloc == 'Couleur') {
'Tester Couleur'
} (bloc == 'Servo') {
'Tester Servo' _QliiC_potentiometre ('[data:convertType]' broche 'number')
} (bloc == 'Demo servo') {
'Démo servomoteurs #26 et #27'
} (bloc == 'Bouton') {
'Tester Bouton' ('[data:convertType]' broche 'number')
} (bloc == 'LED') {
'Tester LED' ('[data:convertType]' broche 'number')
} (bloc == 'Bouton B') {
'Tester Bouton' bloc
} (bloc == 'OLED') {
'Ascii table'
} (bloc == 'Buzzer') {
'Tester Buzzer'
} else {
}
waitMillis 125
'QliiC LED broche' _QliiC_LED true
waitMillis 125
'QliiC LED broche' _QliiC_LED false
waitMillis 125
'QliiC LED broche' _QliiC_LED true
waitMillis 125
'QliiC LED broche' _QliiC_LED false
}
script 62 62 {
whenStarted
'Robot Auto'
}
script 251 120 {
to 'Robot Auto' {}
}
module 'Blocs QliiC'
author 'François Belleau'
version 1 0
description ''
variables cm 'QliiC Configuration'
spec 'r' 'QliiC Bouton' 'QliiC Bouton _ A#0 ou B#15 ou Pin#' 'auto' '10'
spec 'r' 'QliiC Distance en cm' 'QliiC V2 Distance en cm'
spec ' ' 'QliiC Initialiser Bouton' 'QliiC Bouton _ A#0 ou B#4 ou Pin# initialiser' 'auto' 10
spec ' ' 'QliiC Initialiser potentiomètre' 'QliiC Potentiomètre _ #32, #33, #34 ou #35 initialiser' 'num' 10
spec ' ' 'QliiC Initialiser senseur de distance HC-SR04 #12 et #13' 'QliiC V2 Distance initialiser capteur HC-SR04 sur #12 et #14'
spec ' ' 'QliiC Initialiser Écran OLED' 'QliiC Initialiser Écran OLED'
spec 'r' 'QliiC Potentiomètre' 'QliiC Potentiomètre _' 'auto' '10'
spec ' ' 'QliiC Projet' 'QliiC Projet _ version _' 'str auto' '10' 10
spec ' ' 'Qliic TEST' 'QliiC TEST'
spec ' ' 'QliiC Afficher' 'QliiC Afficher _ et attendre bouton A#0' 'str' '10'
spec ' ' 'QliiC Bouton TEST' 'QliiC TEST Bouton'
spec 'r' 'QliiC Capteur IR' 'QliiC Capteur IR numérique'
spec ' ' 'QliiC Capteur IR #14' 'QliiC Capteur IR initialiser sur #32 et #33'
spec 'r' 'QliiC Capteur IR analogique' 'QliiC Capteur IR analogique'
spec ' ' 'QliiC Distance TEST' 'QliiC TEST HC-SR04'
spec 'r' 'QliiC Humidité en %' 'QliiC V2 Humidité en %'
spec ' ' 'QliiC Potentiomètre TEST' 'QliiC TEST Potentiomètre '
spec 'r' 'QliiC Température en celsius' 'QliiC V2 Température en celsius'
spec ' ' 'QliiC Température et humidité DHT-11 sur #14' 'QliiC V2 Température et humidité initialiser capteur DHT11 sur #25'
spec ' ' 'QliiC Température et humidité TEST' 'QliiC TEST DHT11'
spec ' ' 'QliiC Tester IR' 'QliiC TEST IR'
spec 'r' 'QliiC Accéleration X' 'QliiC Accéleration X'
spec 'r' 'QliiC Accéleration Y' 'QliiC Accéleration Y'
spec 'r' 'QliiC Accéleration Z' 'QliiC Accéleration Z'
spec ' ' 'QliiC Accéléromètre TEST' 'QliiC TEST MPU 6050'
spec ' ' 'QliiC Accéléromètre initialiser MPU6050 sur I2C' 'QliiC Accéléromètre initialiser MPU 6050 sur I2C'
spec 'r' 'QliiC Couleur' 'QliiC Couleur'
spec ' ' 'QliiC Couleur TEST' 'QliiC TEST TCS34725'
spec ' ' 'QliiC Couleur inistialiser TCS34725 sur I2C' 'QliiC Couleur initialiser TCS34725 sur I2C'
spec ' ' 'QliiC Allumer LED broche' 'QliiC Allumer LED broche _ [2,5,17,18,19,23] _' 'num bool' 10 true
spec ' ' 'QliiC Buzzer #15 initialiser' 'QliiC Buzzer initialiser sur #15'
spec ' ' 'QliiC Buzzer jouer' 'QliiC Buzzer jouer _ hertz' 'num' 10
spec ' ' 'QliiC Buzzer silence' 'QliiC Buzzer silence'
spec ' ' 'QliiC Capteur de présence' 'QliiC Capteur de présence PIR initialiser sur #13'
spec 'r' 'QliiC Capteur de présence PIR initialiser sur #13' 'QliiC Capteur de présence PIR '
spec ' ' 'QliiC Jouer mélodie RTTL' 'QliiC Buzzer jouer mélodie _ en RTTTL' 'auto' 10
spec ' ' 'QliiC Jouer note' 'QliiC Buzzer jouer note _ octave _ durée _ milliseconde' 'str num num' '10' 10 10
spec ' ' 'QliiC LED RGB couleur' 'QliiC LED RGB couleur _' 'color'
spec ' ' 'QliiC LED RGB initialiser sur #12' 'QliiC V2 LED RGB initialiser sur #13'
spec ' ' 'QliiC LED RGB éteindre' 'QliiC LED RGB éteindre'
spec ' ' 'QliiC LOG' 'QliiC LOG _' 'str' '10'
spec ' ' 'QliiC OLED effacer' 'QliiC OLED effacer'
spec ' ' 'QliiC RGB rouge' 'QliiC LED RGB rouge _ vert _ bleu _ (0-255)' 'num num num' 10 10 10
spec ' ' 'QliiC Servo broche' 'QliiC Servo broche _ à _ degrés' 'num auto' 10 '10'
spec ' ' 'QliiC Servo moteur initialiser sur broche' 'QliiC Servo moteur initialiser sur broche _ (#26, #27)' 'num' 10
spec ' ' 'QliiC TEST Buzzer' 'QliiC TEST Buzzer'
spec ' ' 'QliiC TEST LED' 'QliiC TEST LED'
spec ' ' 'QliiC TEST OLED' 'QliiC TEST OLED'
spec ' ' 'QliiC TEST PIR' 'QliiC TEST PIR'
spec ' ' 'QliiC TEST RGB' 'QliiC TEST RGB'
spec ' ' 'QliiC TEST Servo' 'QliiC TEST Servo'
spec ' ' 'QliiC Écrire' 'QliiC OLED écrire _' 'str' '10'
to 'QliiC Accéleration X' {
return (mpu6050_tiltX)
}
to 'QliiC Accéleration Y' {
return (mpu6050_tiltY)
}
to 'QliiC Accéleration Z' {
return (mpu6050_tiltZ)
}
to 'QliiC Accéléromètre TEST' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester MPU 6050' 1
'QliiC Accéléromètre initialiser MPU6050 sur I2C'
forever {
'QliiC LOG' = ('[data:join]' ' X:' ('QliiC Accéleration X') '
Y:' ('QliiC Accéleration Y') '
Z:' ('QliiC Accéleration Z') ' ')
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
waitMillis 100
}
}
to 'QliiC Accéléromètre initialiser MPU6050 sur I2C' {
'QliiC Afficher' 'MPU 6050 sur bus I2C'
}
to 'QliiC Afficher' message {
if (v 'QliiC Configuration') {
sayIt message
OLEDclear
OLEDwrite message 8 0 false 1
waitMillis 1000
waitUntil (not (digitalReadOp 0))
OLEDclear
}
}
to 'QliiC Allumer LED broche' broche etat {
digitalWriteOp broche etat
}
to 'QliiC Bouton' boutonNom {
local 'boutonEtat' 0
if (boutonNom == 'A') {
return (not (digitalReadOp 0 'up'))
} (boutonNom == 'B') {
return (not (digitalReadOp 15 'up'))
} else {
return (not (digitalReadOp boutonNom 'up'))
}
}
to 'QliiC Bouton TEST' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester boutons A B #16' 1
'QliiC Initialiser Bouton' 'A'
'QliiC Initialiser Bouton' 'B'
'QliiC Initialiser Bouton' 16
forever {
'QliiC LOG' = ('[data:join]' ' A0:' ('QliiC Bouton' 'A') ' B4:' ('QliiC Bouton' 'B') ' B16:' ('QliiC Bouton' 16) ' ')
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
waitMillis 100
}
}
to 'QliiC Buzzer #15 initialiser' {
'attach buzzer to pin' 15
'QliiC Afficher' 'Buzzer sur broche #15'
}
to 'QliiC Buzzer jouer' frequence {
startTone frequence
}
to 'QliiC Buzzer silence' {
stopTone
}
to 'QliiC Capteur IR' {
return (not (digitalReadOp 32 'up'))
}
to 'QliiC Capteur IR #14' {
'QliiC Afficher' 'Capteur IR sur #32 #33'
}
to 'QliiC Capteur IR analogique' {
return (analogReadOp 33)
}
to 'QliiC Capteur de présence' {
'QliiC Afficher' 'Capteur PIR sur #13'
}
to 'QliiC Capteur de présence PIR initialiser sur #13' {
return (digitalReadOp 13 'up')
}
to 'QliiC Couleur' {
return (color ('TCS34725 rgb'))
}
to 'QliiC Couleur TEST' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester TCS34725' 1
'QliiC Couleur inistialiser TCS34725 sur I2C'
forever {
'QliiC LOG' ('[data:join]' ' COULEUR
' ('QliiC Couleur') '')
waitMillis 100
}
}
to 'QliiC Couleur inistialiser TCS34725 sur I2C' {
if ('TCS34725 connected') {
'QliiC Afficher' 'TCS34725 sur bus I2C'
} else {
'QliiC Afficher' 'TCS34725 absent du bus I2C'
}
}
to 'QliiC Distance TEST' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester HC-SR04' 1
'QliiC Initialiser senseur de distance HC-SR04 #12 et #13'
forever {
'QliiC LOG' = 0
'QliiC LOG' ('[data:join]' ' CM:' ('QliiC Distance en cm') ' ')
}
}
to 'QliiC Distance en cm' {
return ('distance (cm)' 14 12)
}
to 'QliiC Humidité en %' {
return (humidity_DHT11 25)
}
to 'QliiC Initialiser Bouton' boutonNom {
if (boutonNom == 'A') {
'QliiC Afficher' 'Bouton A sur la pin #0'
} (boutonNom == 'B') {
'QliiC Afficher' 'Bouton B sur la pin #4'
} else {
'QliiC Afficher' ('[data:join]' 'Bouton sur la pin #' ('[data:convertType]' boutonNom 'string'))
}
}
to 'QliiC Initialiser potentiomètre' potentiometrePin {
if (potentiometrePin == 32) {
'QliiC Afficher' 'Potentiometre sur la broche #32'
} (potentiometrePin == 33) {
'QliiC Afficher' 'Potentiometre sur la broche #33'
} (potentiometrePin == 34) {
'QliiC Afficher' 'Potentiometre sur la broche #34'
} (potentiometrePin == 35) {
'QliiC Afficher' 'Potentiometre sur la broche #35'
} else {
sayIt 'Broche #' ('[data:convertType]' potentiometrePin 'string') 'non disponible'
stopTask
}
}
to 'QliiC Initialiser senseur de distance HC-SR04 #12 et #13' {
'QliiC Afficher' 'HC-SR04 trig #14 echo #12'
}
to 'QliiC Initialiser Écran OLED' {
if (not ('[sensors:i2cExists]' (hexToInt '3C'))) {
sayIt 'ERREUR Ecran OLED I2C absent'
forever {
digitalWriteOp 2 true
waitMillis 500
digitalWriteOp 2 false
waitMillis 500
}
} else {
OLEDInit_I2C_auto 21 false
OLEDInit_I2C 'OLED_0.96in' '3C' 21 false
OLEDclear
OLEDwrite 'QliiC' 8 8 false 3
waitMillis 1000
OLEDclear
}
}
to 'QliiC Jouer mélodie RTTL' mélodie {
comment 'Pacman:d=16,o=6,b=140:
b5,b,f#,d#,8b,8d#,c,c7,g,f,8c7,8e,b5,b,f#,d#,8b,8d#,32d#,32e,f,32f,32f#,g,32g,32g#,a,8b'
'play ringtone' mélodie
}
to 'QliiC Jouer note' note octave duree {
'play tone' note octave duree
}
to 'QliiC LED RGB couleur' couleur {
setNeoPixelColor 1 couleur
}
to 'QliiC LED RGB initialiser sur #12' {
'QliiC Afficher' 'LED RGB sur #13'
neoPixelAttach 1 13
}
to 'QliiC LED RGB éteindre' {
clearNeoPixels
}
to 'QliiC LOG' message {
sayIt message
OLEDwrite message 0 0 false 2
}
to 'QliiC OLED effacer' {
OLEDclear
}
to 'QliiC Potentiomètre' potentiometrePin {
local 'var' 0
local 'nb' 20
repeat nb {
var = (var + (analogReadOp potentiometrePin))
}
return (var / nb)
}
to 'QliiC Potentiomètre TEST' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester potentiometre #34 #35' 1
'QliiC Initialiser potentiomètre' 34
'QliiC Initialiser potentiomètre' 35
forever {
'QliiC LOG' = ('[data:join]' ' P34:' ('QliiC Potentiomètre' 34) '
P35:' ('QliiC Potentiomètre' 35) '')
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
waitMillis 100
}
}
to 'QliiC Projet' projetNom version {
'QliiC LOG' ('[data:join]' projetNom ' v' version)
waitMillis 1000
OLEDclear
}
to 'QliiC RGB rouge' rouge vert bleu {
setNeoPixelColor 1 (colorFromRGB rouge vert bleu)
}
to 'QliiC Servo broche' broche degre {
setServoAngle broche degre
}
to 'QliiC Servo moteur initialiser sur broche' broche {
'QliiC Afficher' ('[data:join]' 'Servo sur #' ('[data:convertType]' broche 'string'))
}
to 'QliiC TEST Buzzer' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester Buzzer' 1
'QliiC Buzzer #15 initialiser'
repeat 3 {
'QliiC Jouer note' 'a' 3 500
waitMillis 500
}
repeat 3 {
'QliiC Buzzer jouer' 440
waitMillis 500
'QliiC Buzzer silence'
waitMillis 500
}
'QliiC Jouer mélodie RTTL' 'Pacman:d=16,o=6,b=140:
b5,b,f#,d#,8b,8d#,c,c7,g,f,8c7,8e'
for i ('[data:range]' 440 880) {
sayIt i
'QliiC Buzzer jouer' i
}
'QliiC Buzzer silence'
}
to 'QliiC TEST LED' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester LED' 1
forever {
'QliiC LOG' = 'LEDs OFF'
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
'QliiC Allumer LED broche' 2 false
'QliiC Allumer LED broche' 5 false
'QliiC Allumer LED broche' 17 false
'QliiC Allumer LED broche' 18 false
'QliiC Allumer LED broche' 19 false
'QliiC Allumer LED broche' 23 false
waitMillis 500
'QliiC LOG' = 'LEDs ON '
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
'QliiC Allumer LED broche' 2 true
'QliiC Allumer LED broche' 5 true
'QliiC Allumer LED broche' 17 true
'QliiC Allumer LED broche' 18 true
'QliiC Allumer LED broche' 19 true
'QliiC Allumer LED broche' 23 true
waitMillis 500
}
}
to 'QliiC TEST OLED' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester OLED' 1
forever {
'QliiC Écrire' ' Allo!
On QliiC
ensemble ?'
waitMillis 3000
'QliiC OLED effacer'
waitMillis 1000
}
}
to 'QliiC TEST PIR' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester PIR' 1
'QliiC Capteur de présence'
forever {
'QliiC LOG' = ('[data:join]' ' PIR:' ('QliiC Capteur de présence PIR initialiser sur #13') ' ')
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
waitMillis 100
}
}
to 'QliiC TEST RGB' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester RGB' 1
'QliiC LED RGB initialiser sur #12'
repeat 2 {
'QliiC RGB rouge' 100 0 0
waitMillis 500
'QliiC RGB rouge' 0 100 0
waitMillis 500
'QliiC RGB rouge' 0 0 100
waitMillis 500
}
forever {
'QliiC LED RGB couleur' (colorSwatch 189 65 190 255)
waitMillis 500
'QliiC LED RGB éteindre'
waitMillis 500
}
}
to 'QliiC TEST Servo' {
local 'pot' 0
local 'servo 26' 0
local 'servo 27' 0
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester Servo' 1
'QliiC Servo moteur initialiser sur broche' 26
'QliiC Servo moteur initialiser sur broche' 27
'QliiC Initialiser Bouton' 0
'QliiC Initialiser potentiomètre' 34
repeat 2 {
'QliiC LOG' '0 degre '
'QliiC Servo broche' 26 0
'QliiC Servo broche' 27 0
waitMillis 1000
'QliiC LOG' '90 degre '
'QliiC Servo broche' 26 90
'QliiC Servo broche' 27 90
waitMillis 1000
'QliiC LOG' '0 degre '
'QliiC Servo broche' 26 0
'QliiC Servo broche' 27 0
waitMillis 1000
'QliiC LOG' '-90 degre'
'QliiC Servo broche' 26 -90
'QliiC Servo broche' 27 -90
waitMillis 1000
}
forever {
pot = ('[misc:rescale]' ('QliiC Potentiomètre v2' 34) 0 1023 -90 90)
if ('QliiC Bouton' 0) {
'servo 26' = pot
'QliiC Servo broche' 26 (v 'servo 26')
'QliiC LOG' ('[data:join]' 'S26:' (v 'servo 26') ' ')
} else {
'servo 27' = pot
'QliiC Servo broche' 27 (v 'servo 27')
'QliiC LOG' ('[data:join]' 'S27:' (v 'servo 27') ' ')
}
}
}
to 'QliiC Température en celsius' {
return (temperature_DHT11 25)
}
to 'QliiC Température et humidité DHT-11 sur #14' {
'QliiC Afficher' 'DHT11 #25'
}
to 'QliiC Température et humidité TEST' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester DHT11' 1
'QliiC Température et humidité DHT-11 sur #14'
forever {
'QliiC LOG' = ('[data:join]' '
TEMP:' ('QliiC Température en celsius') 'C
HUM:' ('QliiC Humidité en %') '%')
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
waitMillis 500
}
}
to 'QliiC Tester IR' {
'QliiC Initialiser Écran OLED'
'QliiC Projet' 'Tester IR' 1
'QliiC Capteur IR #14'
forever {
'QliiC LOG' = ('[data:join]' ' IRN:' ('QliiC Capteur IR') ' IRA:' ('QliiC Capteur IR analogique') ' ')
sayIt (v 'QliiC LOG')
OLEDwrite (v 'QliiC LOG') 0 0 false 2
waitMillis 1500
}
}
to 'QliiC Écrire' message {
OLEDwrite message 0 0 false 2
}
to 'Qliic TEST' {
}
module 'Color (TCS34725)' Input
author 'José García Yeste'
version 1 4
tags sensor color
description 'Support for the TCS34725 RGB color sensor.
Tested with:
https://www.dfrobot.com/product-1546.html
https://www.ebay.es/itm/323902408493
'
variables '_TCS34725 initalized'
spec 'r' 'TCS34725 connected' 'TCS34725 connected'
spec 'r' 'TCS34725 rgb' 'TCS34725 rgb'
spec 'r' 'TCS34725 luminance' 'TCS34725 luminance'
spec 'r' 'color' 'color _ name' 'color'
spec ' ' '_TCS34725 setup' '_TCS34725 setup'
spec 'r' '_TCS34725 raw' '_TCS34725 raw'
to 'TCS34725 connected' {
local 'id' (i2cGet (hexToInt '29') (hexToInt '92'))
comment '0x4D for TCS34727 (untested)'
return (or (id == (hexToInt '44')) (id == (hexToInt '4D')))
}
to 'TCS34725 luminance' {
local 'crgb' ('_TCS34725 raw')
local 'r' (at 2 crgb)
local 'g' (at 3 crgb)
local 'b' (at 4 crgb)
comment '(-0.32466 * r) + (1.57837 * g) + (-0.73191 * b);'
return (maximum 0 ((((r * -3246) + (g * 15784)) + (b * -7319)) / 10000))
}
to 'TCS34725 rgb' {
local 'raw' ('_TCS34725 raw')
local 'rgb' (newList 3)
for i 3 {
atPut i rgb (minimum ((at (i + 1) raw) / 14) 255)
}
return ((((at 1 rgb) << 16) | ((at 2 rgb) << 8)) | (at 3 rgb))
}
to '_TCS34725 raw' {
'_TCS34725 setup'
comment 'read 8 bytes c,r,g,b'
local 'crgb' (newList 8)
if ('TCS34725 connected') {
'[sensors:i2cWrite]' (hexToInt '29') (hexToInt '94')
'[sensors:i2cRead]' (hexToInt '29') crgb
waitMillis 1
atPut 1 crgb (((at 2 crgb) << 8) | (at 1 crgb))
atPut 2 crgb (((at 4 crgb) << 8) | (at 3 crgb))
atPut 3 crgb (((at 6 crgb) << 8) | (at 5 crgb))
atPut 4 crgb (((at 8 crgb) << 8) | (at 7 crgb))
}
waitMillis 50
return crgb
}
to '_TCS34725 setup' {
comment 'https://github.com/DFRobot/DFRobot_TCS34725'
if ((v '_TCS34725 initialized') == 0) {
comment 'setIntegrationTime 50 ms (0xEB)'
i2cSet (hexToInt '29') (hexToInt '81') (hexToInt 'EB')
comment 'setGain 4X (0x01)'
i2cSet (hexToInt '29') (hexToInt '8F') 1
comment 'enable'
i2cSet (hexToInt '29') (hexToInt '80') 1
waitMillis 3
i2cSet (hexToInt '29') (hexToInt '80') 3
'_TCS34725 initialized' = 1
}
}
to color color {
local 'r' ((color >> 16) & 255)
local 'g' ((color >> 8) & 255)
local 'b' (color & 255)
local 'min' (minimum r g b)
local 'max' (maximum r g b)
if (max < 50) {
return 'Black'
}
if (min > 185) {
return 'White'
}
if (max == r) {
local 'l' ((r * 2) / 3)
if (and (g < l) (b < l)) {
return 'Red'
}
if (g < l) {
return 'Magenta'
}
if (b < l) {
return 'Yellow'
}
}
if (max == g) {
local 'l' ((g * 2) / 3)
if (and (r < l) (b < l)) {
return 'Green'
}
if (r < l) {
return 'Cyan'
}
if (b < l) {
return 'Yellow'
}
}
if (max == b) {
local 'l' ((b * 2) / 3)
if (and (r < l) (g < l)) {
return 'Blue'
}
if (r < l) {
return 'Cyan'
}
if (g < l) {
return 'Magenta'
}
}
return ''
}
module 'Distance (HC-SR04)' Input
author MicroBlocks
version 1 5
tags sensor 'hc-sr04' distance ultrasound
description 'Support for the HC-SR04 ultrasound distance sensor.
Originally written by Joan Guillén & Josep Ferràndiz.
Rewritten to use the new pulse capture mechanism.'
variables _sr04_last _sr04_misses
spec 'r' 'distance (cm)' 'distance (cm) trigger _ echo _' 'num num' 2 4
spec 'r' 'sr04_distanceOnePin' 'distance (cm) pin _' 'num' 0
spec 'r' '_sr04_getEchoData' '_getEchoData _ echo _' 'auto auto' 0 1
to '_sr04_getEchoData' trig echo {
comment 'Output a 50 usec pulse on trigger pin to
start distance measurement.'
digitalWriteOp trig false
waitMicros 2
digitalWriteOp trig true
waitMicros 50
digitalWriteOp trig false
comment 'Capture the distance pulse. Width of
pulse is proportional to the distance.'
'[sensors:captureStart]' echo
local 'start' (millisOp)
repeatUntil (('[sensors:captureCount]') >= 2) {
if ((millisSince start) > 24) {exitLoop}
waitMillis 1
}
return ('[sensors:captureEnd]')
}
to 'distance (cm)' trig echo {
comment 'Take a distance measurement. Pulses will be two element
list if successful. If no echo detected it will have only one
element. In rare error cases the second item will be negative.'
local 'pulses' ('_sr04_getEchoData' trig echo)
if (and ((size pulses) >= 2) ((at 2 pulses) > 0)) {
_sr04_misses = 0
comment 'The divisor was determined empirically. It is
less than the expected 2 * 343 meter/sec.'
_sr04_last = ((10 * (at 2 pulses)) / 583)
return _sr04_last
} else {
comment 'No echo, probably because target is out of range.
To avoid short-term glitches, return the last distance
unless the are N misses in a row, then return 400.'
_sr04_misses += 1
return (ifExpression (_sr04_misses < 10) _sr04_last 400)
}
}
to sr04_distanceOnePin pin {
return ('distance (cm)' pin pin)
}
module 'LED Display' Output
author MicroBlocks
version 1 14
choices led_imageMenu heart 'small heart' yes no happy sad confused angry asleep surprised silly fabulous meh 't-shirt' 'roller skate' duck house tortoise butterfly 'stick figure' ghost sword giraffe skull umbrella snake rabbit cow 'quarter note' 'eight note' pitchfork target triangle 'left triangle' 'chess board' diamond 'small diamond' square 'small square' scissors
description 'Display primitives for the 5x5 LED display on the BBC micro:bit, Calliope mini and M5Atom Matrix. Boards with TFT displays (such as the Citilab ED1 or the M5Stack family) support these primitives with a simulated "fat pixel" display.
'
variables _stop_scrolling_text
spec ' ' '[display:mbDisplay]' 'display _' 'microbitDisplay' 15237440
spec ' ' 'led_displayImage' 'display image _ : x _ y _' 'menu.led_imageMenu num num' 'happy' 1 1
spec ' ' '[display:mbDisplayOff]' 'clear display'
space
spec ' ' '[display:mbPlot]' 'plot x _ y _' 'num num' 3 3
spec ' ' '[display:mbUnplot]' 'unplot x _ y _' 'num num' 3 3
space
spec ' ' 'displayCharacter' 'display character _' 'str' 'A'
spec ' ' 'scroll_text' 'scroll text _ : pausing _ ms' 'str num' 'HELLO ROSA!' 100
spec ' ' 'stopScrollingText' 'stop scrolling'
advanced
spec ' ' 'set display color' 'set display color _' 'color'
spec 'r' 'led_image' 'LED image #BR# _' 'microbitDisplay' 15237440
space
spec 'r' '_led_namedImage' '_led_namedImage _' 'menu.led_imageMenu' 'happy'
spec 'r' '_led_imageData' '_led_imageData'
to '_led_imageData' {
return 'heart:4685802,small heart:145728,yes:2269696,no:18157905,happy:15237440,sad:18284864,confused:22348096,angry:23036241,asleep:459616,surprised:4526090,silly:25984017,fabulous:15008639,meh:2236443,t-shirt:15154043,roller skate:11534104,duck:489702,house:10976708,tortoise:359872,butterfly:29332475,stick figure:18158564,ghost:23068334,sword:4657284,giraffe:10946627,skull:15171246,umbrella:6460398,snake:469859,rabbit:16104613,cow:4685361,quarter note:7573636,eight note:7590276,pitchfork:4357813,target:4681156,triangle:1026176,left triangle:32805985,chess board:11184810,diamond:4539716,small diamond:141440,square:33080895,small square:469440,scissors:20287859,'
}
to '_led_namedImage' name {
local 'data' ('_led_imageData')
local 'i' ('[data:find]' name data)
if (i == -1) {
comment 'Name not found'
return 0
}
local 'start' (('[data:find]' ':' data i) + 1)
local 'end' (('[data:find]' ',' data i) - 1)
return ('[data:convertType]' ('[data:copyFromTo]' data start end) 'number')
}
to displayCharacter s {
s = ('[data:join]' '' s)
if ((size s) == 0) {
'[display:mbDisplayOff]'
return 0
}
'[display:mbDrawShape]' ('[display:mbShapeForLetter]' (at 1 s)) 1 1
}
to led_displayImage imageName optionalX optionalY {
local 'image' imageName
if (isType image 'string') {
image = ('_led_namedImage' imageName)
}
'[display:mbDrawShape]' image (argOrDefault 2 1) (argOrDefault 3 1)
}
to led_image twentyFiveBitInt {
comment 'An LED image is a 25-bit integer'
return twentyFiveBitInt
}
to scroll_text text optionalDelay {
text = ('[data:join]' '' text)
local 'delay' 100
if ((pushArgCount) > 1) {
delay = optionalDelay
}
_stop_scrolling_text = (booleanConstant false)
if ('Pico:ed' == (boardType)) {
for position (((size text) * 6) + 18) {
if _stop_scrolling_text {return 0}
'[display:mbDisplayOff]'
'[tft:text]' text (17 - position) 0 (colorSwatch 125 125 125 255) 1 true
waitMillis (delay / 2)
}
} ('kidsIOT' == (boardType)) {
for position (((size text) * 6) + 21) {
if _stop_scrolling_text {return 0}
'[tft:deferUpdates]'
'[tft:clear]'
'[tft:text]' text (128 - (6 * position)) 6 (colorSwatch 255 255 255 255) 6 false
'[tft:resumeUpdates]'
waitMillis (delay / 8)
}
} else {
for position (((size text) * 6) + 6) {
if _stop_scrolling_text {return 0}
for i (size text) {
'[display:mbDrawShape]' ('[display:mbShapeForLetter]' ('[data:unicodeAt]' i text)) (((i * 6) + 2) - position) 1
}
waitMillis delay
}
}
}
to 'set display color' color {
'[display:mbSetColor]' color
}
to stopScrollingText {
_stop_scrolling_text = (booleanConstant true)
waitMillis 10
'[display:mbDisplayOff]'
}
module 'OLED Graphics' Output
author 'Turgut Guneysu and Miroslav Klimos'
version 1 24
choices OnOffMenu On Off
choices VideoMenu Inverse Normal
choices DispTypeMenu 'OLED_0.42in' 'OLED_0.96in' 'OLED_1.3in' 'OLED_1.54in' 'OLED_2.42in'
description 'Supports 0.42in, 0.96in and 1.54in Displays with SSD1306 and 2.42in OLED with SSD1309 chipsets, also 1.3in with SHT1106 chipset. Comm mode is I2C or SPI.
*** As of version 1.22 character table has been changed to MicroBlocks 5x8 internal characters. ***
Changes:
- always display buffer
- defer display updates block
- remove reveal
- switch to x (0-127), y (0-63)
- Pruned commands and vars
- textX and textY
- Text at any x and y
- handles newLines
- removed dependencies
- unified data format for chars, sprites, and images
- image draw at any x,y
- filled rectangle
- image draw bug fix
- stack overflow fix
- improve conversion ops, i2c io, rect fill, img processing, and buffer displays
- reduce i2c buffer to 64 bytes
- correct internal draws, clean-up vars, restore _clearDisplay
- added support for ESP32C3miniOLED 0.42in 72x40 display.
- Corrected page display / clear and PAGE mode operations
- Removed remnants of the old character Table logic.
- Corrected x and y coordinate calculations for proper character wrapping.
- Added IREF Voltage adjustment for brighter display.
Miroslav Klimos
- added Zoom option for text
- added support for 1.3in OLED (1106) - thanks to KwyjiboYue
'
variables OLEDReady OLEDi2cAddr _GDBuffer _comMode _dcPin _delayGDUpd _displayType _eol _resetPin _textX _textY _dataPrefix _byteCount _imgData _imgWidth _imgHeight _ColumnOffset
spec ' ' 'OLEDInit_I2C_auto' 'initialize i2c(auto) reset pin# _ flip _' 'auto bool' '-' false
spec ' ' 'OLEDInit_I2C' 'initialize i2c _ address(hex) _ reset pin# _ flip _' 'str.DispTypeMenu auto auto bool' 'OLED_0.96in' '3C' '-' false
spec ' ' 'OLEDInit_SPI' 'initialize spi _ d/c pin# _ reset pin# _ flip _' 'str.DispTypeMenu auto auto bool' 'OLED_2.42in' 16 8 false
spec ' ' 'OLEDwrite' 'write _ at x _ y _ inverse _ : scale _' 'auto num num bool num' 'Hello!' 0 0 false 1
spec ' ' 'OLEDshowGDBuffer' 'show display buffer'
spec ' ' 'OLEDclear' 'clear'
spec ' ' 'OLEDcontrast' 'set contrast (1-4) _' 'auto' 2
spec ' ' 'OLEDdrawCircle' 'draw circle at x _ y _ radius _ erase _ : filled _' 'auto auto auto bool bool' 64 32 '10' false false
spec ' ' 'OLEDdrawImage' 'draw image _ at x _ y _' 'auto auto auto' 0 0 0
spec ' ' 'OLEDdrawLine' 'draw line from x _ y _ to x _ y _ erase _' 'auto auto auto auto bool any' 0 0 127 63 false
spec ' ' 'OLEDdrawRect' 'draw rectangle x _ y _ w _ h _ erase _ rounding(3-15) _ : filled _' 'auto auto auto auto bool auto bool' 0 0 127 63 false 0 false
spec ' ' 'OLEDfillRect' 'fill rectangle x _ y _ w _ h _ erase _' 'auto auto auto auto bool' 20 20 30 20 false
spec ' ' '_OLEDflip' '_flip display top _' 'bool' false
spec 'r' 'OLEDmakeImage' 'make image _' 'microbitDisplay' 33084991
spec ' ' 'OLEDpixel' 'set pixel x _ y _ erase _' 'auto auto bool' 0 0 false
spec ' ' 'OLEDsetVideo' 'set video _' 'str.VideoMenu' 'Inverse'
spec 'r' 'OLEDwru' 'cursor location'
spec ' ' 'defer display updates' 'defer display updates'
spec ' ' '_GDDRAMoff' '_GDDRAMoff'
spec ' ' '_GDDRAMon' '_GDDRAMon'
spec ' ' '_OLEDcursorReset' '_cursor reset'
spec ' ' '_OLEDsetDisplay' '_set display _' 'str.OnOffMenu' 'On'
spec ' ' '_OLEDreset' '_set reset Pin# _' 'auto' '0'
spec ' ' '_SPIWriteCmd' '_SPIWriteCmd'
spec ' ' '_SPIWriteData' '_SPIWriteData'
spec ' ' '_clearDisplay' '_clearDisplay'
spec ' ' '_corner' '_corner _ _ _ _ _ _' 'auto auto auto auto bool bool' 'TL' 32 1 0 false false
spec 'r' '_dec2hex' '_dec2hex _' 'auto' 0
spec ' ' '_initCheck' '_initCheck'
spec ' ' '_initDisplayHW' '_initDisplayHW'
spec ' ' '_initLibrary' '_initLibrary'
spec ' ' '_process image data' '_process image data _' 'auto' ' '
spec ' ' '_sendCmd' '_sendCmd _' 'auto' ''
spec ' ' '_verifyXY' '_verifyXY _ _' 'auto auto' 0 0
spec ' ' '_OLEDwriteChar' '_write char _ at x _ y _ inverse _ scale _' 'auto auto auto bool num' 'A' 1 1 false 1
to OLEDInit_I2C dispType i2cAddr resetPin flip {
comment 'Sets display type and interface and initializes HW settings.
Do NOT set a ResetPin# unless one exists on the display hardware.
NOTE:
Displays supported:
- OLED 0.42in (SD1306 chip - displayType=5) and
- OLED 0.96in (SD1306 chip - displayType=3) and
- OLED 1.3in (SH1106 chip- displayType=8) and
- OLED 1.54in (SD1309 chip - displayType=6) and
- OLED 2.42" (SD1309 chip - displayType=6 ??? )
OLED 0.42in display is 72x40 pixels or 12x5 characters in size.
All other displays are 128x64 pixels or 16x8 characters in size.
Displays come in dual mode version (i2c and spi) and pure i2c.
Pure i2c models do not have a Reset pin.
flip setting controls display hardware write direction:
- false: top to bottom
- true: bottom to top'
OLEDInit_I2C_auto resetPin flip
}
to OLEDInit_I2C_auto resetPin flip {
comment 'Sets display type and interface and initializes HW settings.
I2C addresss is checked for 0x3C and 0x3D automatically.
Display type is read from status register'
_resetPin = resetPin
_comMode = 'i2c'
_ColumnOffset = '0x00'
OLEDi2cAddr = 60
if (not ('[sensors:i2cExists]' OLEDi2cAddr)) {
OLEDi2cAddr += 1
if (not ('[sensors:i2cExists]' OLEDi2cAddr)) {
sayIt 'I2C OLED Display not found'
waitMillis 2000
return 0
}
}
if (_displayType != 0) {
return
}
local '_statusreg' 0
_statusreg = (newList 1 0)
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:newByteArray]' 1 0)
'[sensors:i2cRead]' OLEDi2cAddr _statusreg
_displayType = ((at 1 _statusreg) & 15)
sayIt 'Display found at address: ' OLEDi2cAddr '- type:' _displayType
if (_displayType == 8) {
_ColumnOffset = ('[data:toString]' '2')
}
'_initDisplayHW'
if flip {
'_OLEDflip' true
}
'_initLibrary'
OLEDclear
OLEDcontrast 4
}
to OLEDInit_SPI dispType dcPin resetPin flip {
comment 'Sets display type and interface and initializes HW settings.
SPI four wire in Mode-0 is supported. Max speed=10000000.
Do NOT set a ResetPin# unless one exists on the display hardware.
NOTE:
Displays supported:
- OLED 0.96in (SD1306 chip) and
- OLED 2.42" (SD1309 chip)
Both displays are 128x64 pixels or 16x8 characters in size.
Displays come in dual mode version (i2c and spi) and pure i2c.
Pure i2c models do not have a Reset pin.
flip setting controls display hardware write direction:
- false: top to bottom
- true: bottom to top'
_comMode = 'spi'
_dcPin = dcPin
if (_displayType != 0) {
return
}
_resetPin = resetPin
if (dispType == 'OLED_0.96in') {
_displayType = 3
} (dispType == 'OLED_1.3in') {
_displayType = 8
} else {
_displayType = 6
}
'[sensors:spiSetup]' 10000000
'_initDisplayHW'
if flip {
'_OLEDflip' true
}
'_initLibrary'
OLEDclear
OLEDcontrast 4
}
to OLEDclear {
comment 'Set bounds to FullScreen and CLEARs display
and GDBuffer.'
_GDBuffer = ('[data:newByteArray]' (ifExpression (5 == _displayType) 360 1024))
'_initCheck'
'_OLEDcursorReset'
OLEDshowGDBuffer
}
to OLEDcontrast contrast {
comment 'Sets the brightness control of the display to one of four values.
1 is the least bright, 4 is the brightest setting.'
'_initCheck'
local 'cLevels' ('[data:makeList]' 0 '1F' '2F' 'FF')
if (and (contrast >= 1) (contrast <= 4)) {
local 'i2cCmd' ('[data:join]' '81,' (at contrast cLevels))
'_sendCmd' i2cCmd
} else {
sayIt 'Error in CONTRAST Level'
}
}
to OLEDdrawCircle cx cy r erase optionalFilled {
comment 'Bresenham Circle:
Draws circles, even partially bigger than the display.
x: 0-127
y: 0-63
void plotCircle(int xm, int ym, int r)
{
int x = -r, y = 0, err = 2-2*r; /* II. Quadrant */
do {
setPixel(xm-x, ym+y); /* I. Quadrant */
setPixel(xm-y, ym-x); /* II. Quadrant */
setPixel(xm+x, ym-y); /* III. Quadrant */
setPixel(xm+y, ym+x); /* IV. Quadrant */
r = err;
if (r <= y) err += ++y*2+1; /* e_xy+e_y < 0 */
if (r > x || err > y) err += ++x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */
} while (x < 0);
}'
'_initCheck'
local 'oldDelayGDUpd' _delayGDUpd
_delayGDUpd = (booleanConstant true)
local 'filled' (argOrDefault 5 (booleanConstant false))
local 'x' (-1 * r)
local 'y' 0
local 'err' (2 - (2 * r))
repeatUntil (x >= 0) {
if filled {
OLEDdrawLine (cx - x) (cy + y) (cx + x) (cy + y) erase
OLEDdrawLine (cx + y) (cy + x) (cx - y) (cy + x) erase
} else {
OLEDpixel (cx - x) (cy + y) erase
OLEDpixel (cx - y) (cy - x) erase
OLEDpixel (cx + x) (cy - y) erase
OLEDpixel (cx + y) (cy + x) erase
}
r = err
if (r <= y) {
y += 1
err = (err + ((y * 2) + 1))
}
if (or (r > x) (err > y)) {
x += 1
err = (err + ((x * 2) + 1))
}
}
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
}
to OLEDdrawImage image x y {
comment '_imgHeight has to be mod8 or 1-8'
if (0 == image) {
return 0
}
local 'oldDelayGDUpd' _delayGDUpd
_delayGDUpd = (booleanConstant true)
for row# (maximum 1 ((minimum _imgHeight ((ifExpression (5 == _displayType) 40 64) - y)) / 8)) {
local 'GDidx' ((((y / 8) * (ifExpression (5 == _displayType) 72 128)) + x) + 1)
local 'imgDispl' ((row# - 1) * _imgWidth)
for byte# (minimum _imgWidth ((ifExpression (5 == _displayType) 72 128) - x)) {
comment 'If y is on page boundary, just copy'
if (0 == (y % 8)) {
atPut GDidx _GDBuffer (at (imgDispl + byte#) image)
GDidx += 1
if (GDidx > (ifExpression (5 == _displayType) 360 1024)) {
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
return 0
}
} else {
comment 'Else, copy GDLowBits + shiftedByte + GDHiBits to GDBuffer and GDBuffer +128'
local 'shiftedByte' ('_dec2hex' ((at (imgDispl + byte#) image) << (y % 8)))
local 'temp' 0
local 'tempHI' ('[data:copyFromTo]' shiftedByte 1 2)
local 'tempLO' ('[data:copyFromTo]' shiftedByte 3 4)
local 'GDLowBits' ((1 << (y % 8)) - 1)
local 'GDHiBits' (255 - GDLowBits)
tempLO = ((hexToInt tempLO) | ((at GDidx _GDBuffer) & GDLowBits))
atPut GDidx _GDBuffer tempLO
if ((GDidx + (ifExpression (5 == _displayType) 72 128)) <= (ifExpression (5 == _displayType) 360 1024)) {
tempHI = ((hexToInt tempHI) | ((at (GDidx + (ifExpression (5 == _displayType) 72 128)) _GDBuffer) & GDHiBits))
atPut (GDidx + (ifExpression (5 == _displayType) 72 128)) _GDBuffer tempHI
}
GDidx += 1
if (GDidx > (ifExpression (5 == _displayType) 360 1024)) {
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
return 0
}
}
waitMillis 0
}
y += 8
}
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
}
to OLEDdrawLine x0 y0 x1 y1 erase {
comment 'Draws a line from x0,y0 to x1,y1 using the Bresenham Algorithm
x: 0-127
y: 0-63
plotLine(int x0, int y0, int x1, int y1)
dx = abs(x1-x0);
sx = x0<x1 ? 1 : -1;
dy = -abs(y1-y0);
sy = y0<y1 ? 1 : -1;
err = dx+dy; /* error value e_xy */
while (true) /* loop */
plot(x0, y0);
if (x0 == x1 && y0 == y1) break;
e2 = 2*err;
if (e2 >= dy) /* e_xy+e_x > 0 */
err += dy;
x0 += sx;
end if
if (e2 <= dx) /* e_xy+e_y < 0 */
err += dx;
y0 += sy;
end if
end while'
'_initCheck'
local 'oldDelayGDUpd' _delayGDUpd
_delayGDUpd = (booleanConstant true)
results = ('[data:makeList]')
local 'dx' (absoluteValue (x1 - x0))
local 'dy' (-1 * (absoluteValue (y1 - y0)))
local 'err' (dx + dy)
local 'e2' 0
local 'done' (booleanConstant false)
if (x0 < x1) {
local 'sx' 1
} else {
local 'sx' -1
}
if (y0 < y1) {
local 'sy' 1
} else {
local 'sy' -1
}
repeatUntil done {
OLEDpixel x0 y0 erase
if (and (x0 == x1) (y0 == y1)) {
done = (booleanConstant true)
}
e2 = (2 * err)
if (e2 >= dy) {
err += dy
x0 += sx
}
if (e2 <= dx) {
err += dx
y0 += sy
}
}
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
}
to OLEDdrawRect TLx TLy width height erase cornerRad optionalFilled {
comment 'Draw Rectangle with optional rounded corners with radius R.
Does not check for reversed rectangle coordinates for round corners.'
'_initCheck'
local 'oldDelayGDUpd' _delayGDUpd
_delayGDUpd = (booleanConstant true)
local 'BRx' (TLx + width)
local 'BRy' (TLy + height)
local 'filled' (argOrDefault 7 (booleanConstant false))
if (cornerRad < 3) {
cornerRad = 0
} else {
'_corner' 'TL' TLx TLy cornerRad erase filled
'_corner' 'TR' BRx TLy cornerRad erase filled
'_corner' 'BR' BRx BRy cornerRad erase filled
'_corner' 'BL' TLx BRy cornerRad erase filled
}
comment 'TOP'
for f ('[data:range]' TLy (ifExpression filled (TLy + cornerRad) TLy)) {
OLEDdrawLine (TLx + cornerRad) f (BRx - cornerRad) f erase
}
comment 'MIDDLE'
if filled {
for f ('[data:range]' ((TLy + 1) + cornerRad) ((BRy - 1) - cornerRad)) {
OLEDdrawLine TLx f BRx f erase
}
} else {
OLEDdrawLine TLx ((BRy - 1) - cornerRad) TLx ((TLy + 1) + cornerRad) erase
OLEDdrawLine BRx ((TLy + 1) + cornerRad) BRx ((BRy - 1) - cornerRad) erase
}
comment 'BOTTOM'
for f ('[data:range]' (ifExpression filled (BRy - cornerRad) BRy) BRy) {
OLEDdrawLine (TLx + cornerRad) f (BRx - cornerRad) f erase
}
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
}
to OLEDfillRect x y w h erase {
local 'oldDelayGDUpd' _delayGDUpd
_delayGDUpd = (booleanConstant true)
for row ('[data:range]' 0 (h - 1)) {
for col ('[data:range]' 0 (w - 1)) {
OLEDpixel (x + col) (y + row) erase
}
}
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
}
to OLEDmakeImage spr# {
comment 'Receives a spr# representing 5x5 image matrix.
Converts it to a HOR array of 5 VERT bitmap numbers.
This can be displayed with the draw image block.
sprNum max is 33554431'
'_initCheck'
local 'spriteList' ('[data:newByteArray]' 5)
local 'val' 0
for col 5 {
for row ('[data:asByteArray]' ('[data:makeList]' 0 5 10 15 20)) {
local 'bit' (col + row)
local 'vertBit#' (bit / 5)
if ((spr# & (1 << (bit - 1))) != 0) {
if (col != 5) {
val += (1 << vertBit#)
} else {
val += (1 << (vertBit# - 1))
}
}
}
atPut col spriteList val
val = 0
}
_imgWidth = 5
_imgHeight = 5
return spriteList
}
to OLEDpixel x y erase {
comment 'Places a pixel at x,y in the virtual GDBuffer
Use OLEDshowGDBuffer to display it
8192 Pixels over 1024 Bytes
x: 0-127
y: 0-63
page#: 0-7
pagePixel#: 0-7
GDIndex: 1-1024
RangeCheck:
verify x and y are in range of display limits
if X <= num <= Y'
'_initCheck'
local 'pagePixel#' (y % 8)
local 'GDIndex' ((x + ((y / 8) * (ifExpression (5 == _displayType) 72 128))) + 1)
if (GDIndex <= (ifExpression (5 == _displayType) 360 1024)) {
local 'byteBMP' (at GDIndex _GDBuffer)
byteBMP = (ifExpression (not erase) (byteBMP | (1 << pagePixel#)) (byteBMP & ('~' (1 << pagePixel#))))
atPut GDIndex _GDBuffer byteBMP
}
}
to OLEDsetVideo videoMode {
comment 'Switches the entire display:
Inverse: inverse video mode (bit 0 = on)
Normal: normal video mode (bit 1 = on).
Any image on the display will be preserved when mode changes.'
'_initCheck'
if (videoMode == 'Inverse') {
local 'i2cCmd' 'A7'
} else {
local 'i2cCmd' 'A6'
}
'_sendCmd' i2cCmd
}
to OLEDshowGDBuffer {
comment 'Copies contents of virtual _GDBuffer to display
i2c:
in 64 byte chunks for speed.
page selection is used to work on OLED with SH1106 cipset
spi:
fastest is dump buffer
_GDBuffer is in decimal
ESP32C3OLED with 72x40 display:
HORIZONTAL Mode: 20,00
COL Start, End: 21,28,99
PAGE Start, End: 22,0,4'
'_initCheck'
comment 'Set display RAM display start line register from 0-63.
0x40: 0 0x7F: 63 '
'_sendCmd' '40'
comment 'Set HORIZONTAL Mode (default)'
'_sendCmd' ('[data:toString]' '20,0')
if (5 == _displayType) {
comment 'Set COL and PAGE start/end values'
'_sendCmd' ('[data:toString]' '21,1c,63')
'_sendCmd' ('[data:toString]' '22,0,4')
} (8 == _displayType) {
comment 'Set PAGE Mode'
'_sendCmd' ('[data:toString]' '20,10')
}
if (_comMode == 'i2c') {
local 'idx' 1
comment 'This LOOP is for:
128 x 64 displays with 1024 byte buffer @ 64 x 2 x 8
OR
72 x 40 displays with 360 byte buffer @ 36 x 2 x 5'
for j (ifExpression (5 == _displayType) 5 8) {
if (8 == _displayType) {
comment 'In PAGE addressing mode, the following steps are required to define the starting RAM access pointer location:
• Set the page start address of the target display location by command B0h to B7h.
• Set the lower start column address of pointer by command 00h~0Fh.
• Set the upper start column address of pointer by command 10h~1Fh. '
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:makeList]' (hexToInt '80') ((hexToInt 'B0') + (j - 1)))
comment 'Sets COL displacement values for LOW (0-F) and HIGH (10-1F) nibbles of the COL Number Byte.'
if ((hexToInt _ColumnOffset) < (hexToInt '10')) {
'_sendCmd' _ColumnOffset
'_sendCmd' ('[data:toString]' '10')
}
}
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:copyFromTo]' _GDBuffer idx (idx + (ifExpression (5 == _displayType) 35 63))))
idx += (ifExpression (5 == _displayType) 36 64)
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:copyFromTo]' _GDBuffer idx (idx + (ifExpression (5 == _displayType) 35 63))))
idx += (ifExpression (5 == _displayType) 36 64)
}
} else {
'_SPIWriteData'
'[sensors:spiExchange]' ('[data:copyFromTo]' _GDBuffer 1)
}
_delayGDUpd = (booleanConstant false)
}
to OLEDwrite string x y invFlag optionalScale {
comment 'Writes strings to display at any x,y; processing CR LF and wrapping at col x.
_textX and _textY are next write locations.'
'_initCheck'
local 'oldDelayGDUpd' _delayGDUpd
_delayGDUpd = true
'_verifyXY' x 0
local 'origX' x
local 'scale' (argOrDefault 5 1)
if (not (isType string 'string')) {
string = ('[data:join]' '' string)
}
for char string {
local 'unicode' ('[data:unicodeAt]' 1 char)
if (13 == unicode) {
noop
} (10 == unicode) {
x = origX
y += (8 * scale)
if (y >= (ifExpression (5 == _displayType) ((40 / (8 * scale)) * (8 * scale)) ((64 / (8 * scale)) * (8 * scale)))) {
y = 0
}
} (and (unicode > 31) (unicode < 128)) {
'_OLEDwriteChar' char x y invFlag scale
x += (6 * scale)
if (x >= (ifExpression (5 == _displayType) ((72 / (6 * scale)) * (6 * scale)) ((128 / (6 * scale)) * (6 * scale)))) {
x = origX
y += (8 * scale)
if (y >= (ifExpression (5 == _displayType) ((40 / (8 * scale)) * (8 * scale)) ((64 / (8 * scale)) * (8 * scale)))) {
y = 0
}
}
} else {
comment 'bad char - STOP'
sayIt 'Invalid CHAR value:' char 'uniCode:' unicode
stopTask
}
}
_textX = x
_textY = y
_delayGDUpd = oldDelayGDUpd
if (not _delayGDUpd) {
OLEDshowGDBuffer
}
}
to OLEDwru {
comment 'Next Row and Column to print
_textY, _textX'
return ('[data:asByteArray]' ('[data:makeList]' _textY _textX))
}
to '_GDDRAMoff' {
comment 'Displays a full empty screen of reverse video.
It disengages the hardware GDBuffer. '
local 'i2cCmd' 'A5'
'_sendCmd' i2cCmd
}
to '_GDDRAMon' {
comment 'It disables the GDDRAMoff mode and engages the hardware GDBuffer for display content.'
local 'i2cCmd' 'A4'
'_sendCmd' i2cCmd
}
to '_OLEDcursorReset' {
comment 'Sets display bounds to full range and resets cursor
to the origin top-left (0,0)
Rows: 0-7
Cols: 0-127
Cursor position is affected by any display operation.'
'_initCheck'
if (5 == _displayType) {
comment 'Set COL and PAGE start/end values'
local 'cmdString' '21,28,99,22,0,4'
} else {
local 'cmdString' '22,00,07,21,00,7F'
}
'_sendCmd' cmdString
_textX = 0
_textY = 0
}
to '_OLEDflip' flip {
comment 'Flips the display initialization horizontally or vertically.
Horizontal or vertical is based on the pin connector location.'
if flip {
'_sendCmd' 'A0,C0'
} else {
'_sendCmd' 'A1,C8'
}
}
to '_OLEDreset' pin {
comment 'Does a power off and on on the display,
thus forcing a hardware initialization.'
digitalWriteOp pin false
waitMillis 1
digitalWriteOp pin true
waitMillis 1
}
to '_OLEDsetDisplay' onoff {
comment 'Puts the display into
Off:SLEEP On:WAKE mode.
Images on display are preserved.'
'_initCheck'
if (onoff == 'On') {
local 'i2cCmd' 'AF'
} else {
local 'i2cCmd' 'AE'
}
'_sendCmd' i2cCmd
}
to '_OLEDwriteChar' char x y inverse scale {
local 'shape' ('[misc:shapeforChar]' char)
if (shape == 0) {
return 0
}
comment 'This LOOP writes a SCALED blank column before the 5 col character.'
for row ('[data:range]' 0 ((9 * scale) - 1)) {
for col ('[data:range]' 0 ((7 * scale) - 1)) {
OLEDpixel (x + col) (y + row) (not inverse)
}
}
x += scale
y += scale
local 'y0' y
for c 5 {
local 'mask' 1
y = y0
repeat 8 {
repeat scale {
repeat scale {
if (((at c shape) & mask) != 0) {OLEDpixel x y inverse}
x += 1
}
x += (0 - scale)
y += 1
}
mask = (mask << 1)
}
x += scale
}
}
to '_SPIWriteCmd' {
comment 'In SPI mode, we send either a write command
or write data control code. Then follow it with
the appropriate command/data bundle.'
digitalWriteOp _dcPin false
}
to '_SPIWriteData' {
comment 'In SPI mode, we send either a write command
or write data control code. Then follow it with
the appropriate command/data bundle.'
digitalWriteOp _dcPin true
}
to '_clearDisplay' {
comment 'Clear Screen without initializing _GDBuffer'
'_initCheck'
'_OLEDcursorReset'
local 'clearBuff' ('[data:newByteArray]' (ifExpression (5 == _displayType) 36 64) 0)
'_sendCmd' '40'
comment 'Set HORIZONTAL Mode (default)'
'_sendCmd' ('[data:toString]' '20,0')
if (5 == _displayType) {
comment 'Set COL and PAGE start/end values'
'_sendCmd' ('[data:toString]' '21,1c,63')
'_sendCmd' ('[data:toString]' '22,0,4')
} (8 == _displayType) {
comment 'Set PAGE Mode'
'_sendCmd' ('[data:toString]' '20,10')
}
if (_comMode == 'i2c') {
comment 'This LOOP is for:
128 x 64 displays with 1024 byte buffer @ 64 x 2 x 8
OR
72 x 40 displays with 360 byte buffer @ 36 x 2 x 5'
for j (ifExpression (5 == _displayType) 5 8) {
if (8 == _displayType) {
comment 'In PAGE addressing mode, the following steps are required to define the starting RAM access pointer location:
• Set the page start address of the target display location by command B0h to B7h.
• Set the lower start column address of pointer by command 00h~0Fh.
• Set the upper start column address of pointer by command 10h~1Fh. '
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:makeList]' (hexToInt '80') ((hexToInt 'B0') + (j - 1)))
comment 'Sets COL displacement values for LOW (0-F) and HIGH (10-1F) nibbles of the COL Number Byte.'
if ((hexToInt _ColumnOffset) < (hexToInt '10')) {
'_sendCmd' _ColumnOffset
'_sendCmd' ('[data:toString]' '10')
}
}
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:copyFromTo]' clearBuff 1))
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:copyFromTo]' clearBuff 1))
}
} else {
'_SPIWriteData'
repeat 8 {
'[sensors:spiExchange]' ('[data:copyFromTo]' clearBuff 1)
}
}
_delayGDUpd = (booleanConstant false)
}
to '_corner' loc cx cy r erase filled {
comment 'Calculates and displays the rounded corners for the rectangles.
loc is one of TL, TR, BL, BR ... topLeft, topright, bottomleft, bottomright
cx,cy are the corner coordinates for the rounded corner.
r is the radius in pixels of the arc to be calculated.'
local 'x' (-1 * r)
local 'y' 0
local 'err' (2 - (2 * r))
if (loc == 'TL') {
cx += r
cy += r
} (loc == 'TR') {
cx += (0 - r)
cy += r
} (loc == 'BL') {
cx += r
cy += (0 - r)
} (loc == 'BR') {
cx += (0 - r)
cy += (0 - r)
}
repeatUntil (x > 0) {
if filled {
if (loc == 'TL') {
OLEDdrawLine (cx + x) (cy - y) cx (cy - y) erase
} (loc == 'TR') {
OLEDdrawLine cx (cy + x) (cx + y) (cy + x) erase
} (loc == 'BL') {
OLEDdrawLine (cx - y) (cy - x) cx (cy - x) erase
} (loc == 'BR') {
OLEDdrawLine cx (cy + y) (cx - x) (cy + y) erase
}
} else {
if (loc == 'TL') {
OLEDpixel (cx + x) (cy - y) erase
} (loc == 'TR') {
OLEDpixel (cx + y) (cy + x) erase
} (loc == 'BL') {
OLEDpixel (cx - y) (cy - x) erase
} (loc == 'BR') {
OLEDpixel (cx - x) (cy + y) erase
}
}
r = err
if (r <= y) {
y += 1
err = (err + ((y * 2) + 1))
}
if (or (r > x) (err > y)) {
x += 1
err = (err + ((x * 2) + 1))
}
}
}
to '_dec2hex' num {
comment 'Fast version w/o inversion. (~115uSecs)'
local '_hexTbl' '0123456789ABCDEF'
local 'hexNum' ''
repeatUntil (num < 0) {
local 'temp' ('[data:join]' (at ((num % 16) + 1) _hexTbl) hexNum)
hexNum = temp
num = (ifExpression ((num / 16) != 0) (num / 16) -1)
}
comment 'If not half-byte length, pad it.'
hexNum = ('[data:join]' ('[data:copyFromTo]' '000' 1 (4 - (size hexNum))) hexNum)
return hexNum
}
to '_initCheck' {
comment 'Verifies Library initialization status.'
if (not OLEDReady) {
sayIt 'Display needs to be initialized before using the library blocks.'
stopTask
}
}
to '_initDisplayHW' {
comment '*** DO NOT CHANGE THESE WITHOUT UNDERSTANDING THEIR MEANINGS ***
*** IT CAN MAKE THE DISPLAY NOT OPERATE CORRECTLY ***
Initializes display HW timings
OLED INITIALIZATION STRINGS:
1306: pins are on top
1309: pins are on the right
A8 3F - Multiplex Ratio 0F-3F (16mux to 64mux)
D3 00 - Display Offset (vertical) 00-63
40 - Display Start Line 40-7F (40:0)
A0 - Set Segment Remap A0: Remap 0:0, A1: 127:0 [A0]
C0 - Scan Direction C0:0-127, C8:127-0 [C0]
DA 12 - COM pin hw config 02:double-high 12:normal bits
81 7F - Set contrast 00-FF (00:dimmest, FF:brightest)
A4 - A4:display shows GDRAM, A5:display all ON pixels
A6 - A6:Normal video, A7:Inverse video
D5 F0 - Set display clock HB:OSC freq / LB:divide ratio (00-FF)
D9 22 - Set pre-charge period HB:Phase2 / LB:Phase1 (1-15 DCLK)
DB 20 - Set Vcomh deselect level 20:1306(~0.77xVcc), 34:1309(~0.78xVcc)
8D 14 - Charge Pump Setting 10:disable CP, 14:enable CP
20 00 - Set HORIZONTAL mode
AD 30 - Internal IREF mode. Sets the reference current to 30\mu, resulting in 240\mu for maximum brightness.
AF - Display ON/OFF AE:off (sleep mode), AF:on'
if (_resetPin != '-') {
'_OLEDreset' _resetPin
}
if (_displayType == 5) {
comment '72x40 OLED MUX value is 39 : 0x27'
local 'initCmd' 'A8,27,D3,00,40,A1,C8,DA,12,81,7F,A4,A6,D5,70,D9,11,DB,34,8D,14,20,00,AD,30,AF'
} else {
local 'initCmd' 'A8,3F,D3,00,40,A1,C8,DA,12,81,7F,A4,A6,D5,70,D9,22,DB,34,8D,14,20,00,AF'
}
'_sendCmd' initCmd
}
to '_initLibrary' {
comment 'Sets all Library variables and initializes the display hardware.
It also initializes the virtual GDBuffer, and clears the display.
NOTE:
Displays supported: OLED1306 (0.96in) and OLED1309 (2.42"), selected via boolean position.
OLED1309 requires the connection of RESET pin to a digital pin.
Both displays are 128x64 pixels or 16x8 characters in size.
Max i2c IO is 64 bytes: buffered writes need to be max that size - 16 x 64'
_eol = ('[data:unicodeString]' 10)
comment 'Col starts are in HEX'
_dataPrefix = ('[data:newByteArray]' 1 (hexToInt '40'))
_GDBuffer = ('[data:newByteArray]' (ifExpression (5 == _displayType) 360 1024))
_textX = 0
_textY = 0
_delayGDUpd = (booleanConstant false)
OLEDReady = (booleanConstant true)
'_OLEDsetDisplay' 'On'
if (_displayType == 5) {
repeat 2 {
digitalWriteOp 8 false
waitMillis 50
digitalWriteOp 8 true
waitMillis 50
}
} else {
repeat 2 {
setUserLED true
waitMillis 50
setUserLED false
waitMillis 50
OLEDpixel 0 0 false
}
}
}
to '_process image data' image {
comment 'Processes the new hex image data format.
Each _imgHex gets added to _imgData in DEC byteArray format.
_byteCount keeps track of total bytes processed.
_imgWidth and _imgHeight (mod8) are dimensions.'
local '_ptr' 1
comment '_imgData is not initialized yet.'
if (or (0 == _imgData) (not (isType _imgData 'byte array'))) {
_imgWidth = (hexToInt ('[data:copyFromTo]' image 1 2))
_imgHeight = (hexToInt ('[data:copyFromTo]' image 3 4))
image = ('[data:copyFromTo]' image 5)
comment 'If _imgHeight is partial byte, adjust to full byte'
if (not (0 == (_imgHeight % 8))) {
_imgHeight += (8 - (_imgHeight % 8))
}
_imgData = ('[data:newByteArray]' ((_imgWidth * _imgHeight) / 8))
}
for byte ('[data:range]' 1 (size image) 2) {
atPut (_byteCount + _ptr) _imgData (hexToInt ('[data:copyFromTo]' image byte (byte + 1)))
_ptr += 1
}
_byteCount += (_ptr - 1)
}
to '_sendCmd' cmdString {
comment 'Input is a comma sep. STRING.
MAKE SURE ALL INPUT PARAMETERS ARE HEX'
local '_cList' ('[data:split]' cmdString ',')
local 'cmdPrefix' (hexToInt '80')
if ('i2c' == _comMode) {
for cmd _cList {
'[sensors:i2cWrite]' OLEDi2cAddr ('[data:asByteArray]' ('[data:makeList]' cmdPrefix (hexToInt cmd)))
}
} else {
'_SPIWriteCmd'
for cmd _cList {
spiSend (hexToInt cmd)
}
}
}
to '_verifyXY' x y {
if (and (and (x >= 0) (x <= 127)) (and (y >= 0) (y <= 63))) {
return 0
} else {
sayIt 'x or y value error:' ('[data:unicodeString]' 10) 'x:' x ' y:' y
stopTask
}
}
to 'defer display updates' {
_delayGDUpd = (booleanConstant true)
}
module OctoStudio Comm
author wwj718
version 1 11
choices octo_shapes 'octo;circle' 'octo;square' 'octo;star' 'octo;heart' 'octo;triangle' 'octo;clover' 'octo;diamond' 'octo;moon'
description 'Communicate with OctoStudio (https://octostudio.org/)
'
variables _octoGroup _octoLastBeamShape _octoLastBeamGroup _octoShapes _octoIsBeaming
spec ' ' 'octoSendBeam' 'Octo beam to phones _ : duration _ ms : group _' 'menu.octo_shapes num num' 'octo;heart' 200 0
space
spec 'r' 'octoBeamReceived' 'Octo beam received?'
spec 'r' 'octoLastBeam' 'Octo last beam'
spec 'r' 'octoLastGroup' 'Octo last beam group'
space
spec ' ' 'octoSetGroup' 'Octo set group _ (0-99)' 'auto' 0
space
spec ' ' '_octoInit' '_octoInit'
spec 'r' '_octoShapeForID' '_octoShapeForID _' 'num' 1
spec 'r' '_octoMakeMessage' '_octoMakeMessage _' 'menu.octo_shapes' 'octo;heart'
spec 'r' '_octoHexDigit' '_octoHexDigit _' 'num' 10
to '_octoHexDigit' n {
return (at ((n & 15) + 1) '0123456789ABCDEF')
}
to '_octoInit' {
if (_octoShapes == 0) {_octoShapes = ('[data:makeList]' 'octo;circle' 'octo;square' 'octo;star' 'octo;heart' 'octo;triangle' 'octo;clover' 'octo;diamond' 'octo;moon')}
}
to '_octoMakeMessage' shape group {
comment 'Mimic iOS, eg: ECA7059C00000001'
'_octoInit'
local 'result' ('[data:makeList]')
repeat 8 {
'[data:addLast]' (at 'random' '0123456789ABCDEF') result
}
repeat 4 {
'[data:addLast]' 0 result
}
local 'shapeNum' (('[data:find]' shape _octoShapes) - 1)
if (shapeNum < 0) {
if (isType shape 'number') {
shapeNum = shape
} else {
return 'Unknown shape'
}
}
comment 'Add group as two hexadecimal digits.'
'[data:addLast]' ('_octoHexDigit' ((group >> 4) & 15)) result
'[data:addLast]' ('_octoHexDigit' (group & 15)) result
comment 'Allow for up to 256 shapes encoded as two hexadecimal digits.'
'[data:addLast]' ('_octoHexDigit' ((shapeNum >> 4) & 15)) result
'[data:addLast]' ('_octoHexDigit' (shapeNum & 15)) result
return ('[data:joinStrings]' result)
}
to '_octoShapeForID' id {
'_octoInit'
if (and (0 <= id) (id < (size _octoShapes))) {
return (at (id + 1) _octoShapes)
}
comment 'If id is out of the shape range, return it as a number.'
return id
}
to octoBeamReceived {
comment 'Return true if a new beam has been received. Use "Octo last beam" to get its value.'
local 'newBeam' ('[ble:octoReceive]')
if (newBeam == (booleanConstant false)) {
return (booleanConstant false)
}
local 'beamGroup' ((newBeam >> 8) & 255)
if (or ('' == _octoGroup) (beamGroup == _octoGroup)) {
_octoLastBeamShape = ('_octoShapeForID' (newBeam & 255))
_octoLastBeamGroup = beamGroup
return (booleanConstant true)
}
return (booleanConstant false)
}
to octoLastBeam {
comment 'Return the name of the last shape received.'
if (_octoLastBeamShape == 0) {
return 'None'
}
return _octoLastBeamShape
}
to octoLastGroup {
comment 'Return the group of the last beam received.'
if (_octoLastBeamShape == 0) {
return -1
}
return _octoLastBeamGroup
}
to octoSendBeam shape optionalDuration optionalGroup {
local 'duration' (argOrDefault 2 500)
local 'group' (argOrDefault 3 ('[data:convertType]' _octoGroup 'number'))
if (_octoIsBeaming == 1) {
sayIt 'waiting...'
waitUntil (_octoIsBeaming == 0)
sayIt ''
}
_octoIsBeaming = 1
'[ble:octoStartBeam]' ('_octoMakeMessage' shape group)
waitMillis duration
'[ble:octoStopBeam]'
_octoIsBeaming = 0
}
to octoSetGroup group {
_octoGroup = group
}
module Servo Output
author MicroBlocks
version 1 4
tags servo motor angle rotation position
description 'Control both positional (angle) and rotational servo motors.
'
variables _servoPin _servoPulseWidth
spec ' ' 'setServoAngle' 'set servo _ to _ degrees (-90 to 90)' 'num num' 1 90
spec ' ' 'setServoSpeed' 'set servo _ to speed _ (-100 to 100)' 'num num' 1 100
spec ' ' 'stopServo' 'stop servo _' 'num' 1
spec 'r' '_servoIndex' '_servoIndex _' 'num' 1
spec ' ' '_servoPulse' '_servoPulse pin _ usecs _' 'num num' 1 1500
spec ' ' '_servoUpdateLoop' '_servoUpdateLoop'
to '_servoIndex' which {
if (_servoPin == 0) {
_servoPin = ('[data:makeList]')
_servoPulseWidth = ('[data:makeList]')
sendBroadcast '_servoUpdateLoop'
}
local 'i' ('[data:find]' which _servoPin)
if (i < 0) {
comment 'Add new pin'
'[data:addLast]' which _servoPin
'[data:addLast]' 1500 _servoPulseWidth
i = (size _servoPin)
}
return i
}
to '_servoPulse' pin usecs {
if (usecs == 0) {
comment 'Servo stopped; do nothing'
return 0
}
usecs = (maximum 500 (minimum usecs 2900))
comment 'Split wait into a long wait followed by a wait of <= 30 usecs for greater accuracy'
local 'endTime' ((microsOp) + usecs)
digitalWriteOp pin true
waitMicros (usecs - 30)
waitMicros (endTime - (microsOp))
digitalWriteOp pin false
}
to '_servoUpdateLoop' {
forever {
if (_servoPin != 0) {
comment 'If the _servoPin list is not 0, update the servos'
for i (size _servoPin) {
local 'pin' (at i _servoPin)
local 'usecs' (at i _servoPulseWidth)
if (and (pin >= 0) (usecs != 0)) {
'_servoPulse' pin usecs
}
}
waitMillis 15
}
}
}
to setServoAngle which degrees optionalReverse {
local 'reversed' false
if ((pushArgCount) > 2) {
reversed = optionalReverse
}
if reversed {
degrees = (0 - degrees)
}
local 'pulseWidth' (1500 - (10 * degrees))
if ('[io:hasServo]') {
'[io:setServo]' which pulseWidth
} else {
atPut ('_servoIndex' which) _servoPulseWidth pulseWidth
}
}
to setServoSpeed which speed optionalReverse {
local 'reversed' false
if ((pushArgCount) > 2) {
reversed = optionalReverse
}
if reversed {
speed = (0 - speed)
}
local 'pulseWidth' (1500 - (10 * speed))
if ((absoluteValue speed) < 2) {
pulseWidth = 0
}
if ('[io:hasServo]') {
'[io:setServo]' which pulseWidth
} else {
atPut ('_servoIndex' which) _servoPulseWidth pulseWidth
}
}
to stopServo which {
if ('[io:hasServo]') {
'[io:setServo]' which 0
} else {
atPut ('_servoIndex' which) _servoPulseWidth 0
}
}
module Tone Output
author MicroBlocks
version 1 10
tags tone sound music audio note speaker
choices tone_NoteName 'nt;c' 'nt;c#' 'nt;d' 'nt;d#' 'nt;e' 'nt;f' 'nt;f#' 'nt;g' 'nt;g#' 'nt;a' 'nt;a#' 'nt;b'
description 'Audio tone generation. Make music with MicroBlocks!
'
variables _tonePin _toneInitalized _toneLoopOverhead _toneNoteNames _toneArezzoNotes _toneFrequencies
spec ' ' 'play tone' 'play note _ octave _ for _ ms' 'str.tone_NoteName num num' 'nt;c' 0 500
spec ' ' 'playMIDIKey' 'play midi key _ for _ ms' 'num num' 60 500
spec ' ' 'play frequency' 'play frequency _ for _ ms' 'num num' 261 500
space
spec ' ' 'startTone' 'start tone _ Hz' 'num' 440
spec ' ' 'stopTone' 'stop tone'
space
spec ' ' 'attach buzzer to pin' 'attach buzzer to pin _' 'auto' ''
space
spec 'r' '_measureLoopOverhead' '_measureLoopOverhead'
spec 'r' '_baseFreqForNote' '_baseFreqForNote _' 'auto' 'c'
spec 'r' '_baseFreqForSemitone' '_baseFreqForSemitone _' 'num' 0
spec ' ' '_toneLoop' '_toneLoop _ for _ ms' 'num num' 440000 100
spec 'r' '_trimmedLowercase' '_trimmedLowercase _' 'str' 'A. b C...'
spec ' ' '_tone init note names' '_tone init note names'
to '_baseFreqForNote' note {
comment 'Return the frequency for the given note in the middle-C octave
scaled by 1000. For example, return 440000 (440Hz) for A.
Note names may be upper or lower case. Note names
may be followed by # for a sharp or b for a flat.'
local 'normalized note' ('_trimmedLowercase' note)
'normalized note' = (ifExpression ((at 1 (v 'normalized note')) == 'n') (v 'normalized note') ('[data:join]' 'nt;' (v 'normalized note')))
'_tone init note names'
if (('[data:find]' (v 'normalized note') _toneArezzoNotes) > 0) {
return ('_baseFreqForSemitone' ('[data:find]' (v 'normalized note') _toneArezzoNotes))
} else {
return ('_baseFreqForSemitone' ('[data:find]' (v 'normalized note') _toneNoteNames))
}
}
to '_baseFreqForSemitone' semitone {
if (_toneFrequencies == 0) {_toneFrequencies = ('[data:makeList]' 261626 277183 293665 311127 329628 349228 369994 391995 415305 440000 466164 493883 246942 277183 277183 311127 311127 349228 329628 369994 369994 415305 415305 466164 466164 523252)}
if (and (1 <= semitone) (semitone <= (size _toneFrequencies))) {
return (at semitone _toneFrequencies)
} else {
comment 'Bad note name; return 10 Hz'
return 10000
}
}
to '_measureLoopOverhead' {
comment 'Measure the loop overhead on this device'
local 'halfCycle' 100
local 'startT' (microsOp)
repeat 100 {
digitalWriteOp _tonePin false
waitMicros halfCycle
digitalWriteOp _tonePin false
waitMicros halfCycle
}
local 'usecs' ((microsOp) - startT)
return ((usecs - 20000) / 200)
}
to '_tone init note names' {
if (_toneNoteNames == 0) {
_toneNoteNames = ('[data:makeList]' 'nt;c' 'nt;c#' 'nt;d' 'nt;d#' 'nt;e' 'nt;f' 'nt;f#' 'nt;g' 'nt;g#' 'nt;a' 'nt;a#' 'nt;b' 'nt;c_' 'nt;db' 'nt;d_' 'nt;eb' 'nt;e_' 'nt;e#' 'nt;f_' 'nt;gb' 'nt;g_' 'nt;ab' 'nt;a_' 'nt;bb' 'nt;b_' 'nt;b#')
_toneArezzoNotes = ('[data:makeList]' 'nt;do' 'nt;do#' 'nt;re' 'nt;re#' 'nt;mi' 'nt;fa' 'nt;fa#' 'nt;sol' 'nt;sol#' 'nt;la' 'nt;la#' 'nt;si' 'nt;do_' 'nt;dob' 'nt;re_' 'nt;reb' 'nt;mi_' 'nt;mi#' 'nt;fa_' 'nt;solb' 'nt;sol_' 'nt;lab' 'nt;la_' 'nt;sib' 'nt;si_' 'nt;si#')
}
}
to '_toneLoop' scaledFreq ms {
if (_toneInitalized == 0) {'attach buzzer to pin' ''}
if ('[io:hasTone]') {
'[io:playTone]' _tonePin (scaledFreq / 1000)
waitMillis ms
'[io:playTone]' _tonePin 0
} else {
local 'halfCycle' ((500000000 / scaledFreq) - _toneLoopOverhead)
local 'cycles' ((ms * 500) / halfCycle)
repeat cycles {
digitalWriteOp _tonePin true
waitMicros halfCycle
digitalWriteOp _tonePin false
waitMicros halfCycle
}
}
}
to '_trimmedLowercase' s {
comment 'Return a copy of the given string without whitespace
or periods and all lowercase.'
local 'result' (newList (size s))
'[data:delete]' 'all' result
for i (size s) {
local 'ch' ('[data:unicodeAt]' i s)
if (and (ch > 32) (ch != 46)) {
if (and (65 <= ch) (ch <= 90)) {ch = (ch + 32)}
'[data:addLast]' ch result
}
}
return ('[data:unicodeString]' result)
}
to 'attach buzzer to pin' pinNumber {
if (pinNumber == '') {
comment 'Pin number not specified; use default pin for this device'
if ((boardType) == 'Citilab ED1') {
_tonePin = 26
} ((boardType) == 'M5Stack-Core') {
_tonePin = 25
} ((boardType) == 'M5StickC') {
_tonePin = 26
} ((boardType) == 'Calliope') {
digitalWriteOp 23 true
digitalWriteOp 24 true
_tonePin = 25
} ((boardType) == 'D1-Mini') {
_tonePin = 12
} ((boardType) == 'CodingBox') {
_tonePin = 32
} else {
_tonePin = -1
}
} else {
_tonePin = pinNumber
}
_toneLoopOverhead = ('_measureLoopOverhead')
_toneInitalized = (booleanConstant true)
}
to 'play frequency' freq ms {
'_toneLoop' (freq * 1000) ms
}
to 'play tone' note octave ms {
local 'freq' ('_baseFreqForNote' note)
if (freq <= 10000) {
waitMillis ms
return 0
}
if (octave < 0) {
repeat (absoluteValue octave) {
freq = (freq / 2)
}
}
repeat octave {
freq = (freq * 2)
}
'_toneLoop' freq ms
}
to playMIDIKey key ms {
local 'freq' ('_baseFreqForSemitone' ((key % 12) + 1))
local 'octave' ((key / 12) - 5)
if (octave < 0) {
repeat (absoluteValue octave) {
freq = (freq / 2)
}
}
repeat octave {
freq = (freq * 2)
}
'_toneLoop' freq ms
}
to startTone freq {
if (_toneInitalized == 0) {'attach buzzer to pin' ''}
if ('[io:hasTone]') {'[io:playTone]' _tonePin freq}
}
to stopTone {
startTone 0
}
Commentaires
Publier un commentaire