1# labplus mPython library
2# MIT license; Copyright (c) 2018 labplus
3# V1.0 Zhang KaiHua(apple_eat@126.com)
4
5# mpython buildin periphers drivers
6
7# history:
8# V1.1 add oled draw function,add buzz.freq(). by tangliufeng
9# V1.2 add servo/ui class,by tangliufeng
10
11from machine import I2C, PWM, Pin, ADC, TouchPad
12from ssd1106 import SSD1106_I2C
13import esp, math, time, network
14import ustruct, array
15from neopixel import NeoPixel
16# from esp import dht_readinto
17from time import sleep_ms, sleep_us, sleep
18import framebuf
19import calibrate_img
20from micropython import schedule,const
21import NVS
22
23i2c = I2C(0, scl=Pin(Pin.P19), sda=Pin(Pin.P20), freq=400000)
24
25if '_print' not in dir(): _print = print
26
27def print(_t, *args, sep=' ', end='\n'):
28 _s = str(_t)[0:1]
29 if u'\u4e00' <= _s <= u'\u9fff':
30 _print(' ' + str(_t), *args, sep=sep, end=end)
31 else:
32 _print(_t, *args, sep=sep, end=end)
33
34# my_wifi = wifi()
35#多次尝试连接wifi
36def try_connect_wifi(_wifi, _ssid, _pass, _times):
37 if _times < 1: return False
38 try:
39 print("Try Connect WiFi ... {} Times".format(_times) )
40 _wifi.connectWiFi(_ssid, _pass)
41 if _wifi.sta.isconnected(): return True
42 else:
43 time.sleep(5)
44 return try_connect_wifi(_wifi, _ssid, _pass, _times-1)
45 except:
46 time.sleep(5)
47 return try_connect_wifi(_wifi, _ssid, _pass, _times-1)
48
49class Font(object):
50 def __init__(self, font_address=0x400000):
51 self.font_address = font_address
52 buffer = bytearray(18)
53 esp.flash_read(self.font_address, buffer)
54 self.header, \
55 self.height, \
56 self.width, \
57 self.baseline, \
58 self.x_height, \
59 self.Y_height, \
60 self.first_char,\
61 self.last_char = ustruct.unpack('4sHHHHHHH', buffer)
62 self.first_char_info_address = self.font_address + 18
63
64 def GetCharacterData(self, c):
65 uni = ord(c)
66 # if uni not in range(self.first_char, self.last_char):
67 # return None
68 if (uni < self.first_char or uni > self.last_char):
69 return None
70 char_info_address = self.first_char_info_address + \
71 (uni - self.first_char) * 6
72 buffer = bytearray(6)
73 esp.flash_read(char_info_address, buffer)
74 ptr_char_data, len = ustruct.unpack('IH', buffer)
75 if (ptr_char_data) == 0 or (len == 0):
76 return None
77 buffer = bytearray(len)
78 esp.flash_read(ptr_char_data + self.font_address, buffer)
79 return buffer
80
81
82class TextMode():
83 normal = 1
84 rev = 2
85 trans = 3
86 xor = 4
87
88
89class OLED(SSD1106_I2C):
90 """ 128x64 oled display """
91
92 def __init__(self):
93 super().__init__(128, 64, i2c)
94 self.f = Font()
95 if self.f is None:
96 raise Exception('font load failed')
97
98 def DispChar(self, s, x, y, mode=TextMode.normal, auto_return=False):
99 row = 0
100 str_width = 0
101 if self.f is None:
102 return
103 for c in s:
104 data = self.f.GetCharacterData(c)
105 if data is None:
106 if auto_return is True:
107 x = x + self.f.width
108 else:
109 x = x + self.width
110 continue
111 width, bytes_per_line = ustruct.unpack('HH', data[:4])
112 # print('character [%d]: width = %d, bytes_per_line = %d' % (ord(c)
113 # , width, bytes_per_line))
114 if auto_return is True:
115 if x > self.width - width:
116 str_width += self.width - x
117 x = 0
118 row += 1
119 y += self.f.height
120 if y > (self.height - self.f.height)+0:
121 y, row = 0, 0
122 for h in range(0, self.f.height):
123 w = 0
124 i = 0
125 while w < width:
126 mask = data[4 + h * bytes_per_line + i]
127 if (width - w) >= 8:
128 n = 8
129 else:
130 n = width - w
131 py = y + h
132 page = py >> 3
133 bit = 0x80 >> (py % 8)
134 for p in range(0, n):
135 px = x + w + p
136 c = 0
137 if (mask & 0x80) != 0:
138 if mode == TextMode.normal or \
139 mode == TextMode.trans:
140 c = 1
141 if mode == TextMode.rev:
142 c = 0
143 if mode == TextMode.xor:
144 c = self.buffer[page * (self.width if auto_return is True else 128) + px] & bit
145 if c != 0:
146 c = 0
147 else:
148 c = 1
149 super().pixel(px, py, c)
150 else:
151 if mode == TextMode.normal:
152 c = 0
153 super().pixel(px, py, c)
154 if mode == TextMode.rev:
155 c = 1
156 super().pixel(px, py, c)
157 mask = mask << 1
158 w = w + 8
159 i = i + 1
160 x = x + width + 1
161 str_width += width + 1
162 return (str_width-1,(x-1, y))
163
164 def DispChar_font(self, font, s, x, y, invert=False):
165 """
166 custom font display.Ref by , https://github.com/peterhinch/micropython-font-to-py
167 :param font: use font_to_py.py script convert to `py` from `ttf` or `otf`.
168 """
169 screen_width = self.width
170 screen_height = self.height
171 text_row = x
172 text_col = y
173 text_length = 0
174 if font.hmap():
175 font_map = framebuf.MONO_HMSB if font.reverse() else framebuf.MONO_HLSB
176 else:
177 raise ValueError('Font must be horizontally mapped.')
178 for c in s:
179 glyph, char_height, char_width = font.get_ch(c)
180 buf = bytearray(glyph)
181 if invert:
182 for i, v in enumerate(buf):
183 buf[i] = 0xFF & ~ v
184 fbc = framebuf.FrameBuffer(buf, char_width, char_height, font_map)
185 if text_row + char_width > screen_width - 1:
186 text_length += screen_width-text_row
187 text_row = 0
188 text_col += char_height
189 if text_col + char_height > screen_height + 2:
190 text_col = 0
191
192 super().blit(fbc, text_row, text_col)
193 text_row = text_row + char_width+1
194 text_length += char_width+1
195 return (text_length-1, (text_row-1, text_col))
196
197# display
198if 60 in i2c.scan():
199 oled = OLED()
200 display = oled
201else:
202 pass
203
204class MOTION(object):
205 def __init__(self):
206 self.i2c = i2c
207 addr = self.i2c.scan()
208 if 38 in addr:
209 MOTION.chip = 1 # MSA300
210 MOTION.IIC_ADDR = 38
211 elif 107 in addr:
212 MOTION.chip = 2 # QMI8658
213 MOTION.IIC_ADDR = 107
214 else:
215 raise OSError("MOTION init error")
216 if(MOTION.chip == 1):
217 pass
218 elif(MOTION.chip == 2):
219 MOTION._writeReg(0x60, 0x01) # soft reset regist value.
220 time.sleep_ms(20)
221 MOTION._writeReg(0x02, 0x60) # Enabe reg address auto increment auto
222 MOTION._writeReg(0x08, 0x03) # Enable accel and gyro
223 MOTION._writeReg(0x03, 0x1c) # accel range:4g ODR 128HZ
224 MOTION._writeReg(0x04, 0x40) # gyro ODR 8000HZ, FS 256dps
225 MOTION._writeReg(0x06, 0x55) # Enable accel and gyro Low-Pass Filter
226 # print('Motion init finished!')
227
228 # @staticmethod
229 def _readReg(reg, nbytes=1):
230 return i2c.readfrom_mem(MOTION.IIC_ADDR, reg, nbytes)
231
232 # @staticmethod
233 def _writeReg(reg, value):
234 i2c.writeto_mem(MOTION.IIC_ADDR, reg, value.to_bytes(1, 'little'))
235
236 def get_fw_version(self):
237 if(self.chip==1):
238 pass
239 elif(self.chip==2):
240 MOTION._writeReg(0x0a, 0x10) # send ctrl9R read FW cmd
241 while True:
242 if (MOTION._readReg(0x2F, 1)[0] & 0X01) == 0X01:
243 break
244 buf = MOTION._readReg(0X49, 3)
245 # print(buf[0])
246 # print(buf[1])
247 # print(buf[2])
248
249 class Accelerometer():
250 """MSA300"""
251 # Range and resolustion
252 RANGE_2G = const(0)
253 RANGE_4G = const(1)
254 RANGE_8G = const(2)
255 RANGE_16G = const(3)
256 RES_14_BIT = const(0)
257 RES_12_BIT = const(1)
258 RES_10_BIT = const(2)
259 # Event
260 TILT_LEFT = const(0)
261 TILT_RIGHT = const(1)
262 TILT_UP = const(2)
263 TILT_DOWN = const(3)
264 FACE_UP = const(4)
265 FACE_DOWN = const(5)
266 SINGLE_CLICK = const(6)
267 DOUBLE_CLICK = const(7)
268 FREEFALL = const(8)
269
270 """QMI8658C"""
271 # Range and resolustion
272 # QMI8658C_RANGE_2G = const(0x00)
273 # QMI8658C_RANGE_4G = const(0x10)
274 # QMI8658C_RANGE_8G = const(0x20)
275 # QMI8658C_RANGE_16G = const(0x40)
276
277 def __init__(self):
278 if(MOTION.chip==1):
279 self.set_resolution(MOTION.Accelerometer.RES_10_BIT)
280 self.set_range(MOTION.Accelerometer.RANGE_2G)
281 MOTION._writeReg(0x12, 0x03) # polarity of y,z axis,
282 MOTION._writeReg(0x11, 0) # set power mode = normal
283 # interrupt
284 MOTION._writeReg(0x16, 0x70) # int enabled: Orient | S_TAP | D_TAP
285 MOTION._writeReg(0x17, 0x08) # int enabled: Freefall
286 MOTION._writeReg(0x19, 0x71) # int1 map to: Orient, S_TAP, D_TAP, Freefall
287 MOTION._writeReg(0x20, 0x02) # int1 active level = 0, output = OD
288 MOTION._writeReg(0x21, 0x0C) # int tempoary latched 25ms
289 # freefall:
290 # single mode: |acc_x| < Threshold && |acc_y| < Threshold && |acc_z| < Threshold, at least time > Duration
291 # sum mode: |acc_x| + |acc_y| + |acc_z| < Threshold, at least time > Duration
292 MOTION._writeReg(0x22, 20) # Freefall Duration:(n+1)*2ms, range from 2ms to 512ms
293 MOTION._writeReg(0x23, 48) # Freefall Threshold: n*7.81mg
294 MOTION._writeReg(0x24, 0x01) # Freefall mode = 0-singlemode;hysteresis = n*125mg
295 # tap:
296 MOTION._writeReg(0x2A, 0x06) # Tap duration:quit = 30ms, shock=50ms, time window for secent shock=500ms
297 MOTION._writeReg(0x2B, 0x0A) # Tap threshold = 10*[62.5mg@2G | 125mg@4G | 250mg@8G | 500mg@16g]
298 # Orient
299 MOTION._writeReg(0x2C, 0x18) # Orient hysteresis= 1*62.5mg;
300 # block mode = 10 z_axis blocking or slope in any axis > 0.2g;
301 # orient mode = 00-symetrical
302 MOTION._writeReg(0x2D, 8) # Z-axis block
303 # int pin irq register
304 self.int = Pin(37, Pin.IN)
305 self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.irq)
306 # event handler
307 self.event_tilt_up = None
308 self.event_tilt_down = None
309 self.event_tilt_left = None
310 self.event_tilt_right = None
311 self.event_face_up = None
312 self.event_face_down = None
313 self.event_single_click = None
314 self.event_double_click = None
315 self.event_freefall = None
316 elif(MOTION.chip==2):
317 # 设置偏移值
318 self.x_offset = 0
319 self.y_offset = 0
320 self.z_offset = 0
321 self.get_nvs_offset()
322 try:
323 id = MOTION._readReg(0x0, 2)
324 except:
325 pass
326 self.set_range(MOTION.Accelerometer.RANGE_2G) #设置默认分辨率+-2g
327 self.int = Pin(37, Pin.IN)
328 self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.irq)
329 # event handler
330 self.wom = None
331
332
333 def irq(self, arg):
334 if(MOTION.chip==1):
335 reg_int = MOTION._readReg(0x09)[0]
336 reg_orent = MOTION._readReg(0x0C)[0]
337 # orient_int
338 if (reg_int & 0x40):
339 if ((reg_orent & 0x30) == 0x00 and self.event_tilt_left is not None):
340 schedule(self.event_tilt_left, self.TILT_LEFT)
341 if ((reg_orent & 0x30) == 0x10 and self.event_tilt_right is not None):
342 schedule(self.event_tilt_right, self.TILT_RIGHT)
343 if ((reg_orent & 0x30) == 0x20 and self.event_tilt_up is not None):
344 schedule(self.event_tilt_up, self.TILT_UP)
345 if ((reg_orent & 0x30) == 0x30 and self.event_tilt_down is not None):
346 schedule(self.event_tilt_down, self.TILT_DOWN)
347 if ((reg_orent & 0x40) == 0x00 and self.event_face_up):
348 schedule(self.event_face_up, self.FACE_UP)
349 if ((reg_orent & 0x40) == 0x40 and self.event_face_down):
350 schedule(self.event_face_down, self.FACE_DOWN)
351 # single tap
352 if (reg_int & 0x20):
353 if (self.event_single_click is not None):
354 schedule(self.event_single_click, self.SINGLE_CLICK)
355 # double tap
356 if (reg_int & 0x10):
357 if (self.event_double_click is not None):
358 schedule(self.event_double_click, self.DOUBLE_CLICK)
359 # freefall
360 if (reg_int & 0x01):
361 if (self.event_freefall is not None):
362 schedule(self.event_freefall, self.FREEFALL)
363 # print("acc sensor interrupt, because 0x%2x, orient = 0x%2x" % (reg_int, reg_orent))
364 elif(MOTION.chip==2):
365 flag = MOTION._readReg(0x2F, 1)[0]
366 if (flag & 0x04) == 0x04:
367 print('wom int trigged.')
368
369 def wom_config(self):
370 if(MOTION.chip==1):
371 pass
372 elif(MOTION.chip==2):
373 MOTION._writeReg(0x60, 0x01) # soft reset regist value.
374 time.sleep_ms(20)
375 MOTION._writeReg(0x08, 0x0) # disable all sensor
376 MOTION._writeReg(0x03, 0x1c) # accel range:4g ODR 128HZ
377 MOTION._writeReg(0x0B, 0xfF) # CAL_L WoM Threshold(1mg/LSB resolution)
378 MOTION._writeReg(0x0C, 0x8F) # CAL_H WoM (INT1 blank time 0x1f)
379 MOTION._writeReg(0x0A, 0x08)
380 while True:
381 if (MOTION._readReg(0x2F, 1)[0] & 0X01) == 0X01:
382 break
383 MOTION._writeReg(0x08, 0x01) # enable accel
384
385 def set_resolution(self, resolution):# set data output rate
386 if(MOTION.chip==1):
387 format = MOTION._readReg(0x0f, 1)
388 format = format[0] & ~0xC
389 format |= (resolution << 2)
390 MOTION._writeReg(0x0f, format)
391 elif(MOTION.chip==2):
392 self.odr = resolution
393 format = MOTION._readReg(0x03, 1)
394 format = format[0] & 0xf0
395 format |= (resolution & 0x0f)
396 MOTION._writeReg(0x03, format)
397
398 def set_range(self, range):
399 if(MOTION.chip==1):
400 self.range = range
401 format = MOTION._readReg(0x0f, 1)
402 format = format[0] & ~0x3
403 format |= range
404 MOTION._writeReg(0x0f, format)
405 elif(MOTION.chip==2):
406 if(range==3):
407 range = 64 #0x40
408 else:
409 range = range << 4
410 self.FS = 2*(2**(range >> 4))
411 format = MOTION._readReg(0x03, 1)
412 format = format[0] & 0x8F
413 format |= range
414 MOTION._writeReg(0x03, format)
415
416 def set_offset(self, x=None, y=None, z=None):
417 if(MOTION.chip==1):
418 for i in (x, y, z):
419 if i is not None:
420 if i < -1 or i > 1:
421 raise ValueError("out of range,only offset 1 gravity")
422 if x is not None:
423 MOTION._writeReg(0x39, int(round(x/0.0039)))
424 elif y is not None:
425 MOTION._writeReg(0x38, int(round(y/0.0039)))
426 elif z is not None:
427 MOTION._writeReg(0x3A, int(round(z/0.0039)))
428 elif(MOTION.chip==2):
429 for i in (x, y, z):
430 if i is not None:
431 if i < -16 or i > 16:
432 raise ValueError("超出调整范围!!!")
433 if x is not None:
434 self.x_offset = x
435 self.set_nvs_offset("x", x)
436 if y is not None:
437 self.y_offset = y
438 self.set_nvs_offset("y", y)
439 if z is not None:
440 self.z_offset = z
441 self.set_nvs_offset("z", z)
442
443 def get_x(self):
444 if(MOTION.chip==1):
445 retry = 0
446 if (retry < 5):
447 try:
448 buf = MOTION._readReg(0x02, 2)
449 x = ustruct.unpack('h', buf)[0]
450 return x / 4 / 4096 * 2**self.range
451 except:
452 retry = retry + 1
453 else:
454 raise Exception("i2c read/write error!")
455 elif(MOTION.chip==2):
456 buf = MOTION._readReg(0x35, 2)
457 x = ustruct.unpack('<h', buf)[0]
458 return (x * self.FS) / 32768 + self.x_offset
459
460 def get_y(self):
461 if(MOTION.chip==1):
462 retry = 0
463 if (retry < 5):
464 try:
465 buf = MOTION._readReg(0x04, 2)
466 y = ustruct.unpack('h', buf)[0]
467 return y / 4 / 4096 * 2**self.range
468 except:
469 retry = retry + 1
470 else:
471 raise Exception("i2c read/write error!")
472 elif(MOTION.chip==2):
473 buf = MOTION._readReg(0x37, 2)
474 y = ustruct.unpack('<h', buf)[0]
475 return (y * self.FS) / 32768 + self.y_offset
476
477 def get_z(self):
478 if(MOTION.chip==1):
479 retry = 0
480 if (retry < 5):
481 try:
482 buf = MOTION._readReg(0x06, 2)
483 z = ustruct.unpack('h', buf)[0]
484 return z / 4 / 4096 * 2**self.range
485 except:
486 retry = retry + 1
487 else:
488 raise Exception("i2c read/write error!")
489 elif(MOTION.chip==2):
490 buf = MOTION._readReg(0x39, 2)
491 z = ustruct.unpack('<h', buf)[0]
492 return (z * self.FS) / 32768 + self.z_offset
493 # return -(z * self.FS) / 32768
494
495 def roll_pitch_angle(self):
496 x, y, z = self.get_x(), self.get_y(), -self.get_z()
497 # vector normalize
498 mag = math.sqrt(x ** 2 + y ** 2+z ** 2)
499 x /= mag
500 y /= mag
501 z /= mag
502 roll = math.degrees(-math.asin(y))
503 pitch = math.degrees(math.atan2(x, z))
504
505 return roll, pitch
506
507 def get_nvs_offset(self):
508 try:
509 tmp = NVS("offset_a")
510 self.x_offset = round(tmp.get_i32("x")/1e5, 5)
511 self.y_offset = round(tmp.get_i32("y")/1e5, 5)
512 self.z_offset = round(tmp.get_i32("z")/1e5, 5)
513 except OSError as e:
514 # print('Accelerometer get_nvs_offset:',e)
515 # self.x_offset = 0
516 # self.y_offset = 0
517 # self.z_offset = 0
518 self.set_offset(0,0,0)
519
520 def set_nvs_offset(self, key, value):
521 try:
522 nvs = NVS("offset_a")
523 nvs.set_i32(key, int(value*1e5))
524 nvs.commit()
525 except OSError as e:
526 print('Gyroscope set_nvs_offset error:',e)
527
528 class Gyroscope():
529 # gyro full scale
530 RANGE_16_DPS = const(0x00)
531 RANGE_32_DPS = const(0x10)
532 RANGE_64_DPS = const(0x20)
533 RANGE_128_DPS = const(0x30)
534 RANGE_256_DPS = const(0x40)
535 RANGE_512_DPS = const(0x50)
536 RANGE_1024_DPS = const(0x60)
537 RANGE_2048_DPS = const(0x70)
538
539 def __init__(self):
540 if(MOTION.chip==1):
541 pass
542 elif(MOTION.chip==2):
543 # 设置偏移值
544 self.x_offset = 0
545 self.y_offset = 0
546 self.z_offset = 0
547 self.get_nvs_offset()
548 self.set_range(MOTION.Gyroscope.RANGE_256_DPS)
549
550 def set_range(self, range):
551 if(MOTION.chip==1):
552 pass
553 elif(MOTION.chip==2):
554 self.FS = 16*(2**(range >> 4))
555 format = MOTION._readReg(0x04, 1)
556 format = format[0] & 0x8F
557 format |= range
558 MOTION._writeReg(0x04, format)
559
560 def set_ODR(self, odr): # set data output rate
561 if(MOTION.chip==1):
562 pass
563 elif(MOTION.chip==2):
564 self.odr = odr
565 format = MOTION._readReg(0x04, 1)
566 format = format[0] & 0xF0
567 format |= odr
568 MOTION._writeReg(0x04, format)
569
570 def get_x(self):
571 if(MOTION.chip==1):
572 pass
573 elif(MOTION.chip==2):
574 buf = MOTION._readReg(0x3b, 2)
575 x = ustruct.unpack('<h', buf)[0]
576 return (x * self.FS) / 32768 + self.x_offset
577
578 def get_y(self):
579 if(MOTION.chip==1):
580 pass
581 elif(MOTION.chip==2):
582 buf = MOTION._readReg(0x3d, 2)
583 y = ustruct.unpack('<h', buf)[0]
584 return (y * self.FS) / 32768 + self.y_offset
585
586 def get_z(self):
587 if(MOTION.chip==1):
588 pass
589 elif(MOTION.chip==2):
590 buf = MOTION._readReg(0x3f, 2)
591 z = ustruct.unpack('<h', buf)[0]
592 return (z * self.FS) / 32768 + self.z_offset
593
594 def set_offset(self, x=None, y=None, z=None):
595 if(MOTION.chip==1):
596 pass
597 elif(MOTION.chip==2):
598 for i in (x, y, z):
599 if i is not None:
600 if i < -4096 or i > 4096:
601 raise ValueError("超出调整范围!!!")
602 if x is not None:
603 self.x_offset = x
604 self.set_nvs_offset("x", x)
605 if y is not None:
606 self.y_offset = y
607 self.set_nvs_offset("y", y)
608 if z is not None:
609 self.z_offset = z
610 self.set_nvs_offset("z", z)
611
612 def get_nvs_offset(self):
613 if(MOTION.chip==1):
614 pass
615 elif(MOTION.chip==2):
616 try:
617 tmp = NVS("offset_g")
618 self.x_offset = round(tmp.get_i32("x")/1e5, 5)
619 self.y_offset = round(tmp.get_i32("y")/1e5, 5)
620 self.z_offset = round(tmp.get_i32("z")/1e5, 5)
621 except OSError as e:
622 # print('Gyroscope get_nvs_offset:',e)
623 self.set_offset(0,0,0)
624 # self.x_offset = 0
625 # self.y_offset = 0
626 # self.z_offset = 0
627
628 def set_nvs_offset(self, key, value):
629 try:
630 nvs = NVS("offset_g")
631 nvs.set_i32(key, int(value*1e5))
632 nvs.commit()
633 except OSError as e:
634 print('Gyroscope set_nvs_offset error:',e)
635
636
637motion = MOTION()
638accelerometer = motion.Accelerometer()
639gyroscope = motion.Gyroscope()
640
641class Magnetic(object):
642 """ MMC5983MA driver """
643 """ MMC5603NJ driver 20211028替换"""
644 def __init__(self):
645 self.addr = 48
646 self.i2c = i2c
647 self._judge_id()
648 time.sleep_ms(5)
649 if (self.product_ID==48):
650 pass # MMC5983MA
651 elif (self.product_ID==16):
652 pass # MMC5603NJ
653 else:
654 raise OSError("Magnetic init error")
655 """ MMC5983MA driver """
656 # 传量器裸数据,乘0.25后转化为mGS
657 self.raw_x = 0.0
658 self.raw_y = 0.0
659 self.raw_z = 0.0
660 # 校准后的偏移量, 基于裸数据
661 self.cali_offset_x = 0.0
662 self.cali_offset_y = 0.0
663 self.cali_offset_z = 0.0
664 # 去皮偏移量,类似电子秤去皮功能,基于裸数据。
665 self.peeling_x = 0.0
666 self.peeling_y = 0.0
667 self.peeling_z = 0.0
668 self.is_peeling = 0
669 if (self.chip==1):
670 self.i2c.writeto(self.addr, b'\x09\x20\xbd\x00', True)
671 """ MMC5603NJ driver """
672 if (self.chip==2):
673 self._writeReg(0x1C, 0x80)#软件复位
674 time.sleep_ms(100)
675 self._writeReg(0x1A, 255)
676 self._writeReg(0x1B, 0b10100001)
677 # self._writeReg(0x1C, 0b00000011)
678 self._writeReg(0x1C, 0b00000000)
679 self._writeReg(0x1D, 0b10010000)
680 time.sleep_ms(100)
681
682 def _readReg(self, reg, nbytes=1):
683 return i2c.readfrom_mem(self.addr, reg, nbytes)
684
685 def _writeReg(self, reg, value):
686 i2c.writeto_mem(self.addr, reg, value.to_bytes(1, 'little'))
687
688 def _set_offset(self):
689 if(self.chip == 1):
690 self.i2c.writeto(self.addr, b'\x09\x08', True) #set
691 self.i2c.writeto(self.addr, b'\x09\x01', True)
692 while True:
693 self.i2c.writeto(self.addr, b'\x08', False)
694 buf = self.i2c.readfrom(self.addr, 1)
695 status = ustruct.unpack('B', buf)[0]
696 if(status & 0x01):
697 break
698 self.i2c.writeto(self.addr, b'\x00', False)
699 buf = self.i2c.readfrom(self.addr, 6)
700 data = ustruct.unpack('>3H', buf)
701
702 self.i2c.writeto(self.addr, b'\x09\x10', True) #reset
703
704 self.i2c.writeto(self.addr, b'\x09\x01', True)
705 while True:
706 self.i2c.writeto(self.addr, b'\x08', False)
707 buf = self.i2c.readfrom(self.addr, 1)
708 status = ustruct.unpack('B', buf)[0]
709 if(status & 0x01):
710 break
711 self.i2c.writeto(self.addr, b'\x00', False)
712 buf = self.i2c.readfrom(self.addr, 6)
713 data1 = ustruct.unpack('>3H', buf)
714
715 self.x_offset = (data[0] + data1[0])/2
716 self.y_offset = (data[1] + data1[1])/2
717 self.z_offset = (data[2] + data1[2])/2
718 elif(self.chip == 2):
719 pass
720
721 def _get_raw(self):
722 if (self.chip == 1):
723 retry = 0
724 if (retry < 5):
725 try:
726 self.i2c.writeto(self.addr, b'\x09\x08', True) #set
727
728 self.i2c.writeto(self.addr, b'\x09\x01', True)
729 while True:
730 self.i2c.writeto(self.addr, b'\x08', False)
731 buf = self.i2c.readfrom(self.addr, 1)
732 status = ustruct.unpack('B', buf)[0]
733 if(status & 0x01):
734 break
735 self.i2c.writeto(self.addr, b'\x00', False)
736 buf = self.i2c.readfrom(self.addr, 6)
737 data = ustruct.unpack('>3H', buf)
738
739 self.i2c.writeto(self.addr, b'\x09\x10', True) #reset
740
741 self.i2c.writeto(self.addr, b'\x09\x01', True)
742 while True:
743 self.i2c.writeto(self.addr, b'\x08', False)
744 buf = self.i2c.readfrom(self.addr, 1)
745 status = ustruct.unpack('B', buf)[0]
746 if(status & 0x01):
747 break
748 self.i2c.writeto(self.addr, b'\x00', False)
749 buf = self.i2c.readfrom(self.addr, 6)
750 data1 = ustruct.unpack('>3H', buf)
751
752 self.raw_x = -((data[0] - data1[0])/2)
753 self.raw_y = -((data[1] - data1[1])/2)
754 self.raw_z = -((data[2] - data1[2])/2)
755 # print(str(self.raw_x) + " " + str(self.raw_y) + " " + str(self.raw_z))
756 except:
757 retry = retry + 1
758 else:
759 raise Exception("i2c read/write error!")
760 elif(self.chip == 2):
761 retry = 0
762 if (retry < 5):
763 try:
764 _raw_x = 0.0
765 _raw_y = 0.0
766 _raw_z = 0.0
767
768 # self.i2c.writeto(self.addr, b'\x1B\x08', True) #set
769 # self.i2c.writeto(self.addr, b'\x1B\x01', True)
770
771 # while True:
772 # buf = self._readReg(0x18, 1)
773 # status = buf[0]
774 # if(status & 0x40):
775 # break
776
777 # _buf = self._readReg(0x00, 9)
778
779 self.i2c.writeto(self.addr, b'\x1B\x08', True) #set
780 # self.i2c.writeto(self.addr, b'\x1B\x80', True)
781 self.i2c.writeto(self.addr, b'\x1B\x01', True)
782
783 while True:
784 sleep_ms(25)
785 buf = self._readReg(0x18, 1)
786 status = buf[0]
787 if(status & 0x40):
788 break
789
790 buf = self._readReg(0x00, 9)
791
792 _raw_x = (buf[0] << 12) | (buf[1] << 4) | (buf[6] >> 4)
793 _raw_y = (buf[2] << 12) | (buf[3] << 4) | (buf[7] >> 4)
794 _raw_z = (buf[4] << 12) | (buf[5] << 4) | (buf[8] >> 4)
795
796 self.raw_x = _raw_x
797 self.raw_y = _raw_y
798 self.raw_z = _raw_z
799 except:
800 retry = retry + 1
801 else:
802 raise Exception("i2c read/write error!")
803
804 def peeling(self):
805 '''
806 去除磁场环境
807 '''
808 self._get_raw()
809 self.peeling_x = self.raw_x
810 self.peeling_y = self.raw_y
811 self.peeling_z = self.raw_z
812 self.is_peeling = 1
813
814 def clear_peeling(self):
815 self.peeling_x = 0.0
816 self.peeling_y = 0.0
817 self.peeling_z = 0.0
818 self.is_peeling = 0
819
820 def get_x(self):
821 if (self.chip == 1):
822 self._get_raw()
823 return self.raw_x * 0.25
824 if (self.chip == 2):
825 self._get_raw()
826 if(self.cali_offset_x):
827 return -0.0625 * (self.raw_x - self.cali_offset_x)
828 else:
829 return -0.0625 * (self.raw_x - 524288)
830 # return -(self.raw_x - 524288)/16384
831
832 def get_y(self):
833 if (self.chip == 1):
834 self._get_raw()
835 return self.raw_y * 0.25
836 if (self.chip == 2):
837 self._get_raw()
838 if(self.cali_offset_y):
839 return -0.0625 * (self.raw_y - self.cali_offset_y)
840 else:
841 return -0.0625 * (self.raw_y - 524288)
842 # return -(self.raw_y - 524288)/16384
843
844 def get_z(self):
845 if (self.chip == 1):
846 self._get_raw()
847 return self.raw_z * 0.25
848 if (self.chip == 2):
849 self._get_raw()
850 if(self.cali_offset_z):
851 return 0.0625 * (self.raw_z - self.cali_offset_z)
852 else:
853 return 0.0625 * (self.raw_z - 524288)
854 # return (self.raw_z - 524288)/16384
855
856 def get_field_strength(self):
857 if(self.chip==1):
858 self._get_raw()
859 if self.is_peeling == 1:
860 return (math.sqrt((self.raw_x - self.peeling_x)*(self.raw_x - self.peeling_x) + (self.raw_y - self.peeling_y)*(self.raw_y - self.peeling_y) + (self.raw_z - self.peeling_z)*(self.raw_z - self.peeling_z)))*0.25
861 return (math.sqrt(self.raw_x * self.raw_x + self.raw_y * self.raw_y + self.raw_z * self.raw_z))*0.25
862 elif(self.chip==2):
863 self._get_raw()
864 if self.is_peeling == 1:
865 return (math.sqrt(math.pow(self.raw_x - self.peeling_x, 2) + pow(self.raw_y - self.peeling_y, 2) + pow(self.raw_z - self.peeling_z , 2)))*0.0625
866 return (math.sqrt(math.pow(self.get_x(), 2) + pow(self.get_y(), 2) + pow(self.get_z(), 2)))
867
868 def calibrate(self):
869 oled.fill(0)
870 oled.DispChar("步骤1:", 0,0,1)
871 oled.DispChar("如图",0,26,1)
872 oled.DispChar("转几周",0,43,1)
873 oled.bitmap(64,0,calibrate_img.rotate,64,64,1)
874 oled.show()
875 self._get_raw()
876 min_x = max_x = self.raw_x
877 min_y = max_y = self.raw_y
878 min_z = max_z = self.raw_z
879 ticks_start = time.ticks_ms()
880 while (time.ticks_diff(time.ticks_ms(), ticks_start) < 15000) :
881 self._get_raw()
882 min_x = min(self.raw_x, min_x)
883 min_y = min(self.raw_y, min_y)
884 max_x = max(self.raw_x, max_x)
885 max_y = max(self.raw_y, max_y)
886 time.sleep_ms(100)
887 self.cali_offset_x = (max_x + min_x) / 2
888 self.cali_offset_y = (max_y + min_y) / 2
889 print('cali_offset_x: ' + str(self.cali_offset_x) + ' cali_offset_y: ' + str(self.cali_offset_y))
890 oled.fill(0)
891 oled.DispChar("步骤2:", 85,0,1)
892 oled.DispChar("如图",85,26,1)
893 oled.DispChar("转几周",85,43,1)
894 oled.bitmap(0,0,calibrate_img.rotate1,64,64,1)
895 oled.show()
896 ticks_start = time.ticks_ms()
897 while (time.ticks_diff(time.ticks_ms(), ticks_start) < 15000) :
898 self._get_raw()
899 min_z = min(self.raw_z, min_z)
900 max_z = max(self.raw_z, max_z)
901 time.sleep_ms(100)
902 self.cali_offset_z = (max_z + min_z) / 2
903
904 print('cali_offset_z: ' + str(self.cali_offset_z))
905
906 oled.fill(0)
907 oled.DispChar("校准完成", 40,24,1)
908 oled.show()
909 oled.fill(0)
910
911 def get_heading(self):
912 if(self.chip==1):
913 self._get_raw()
914 temp_x = self.raw_x - self.cali_offset_x
915 temp_y = self.raw_y - self.cali_offset_y
916 # temp_z = self.raw_z - self.cali_offset_z
917 heading = math.atan2(temp_y, -temp_x) * (180 / 3.14159265) + 180 + 3
918 return heading
919 else:
920 if(self.cali_offset_x):
921 self._get_raw()
922 temp_x = -(self.raw_x - self.cali_offset_x)
923 temp_y = -(self.raw_y - self.cali_offset_y)
924 heading = math.atan2(temp_y, -temp_x) * (180 / 3.14159265) + 180 + 3
925 else:
926 heading = math.atan2(self.get_y(), -self.get_x()) * (180 / 3.14159265) + 180 + 3
927 return heading
928
929 def _get_temperature(self):
930 if(self.chip==1):
931 retry = 0
932 if (retry < 5):
933 try:
934 self.i2c.writeto(self.addr, b'\x09\x02', True)
935 while True:
936 self.i2c.writeto(self.addr, b'\x08', False)
937 buf = self.i2c.readfrom(self.addr, 1)
938 status = ustruct.unpack('B', buf)[0]
939 if(status & 0x02):
940 break
941 self.i2c.writeto(self.addr, b'\x07', False)
942 buf = self.i2c.readfrom(self.addr, 1)
943 temp = (ustruct.unpack('B', buf)[0])*0.8 -75
944 # print(data)
945 return temp
946 except:
947 retry = retry + 1
948 else:
949 raise Exception("i2c read/write error!")
950 elif(self.chip == 2):
951 pass
952
953 def _get_id(self):
954 if (self.chip==1):
955 retry = 0
956 if (retry < 5):
957 try:
958 self.i2c.writeto(self.addr, bytearray([0x2f]), False)
959 buf = self.i2c.readfrom(self.addr, 1, True)
960 print(buf)
961 id = ustruct.unpack('B', buf)[0]
962 return id
963 except:
964 retry = retry + 1
965 else:
966 raise Exception("i2c read/write error!")
967 elif (self.chip==2):
968 retry = 0
969 if (retry < 5):
970 try:
971 self.i2c.writeto(self.addr, bytearray([0x39]), False)
972 buf = self.i2c.readfrom(self.addr, 1, True)
973 id = ustruct.unpack('B', buf)[0]
974 return id
975 except:
976 retry = retry + 1
977 else:
978 raise Exception("i2c read/write error!")
979
980 def _judge_id(self):
981 """
982 判断product_ID
983 """
984 retry = 0
985 if (retry < 5):
986 try:
987 self.i2c.writeto(self.addr, bytearray([0x39]), False)
988 buf = self.i2c.readfrom(self.addr, 1, True)
989 id = ustruct.unpack('B', buf)[0]
990 if(id == 16):
991 self.chip = 2
992 self.product_ID = 16
993 else:
994 self.chip = 1
995 self.product_ID = 48
996 except:
997 retry = retry + 1
998 else:
999 raise Exception("i2c read/write error!")
1000
1001# Magnetic
1002if 48 in i2c.scan():
1003 magnetic = Magnetic()
1004
1005class BME280(object):
1006 def __init__(self):
1007 self.addr = 119
1008 # The “ctrl_hum” register sets the humidity data acquisition options of the device
1009 # 0x01 = [2:0]oversampling ×1
1010 i2c.writeto(self.addr, b'\xF2\x01')
1011 # The “ctrl_meas” register sets the pressure and temperature data acquisition options of the device.
1012 # The register needs to be written after changing “ctrl_hum” for the changes to become effective.
1013 # 0x27 = [7:5]Pressure oversampling ×1 | [4:2]Temperature oversampling ×4 | [1:0]Normal mode
1014 i2c.writeto(self.addr, b'\xF4\x27')
1015 # The “config” register sets the rate, filter and interface options of the device. Writes to the “config”
1016 # register in normal mode may be ignored. In sleep mode writes are not ignored.
1017 i2c.writeto(self.addr, b'\xF5\x00')
1018
1019 i2c.writeto(self.addr, b'\x88', False)
1020 bytes = i2c.readfrom(self.addr, 6)
1021 self.dig_T = ustruct.unpack('Hhh', bytes)
1022
1023 i2c.writeto(self.addr, b'\x8E', False)
1024 bytes = i2c.readfrom(self.addr, 18)
1025 self.dig_P = ustruct.unpack('Hhhhhhhhh', bytes)
1026
1027 i2c.writeto(self.addr, b'\xA1', False)
1028 self.dig_H = array.array('h', [0, 0, 0, 0, 0, 0])
1029 self.dig_H[0] = i2c.readfrom(self.addr, 1)[0]
1030 i2c.writeto(self.addr, b'\xE1', False)
1031 buff = i2c.readfrom(self.addr, 7)
1032 self.dig_H[1] = ustruct.unpack('h', buff[0:2])[0]
1033 self.dig_H[2] = buff[2]
1034 self.dig_H[3] = (buff[3] << 4) | (buff[4] & 0x0F)
1035 self.dig_H[4] = (buff[5] << 4) | (buff[4] >> 4 & 0x0F)
1036 self.dig_H[5] = buff[6]
1037
1038 def temperature(self):
1039 retry = 0
1040 if (retry < 5):
1041 try:
1042 i2c.writeto(self.addr, b'\xFA', False)
1043 buff = i2c.readfrom(self.addr, 3)
1044 T = (((buff[0] << 8) | buff[1]) << 4) | (buff[2] >> 4 & 0x0F)
1045 c1 = (T / 16384.0 - self.dig_T[0] / 1024.0) * self.dig_T[1]
1046 c2 = ((T / 131072.0 - self.dig_T[0] / 8192.0) * (T / 131072.0 - self.dig_T[0] / 8192.0)) * self.dig_T[2]
1047 self.tFine = c1 + c2
1048 return self.tFine / 5120.0
1049 except:
1050 retry = retry + 1
1051 else:
1052 raise Exception("i2c read/write error!")
1053
1054 def pressure(self):
1055 retry = 0
1056 if (retry < 5):
1057 try:
1058 self.temperature()
1059 i2c.writeto(self.addr, b'\xF7', False)
1060 buff = i2c.readfrom(self.addr, 3)
1061 P = (((buff[0] << 8) | buff[1]) << 4) | (buff[2] >> 4 & 0x0F)
1062 c1 = self.tFine / 2.0 - 64000.0
1063 c2 = c1 * c1 * self.dig_P[5] / 32768.0
1064 c2 = c2 + c1 * self.dig_P[4] * 2.0
1065 c2 = c2 / 4.0 + self.dig_P[3] * 65536.0
1066 c1 = (self.dig_P[2] * c1 * c1 / 524288.0 + self.dig_P[1] * c1) / 524288.0
1067 c1 = (1.0 + c1 / 32768.0) * self.dig_P[0]
1068 if c1 == 0.0:
1069 return 0
1070 p = 1048576.0 - P
1071 p = (p - c2 / 4096.0) * 6250.0 / c1
1072 c1 = self.dig_P[8] * p * p / 2147483648.0
1073 c2 = p * self.dig_P[7] / 32768.0
1074 p = p + (c1 + c2 + self.dig_P[6]) / 16.0
1075 return p
1076 except:
1077 retry = retry + 1
1078 else:
1079 raise Exception("i2c read/write error!")
1080
1081 def humidity(self):
1082 retry = 0
1083 if (retry < 5):
1084 try:
1085 self.temperature()
1086 i2c.writeto(self.addr, b'\xFD', False)
1087 buff = i2c.readfrom(self.addr, 2)
1088 H = buff[0] << 8 | buff[1]
1089 h = self.tFine - 76800.0
1090 h = (H - (self.dig_H[3] * 64.0 + self.dig_H[4] / 16384.0 * h)) * \
1091 (self.dig_H[1] / 65536.0 * (1.0 + self.dig_H[5] / 67108864.0 * h * \
1092 (1.0 + self.dig_H[2] / 67108864.0 * h)))
1093 h = h * (1.0 - self.dig_H[0] * h / 524288.0)
1094 if h > 100.0:
1095 return 100.0
1096 elif h < 0.0:
1097 return 0.0
1098 else:
1099 return h
1100 except:
1101 retry = retry + 1
1102 else:
1103 raise Exception("i2c read/write error!")
1104
1105# bm280
1106# if 119 in i2c.scan():
1107# bme280 = BME280()
1108
1109class PinMode(object):
1110 IN = 1
1111 OUT = 2
1112 PWM = 3
1113 ANALOG = 4
1114 OUT_DRAIN = 5
1115
1116
1117pins_remap_esp32 = (33, 32, 35, 34, 39, 0, 16, 17, 26, 25, 36, 2, -1, 18, 19, 21, 5, -1, -1, 22, 23, -1, -1, 27, 14, 12,
1118 13, 15, 4)
1119
1120
1121class MPythonPin():
1122 def __init__(self, pin, mode=PinMode.IN, pull=None):
1123 if mode not in [PinMode.IN, PinMode.OUT, PinMode.PWM, PinMode.ANALOG, PinMode.OUT_DRAIN]:
1124 raise TypeError("mode must be 'IN, OUT, PWM, ANALOG,OUT_DRAIN'")
1125 if pin == 4:
1126 raise TypeError("P4 is used for light sensor")
1127 if pin == 10:
1128 raise TypeError("P10 is used for sound sensor")
1129 try:
1130 self.id = pins_remap_esp32[pin]
1131 except IndexError:
1132 raise IndexError("Out of Pin range")
1133 if mode == PinMode.IN:
1134 # if pin in [3]:
1135 # raise TypeError('IN not supported on P%d' % pin)
1136 self.Pin = Pin(self.id, Pin.IN, pull)
1137 if mode == PinMode.OUT:
1138 if pin in [2, 3]:
1139 raise TypeError('OUT not supported on P%d' % pin)
1140 self.Pin = Pin(self.id, Pin.OUT, pull)
1141 if mode == PinMode.OUT_DRAIN:
1142 if pin in [2, 3]:
1143 raise TypeError('OUT_DRAIN not supported on P%d' % pin)
1144 self.Pin = Pin(self.id, Pin.OPEN_DRAIN, pull)
1145 if mode == PinMode.PWM:
1146 if pin not in [0, 1, 5, 6, 7, 8, 9, 11, 13, 14, 15, 16, 19, 20, 23, 24, 25, 26, 27, 28]:
1147 raise TypeError('PWM not supported on P%d' % pin)
1148 self.pwm = PWM(Pin(self.id), duty=0)
1149 if mode == PinMode.ANALOG:
1150 if pin not in [0, 1, 2, 3, 4, 10]:
1151 raise TypeError('ANALOG not supported on P%d' % pin)
1152 self.adc = ADC(Pin(self.id))
1153 self.adc.atten(ADC.ATTN_11DB)
1154 self.mode = mode
1155
1156 def irq(self, handler=None, trigger=Pin.IRQ_RISING):
1157 if not self.mode == PinMode.IN:
1158 raise TypeError('the pin is not in IN mode')
1159 return self.Pin.irq(handler, trigger)
1160
1161 def read_digital(self):
1162 if not self.mode == PinMode.IN:
1163 raise TypeError('the pin is not in IN mode')
1164 return self.Pin.value()
1165
1166 def write_digital(self, value):
1167 if self.mode not in [PinMode.OUT, PinMode.OUT_DRAIN]:
1168 raise TypeError('the pin is not in OUT or OUT_DRAIN mode')
1169 self.Pin.value(value)
1170
1171 def read_analog(self):
1172 if not self.mode == PinMode.ANALOG:
1173 raise TypeError('the pin is not in ANALOG mode')
1174 return self.adc.read()
1175
1176
1177 def write_analog(self, duty, freq=1000):
1178 if not self.mode == PinMode.PWM:
1179 raise TypeError('the pin is not in PWM mode')
1180 self.pwm.freq(freq)
1181 self.pwm.duty(duty)
1182
1183
1184'''
1185# to be test
1186class LightSensor(ADC):
1187
1188 def __init__(self):
1189 super().__init__(Pin(pins_remap_esp32[4]))
1190 # super().atten(ADC.ATTN_11DB)
1191
1192 def value(self):
1193 # lux * k * Rc = N * 3.9/ 4096
1194 # k = 0.0011mA/Lux
1195 # lux = N * 3.9/ 4096 / Rc / k
1196 return super().read() * 1.1 / 4095 / 6.81 / 0.011
1197
1198'''
1199
1200
1201class wifi:
1202 def __init__(self):
1203 self.sta = network.WLAN(network.STA_IF)
1204 self.ap = network.WLAN(network.AP_IF)
1205
1206 def connectWiFi(self, ssid, passwd, timeout=10):
1207 if self.sta.isconnected():
1208 self.sta.disconnect()
1209 self.sta.active(True)
1210 list = self.sta.scan()
1211 for i, wifi_info in enumerate(list):
1212 try:
1213 if wifi_info[0].decode() == ssid:
1214 self.sta.connect(ssid, passwd)
1215 wifi_dbm = wifi_info[3]
1216 break
1217 except UnicodeError:
1218 self.sta.connect(ssid, passwd)
1219 wifi_dbm = '?'
1220 break
1221 if i == len(list) - 1:
1222 raise OSError("SSID invalid / failed to scan this wifi")
1223 start = time.time()
1224 print("Connection WiFi", end="")
1225 while (self.sta.ifconfig()[0] == '0.0.0.0'):
1226 if time.ticks_diff(time.time(), start) > timeout:
1227 print("")
1228 raise OSError("Timeout!,check your wifi password and keep your network unblocked")
1229 print(".", end="")
1230 time.sleep_ms(500)
1231 print("")
1232 print('WiFi(%s,%sdBm) Connection Successful, Config:%s' % (ssid, str(wifi_dbm), str(self.sta.ifconfig())))
1233
1234 def disconnectWiFi(self):
1235 if self.sta.isconnected():
1236 self.sta.disconnect()
1237 self.sta.active(False)
1238 print('disconnect WiFi...')
1239
1240 def enable_APWiFi(self, essid, password=b'',channel=10):
1241 self.ap.active(True)
1242 if password:
1243 authmode=4
1244 else:
1245 authmode=0
1246 self.ap.config(essid=essid,password=password,authmode=authmode, channel=channel)
1247
1248 def disable_APWiFi(self):
1249 self.ap.active(False)
1250 print('disable AP WiFi...')
1251
1252
1253# 3 rgb leds
1254rgb = NeoPixel(Pin(17, Pin.OUT), 3, 3, 1, brightness=0.3)
1255rgb.write()
1256
1257# light sensor
1258light = ADC(Pin(39))
1259light.atten(light.ATTN_11DB)
1260
1261# sound sensor
1262sound = ADC(Pin(36))
1263sound.atten(sound.ATTN_11DB)
1264
1265# buttons
1266class Button:
1267 def __init__(self, pin_num, reverse=False):
1268 self.__reverse = reverse
1269 (self.__press_level, self.__release_level) = (0, 1) if not self.__reverse else (1, 0)
1270 self.__pin = Pin(pin_num, Pin.IN, pull=Pin.PULL_UP)
1271 self.__pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self.__irq_handler)
1272 # self.__user_irq = None
1273 self.event_pressed = None
1274 self.event_released = None
1275 self.__pressed_count = 0
1276 self.__was_pressed = False
1277 # print("level: pressed is {}, released is {}." .format(self.__press_level, self.__release_level))
1278
1279
1280 def __irq_handler(self, pin):
1281 irq_falling = True if pin.value() == self.__press_level else False
1282 # debounce
1283 time.sleep_ms(10)
1284 if self.__pin.value() == (self.__press_level if irq_falling else self.__release_level):
1285 # new event handler
1286 # pressed event
1287 if irq_falling:
1288 if self.event_pressed is not None:
1289 schedule(self.event_pressed, self.__pin)
1290 # key status
1291 self.__was_pressed = True
1292 if (self.__pressed_count < 100):
1293 self.__pressed_count = self.__pressed_count + 1
1294 # release event
1295 else:
1296 if self.event_released is not None:
1297 schedule(self.event_released, self.__pin)
1298
1299
1300 def is_pressed(self):
1301 if self.__pin.value() == self.__press_level:
1302 return True
1303 else:
1304 return False
1305
1306 def was_pressed(self):
1307 r = self.__was_pressed
1308 self.__was_pressed = False
1309 return r
1310
1311 def get_presses(self):
1312 r = self.__pressed_count
1313 self.__pressed_count = 0
1314 return r
1315
1316 def value(self):
1317 return self.__pin.value()
1318
1319 def irq(self, *args, **kws):
1320 self.__pin.irq(*args, **kws)
1321
1322
1323
1324class Touch:
1325
1326 def __init__(self, pin):
1327 self.__touch_pad = TouchPad(pin)
1328 self.__touch_pad.irq(self.__irq_handler)
1329 self.event_pressed = None
1330 self.event_released = None
1331 self.__pressed_count = 0
1332 self.__was_pressed = False
1333 self.__value = 0
1334
1335 def __irq_handler(self, value):
1336 # when pressed
1337 if value == 1:
1338 if self.event_pressed is not None:
1339 self.event_pressed(value)
1340 self.__was_pressed = True
1341 self.__value = 1
1342 if (self.__pressed_count < 100):
1343 self.__pressed_count = self.__pressed_count + 1
1344 # when released
1345 else:
1346 self.__value = 0
1347 if self.event_released is not None:
1348 self.event_released(value)
1349
1350 def config(self, threshold):
1351 self.__touch_pad.config(threshold)
1352
1353 def is_pressed(self):
1354 if self.__value:
1355 return True
1356 else:
1357 return False
1358
1359 def was_pressed(self):
1360 r = self.__was_pressed
1361 self.__was_pressed = False
1362 return r
1363
1364 def get_presses(self):
1365 r = self.__pressed_count
1366 self.__pressed_count = 0
1367 return r
1368
1369 def read(self):
1370 return self.__touch_pad.read()
1371
1372
1373# button_a = Pin(0, Pin.IN, Pin.PULL_UP)
1374# button_b = Pin(2, Pin.IN, Pin.PULL_UP)
1375button_a = Button(0)
1376button_b = Button(2)
1377
1378
1379# touchpad
1380touchpad_p = touchPad_P = Touch(Pin(27))
1381touchpad_y = touchPad_Y = Touch(Pin(14))
1382touchpad_t = touchPad_T = Touch(Pin(12))
1383touchpad_h = touchPad_H = Touch(Pin(13))
1384touchpad_o = touchPad_O = Touch(Pin(15))
1385touchpad_n = touchPad_N = Touch(Pin(4))
1386
1387from gui import *
1388
1389
1390def numberMap(inputNum, bMin, bMax, cMin, cMax):
1391 outputNum = 0
1392 outputNum = ((cMax - cMin) / (bMax - bMin)) * (inputNum - bMin) + cMin
1393 return outputNum