如何燒錄 MicroPython 韌體到 ESP-01 參考 :
# MicroPython on ESP8266 (一) : 燒錄韌體
MicroPython 文件參考 :
# MicroPython tutorial for ESP8266 (官方教學)
# http://docs.micropython.org/en/latest/micropython-esp8266.pdf
# http://docs.micropython.org/en/latest/pyboard/library/usocket.html#class-socket
# http://docs.micropython.org/en/v1.8.7/esp8266/library/usocket.html#module-usocket
# https://gist.github.com/xyb/9a4c8d7fba92e6e3761a (驅動程式)
下面是我測試 512KB MicroPython 的紀錄, 主要參考了下面兩本書 :
# Python 程式設計入門 (博碩出版, 葉難) :
這本是我看過 Python 中文入門書籍寫得最深入詳盡的一本 (不是之一).
Source : 金石堂
這本書原文就寫得很棒, 原作者 Bill Lubanovic 筆調非常風趣, 譯者賴屹民翻譯功夫也是了得, 我覺得這本是最適合入門者看的第一本 Python 書, 原文書是歐萊禮出版的 "Introducing Python" :
Source : 歐萊禮
Python 的資料型態分為數值資料型態與容器資料型態, 數值資料型態有下列四種 :
- int (整數)
- float (浮點數)
- bool (布林)
- complex (複數, MicroPython 由於記憶體限制沒有實作)
- str (字串)
- tuple (元組)
- list (串列)
- dict (字典)
- set (集合)
直接輸入 int, float, str 等資料類型名稱可檢查該類型有無實作 :
<<< int
Traceback (most recent call last):
File "
Python 的內建函數 type() 則可檢查資料的型態 :
(
(
(
Traceback (most recent call last):
File "
Python 的數值資料型態有三種 : 整數 (int), 浮點數 (float), 以及複數 (complex). 支援複數使得 Python 在科學運算上具有其他語言沒有的優勢, 不過因為 MicroPython 是 Python 3 在嵌入式設備上的精簡版, 受大小限制不支援複數 :
>>> 1+1j
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: complex values not supported
另外 MicroPython 也沒有實作 decimal 函式庫 :
>>> from decimal import *
Traceback (most recent call last):
File "
一. 整數 (int) :
Python 3 的整數具有無限精準度, 可以表示極大整數直到記憶體容量的極限為止. MicroPython 的整數可以表示到多大呢? 表示 Googol (10 的 100 次方) 是沒問題的 :
>>> googol=10**100
>>> googol
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
表示 10**200 也沒問題 :
>>> googol*googol
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
但是 googol 的 googol 次方就不行了, 好像是記憶體溢位導致系統重置 (reset) :
>>> googol ** googol
ets Jan 8 2013,rst cause:1, boot mode:(3,7)
load 0x40100000, len 31888, room 16
tail 0
chksum 0x65
load 0x3ffe8000, len 1072, room 8
tail 8
chksum 0xa4
load 0x3ffe8430, len 3000, room 0
tail 8
chksum 0x0c
csum 0x0c
......
......
lŒŒŽbl`‚‚lû#4 ets_task(40100164, 3, 3fff827c, 4)
OSError: [Errno 2] ENOENT
OSError: [Errno 2] ENOENT
MicroPython v1.8.7-662-gf85fd79 on 2017-04-25; ESP module with ESP8266
Type "help()" for more information.
>>>
到底對 512KB 的 ESP-01 模組而言所能表示的整數是多少? 經過用二分法逐步測試發現, 10**2129 沒問題, 但 10**2130 就不行了.
>>> 10**2030
ets Jan 8 2013,rst cause:1, boot mode:(3,7)
load 0x40100000, len 31888, room 16
tail 0
chksum 0x65
load 0x3ffe8000, len 1072, room 8
Python 的算術運算子有如下七個 :
基本的算術運算測試如下 :運算子 | 說明 |
x + y | 加法運算 |
x - y | 減法運算 |
x * y | 乘法運算 |
x / y | 除法運算 |
x // y | 整數除法運算 |
x ** y | 冪次運算 |
x % y | 取餘數運算 |
>>> 1+2+3+4+5+6+7+8+9+10
55
>>> 1 - 2-3
-4
>>> 2*3
6
>>> 1+2*3 #先乘除後加減
7
>>> (1+2)*3 #用括號改變優先順序
9
>>> 11/3 #一般除法 (只精確到小數後第 5 位四捨五入)
3.66667
>>> 11//3 #整數除法 (求商)
3
>>> 11%3 #整數除法 (求餘數)
2
>>> divmod(11,3) #求商與餘數 (傳回 tuple, 前為商, 後為餘數)
(3, 2)
>>> 11/0 #除以 0 會導致例外
Traceback (most recent call last):File "
>>> 10**3 #次方
1000
>>> a=10
>>> a += 10 #運算前 a=10
>>> a
20
>>> a -= 10 #運算前 a=20
>>> a
10
>>> a *= 10 #運算前 a=10
>>> a
100
>>> a //= 10 #運算前 a=100
>>> a
10
>>> a /= 10 #運算前 a=10
>>> a
1.0
Python 的整數字面值 (Linteral) 預設是 10 進位表示法, 除此之外也可以用 2 進位, 8 進位或 16 進位等基數系統來表示, 以 0b 或 0B 開頭的整數為 2 進位; 0o 或 0O 開頭為 8 進位; 0x 或 0X 開頭則為 16 進位, 如下所示 :
>>> 0b10
2
>>> 0B10
2
>>> 0o10
8
>>> 0O10
8
>>> 0x10
16
>>> 0X10
16
31
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (
Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 012 #被認為是 8 進位整數
10
但這在 Python 3 已經被廢棄了, 整數前面的 0 會被忽略去除 :
12
Python 內建函數 bin(), oct(), 與 hex() 可將 10 進位整數分別轉成 2, 8, 與 16 進位表示法 :
>>> bin(255)
'0b11111111'
>>> oct(255)
'0o377'
>>> hex(255)
'0xff'
除了使用字面值 (Literal) 直接產生整數物件外, 也可以用 Python 內建函數 int() 來建立 int 物件, 此函數能將整數或字串轉成 int 物件, 它可以傳入一或兩個參數 :
int(p1 [,p2])
第一個參數可以是整數字面值或字串, 只有當第一參數是字串時可以用第二參數指定要用哪種基數轉換, 而且不限 2, 8, 16 進位, 可以是任何進位, 最多可到 36 進位 (0~9, A~Z, 共 36 個符號, 大小寫不分), 可用 0, 2~36, 其中 0 表示依字串格式 :
int(p1 [,p2])
第一個參數可以是整數字面值或字串, 只有當第一參數是字串時可以用第二參數指定要用哪種基數轉換, 而且不限 2, 8, 16 進位, 可以是任何進位, 最多可到 36 進位 (0~9, A~Z, 共 36 個符號, 大小寫不分), 可用 0, 2~36, 其中 0 表示依字串格式 :
>>> int(3.14159)
3
>>> int("0b1111",2), int("0b1111")
(15, 15)
>>> int("0o20",8), int("0o20")
(16, 16)
>>> int("0xffff",16), int("0xffff")
(65535, 65535)
>>> int('0xff',0)
255
>>> int('ABCXYZ1230',36) #36 進位轉成 10 進位
1047646094138316>>> int('ABCXYZ1230',37) #第二個參數只能 2~36
Traceback (most recent call last):
File "
但是如果格式不符合要求會產生錯誤 :
>>> int("0o20",10)
Traceback (most recent call last):
File "
>>> int("0o20",16)
Traceback (most recent call last):
File "
運算子 | 說明 |
~x | 位元 NOT 運算, 每一個位元做 0 變 1 與 1 變 0 運算 |
x< | 位元左移運算, 運算元 x 的每一個位元往左移 y 次, 右方補 0 |
x>>y | 位元右移運算, 運算元 x 的每一個位元往右移 y 次, 左方補 0 |
x&y | 位元 AND 運算, 運算元 x 與 y 的相對位元做 AND 運算 |
x|y | 位元 OR 運算, 運算元 x 與 y 的相對位元做 OR 運算 |
x^y | 位元 XOR 運算, 運算元 x 與 y 的相對位元做 XOR 運算 |
左移運算值會變大, 每左移一位元增大 2 倍 (乘以 2); 而右移運算值會變小, 每右移一位元減小 2 倍 (除以 2), 例如 :
>>> 2<<1
4
>>> 4<<1
8
>>> 8<<1
16
>>> 16>>1
8
>>> 8>>1
4
>>> 4>>1
2
>>> 2>>1
1
>>> 1>>1
0
>>> 2<<3
16
浮點數 (float 型別) 可以用小數點與科學表示法 e 或 E (10 的次方之意, 不是自然指數的 e) 來表示, 但小數在 MicroPython 只能表示到小數點後 5 位四捨五入 (
>>> 1.23456789
1.23457
>>> 3.1415926 #圓周率
3.14159
>>> 6.02e23 #亞佛加厥數
6.02e+23
>>> 6.626070040e-34 #普郎克常數
6.62607e-34
>>> 1.38064852e-23 #波茲曼常數
1.38065e-23
MicroPython 浮點數絕對值用科學表示法最大到 3e48, 最小約為 1e-40 :
3.4e+38
>>> 3.41e38
inf
>>> 1e-39
1e-39
>>> 1e-40
9.99967e-41 #開始有誤差
>>> 1e-43
9.52883e-44 #誤差變大
>>> 1e-445.60519e-45 #誤差更大
>>> 1e-45
0.0 #太小變 0 了
>>> for i in range(10):
... s += 0.1
...
...
...
>>> sum==1
False #竟然不是 1
>>> sum==1.0
False #竟然不是 1
>>> s
0.999999 #理論值為 1.0, 實際上是 0.999999
>>> (s-1) <= 0.0000000001 #與理論值的差比較小於容許誤差就可認為相等
True
除了用字面值建立浮點數物件外, 還可以用內建函數 float() 來建立 float 物件, 它只有一個參數, 可傳入整數或浮點數字面值, 或者是一個字串, 傳回一個 float 物件 :
>>> float() #沒有傳入參數預設為 0.0
0.0
>>> float(123), float(-123)
(123.0, -123.0)
>>> float(3.1415926) #精確度為小數點後五位
3.14159
>>> float('3.1415926') #傳入字串
3.14159
>>> float('1.23456789e23')
1.23457e+23
>>> float(3.4e38) #科學表示法最大為 3.4e38
3.4e+38
>>> float(3.41e38)
inf
>>> float(1e-38)
1e-38
>>> float(1e-39)
1e-39
>>> float(1e-40) #開始有誤差
9.99967e-41
>>> float(1e-43)
9.52883e-44
>>> float(1e-44)
5.60519e-45
>>> float(1e-45) #太小變 0 了
0.0
與浮點數運算相關最常用的內建函數是 round(), 可以傳入一或兩個參數, 其中第二參數是指定四捨五入到小數點後第幾位, MicroPython 只能表示到小數後 5 位, 故第二參數大於 5 之後結果都一樣, 直到 39 時會傳回一個特殊值 nan (非數字, not a number), 例如 :
<<< round(3.1415926)
更奇怪的是, round() 在 Python 3 有向偶數靠攏的怪癖 (參考上述葉難書中的 3-1 節), 例如 :
3
<<< round(3.1415926,1)
3.1
<<< round(3.1415926,2)
3.14
<<< round(3.1415926,3)
3.142
<<< round(3.1415926,4)
3.1416
<<< round(3.1415926,5)
3.14159
<<< round(3.1415926,6)
3.14159
<<< round(3.1415926,38)
3.14159
<<< round(3.1415926,39)
nan
<<< round(1.5),round(-1.5)
(2, -2)
<<< round(2.5),round(-2.5)
(2, -2)
<<< round(3.5),round(-3.5)
(4, -4)
<<< round(4.5),round(-4.5)
(4, -4)
<<< round(5.5),round(-5.5)
(6, -6)
<<< round(6.5),round(-6.5)
(6, -6)
藍色部分是預期要四捨五入進位到個位數得到 (3, -3), (5, -5), 以及 (7,-7) 的, 但結果卻是捨去 .5 而倒向偶數. 此特性在使用 round() 進行數學計算時必須注意, 否則會得到非預期結果.
而在 Python 2.x 執行結果卻不是這樣 :
C:\Users\Tony>py -2
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> round(1.5),round(-1.5)
(2.0, -2.0)
>>> round(2.5),round(-2.5)
(3.0, -3.0)
>>> round(3.5),round(-3.5)
(4.0, -4.0)
>>> round(4.5),round(-4.5)
(5.0, -5.0)
>>> round(5.5),round(-5.5)
(6.0, -6.0)
>>> round(6.5),round(-6.5)
(7.0, -7.0)
而在 Python 2.x 執行結果卻不是這樣 :
C:\Users\Tony>py -2
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> round(1.5),round(-1.5)
(2.0, -2.0)
>>> round(2.5),round(-2.5)
(3.0, -3.0)
>>> round(3.5),round(-3.5)
(4.0, -4.0)
>>> round(4.5),round(-4.5)
(5.0, -5.0)
>>> round(5.5),round(-5.5)
(6.0, -6.0)
>>> round(6.5),round(-6.5)
(7.0, -7.0)
感覺 Python 2.x 的 round() 處理四捨五入方式較合理, 但據說 Python 3 改成這樣其實是符合 IEEE 754 預設規範的, 參考 :
# Python 3.x rounding behavior
此文的回應中提到 IEEE 754 裡面有五種處理浮點數 rounding 的方式, 而 Python 2.x 所用的四捨五入只是其中一種. 英文 Rounding 一般翻成四捨五入其實是有偏見的, 正確的翻譯應該是 "湊整", 就是湊成一個鄰近的整數.
Python 3 所採用的是 IEEE 754 的預設湊整方式 : rounding to even (湊整到最近的偶數). 四捨五入法 (rounding up) 是原數加 0.5 的方式進行湊整, 此法在大部分數據趨向於兩個整數中間值 (x.4, x.5, x.6 附近) 時會造成平均值與其他統計量的較明顯偏差. 參考 :
# What's the difference between round up, round down and round off?
"There are two schools of thought on this. One is to round UP in this situation. Rounding off is then analogous to adding 0.5 to the number and rounding DOWN the result. This is simple and computers often use this method of rounding off. However, when dealing with a large set of numbers (many being half way between two integers), this process will introduce a bias which would affect the mean of the numbers and other statistics.
The other school of thought is to round OFF to the nearest EVEN integer. This is not that difficult to code in a computer and eliminates any bias that might be introduced in the rounding process."
另外有三個特殊的浮點數 float('nan'), float('inf'), 以及 float('-inf'), 分別用來表示非數值 (nan), 正無窮大 (inf), 以及負無窮大 (-inf). 當浮點數超過硬體所能表示最大值時就會得到 inf, 在 ESP-01 大於 3.4e34 就被認為是 inf. 而 nan 會在無法進行的數學運算時產生, 例如 :
>>> 3.4e38
3.4e+38
>>> 3.41e38
inf>>> -3.4e38
-3.4e+38
>>> -3.41e38
-inf
>>> 3.41e38/3.41e38
nan
三. 布林值 (bool) :
布林 (bool) 是 Python 最簡單的資料型態, 其值只有 True 與 False 兩個 (注意首字母需大寫, true 與 false 都不是布林值), 布林 True 與 False 的值 (value) 其實就是整數 1 與 0, 用值的比較運算子 == 去比較會傳回真, 但是 True/False 與 1/0 的物件參考不同, 因此用參考比較運算子 is 去比較時都會傳回 False (因參考不同, 記憶體位址也不同之故), 例如 :
<<< True==1 #True 與 1 的值相同
True
<<< False==0 #False 與 0 的值相同
True
<<< True is 1 #True 與 1 的物件參考不同
False
<<< False is 0 #False 與 0 的物件參考不同
False
利用內建函數 int() 函數可以將布林值轉成 1 與 0, 轉換後值與參考均相同, 例如 :
<<< int(True) #True 會轉成 1 的 int 物件
1
<<< int(False) #False 會轉成 0 的 int 物件
0
<<< int(True)==1 #值相同
True
<<< int(False)==0 #值相同
True
<<< int(True) is 1 #物件參考相同
True
<<< int(False) is 0 #物件參考相同
True
因為 True 與 False 的值為 1 與 0, 因此可以進行四則運算, 雖然看起來沒甚麼意義 :
<<< True + 1
2
<<< False + 1
1
<<< True + 1.1
2.1
<<< False + 1.1
1.1
與布林值相關的運算子有邏輯運算與關係運算, 邏輯運算子有三個 :
例如 :
>>> not True
False
>>> not False
True
>>> True and False
False
>>> True and True
True
>>> False and True
False
>>> False and False
False
Python 沒有提供邏輯互斥或運算子 xor (但有提供互斥或運算子 ^), 不過互斥或運算子可以用 and 與 or 運算來組合, 其真值是只有當兩個運算元相異時才傳回真, 此為互斥名稱由來 :
x xor y=(x or y) and not (x and y)
參考 : 邏輯異或
例如 :
>>> x,y=True,True
>>> (x or y) and not (x and y)
False
>>> x,y=False,False
>>> (x or y) and not (x and y)
False
>>> x,y=True,False
>>> (x or y) and not (x and y)
True
>>> x,y=False,True
>>> (x or y) and not (x and y)
True
Python 內建函數 bool() 可以將其他資料類型轉換成布林型態, 除了空值 (空字串, 0, None) 以外都傳回 True, 例如 :
>>> bool(None) #無值
False
>>> bool('') #空字串
False
>>> bool("") #空字串
False
>>> bool(()) #空元組
False
>>> bool([]) #空串列
False
>>> bool(0)
False
>>> bool(1)
True
>>> bool(2)
True
而關係運算子則有下列六個 :
例如 :
>>> 1==1
True
>>> 1>1
False
>>> 2>1
True
>>> 1<1
False
>>> 1<2
True
>>> 1>=1
True
>>> 1>=2
False
>>> 1<=1
True
>>> 1<=0
False
>>> 1!=2
True
>>> 1!=1
False
>>> 1==1
True
>>> 1==2
False
四. 複數 (compound) :
支援複數是 Python 的特色, 主要用在科學計算上面. 但對於用在嵌入式設備上的 MicroPython 來說用不到, 所以未支援 :
>>> 1+1j
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: complex values not supported
複數由實部 Real 與虛部 Imagine 組成 : R+ Ij, 其中 j 代表虛部, j 為 -1 的平方根, R 與 I 都是浮點數, 不過虛部若為 1 時不能省略, 否則 j 會被視為未宣告的變數而出現錯誤, 以下是在 CPython 上做的測試 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
<<< 1+1j
(1+1j)
<<< 1+j #虛部為 1 也必須寫出來
Traceback (most recent call last):
File "NameError: name 'j' is not defined
<<< 1+j1 #j 必須放在最後面
Traceback (most recent call last):
File "NameError: name 'j1' is not defined
<<< 1j**2 #j 的平方是 -1
(-1+0j)
<<< (1+j)*(1-j) #虛部為 1 也必須寫出來
Traceback (most recent call last):
File "NameError: name 'j' is not defined
<<< (1+1j)*(1-1j) #複數相乘運算
(2+0j)
<<< True + 1
2
<<< False + 1
1
<<< True + 1.1
2.1
<<< False + 1.1
1.1
與布林值相關的運算子有邏輯運算與關係運算, 邏輯運算子有三個 :
運算子 | 說明 |
x and y | 邏輯 AND 運算, 須 x 與 y 均為 True 時才傳回 True, 否則為 False |
x or y | 邏輯 OR 運算, 只要 x 或 y 有一個為 True 時就傳回 True |
not x | 邏輯 NOT 運算, 若 x 為 True 就傳回 False, 否則傳回 True |
例如 :
>>> not True
False
>>> not False
True
>>> True and False
False
>>> True and True
True
>>> False and True
False
>>> False and False
False
>>> True or False
True
>>> True or True
True
>>> False or True
True
>>> False or False
False
Python 沒有提供邏輯互斥或運算子 xor (但有提供互斥或運算子 ^), 不過互斥或運算子可以用 and 與 or 運算來組合, 其真值是只有當兩個運算元相異時才傳回真, 此為互斥名稱由來 :
x xor y=(x or y) and not (x and y)
參考 : 邏輯異或
例如 :
>>> x,y=True,True
>>> (x or y) and not (x and y)
False
>>> x,y=False,False
>>> (x or y) and not (x and y)
False
>>> x,y=True,False
>>> (x or y) and not (x and y)
True
>>> x,y=False,True
>>> (x or y) and not (x and y)
True
>>> bool(None) #無值
False
>>> bool('') #空字串
False
>>> bool("") #空字串
False
>>> bool(()) #空元組
False
>>> bool([]) #空串列
False
>>> bool(0)
False
>>> bool(1)
True
>>> bool(2)
True
而關係運算子則有下列六個 :
運算子 | 說明 |
x > y | 大於運算 |
x < y | 小於運算 |
x >= y | 大於等於運算 |
x <= y | 小於等於運算 |
x != y | 不等於運算 |
x == y | 等於運算 |
例如 :
>>> 1==1
True
>>> 1>1
False
>>> 2>1
True
>>> 1<1
False
>>> 1<2
True
>>> 1>=1
True
>>> 1>=2
False
>>> 1<=1
True
>>> 1<=0
False
>>> 1!=2
True
>>> 1!=1
False
>>> 1==1
True
>>> 1==2
False
四. 複數 (compound) :
支援複數是 Python 的特色, 主要用在科學計算上面. 但對於用在嵌入式設備上的 MicroPython 來說用不到, 所以未支援 :
>>> 1+1j
Traceback (most recent call last):
File "<stdin>", line 1
SyntaxError: complex values not supported
複數由實部 Real 與虛部 Imagine 組成 : R+ Ij, 其中 j 代表虛部, j 為 -1 的平方根, R 與 I 都是浮點數, 不過虛部若為 1 時不能省略, 否則 j 會被視為未宣告的變數而出現錯誤, 以下是在 CPython 上做的測試 :
C:\Users\Tony>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
<<< 1+1j
(1+1j)
<<< 1+j #虛部為 1 也必須寫出來
Traceback (most recent call last):
File "
<<< 1+j1 #j 必須放在最後面
Traceback (most recent call last):
File "
<<< 1j**2 #j 的平方是 -1
(-1+0j)
<<< (1+j)*(1-j) #虛部為 1 也必須寫出來
Traceback (most recent call last):
File "
<<< (1+1j)*(1-1j) #複數相乘運算
(2+0j)