tag:blogger.com,1999:blog-61013896865049543972024-03-07T14:32:05.772+08:00Mee's Notes也許因為編輯工作的關係,書寫成為一種習慣。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.comBlogger223125tag:blogger.com,1999:blog-6101389686504954397.post-38226561951496066672021-05-10T10:12:00.001+08:002021-05-10T10:12:54.581+08:00『質量』很好, 到底是質好還是量多很多與我一樣的 5 年級生會不習慣對岸的用詞, 這倒不一定是對岸的用詞一定不好, 而是有些詞用起來就是很混淆。舉例來說, 『質量』一詞就很怪, 因為『質』與『量』是兩件事, 但是對岸口語上講的『質量』通常是指『質』, 例如, 『A 選手這一球質量很高, B 選手雖然接到了球卻無法回擊』, 不如就直接講『A 選手這一球力道很強』。『質』『量』不分, 實在很有問題。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com1tag:blogger.com,1999:blog-6101389686504954397.post-83090908472343736612020-09-11T13:55:00.007+08:002020-09-11T14:05:39.611+08:00在 linux 下複製資料夾內的所有檔案但不複製資料夾同事問了一個問題, 他想要只把 A 資料夾下包含子資料夾內的檔案通通複製到 B 資料夾下, 但是不要在 B 資料夾下建立各層的子資料夾, 例如:
<pre><code class="bash">$ ls -R test
test:
a.txt t2/
test/t2:
a2.txt</code></pre>
若希望把 test 下的 a.txt 和 test/t2 下的 a2.txt 複製到同一個資料夾下, 例如 dd 下, 但是不要在 dd 內建立 t2 資料夾, 這只靠 cp 指令的 -r 選項是做不到的。根據估狗大神幫我找到了<a href="https://superuser.com/questions/1078149/cp-only-files-skipping-directories" target="_blank">這一篇討論</a>, 找到了使用 <a href="https://linux.die.net/man/1/find" target="_blank">find</a> 指令的方式如下:
<pre><code class="bash">$ find test -type f -exec cp "{}" dd ";"
$ ls dd
a2.txt a.txt</code></pre>
find 指令可以使用 -exec 選項在每次找到一個檔案時執行指定的指令, 指令中的 {} 會被取代為找到的檔案名稱, -exec 到 ";" 之間就是要執行的指令。利用這個選項, 就可以為資料夾中的每一個檔案執行 cp 指令, 複製到同一個資料夾中了。上述指令中之所以要將 {} 以及 ; 用 "" 括起來, 是為了避免被 shell 執行 shell expansion 而出錯。
meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-81369382845175025252020-05-26T19:07:00.004+08:002020-05-26T19:12:36.185+08:00Arduino Keyboard 程式庫 println 沒有送出 Enter 的問題同事有一個程式模擬鍵盤輸入裝置, 使用了 Arduino 的 Keyboard 函式庫, 程式大概是這樣:
<pre><code class="CPP"> Keyboard.begin();
delay(2000);
Keyboard.press(KEY_LEFT_GUI);
delay(500);
Keyboard.press('r');
delay(500);
Keyboard.releaseAll();
Keyboard.println("NOTEPAD"); //輸入文字 NOTEPAD
delay(500);
</code></pre>
也就是模擬按了 <kbd>Win</kbd> + <kbd>r</kbd> 開啟 Widnows 的『執行』交談窗, 然後輸入 "notepad" 開啟記事本, 但是卻發現執行後只會停在『執行』交談窗, 少了最後按下 <kbd>Enter</kbd> 執行所輸入指令的動作。後來使用了新版的 Arduino IDE 重新編譯執行這個程式卻又正常, 可以開啟記事本, 經過<a href="https://github.com/arduino-libraries/Keyboard/issues/13" target="_blank">查證</a>, 才發現 Arduino IDE 1.8.5 (含) 之前的 Keyboard 程式庫有問題, 1.8.6 就修正了。這個問題主要在於 Keyboard 是繼承自 Print 類別, Print 的 println 會使用字串版的 write 輸出字串, 程式如下:
<pre><code class="CPP">size_t Print::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
while (size--) {
if (write(*buffer++)) n++;
else break;
}
return n;
}
</code></pre>
在 while 迴圈中, 如果目前輸出的字元是 0, 就會當成是字串結尾, 跳離迴圈;否則會叫用字元版的 write() 輸出單一字元, 而在 Keyboard 類別中重新定義了這個字元版的 write(), 程式如下:
<pre><code class="CPP">size_t Keyboard_::write(uint8_t c)
{
uint8_t p = press(c); // Keydown
release(c); // Keyup
return p; // just return the result of press() since release() almost always returns 1
}
</code></pre>
這主要就是模擬按下並放開鍵盤上對應該字元按鍵的動作, 不過 press() 中會把 ASCII 碼透過 _asciimap 這個陣列轉換成對應按鍵的掃描碼, 而 '\r' (CR, 0x0D) 會對應到掃描碼 0:
<pre><code class="CPP">const uint8_t _asciimap[128] =
{
0x00, // NUL
0x00, // SOH
0x00, // STX
0x00, // ETX
0x00, // EOT
0x00, // ENQ
0x00, // ACK
0x00, // BEL
0x2a, // BS Backspace
0x2b, // TAB Tab
0x28, // LF Enter
0x00, // VT
0x00, // FF
0x00, // CR
......
</code></pre>
使得字元版的 write() 傳回 0, 導致字串版的 write() 認為字串結束而返回。由於 println() 在送出字串後會再送出 "\r\n", 也就是 CRLF 當成換行, 因此處理到 '\r' 就被當成字串結束而停止, 最後的 '\n' 就沒有機會送出, 因此不會模擬成按下 <kbd>Enter</kbd> 了。
為了修正這個問題, 從 Arduino 1.8.6 開始, Keyboard 類別就重新定義了<a href="https://github.com/arduino-libraries/Keyboard/commit/7d7681fc102d75edd32d62b6e452ef982e3d860f#diff-25d902c24283ab8cfbac54dfa101ad31" target="_blank">自己的 write() 版本</a>, 如下所示:
<pre><code class="CPP">size_t Keyboard_::write(const uint8_t *buffer, size_t size) {
size_t n = 0;
while (size--) {
if (*buffer != '\r') {
if (write(*buffer)) {
n++;
} else {
break;
}
}
buffer++;
}
return n;
}
</code></pre>
你可以看到當遇到 'r' 字元時, 它會當成沒看到, 繼續處理下一個字元, 這樣就可以避免上述問題了。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-61054607504200610372020-05-26T16:14:00.003+08:002020-05-26T19:17:15.950+08:00判斷 Arduino IDE 版本由於同事遇到一個怪問題, 需要根據 Arduino IDE 版本使用不同的程式, 查了一下才知道, Arduino 在編譯時會定義一個巨集 ARDUINO, 格式為類似 10812, 表示 1.8.12 版, 只要利用 #if 判斷, 即可區別不同版本的 Arduino IDE 了, 例如:
<pre><code class="CPP">#if ARDUINO<=10805
Keyboard.press(KEY_RETURN); //按下 Enter
Keyboard.release(KEY_RETURN);
#endif
</code></pre>
就可以讓程式只有在 Arduino IDE 版本為 1.8.5(含) 之前的版本才會執行, 教新的版本就不會執行了。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-33465579060496479802020-04-12T01:07:00.000+08:002020-04-12T01:32:30.140+08:00在 WSL 1/2 執行 GUI 程式WSL 很好用, 不過預設的情況下你只有 Terminal 跑 Shell 可以用, 如果想要測試一些圖形化界面的程式, 就要借助額外的程式, 好在已經有許多善心人士提供了免費的 X server 軟體, 可以在 Windows 環境裡執行 GUI 程式。我自己習慣使用的是 <a href="https://mobaxterm.mobatek.net/">mobaXterm</a> 軟體, 預設安裝好並不需要其他設定, 只要執行就會啟動 X server。接著, 就可以在 WSL 裡設定 X server 的位址與螢幕編號:<br />
<pre><code class="bash">export DISPLAY=:0</code></pre>上例中表示 X server 的位址就是 localhost, 或者 127.0.0.1, 螢幕編號為 0, 也就是第一個螢幕。設定好之後就可以執行 GUI 程式, 例如 gvim:<br />
<br />
<blockquote class="imgur-embed-pub" lang="en" data-id="DBQrgtf"><a href="//imgur.com/DBQrgtf">View post on imgur.com</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script><br />
<br />
如果使用 WSL2, 它會像是 VirtulaBox 一樣幫你建立一個虛擬網路界面, 你可以透過 Windows 下的 ipconfig 指令看到有一個網路界面名稱裡面有一個有 WSL 字樣, 就會標示這個界面中 Windows 這一端的 IP:<pre><code>D:\wsl2 ❯❯❯ ipconfig
Windows IP 設定
....
乙太網路卡 vEthernet (WSL):
連線特定 DNS 尾碼 . . . . . . . . :
連結-本機 IPv6 位址 . . . . . . . : fe80::2d93:534a:4692:bc2e%53
IPv4 位址 . . . . . . . . . . . . : 172.31.80.1
子網路遮罩 . . . . . . . . . . . .: 255.255.240.0
預設閘道 . . . . . . . . . . . . .:</code></pre><br />
172.31.80.1 就是 Windows 在這個虛擬網路中的 IP 位址。或者你也可以在 WSL2 中使用 ip route 指令查看, 就可以知道 Windows 那一端的 IP:<pre><code class="bash">$ip route
default via 172.31.80.1 dev eth0
172.31.80.0/20 dev eth0 proto kernel scope link src 172.31.86.214</code></pre>上述設定 X server 位址的指令就要改成:<br />
<pre><code class="bash">export DISPLAY=172.31.80.1:0</code></pre>才能正確連到 X server。<br />
meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-63565953901679029582020-04-12T00:32:00.001+08:002020-04-12T01:08:59.111+08:00WSL2 與 VirtualBox 不相容<a href="https://docs.microsoft.com/zh-tw/windows/wsl/wsl2-index">WSL2 </a>因為使用了 Hyper-V 虛擬機器, 所以比透過 API 轉換層執行的 WSL1 快得多, 不過也因為這個原因, 和 VirtualBox 並不相容, 即使使用了支援 HyperV 的 VirtualBox 6.X 版也一樣, 如果你在啟用了 WSL2 的系統上使用 VirtualBox 安裝例如 Linux 作業系統, 就會遇到到一些靈異現象, 像是我自己就遇到安裝到最後不成功, 或是好像安裝成功, 但是使用時執行 git clone 老是說什麼 hashcode 不對、或者是下載 .deb 檔但要透過 dpkg 安裝卻解壓縮失敗之類的。目前若要同時使用 WSL 與 VirtualBox, 就必須改用 WSL1, 而且要確認沒有啟用『虛擬機器平台』功能:<br />
<br />
<blockquote class="imgur-embed-pub" lang="en" data-id="TsZy2LD"><a href="//imgur.com/TsZy2LD">View post on imgur.com</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script><br />
<br />
另外, 也要確認 WSL2 要求你要安裝的 <a href="https://docs.microsoft.com/zh-tw/windows/wsl/wsl2-kernel">WSL2 Linux kernel update package</a> 也要移除, 才能正常使用 VirtualBox。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-10250476822834596652020-04-11T22:14:00.001+08:002020-04-11T22:14:57.801+08:00VIM 的眾多版本差異在 Linux 上安裝 vim 如果沒有特別指名套件名稱, 例如:<br />
<pre><code class="bash">sudo apt install vim</code></pre>那麼安裝的會是 vim-common 套件, 這個套件只會安裝文字模式的 vim, 不會安裝圖形化版本的 gvim, 而沒有圖形化版本的套件, 邊一時是不會加上 +xterm_clipboard 模組的, 也就是無法讓 vim 複製資料到系統剪貼區 (clipboard), 也無法從剪貼區貼資料到 vim 中。<br />
<br />
因此, 建議在安裝 vim 時, 可以選擇有圖形化版本的套件, 例如:<br />
<ul><li>vim-gui-common:通用行的圖形化版本, 如果沒有什麼特別需求, 或是面對以下版本不知道該選那一種, 就可以安裝這個版本。</li>
<li>vim-athena:採用 X Athena 圖形元件程式庫的版本, 如果你執行這個套建中的 gvim, 會注意到他的圖形界面長的很不一樣, 那就是 X Athena 程式庫。這個版本體積小一點, 如果你不介意界面長的怪怪的, 或者根本就不會執行 gvim, 那安裝這個版本根本沒差。</li>
<li>vim-gtk/vim-gtk3:搭配 gtk 同行界面程式庫的版本, gvim 的界面看起來會正常許多。如果你的環境本來就會用到許多使用 gtk 建制的軟體, 那就可以安裝這一個套件。</li>
</ul>如果你根本不會執行 gvim, 也不在乎能不能與系統剪貼簿交換資料, 那麼也可以安裝 vim-tiny 套件, 這個套件是 vim-common 的精簡版, 最主要的差別是 vim-tiny 只能使用 vim 語法撰寫 vim 腳本, 無法使用 Python 或是其他程式語言撰寫 vim 腳本。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-13151209244727886192020-03-19T19:41:00.001+08:002020-04-08T08:33:46.685+08:00ESP8266 MicroPython 所有的 PWM 都是同一頻率下午看了一下 ESP8266 MicroPython 的原始碼, 才發現原來所有的 PWM 都是共同頻率, 無法個別設計, 無論使用哪一個 PWM 物件叫用 freq(), 都會影響到所有的 PWM 物件。原始碼中實際設定頻率的程式如下:<br />
<pre><code class="C++">void ICACHE_FLASH_ATTR
pwm_set_freq(uint16 freq, uint8 channel) {
LOCK_PWM(critical); // enter critical
if (freq > PWM_FREQ_MAX) {
pwm.freq = PWM_FREQ_MAX;
} else if (freq < 1) {
pwm.freq = 1;
} else {
pwm.freq = freq;
}
pwm.period = PWM_1S / pwm.freq;
UNLOCK_PWM(critical); // leave critical
}
</code></pre>你可以看到雖然函式有 channel 參數, 但在函式內根本不會用到這個參數, 而且頻率是記錄在 pwm.freq 中, 不會區分是那個 channel 的頻率。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-81428542259155838542020-03-18T16:18:00.000+08:002020-03-18T16:18:00.384+08:00改用 highlight.js 為文章中的程式碼加上語法顏色標示原本使用的 <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a> 在 Blogger 上一整個炸壞掉, 現在改用 <a href="https://highlightjs.org/">highlight.js</a>, 快速簡單, 中間也考慮過 Google 的 <a href="https://github.com/google/code-prettify">code-prettify</a>, 但是會有程式過長疊到右邊側欄內容的問題。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-82682334410502468002020-03-18T14:13:00.013+08:002020-09-11T14:19:35.007+08:00ESP8266 MicroPython PWM 的奇怪現象同事在使用 ESP8266 的 MicroPython 時, 使用 PWM 製作呼吸燈, 但卻遇到了奇怪的狀況, 程式如下:<br />
<pre><code class="python">from machine import Pin, PWM
import utime
# R:D5 G:D6 B:D7
r = PWM(Pin(14, Pin.OUT), freq=500, duty=0)
# this line would make PWM work in a strange way
g = PWM(Pin(12, Pin.OUT), freq=500, duty=0)
b = PWM(Pin(13, Pin.OUT), freq=500, duty=0)
while True:
for i in range(512):
b.duty(i)
#g.duty(i)
r.duty(i)
utime.sleep_ms(1)
for i in reversed(range(512)):
b.duty(i)
#g.duty(i)
r.duty(i)
utime.sleep_ms(1)
</code></pre><p>其實就是簡單的用 2 個腳位 PWM 從 0~512 再回到 0 製作陽春的呼吸燈效果, 不過執行後卻發現其中一個燈看起來一直亮著、另外一個燈卻偶而才閃一下, 根本沒有 PWM 漸次變化的效果。</p><p>
經過實驗測試後發現, 程式一開始建立了 3 個 PWM 物件, 但是 g 這個 PWM 物件卻沒有用到, 如果不要建立這個多餘的 PWM 物件 g , 或是在實際上有使用到 g 物件, 例如把程式中 for 迴圈內的註解符號移除, 結果就正常了。目前還不知道實際發生問題的原因。</p><p>
20200830 補充:這個問題我有貼到<a href="https://forum.micropython.org/viewtopic.php?f=16&t=8034&p=50553#p50553"> MicroPython 論壇</a>上, 經過善心人士回饋到<a href="https://github.com/micropython/micropython/pull/5966"> MicroPython github</a> 上後, 已經把 bug 解掉了, 如果你改用 2020/3/27 之後的韌體版本, 就不會發生一樣的問題了。</p>
20200909 補充:在 2020/09/02 發佈的 <a href="http://micropython.org/resources/firmware/esp8266-20200902-v1.13.bin" target="_blank">1.13 版韌體</a>中, 已經將上述修正併入正式版本了。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-15445115676635321432020-02-14T18:14:00.001+08:002020-02-14T18:15:44.871+08:00macOS 的 APFS 與 HFS+ 檔案系統對磁碟影像檔的影響如果要製作磁碟影像檔, 由於 macOS 在 High Sierra(也就是 10.13) 以後的預設檔案系統是 APFS, 因此若沒有更改設定, 指定使用 HFS+ 檔案系統, 製作出來的磁碟影像檔就無法在舊版的作業系統上開啟。製作影像檔時請務必小心:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5Iaj304TzU9u3mT1sEV2MRxhJ-nPG16YcrQVHsa8sQZEBe_-WRyGMXwO-zOIsN7H3hA4Q-UFrMtSiz3MCAyKQTBkRrTlHhqFzKFKdUYzLABDj7D6l9NFFX2V19WlI7JbSSGcD3p-HtGog/s1600/%25E6%2588%25AA%25E5%259C%2596+2020-02-14+%25E4%25B8%258B%25E5%258D%25886.07.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5Iaj304TzU9u3mT1sEV2MRxhJ-nPG16YcrQVHsa8sQZEBe_-WRyGMXwO-zOIsN7H3hA4Q-UFrMtSiz3MCAyKQTBkRrTlHhqFzKFKdUYzLABDj7D6l9NFFX2V19WlI7JbSSGcD3p-HtGog/s400/%25E6%2588%25AA%25E5%259C%2596+2020-02-14+%25E4%25B8%258B%25E5%258D%25886.07.09.png" width="400" height="263" data-original-width="1037" data-original-height="682" /></a></div><br />
meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-49638813334370559952020-02-03T15:38:00.002+08:002020-03-18T16:08:22.686+08:00MicroPython 文件上 framebuffer 的 framebuf.MONO_HLSB 與 framebuf.MONO_HMSB 說明反了在 MicroPython 的文件中, <a href="https://docs.micropython.org/en/latest/library/framebuf.html#framebuf.framebuf.MONO_HLSB">framebuffer</a> 的說明中對於 framebuf.MONO_HLSB 這樣一段:<br />
<br />
<blockquote>Monochrome (1-bit) color format This defines a mapping where the bits in a byte are horizontally mapped. Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. </blockquote><br />
因此, 如果有以下的 8X8 的圖:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://i.imgur.com/2oLqPL1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://i.imgur.com/2oLqPL1.png" data-original-width="178" data-original-height="177" /></a></div><br />
就應該表示為這樣:<br />
<pre><code class="python">[0b10001001,
0b00001001,
0b00001001,
0b00001001.
0b00001001.
0b00000001,
0b00000001,
0b00000001]</code></pre>不過實際上顯示出來的圖左右會相反, 因此推測文件上 framebuf.MONO_HLSB 與 framebuf.MONO_HMSB 的說明應該是弄反了。在 <a href="https://forum.micropython.org/viewtopic.php?f=15&t=7683&sid=67c3dfa39627a1ded4570a50f50efa0b">MicroPython Forum 上也有人確認我的疑問</a>。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-13825543978421286962019-12-23T14:54:00.001+08:002020-03-18T15:41:42.730+08:00Maixduino 編譯 selfie 範例出現 "cannot declare variable 'camera' to be of abstract type 'Sipeed_OV2640'" 錯誤在編譯 Maixduino 板的 selfie 範例時, 竟然出現以下錯誤:<br />
<blockquote>cannot declare variable 'camera' to be of abstract type 'Sipeed_OV2640'</blockquote>經過查證, 在<a href="https://github.com/sipeed/Maixduino/issues/59">這一篇文章</a>中提到在 0.3.11 版的原始碼中, Sipeed_OV2640 類別的內容把虛擬函式的名字 setRota<b>t</b>ion 打錯字變成 setRotaion, 導致繼承自 Camera 類別的 setRotation 虛擬函式沒有實作的內容, 讓 Sipeed_OV2640 類別仍舊是虛擬類別, 無法用來建立物件。解決的方法很簡單, 就是自己去 c:\users\你的使用者名稱\AppData\Local\Arduino15\packages\Maixduino\hardware\k210\0.3.11\libraries\Sipeed_OV2640\src 下, 把 Sipeed_OV2640.h 以及 Sipeed_OV2640.cpp 中的錯字 setRotaion 更正為 setRota<b>t</b>ion 就可以了。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-23206557458854181102019-11-26T20:07:00.001+08:002020-03-18T16:09:06.012+08:00MacOS Catalina App 『已損毀,無法打開。你應該將其丟到「垃圾桶」』的錯誤訊息MacOS 升級到 Catalina 後, 一定會被他嚴密的安全控管驚嚇, 比如說, 你從 Arduino 官網下載了 Arduino, 可以正常執行, 但如果你把這個 Arduino 上傳到 Google 雲端硬碟, 然後再從雲端硬碟下載回來, 一執行可能就會遇到這樣的畫面:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf9HeLPksVrWN4i4Po63zb8J-ma0mFQhnqnCiaQQMqrlrWZiKwUDrOkoMsUMrL2vaP_diDsFZ0a-Z1PMKVT4Bu8QneNd2ifGVYjARMvP_hJiwPd3L8wl7IrwgBUwQYWDmq25mIBp9T_GuK/s1600/%25E6%2588%25AA%25E5%259C%2596+2019-11-26+%25E4%25B8%258B%25E5%258D%25887.41.44.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf9HeLPksVrWN4i4Po63zb8J-ma0mFQhnqnCiaQQMqrlrWZiKwUDrOkoMsUMrL2vaP_diDsFZ0a-Z1PMKVT4Bu8QneNd2ifGVYjARMvP_hJiwPd3L8wl7IrwgBUwQYWDmq25mIBp9T_GuK/s1600/%25E6%2588%25AA%25E5%259C%2596+2019-11-26+%25E4%25B8%258B%25E5%258D%25887.41.44.png" data-original-width="488" data-original-height="223" /></a></div><br />
這是因為 Catalina 會自動幫不是從註冊網站下載回來的 App 加上註記, 執行時會根據註記的資料, 判斷是否可安全執行。你可以透過以下的指令觀察註記資料:<br />
<pre><code class="bash">xattr -l Arduino.app/
com.apple.quarantine: 0181;5ddd072e;Firefox;BCD73B6E-DE9E-4821-93E6-C73238A5F5AF</code></pre>xattr 是操作檔案延伸屬性的指令, 這裡可以看到 Arduino.app 有一項延伸屬性, 屬性名稱是 com.apple.quarantine, 而屬性內容是雖然是編碼過的資料, 但可以看到註記了此 App 是使用 Firefox 下載回來的, 只要將此註記資料刪除, Catalina 就不會檢查 App 是不是從註冊網站下載的, 也就可以正常執行了。刪除此註記資料的指令如下:<br />
<pre><code class="bash">xattr -rd com.apple.quarantine Arduino.app</code></pre>-d 選項是刪除後面指定的延伸屬性, 而 -r 選項是遞迴處理資料夾內的所有檔案與子資料夾。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-23014287925471602602019-09-27T15:56:00.003+08:002022-08-04T10:01:06.321+08:00APDS9930 程式庫造成使用 bearssl 程式庫時編譯錯誤如果你使用 ESP8266 為基礎的開發板, 例如 D1 mini, 搭配 APSD9930 程式庫, 同時又有使用到 ESP8266Wifi 程式庫的話, 依照以下順序撰寫 #incldue 敘述:<br />
<br />
<pre><code class="c++">#include <APDS9930.h>
#include <ESP8266WiFi.h>
</code></pre>就會出現以下的編譯錯誤:<br />
<pre><code class="c++">In file included from D:\FlagsBlockSketch.ino:3:0:
D:\arduino\libraries\APDS9930-master\src/APDS9930.h:134:33: error: expected ',' or '...' before numeric constant
#define B 1.862
^
D:\arduino\hardware\esp8266com\esp8266/tools/sdk/include/bearssl/bearssl_ec.h:412:60: note: in expansion of macro 'B'
uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
^
</code></pre>這主要是因為 APDS9930.h 中定義了巨集 B 為 1.862, 而在 bearssl_ec.h 中個地方定義了函式的原型為:<br />
<pre><code class="c++">uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
const unsigned char *x, size_t xlen,
const unsigned char *y, size_t ylen, int curve);
</code></pre>所以前置處理器會把 B 展開替換成 1.862, 所以這個函式原型就變成:<br />
<br />
<pre><code class="c++">uint32_t (*muladd)(unsigned char *A, const unsigned char *1.862, size_t len,
const unsigned char *x, size_t xlen,
const unsigned char *y, size_t ylen, int curve);
</code></pre>而造成編譯錯誤, 錯誤訊息為:<br />
<pre><code class="c++">error: expected ',' or '...' before numeric constant
</code></pre>這個問題我已經通知<a href="https://github.com/Depau/APDS9930">程式庫</a>的原作者, 也發了 pull request 給他, 你可以自己把程式庫中的巨集 B 改名字, 或者是更改 #include 的順序, 把 APDS9930.h 放到最後就可以了。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com1tag:blogger.com,1999:blog-6101389686504954397.post-13007940751565154492019-09-27T10:52:00.001+08:002019-09-27T10:52:50.596+08:00使用 id 名稱直接存取 DOM 物件同事問了我一個問題, 為什麼我們總是要叫用 document.getElementById() 來取得 HTML 網頁上的物件?不是明明就可以直接用 id 名稱嗎?由於我的知識停留在古時候, 一查 <a href="https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object">HTML 標準</a>才發現原來可以直接用 id 或是 name 屬性定義的名稱直接存取, 不需要叫用 document.getElementById(), 例如:<br />
<br />
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="meebox" data-slug-hash="mdbgxJo" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="TestID"> <span>See the Pen <a href="https://codepen.io/meebox/pen/mdbgxJo"><br />
TestID</a> by 黃昕暐 (<a href="https://codepen.io/meebox">@meebox</a>)<br />
on <a href="https://codepen.io">CodePen</a>.</span><br />
</p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><br />
<br />
不過在文件中寫到, 到底是哪些名稱會對應到 window 物件的屬性在未來可能會變化, 因此並不建議這樣用, 還是請乖乖的用 document.gettElementById(), 既然如此, 那幹嘛提供這個功能呢?meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-64125851457803196552019-08-01T11:01:00.002+08:002019-08-01T11:01:44.840+08:00macOS 上執行 Arduino 出現奇怪的錯誤同事協助測試 macOS 版軟體時, 遇到從 Python 執行 Arduino 1.8.5 就會掛掉, 看到以下的錯誤:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAoixWGGL8zM5bg3sEE2O2r42WlfbgWZMvEdD0t9Xnp5Jv6aOMFo0VYWlI0gddLHcxjZcA0O4jdqbxloRpnmkgfSmzTXKl4oBYFzfWWTKu_Thckgf2dBRYESgPfeOl70HBd6_aEhG3h88t/s1600/dns1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAoixWGGL8zM5bg3sEE2O2r42WlfbgWZMvEdD0t9Xnp5Jv6aOMFo0VYWlI0gddLHcxjZcA0O4jdqbxloRpnmkgfSmzTXKl4oBYFzfWWTKu_Thckgf2dBRYESgPfeOl70HBd6_aEhG3h88t/s400/dns1.png" width="400" height="64" data-original-width="1600" data-original-height="256" /></a></div><br />
實在搞不懂怎麼回事, 根據<a href="https://github.com/arduino/Arduino/issues/7388">網路上找到的相關問題</a>, 似乎和 MacBook Pro 的 touchbar 衝突, 後來改成 1.8.9 版的 Arduino 就沒事了, 算是先解決了, 但還是不很確定原因。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-50719573308880934492019-07-29T19:32:00.001+08:002019-07-29T19:35:56.713+08:00Arduino 的整數字面值寫法雖然根據<a href="https://www.arduino.cc/reference/en/language/variables/constants/integerconstants/"> Arduino 自己的參考文件</a>, 整數字面值若是 2 進位, 要用 'B' 開頭, 不過實際上測試, 例如 B112, 在某些地方會編譯器當成變數名稱, 導致發生此名稱尚未定義的錯誤。由於 Arduino 是採用 C++ 程式語言, 因此回頭<a href="https://en.cppreference.com/w/cpp/language/integer_literal">查 C++ 程式語言</a>, 會發現改成加上開頭的 0B112, 就可以正常編譯了。另外, 你也可以用小寫的 b, 例如 0b112。<br />
<br />
順道一提, 文件中對於以 16 進位格式表示時, 是用大寫的 0X, 不過根據<a href="https://en.cppreference.com/w/cpp/language/integer_literal">查 C++ 程式語言</a>, 一樣可以使用小寫的 0x, 至於 16 進位數字則可以隨意大小寫混用, 因此 0XFF 或是 0Xff, 甚至 0XFf 都是可以的。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-17233672391779345402019-01-28T18:05:00.002+08:002019-01-28T18:50:40.080+08:00MicroPython 的記憶體限制MicroPython 由於是跑在資源有限的單晶片控制板上, 所以寫程式時必須錙銖必較, 在 <a href="https://docs.micropython.org/en/latest/reference/constrained.html#execution-phase">MicroPython ESP8266 的文件</a>上有提到一種作法是避免建立不必要的物件, 原文是這樣說的:<br />
<br />
<blockquote>There are a number of situations where objects may unwittingly be created and destroyed. This can reduce the usability of RAM through fragmentation.</blockquote><br />
底下有舉例, 一個常見的例子就是字串的串接操作, 每次使用 '+' 來串接字串時, 就會牽涉到 3 個字串物件, '+' 號左右各一個, 以及串接後建立的新字串物件。最近就剛好遇到一個案例, 使用 urequests.get 向 OpenWeatherMap 網站查詢器項資料, 為了讓人看清楚整個參數的結構, 所以寫成這樣 (整個程式不只這樣):<br />
<br />
<script src="https://gist.github.com/codemee/9426cb198e13597d9943f1e4e5976e47.js"></script><br />
結果程式一執行, 雖然可以看到結果, 但是程式結束後要回到交談模式時, ESP8266 就會當掉。只要把其中 "q=" + ... 這邊改成不要串接, 直接寫成 "q=Taipei,TW" + 就可以了, 還害我找了好久的問題。畢竟在單晶片控制板上跑的 Python 和在一般電腦上跑得不一樣, 撰寫程式時要特別小心。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com4tag:blogger.com,1999:blog-6101389686504954397.post-75306884972595685632019-01-01T21:44:00.001+08:002020-03-18T15:30:18.146+08:00Python 中跨平台播放固定頻率聲音的模組--pysine找了很久, 終於找到了, Windows 平台上有 winsound 模組簡單易用, 可是這是 Windows 專屬, 如果需要跨平台, 可以使用 <a href="https://pypi.org/project/pysine/0.9.2/">pysine</a>:<br />
<pre><code class="python">from pysine import sine
sine(frequency=440.0, duration=1.0)
</code></pre>meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-85165602807736284862019-01-01T18:22:00.000+08:002020-03-18T15:30:44.104+08:00被誤解的亞里斯多德--爛翻譯的可怕之前看到這一篇文章《<a href="https://www.bnext.com.tw/article/51020/amazon-use-memo-to-replace-ppt-in-meeting">提倡寫故事,貝佐斯禁止開會用PPT</a>》時, 只覺得這是一篇誤會 PowerPoint 的文章, 你的投影片上只有條列項目, 當然效果差。不過今天老婆看到同一篇文章, 問我文章裡面提到亞里斯多德說:<br />
<blockquote>有說服力的論據必須有效的3個要素,分別為精神、標誌和悲觀情緒</blockquote>是什麼意思?一看直覺就是這一定是譯者亂翻, 找到原來的文章 <a href="https://www.inc.com/carmine-gallo/jeff-bezos-bans-powerpoint-in-meetings-his-replacement-is-brilliant.html?cid=cp01002quartz&fbclid=IwAR2rlIftUVz0rcU1TRSuXI5849Levd-bC4jgrPTFkWrCCK7RoiYklrIGcPc"><i>Jeff Bezos Banned PowerPoint in Meetings. His Replacement Is Brilliant</i></a>一看, 原來這三個要素是 "ethos, logos, and pathos.", 我會翻譯為『中心思想、邏輯與感染力』, 譯者顯然把 "logos" 當成 "logo+s", 所以翻成『標誌』, 也把 "pathos" 隨便查字典就譯為『悲觀情緒』, 完全不顧邏輯性, 真的是用自己的翻譯打臉自己的譯文。<br />
<br />
附記:數位時代的文章是從<a href="https://technews.tw/2018/10/22/amazon-use-memo-to-replace-ppt-in-meeting/">科技新報</a>而來, 但顯然沒有人審稿。<br />
meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-23685172829382966352018-12-08T21:54:00.000+08:002018-12-08T21:55:23.498+08:00Line Messaging API 在 Messaging Settings 頁面設定 Webhooks 時的陷阱 不知道從什麼時候開始, Line的 Messaging API在 Messaging Settings 頁面上出現一個古怪的陷阱:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipVLDNYjg-VKnNWMv1gouBhOG76hnuYZ1ILX-NkjztsWIjL58WCbG3JEdyNFAG2wmG6V_3UX25iF7z3nxUxOFJAvzs4t7p2RkWY-NBdWYOKOfQA8PQTeuueNMNCPeUFXiMXcDglwGMZcHV/s1600/Image+15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="526" data-original-width="883" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipVLDNYjg-VKnNWMv1gouBhOG76hnuYZ1ILX-NkjztsWIjL58WCbG3JEdyNFAG2wmG6V_3UX25iF7z3nxUxOFJAvzs4t7p2RkWY-NBdWYOKOfQA8PQTeuueNMNCPeUFXiMXcDglwGMZcHV/s400/Image+15.png" width="400" /></a></div>
如果您先設定 Use webhooks 為 Enabled, 然後才填入 Webhook URL,那麼剛剛修改的 Use webhooks就會被暗地設回 Disabled, 但是看到的仍然是 Enabled, 像是這樣:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHqwxZ2Z9myiTAZuv3-T35abwrF2kEzNLXx4FGkrkk-iFiAsCelm_MM8l5WvE7mozd4wXrpptNK2HvJw_xiX_u03lL_yG5doiGMGU4T5I-OXNUCP1ljduC8ndRRU_oKGREiXIUBM8MLUQ5/s1600/Image+16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="526" data-original-width="883" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHqwxZ2Z9myiTAZuv3-T35abwrF2kEzNLXx4FGkrkk-iFiAsCelm_MM8l5WvE7mozd4wXrpptNK2HvJw_xiX_u03lL_yG5doiGMGU4T5I-OXNUCP1ljduC8ndRRU_oKGREiXIUBM8MLUQ5/s400/Image+16.png" width="400" /></a></div>
實際上 webhook 並沒有生效, 會讓你的 Line Chatbot 已讀不回。這時候只要按 F5 重新載入頁面, 就會看到暗中被設回 Disabled 的 Use webhooks 選項: <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijJmgyKVCJVvn5ce81TJyUm6YFAV4dph0SzvSW3z7Z4xXYvuf-Rj3vCPtvQSH7LWDXA7pG3HQjmByLQ1KyB00XGG0wgY7a-BFUnxcHQazeEc4syzLGYHMqNNapyxrKUIN_lD2PzRiZBvPP/s1600/Image+17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="526" data-original-width="883" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijJmgyKVCJVvn5ce81TJyUm6YFAV4dph0SzvSW3z7Z4xXYvuf-Rj3vCPtvQSH7LWDXA7pG3HQjmByLQ1KyB00XGG0wgY7a-BFUnxcHQazeEc4syzLGYHMqNNapyxrKUIN_lD2PzRiZBvPP/s400/Image+17.png" width="400" /></a></div>
只要重新再設定為 Enabled 就好了。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-27013512412534120812018-11-08T16:25:00.001+08:002020-03-18T15:32:06.564+08:00使用 Python 從 excel 檔終結取資料由於需要從大量的 excel 檔中擷取資料,就想是否可以用程式的方式來解決,一查知下, 果然有個 <a href="https://xlrd.readthedocs.io/en/latest/">xlrd </a>模組可以讀寫 excel 檔。例如, 我想從當前資料夾下一個個打開 excel 檔,並且檢查每一筆資料中, 若第 B 欄的內容符合條件, 就將同一列 B 欄與 D欄的資料寫入輸出檔案中, 就可以撰寫類似以下的程式:<br />
<pre><code class="python">import glob
import xlrd
with open('result.txt', mode='w', encoding='utf-8') as of:
for xlsfile in glob.iglob("order*.xls"):
wb = xlrd.open_workbook(xlsfile)
for i in range(wb.nsheets):
st = wb.sheet_by_index(i)
if st.nrows > 1:
for r in range(st.nrows):
if st.cell(r, 1).value in ('table','chair'):
of.write(st.cell(r, 1).value + ',' +
st.cell(r, 3).value + "\n")
</code></pre>要注意的是, 這個套件中不論是列編號或是欄編號都是從 0 開始, 因此 excel 檔中的第 1 列編號為 0, 第 B 欄編號為 1, 所以上面程式中 cell(r, 1) 就是 excel 檔中第 r+1 列的第 B 欄。詳細的用法可以參考該模組的<a href="https://xlrd.readthedocs.io/en/latest/">說明文件</a>, 或是參考這一份<a href="https://www.sitepoint.com/using-python-parse-spreadsheet-data/">簡單的教學</a>。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-38499423012182118542018-11-08T16:10:00.001+08:002018-11-08T16:10:15.537+08:00從 eml 檔擷取郵件夾檔最近遇到一個需求, 需要從一大堆的 eml 檔把郵件中的夾檔抽出來,因此找到一個 outlook add-on, 叫做 <a href="https://www.outlookfreeware.com/en/products/all/OutlookSaveAttachmentsEML">Ourlook Save Attachments from EML files</a>, 可以針對特定的資料夾中的 eml 檔把其中的夾檔通取出存檔。<br />
<br />
這個 add-on 其實跟 outlook一點都沒關係, 但是因為不是獨立的執行檔, 所以還是得要有 outlook 才行, 這是唯一美中不足之處。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0tag:blogger.com,1999:blog-6101389686504954397.post-83862165480002696742018-10-10T13:54:00.000+08:002018-10-10T13:54:57.420+08:00雷射模組 (KY-008) 的 3 根針腳同事因為專案使用了市面上極容易買到的 KY-008 模組:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://electronicsforu.com/wp-contents/uploads/2018/09/KY-008-laser-LED-module.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://electronicsforu.com/wp-contents/uploads/2018/09/KY-008-laser-LED-module.jpg" width="400" height="216" data-original-width="636" data-original-height="344" /></a></div><br />
大部分的使用案例都會告訴你 S 接數位輸出控制開關, 中間腳接 5V, - 腳接地, 測試後發現怪怪的, S 的電壓會影響雷射的亮度, 並不是單純的開關;而且, 如果 S 腳完全不接, 似乎雷射會有微光。經過檢查模組上的線路後, 是這樣:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEx-CXpZ7sJ7JUz4j2mgv_J1cjkyvudKRiKADfAyH8gruYZRM7vbg23LJYuHLDNQpJp9Ruw9NC1yUewKGq3zM2V8j7gkHGN1oywR4__1-sFBikaPnLDbbK9hXE8U1wBPynYHDxVPHXw0mp/s1600/laser_bb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEx-CXpZ7sJ7JUz4j2mgv_J1cjkyvudKRiKADfAyH8gruYZRM7vbg23LJYuHLDNQpJp9Ruw9NC1yUewKGq3zM2V8j7gkHGN1oywR4__1-sFBikaPnLDbbK9hXE8U1wBPynYHDxVPHXw0mp/s400/laser_bb.png" width="293" height="400" data-original-width="486" data-original-height="663" /></a></div><br />
所以其實 S 和 - 就是供電控制雷射開關, 因此 S 的電壓會影像雷射光的亮度, 只要這兩隻腳就可以控制雷射。那麼為什麼要從 S 接一個 10KΩ電阻到中間腳呢?網路上有人稱呼中間腳為『神秘』腳, 因為不知道做什麼用途?根據<a href="https://electronicsforu.com/electronics-projects/interfacing-ky-008-laser-led-arduino">這一篇文章</a>的說明, 中間腳應該是模組的輸出腳位, 10KΩ電阻是為了限流, 可以讓你監控供給模組的電壓, 比方說偵測電源中斷、或是電壓意外陡降或是不穩等等, 至於實際上的用法, 就有待各位自行發想囉。meeboxhttp://www.blogger.com/profile/00690710368155876262noreply@blogger.com0