總之這是一種試驗看看WiFi的耗電量究竟可以做到什麼程度,設計上以耗電量作為主要的考量
螢幕用的是Sharp Memory LCD,之前用過的感想覺得效果真的很棒,所以看到秋葉原賣另一個型號就請別人帶回來了,這次用的是2.7" 400x240的版本,不過技術和之前96x96的有差異,這個比較像是以前的TFT LCD,只是增強了反射性,但是耗電量還是相當的低,Datasheet規格是50uW = 5V x 10uA (這個螢幕真需要5V),雖然不像之前的那個拔掉一兩分鐘都還有顯示就是了XD
功能目前是每六個小時去撈中央氣象局的OpenData,抓36小時的天氣預報顯示這樣
核心這次有兩個,分別是WiFi SoC 的 MT7687,與 Power Management 的 MSP430G2553
首先來講一下MT7687,這顆是聯發科新推出的WiFi SoC, 標準的ARM Cortex - M4, 特色是記憶體有300K,而且有Arduino IDE支援, Prototype很快.
https://docs.labs.mediatek.com/resource/mt7687-mt7697/zh_tw/downloads
另外一個是MSP430G2553,由於Sharp Memory LCD需要一個Low Freq的Clock去翻Vcom的電位,所以單純只用WiFi Soc耗電量我想會有點太大,所以想找一顆小的MCU專門開關MT7687以及生出Memory LCD需要的Clock.最先的目標其實是手邊有一堆的Attiny84/85,但是後來研究了一下才發現這系列的待機耗電量還頗大...想想倒不如拿MSP430來做,發現便宜的G2553待機耗電量(With LPM3)就遠遠超過了Attiny85的能耐,只有1uA,而且可以用32Khz的Clock做timer,就拿MSP430G2553做了
然後是電源供應的設計,由於Memory LCD需要5V的電壓,所以勢必是需要一個5V的Step-up,
又因為這個螢幕超省電的,所以目光集中在低附載的效率與Iq,找到一顆Ti的TPS61099,BGA封裝還滿省空間的,而且從Datasheet看起來,感覺就是為了這目的(Low Power LCD Bais)設計的XDD
而3.3V因為MT7687的電流不小,所以決定還是用一個Buck-Boost增加效率,同樣找Iq與輕載效率高的,找到的是Ti的TPS62740,然後想說乾脆就在Ti找一個鋰電池的充電IC,就挑了個BQ24045
另外,由於PCB需要Cover到Memory LCD作為支撐,所以有一整面的空白覺得太空虛了,所以找了一個NFC Tag作為設定Wifi AP/Passwd用,然後再LCD底下放滿滿的NFC天線
然後就開始寫程式了
首先當然是要先寫個Parser去處理Wifi設定,Wifi 為了方便使用,有些廠商會在AP上面裝上NFC Tag,格式是同一個=>application/vnd.wfa.wsc
稍微查了一下格式長這樣:
Header : 0x10
Data Type: one byte
Data Length:two byte
Data[len]
Data type:
0x26 : Network index
0x45 : SSID
0x03 : authentication type
0x0F : encryption type
0x27 : Password
0x20 : MAC Address
encryption type分為:
0x0001
None
0x0002
WEP
Deprecated.
0x0004
TKIP
Deprecated. Use only for mixed mode.
0x0008
AES
Includes both CCMP and GCMP
Authentication Type分為:
0x0001
Open
0x0002
WPA-Personal
deprecated in version 2.0
0x0004
Shared
deprecated in version 2.0
0x0008
WPA-Enterprise
deprecated in version 2.0
0x0010
WPA2-Enterprise
includes both CCMP and GCMP
0x0020
WPA2-Personal
includes both CCMP and GCMP
Code 大概是這樣
使用方式是把NFC的資料Array和SSID,Passward與有無加密的Variable address pass進去
阿記得就是SSID,Passward的陣列開大一點,我在寫的時候沒檢查喔O.<
void parsing(uint8_t *data,uint8_t len,uint8_t *SSID,uint8_t*PASSWD,bool* auth){
for(int i=0;i<len;i++){
if(data[i]==0x10){ //Headder get
i = i + 1;
uint16_t len = (uint16_t)data[i+1]<<8 | (uint16_t)data[i+2];
uint8_t type = data[i];
//Serial.print("Type:");Serial.print(type,HEX);Serial.print(" Len:");Serial.println(len);
if(type == 0x45){ //SSID
display.println("SSID:");
for(int k=0;k<len;k++){
SSID[k] = data[i+3+k];
//Serial.println(SSID[k]);
display.write(SSID[k]);
}
//display.write((char*)SSID);
display.println();
display.refresh();
}
if(type == 0x0E){
continue;
}
if(type == 0x27){ //PASSWD
display.println("Passward GET");
for(int k=0;k<len;k++){
PASSWD[k] = data[i+3+k];
//Serial.println(PASSWD[k]);
//display.write(PASSWD[k]);
}
//display.write((char*)PASSWD);
//display.println();
display.refresh();
}
if(type == 0x03){
display.println("Auth:");
if(data[i+4]==0x01){
*auth = 0;
display.println("OPEN");
}
else{
*auth = 1;
display.println("WPA");
}
display.refresh();
}
i = i + 2 + len;
}
}
}
然後接下來是去撈Opendata......
所以我說那個中央氣象局為啥要用XML啊啊啊啊啊啊啊啊
真心覺得崩潰,所以我就不貼上來了Orz....
有需要再問,我再整理放上來
接下來是要把資料顯示出來,首先就是要顯示中文,然後就崩潰惹
因為再沒有外掛Flash的狀況下,一個中文字型檔案~1Mb是放不進去MCU的
所以我需要做兩件事情,地一個是把我要顯示的中文字列出來,第二件事情是找出一個方法
讓我可以把UTF-8的字找到對應的點陣字的Array index
第一件事情很簡單,拿個Python Script把CWB的Opendata說明檔的每個字抓出來比對就好
第二件事情我用的方式是Hash function,透過事先計算出一個UTF-8->index的Hash Function
我目前用的Graphics library是Adafruit GFX,所以我稍微修改了一下library之後
用Python做出前面的兩件事情之後,生出GFX用的fontfile.
其他的我就丟Github了:
https://github.com/will127534/AdafruitGFX-ChineseFont-Addon
最後是MSP430惹,MSP430的工作非常簡單,就是要生出Clock還有關MT7687
MT7687結束的時候,會拉高一個pin,通知MSP430關電源這樣
我有點偷懶的是都寫在timer interrupt裡面,沒有特別開GPIO Interrupt就是了
#include <msp430g2553.h>
#define Power P3_6
volatile unsigned int MT7687SleepCount = 0;
volatile bool MT7687Sleeped = 0;
void setup(void)
{
WDTCTL = WDTPW + WDTHOLD;
// Stop WDT
BCSCTL1 |= DIVA_3;
// ACLK/8
BCSCTL3 |= XCAP_3;
//12.5pF cap- setting for 32768Hz crystal
P1DIR = 0xFF;
P2DIR = 0xFF;
P3DIR = 0xFF;
P1OUT = 0x00;
P2OUT = 0x00;
P3OUT = 0x00;
pinMode(P3_7,OUTPUT);
pinMode(Power,OUTPUT);
digitalWrite(Power,LOW);
delayMicroseconds(500);
pinMode(P1_4,INPUT);
pinMode(P1_5,INPUT);
CCTL0 = CCIE;
// CCR0 interrupt enabled
CCR0 = 255;
// 512 -> 1 sec, 30720 -> 1 min
TACTL = TASSEL_1 + ID_3 + MC_1;
// ACLK, /8, upmode
_BIS_SR(LPM3_bits + GIE);
// Enter LPM3 w/ interrupt
}
void loop(){
_BIS_SR(LPM3_bits + GIE);
// Enter LPM3 w/ interrupt
}
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
digitalWrite(P3_7,!digitalRead(P3_7));
if(digitalRead(P1_5)==HIGH){
digitalWrite(Power,HIGH);
pinMode(P1_4,OUTPUT);
digitalWrite(P1_4,LOW);
MT7687SleepCount = 0;
MT7687Sleeped = 1;
}
if(sleep){
MT7687SleepCount ++;
if(MT7687SleepCount>43200){
digitalWrite(Power,LOW);
delayMicroseconds(50000);
pinMode(P1_4,INPUT);
MT7687Sleeped = 0;
}
}
}
每隔半秒就翻轉一次Pin,這樣耗電量<1uA
少數幾個缺點大概列一下
首先就是該隔離的就該隔離,MT7687因為要控制LCD,所以SPI一定要接在一起,但只要MT7687電源關閉,那SPI拉高的CS就會倒灌回去MT7687造成很大的耗電量,我原先以為MT7687的Floating Well就是設計來擋掉這件事情的,但是實測發現很明顯地沒有,所以才多了那一堆銅線Orz
第二個就是沒辦法量電壓,雖然板子上有預留測量Vbat的電阻,但是我沒有斷開分壓電阻的機制,這樣一來會造成漏電.
應該是不會繼續改版了,畢竟這樣穩穩用也沒啥問題
一切都藏得好好der