由於最近Rpi一代借出去了,目前沒有Server可以用,所以就把我的Wifi Arduino拿來用
基本上這個就是Leonardo + Linkit connect module
總之就是將nRF24l01接收到的資料打包之後,送到Xively上面(P.S Xively看來是很難在註冊了..)
完整的程式在這邊(待補)
底下因為Sublime Text 3 的字體+上色太好看了,所以我用截圖來說明
首先是Setup,要做的就是設定nRF24l01,這邊使用的Library是Mirf,很方便使用的一個library,設定完通訊方式,接收地址,以及接收大小之後就可以了.
再來就是利用AT cmd讓MT7681模組Reset,之後等待RecoveryMode結束的左箭頭之後就連線到AP.
但是如果MT7681並沒有對Reset回應的話,就會用GPIO將Wifi Arduino整台Reset,因為我當初Layout的時候並沒有把MT7681的RST接上GPIO而是和Leonardo的接在一起.
Loop也很簡單,收到nRF的資料之後,就將資料放到Structure裡面,然後把Wifi 的資料送出去
另外我用WatchDog來防止整台因網路不通的關西而Freeze的狀況.
最後就是Linkit connect module library當中需要的callback了
Wifi送資料的部分,剛開始先準備好資料,將Structure內的各個資料轉成String,同時查詢api.xively.com的IP位置,最後連到Server送Http header與資料.
============================
PUT /v2/feeds/(feedID).csv HTTP/1.1
Host: api.xively.com
X-ApiKey: (API_key)
Content-Length: (datalength)
Content-Type: text/csv
Connection: close
Humidity,(humidity)
Temperature,(temperature)
============================
大概是這種感覺
順帶一提,一樣是為了防止網路連線出錯導致的Freezing,加了WDT作保護
連線到AP的大概就是這種感覺...
以上就是針對接收站的紀錄了~
2015年4月28日 星期二
2015年4月27日 星期一
Linkit connect module 使用
上圖就是Linkit connect module,使用的其實就是MT7681 Wifi Soc
最近在完成的Project其中一個有用到這個模組,所以留個筆記方便日後使用
首先就是Linkit connect module其實是一個可以獨立Program的Wifi module
SDK是Open出來的,在官方網站就可以抓到最新的SDK與說明文件
先從硬體開始,因為這個模組,Seedstudio有做了一個Open Hardware的開發版可以用,所以可以先從HDK上面下載Eagle Layout files,打開來之後就可以直接沿用他們的做好的Linkit connect module Library,順帶一提,在Eagle裡面要跨檔案的複製只需要再命令列打copy之後打paste就可以貼上了,直接用左邊那一欄的複製是不行的
Update:我把它拿出來做成Library了,在這邊下載
把Arduino_sample底下的MT7681的資料夾整包放到Arduino 的 library資料夾就可以在Arduino裡面使用了.
燒錄方式如下:在官網下載好Linkit connect module SDK之後,找個Serial to USB(總之就是一個接上Linkit connect module 的 COM port)接上模組,SDK裡面有個資料夾叫做Uploader,開命令程式列並且把AT cmd的兩個韌體放到該資料夾之後打這串指令:
Update:我把Uploader從SDK拿出來放在Github了,在這邊下載
接下來就從範例開始
首先,修改這三行
LC7681Wifi wifi(&Serial1); <=填入使用的Serial
Uno的話因為只有一個Serial,所以把Linkit connect接上Serial之後,這邊填入Serial
Leonardo的話因為本身有USB CDC的Serial,所以實體的Serial是Serial1,所以填 Serial1而Due,與Mega等等具有多個Serial的就看你是接上哪一組就填哪一組
const char ssid[] = "";
const char key[] = "";
以上兩行填入你想連接AP的SSID與Key
接下來接上模組,燒錄完就可以用了.
最近在完成的Project其中一個有用到這個模組,所以留個筆記方便日後使用
首先就是Linkit connect module其實是一個可以獨立Program的Wifi module
SDK是Open出來的,在官方網站就可以抓到最新的SDK與說明文件
先從硬體開始,因為這個模組,Seedstudio有做了一個Open Hardware的開發版可以用,所以可以先從HDK上面下載Eagle Layout files,打開來之後就可以直接沿用他們的做好的Linkit connect module Library,順帶一提,在Eagle裡面要跨檔案的複製只需要再命令列打copy之後打paste就可以貼上了,直接用左邊那一欄的複製是不行的
Update:我把它拿出來做成Library了,在這邊下載
所以就可以很直接的整合到其他PCB當中,底下這是Linkit connect with Arduino的電路圖
再來就是軟體,因為我的使用方式是把模組當作Wifi模組使用,所以是Arduino控制的,這就需要在Linkit connect上面燒錄AT cmd 的韌體,網路上已經有人寫好了一套韌體可以拿來用,不過我有再修改過,在這邊,可以看到我是fork IOTPlayer來改的把Arduino_sample底下的MT7681的資料夾整包放到Arduino 的 library資料夾就可以在Arduino裡面使用了.
燒錄方式如下:在官網下載好Linkit connect module SDK之後,找個Serial to USB(總之就是一個接上Linkit connect module 的 COM port)接上模組,SDK裡面有個資料夾叫做Uploader,開命令程式列並且把AT cmd的兩個韌體放到該資料夾之後打這串指令:
mt7681_uploader.exe -f MT7681_sta_header.bin -c COM7
這樣就燒錄好了Update:我把Uploader從SDK拿出來放在Github了,在這邊下載
接下來就從範例開始
首先,修改這三行
LC7681Wifi wifi(&Serial1); <=填入使用的Serial
Uno的話因為只有一個Serial,所以把Linkit connect接上Serial之後,這邊填入Serial
Leonardo的話因為本身有USB CDC的Serial,所以實體的Serial是Serial1,所以填 Serial1而Due,與Mega等等具有多個Serial的就看你是接上哪一組就填哪一組
const char ssid[] = "";
const char key[] = "";
以上兩行填入你想連接AP的SSID與Key
接下來接上模組,燒錄完就可以用了.
2015年4月24日 星期五
Nrf24l01 Sensor node (氣象站 3.1)
這是繼氣象站3.0的後續版本,基本上因為前一版真的是頗悲劇的
前一版的主要問題在於耗電量與體積問題,還有Layout的各種錯誤
這次的版本基本上就是
可以看到上方的Nrf24l01模組與底下的BMP085和右邊的HDC1000以及被遮住的Atmega328
這次重點就擺在耗電量了,上次做的那一版可能是LDO的耗電量吧,啥待機耗電量大成這樣(60uA),這次是CR2032直接接上系統電壓,所以基本上不會需要任何穩壓,降低耗電量,
同時把讀取的時序調整過了,我簡單說明一下:
通常Sensor在測量的時候都會需要點時間,但是Arduino的Library常常會將這點時間用delay帶過
這就造成Arduino長時間的閒置,徒增耗電量的概念,所以我把開始測量和讀取測量值分開,中間用待機,這樣就可以省掉滿多閒置時間的
文字說明似乎不夠,用圖來解釋好了.
這是測試方法,由於最高耗電量不到數百mA的等級,用一個10歐姆的電阻串在中間,然後拿個示波器量就好(待機耗電量依然需要用電表來測)
這是目前的耗電量曲線,可以看到剛開始有兩次高峰,分別是HDC1000和BMP085的溫度啟動測量,第二個就是把測量的值讀進來,然後啟動BMP085的氣壓和HDC1000的濕度測量,最後將資料計算完之後,啟動RF,把資料發射出去
如果沒有特別設定的話,從第一個高峰到最後一個通通都會耗電.
這是RF發射的詳細波形,可以看到基本上設定要發射之後Arduino就睡眠了,等到最後面在啟動看有沒有傳成功.
耗電量的計算,基本上就是算面積,小心估計出各個耗電的時間和耗電量之後(V=IR,所以示波器上面的電壓除以10(我用的電阻值)就是電流),加總起來算平均
我的計算出來大概.....我忘了,等等翻一下計算過程去哪裡.....= ___ =
只記得大概靠CR2032撐個一年
有發射器當然就要有個接收站,但是我手邊的Raspberry Pi 一代借出去了,所以拿我的Wifi Arduino來傳,這就下一篇來解釋了.
前一版的主要問題在於耗電量與體積問題,還有Layout的各種錯誤
這次的版本基本上就是
- 核心 Arduino Atmega328
- 氣壓計 BMP085
- 溫溼度計 HDC1000
- 無線模組 Nrf24l01
可以看到上方的Nrf24l01模組與底下的BMP085和右邊的HDC1000以及被遮住的Atmega328
這次重點就擺在耗電量了,上次做的那一版可能是LDO的耗電量吧,啥待機耗電量大成這樣(60uA),這次是CR2032直接接上系統電壓,所以基本上不會需要任何穩壓,降低耗電量,
同時把讀取的時序調整過了,我簡單說明一下:
通常Sensor在測量的時候都會需要點時間,但是Arduino的Library常常會將這點時間用delay帶過
這就造成Arduino長時間的閒置,徒增耗電量的概念,所以我把開始測量和讀取測量值分開,中間用待機,這樣就可以省掉滿多閒置時間的
文字說明似乎不夠,用圖來解釋好了.
這是測試方法,由於最高耗電量不到數百mA的等級,用一個10歐姆的電阻串在中間,然後拿個示波器量就好(待機耗電量依然需要用電表來測)
這是目前的耗電量曲線,可以看到剛開始有兩次高峰,分別是HDC1000和BMP085的溫度啟動測量,第二個就是把測量的值讀進來,然後啟動BMP085的氣壓和HDC1000的濕度測量,最後將資料計算完之後,啟動RF,把資料發射出去
如果沒有特別設定的話,從第一個高峰到最後一個通通都會耗電.
這是RF發射的詳細波形,可以看到基本上設定要發射之後Arduino就睡眠了,等到最後面在啟動看有沒有傳成功.
耗電量的計算,基本上就是算面積,小心估計出各個耗電的時間和耗電量之後(V=IR,所以示波器上面的電壓除以10(我用的電阻值)就是電流),加總起來算平均
我的計算出來大概.....我忘了,等等翻一下計算過程去哪裡.....= ___ =
只記得大概靠CR2032撐個一年
有發射器當然就要有個接收站,但是我手邊的Raspberry Pi 一代借出去了,所以拿我的Wifi Arduino來傳,這就下一篇來解釋了.
2015年4月10日 星期五
Arduino countdown timer
好久沒有用洞洞板做東西了..
這次是一個Arduino 倒數計時器,只是比一般的計時器多了一個警告的控制,也就是說倒數到幾分鐘會亮黃燈,歸零就亮紅燈這樣,功能很簡單,
架構就是三個按鈕,上/下/開始(長按:設定警告分鐘),一個Reset(回到開始的設定),然後兩個LED與四個七段顯示器.另外因為Pin不夠用了,所以加了一個74HC595控制七段顯示器的abcdefg
程式方面比較複雜的有兩個,長按切換模式,以及四個七段顯示器的掃描
接線圖我就不畫了,反正把程式碼的各個Pin設定好就能用
#include <stdio.h>
byte digit[8] = {1, 3, 5, 6, 7, 2, 4, 0};
byte num[4] = {5, 6, 7, 4};
byte led[3] = {2, 3, A4};
byte button[3] = {A0, A1, A2};
int SER_Pin = 8; //pin 14 on the 75HC595
int RCLK_Pin = 9; //pin 12 on the 75HC595
int SRCLK_Pin = A3; //pin 11 on the 75HC595
int reset = 10;
#define number_of_74hc595s 1
#define numOfRegisterPins number_of_74hc595s * 8
boolean registers[numOfRegisterPins];
byte seven_seg_digits[10][7] = { { 1, 1, 1, 1, 1, 1, 0 }, // = 0
{ 0, 1, 1, 0, 0, 0, 0 }, // = 1
{ 1, 1, 0, 1, 1, 0, 1 }, // = 2
{ 1, 1, 1, 1, 0, 0, 1 }, // = 3
{ 0, 1, 1, 0, 0, 1, 1 }, // = 4
{ 1, 0, 1, 1, 0, 1, 1 }, // = 5
{ 1, 0, 1, 1, 1, 1, 1 }, // = 6
{ 1, 1, 1, 0, 0, 0, 0 }, // = 7
{ 1, 1, 1, 1, 1, 1, 1 }, // = 8
{ 1, 1, 1, 0, 0, 1, 1 } // = 9
};
void setup() {
Serial.begin(115200);
for (int i = 0; i < 3; i++) {
pinMode(button[i], INPUT_PULLUP);
}
pinMode(reset, INPUT_PULLUP);
for (int i = 0; i <= 3; i++) {
pinMode(num[i], OUTPUT);
}
for (int i = 0; i < 3; i++) {
pinMode(led[i], OUTPUT);
digitalWrite(led[i], HIGH);
}
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
clearRegisters();
writeRegisters();
}
int second = 0;
int minute = 0;
int lastth = 0;
int lastminute = 0;
uint32_t lastbutton = 0;
uint32_t counttime = 0;
uint32_t ledtime = 0;
bool counting = 0;
int state = 0;
bool settime = 0;//0=countdown 1=last
int th = 5;
void loop() {
if (settime) {
disp(th / 10, th % 10, 0, 0);
digitalWrite(led[1], HIGH);
}
else if(0==digitalRead(reset)){
settime=0;
counting =0;
minute = lastminute;
th = lastth;
second = 0;
}
else {
disp(minute / 10, minute % 10, second / 10, second % 10);
if (millis() - counttime > 1000) {
if (counting == 1) {
second--;
if (second < 0) {
minute--;
second = 59;
}
if (minute < 0) {
minute = 0;
second = 0;
}
Serial.print(minute);
Serial.print(",");
Serial.println(second);
if (minute < th) {
digitalWrite(led[0], HIGH);
// Serial.println("Alarm");
}
else {
digitalWrite(led[0], LOW);
}
if (minute <= 0 && second <= 0) {
digitalWrite(led[1], HIGH);
//Serial.println("STOP");
}
else {
digitalWrite(led[1], LOW);
}
state = !state;
digitalWrite(led[2], state);
//Serial.println(digitalRead(led[2]));
}
else {
//Serial.print(digitalRead(led[0]));
//Serial.print(digitalRead(led[1]));
//Serial.println(digitalRead(led[2]));
// digitalWrite(led[0], !digitalRead(led[0]));
// digitalWrite(led[1], !digitalRead(led[1]));
}
counttime = millis();
}
else if (millis() - ledtime>200){
if (counting == 0){
digitalWrite(led[0], !digitalRead(led[0]));
digitalWrite(led[1], !digitalRead(led[1]));
state = !state;
digitalWrite(led[2], state); //ditry fix about digitalRead error on led2
ledtime = millis();
}
}
}
scan();
}
void change(int i) {
switch (i) {
case 0:
if (0 == settime) {
if(counting){
counting = 0;
}
else{
counting = 1;
lastminute = minute;
lastth = th;
}
}
else {
}
break;
case 1:
if (0 == settime && counting == 0) {
minute++;
second = 0;
//Serial.println(minute);
}
else if (1 == settime) {
th++;
//Serial.println(th);
}
break;
case 2:
if (0 == settime && counting == 0) {
minute--;
if (minute < 0) {
minute = 0;
}
second = 0;
//Serial.println(minute);
}
else if (1 == settime) {
th--;
if (th < 0) {
th = 0;
}
//Serial.println(th);
}
break;
}
}
void scan() {
uint32_t start = 0;
int flag = 0;
for (int i = 0; i <= 2; i++) {
if (0 == digitalRead(button[i])) {
if (millis() - lastbutton > 150) {
start = millis();
while (0 == digitalRead(button[i])) {
if (settime) {
disp(th / 10, th % 10, 0, 0);
}
else {
disp(minute / 10, minute % 10, second / 10, second % 10);
}
if (i == 0 && millis() - start >= 500 && flag==0) {
settime = !settime;
//Serial.print("SET TIME:");
//Serial.println(settime);
flag = 1;
lastbutton = millis();
}
}
if(flag==0){
change(i);
lastbutton = millis();
}
}
//Serial.println(millis() - start);
}
}
}
void disp(int a, int b, int c, int d) {
int data[4] = {a, b, c, d};
for (int dig = 0; dig <= 3; dig++) {
for (byte seg = 0; seg < 7; ++seg) {
setRegisterPin(digit[seg], !seven_seg_digits[data[dig]][seg]);
// digitalWrite(digit[seg], !seven_seg_digits[data[dig]][seg]);
}
writeRegisters();
digitalWrite(num[dig], HIGH);
delayMicroseconds(100);
digitalWrite(num[dig], LOW);
}
}
//set all register pins to LOW
void clearRegisters() {
for (int i = numOfRegisterPins - 1; i >= 0; i--) {
registers[i] = HIGH;
}
}
//Set and display registers
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters() {
digitalWrite(RCLK_Pin, LOW);
for (int i = numOfRegisterPins - 1; i >= 0; i--) {
digitalWrite(SRCLK_Pin, LOW);
int val = registers[i];
digitalWrite(SER_Pin, val);
digitalWrite(SRCLK_Pin, HIGH);
}
digitalWrite(RCLK_Pin, HIGH);
}
//set an individual pin HIGH or LOW
void setRegisterPin(int index, int value) {
registers[index] = value;
}
void serialEvent(){
minute = Serial.parseInt();
second = Serial.parseInt();
th = Serial.parseInt();
counting = Serial.parseInt();
settime = 0;
while(Serial.available()){
int dummy = Serial.read();// statement
}
}
====Update:2016/08/28====
這次是一個Arduino 倒數計時器,只是比一般的計時器多了一個警告的控制,也就是說倒數到幾分鐘會亮黃燈,歸零就亮紅燈這樣,功能很簡單,
架構就是三個按鈕,上/下/開始(長按:設定警告分鐘),一個Reset(回到開始的設定),然後兩個LED與四個七段顯示器.另外因為Pin不夠用了,所以加了一個74HC595控制七段顯示器的abcdefg
很亂的配線... |
接線圖我就不畫了,反正把程式碼的各個Pin設定好就能用
#include <stdio.h>
byte digit[8] = {1, 3, 5, 6, 7, 2, 4, 0};
byte num[4] = {5, 6, 7, 4};
byte led[3] = {2, 3, A4};
byte button[3] = {A0, A1, A2};
int SER_Pin = 8; //pin 14 on the 75HC595
int RCLK_Pin = 9; //pin 12 on the 75HC595
int SRCLK_Pin = A3; //pin 11 on the 75HC595
int reset = 10;
#define number_of_74hc595s 1
#define numOfRegisterPins number_of_74hc595s * 8
boolean registers[numOfRegisterPins];
byte seven_seg_digits[10][7] = { { 1, 1, 1, 1, 1, 1, 0 }, // = 0
{ 0, 1, 1, 0, 0, 0, 0 }, // = 1
{ 1, 1, 0, 1, 1, 0, 1 }, // = 2
{ 1, 1, 1, 1, 0, 0, 1 }, // = 3
{ 0, 1, 1, 0, 0, 1, 1 }, // = 4
{ 1, 0, 1, 1, 0, 1, 1 }, // = 5
{ 1, 0, 1, 1, 1, 1, 1 }, // = 6
{ 1, 1, 1, 0, 0, 0, 0 }, // = 7
{ 1, 1, 1, 1, 1, 1, 1 }, // = 8
{ 1, 1, 1, 0, 0, 1, 1 } // = 9
};
void setup() {
Serial.begin(115200);
for (int i = 0; i < 3; i++) {
pinMode(button[i], INPUT_PULLUP);
}
pinMode(reset, INPUT_PULLUP);
for (int i = 0; i <= 3; i++) {
pinMode(num[i], OUTPUT);
}
for (int i = 0; i < 3; i++) {
pinMode(led[i], OUTPUT);
digitalWrite(led[i], HIGH);
}
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
clearRegisters();
writeRegisters();
}
int second = 0;
int minute = 0;
int lastth = 0;
int lastminute = 0;
uint32_t lastbutton = 0;
uint32_t counttime = 0;
uint32_t ledtime = 0;
bool counting = 0;
int state = 0;
bool settime = 0;//0=countdown 1=last
int th = 5;
void loop() {
if (settime) {
disp(th / 10, th % 10, 0, 0);
digitalWrite(led[1], HIGH);
}
else if(0==digitalRead(reset)){
settime=0;
counting =0;
minute = lastminute;
th = lastth;
second = 0;
}
else {
disp(minute / 10, minute % 10, second / 10, second % 10);
if (millis() - counttime > 1000) {
if (counting == 1) {
second--;
if (second < 0) {
minute--;
second = 59;
}
if (minute < 0) {
minute = 0;
second = 0;
}
Serial.print(minute);
Serial.print(",");
Serial.println(second);
if (minute < th) {
digitalWrite(led[0], HIGH);
// Serial.println("Alarm");
}
else {
digitalWrite(led[0], LOW);
}
if (minute <= 0 && second <= 0) {
digitalWrite(led[1], HIGH);
//Serial.println("STOP");
}
else {
digitalWrite(led[1], LOW);
}
state = !state;
digitalWrite(led[2], state);
//Serial.println(digitalRead(led[2]));
}
else {
//Serial.print(digitalRead(led[0]));
//Serial.print(digitalRead(led[1]));
//Serial.println(digitalRead(led[2]));
// digitalWrite(led[0], !digitalRead(led[0]));
// digitalWrite(led[1], !digitalRead(led[1]));
}
counttime = millis();
}
else if (millis() - ledtime>200){
if (counting == 0){
digitalWrite(led[0], !digitalRead(led[0]));
digitalWrite(led[1], !digitalRead(led[1]));
state = !state;
digitalWrite(led[2], state); //ditry fix about digitalRead error on led2
ledtime = millis();
}
}
}
scan();
}
void change(int i) {
switch (i) {
case 0:
if (0 == settime) {
if(counting){
counting = 0;
}
else{
counting = 1;
lastminute = minute;
lastth = th;
}
}
else {
}
break;
case 1:
if (0 == settime && counting == 0) {
minute++;
second = 0;
//Serial.println(minute);
}
else if (1 == settime) {
th++;
//Serial.println(th);
}
break;
case 2:
if (0 == settime && counting == 0) {
minute--;
if (minute < 0) {
minute = 0;
}
second = 0;
//Serial.println(minute);
}
else if (1 == settime) {
th--;
if (th < 0) {
th = 0;
}
//Serial.println(th);
}
break;
}
}
void scan() {
uint32_t start = 0;
int flag = 0;
for (int i = 0; i <= 2; i++) {
if (0 == digitalRead(button[i])) {
if (millis() - lastbutton > 150) {
start = millis();
while (0 == digitalRead(button[i])) {
if (settime) {
disp(th / 10, th % 10, 0, 0);
}
else {
disp(minute / 10, minute % 10, second / 10, second % 10);
}
if (i == 0 && millis() - start >= 500 && flag==0) {
settime = !settime;
//Serial.print("SET TIME:");
//Serial.println(settime);
flag = 1;
lastbutton = millis();
}
}
if(flag==0){
change(i);
lastbutton = millis();
}
}
//Serial.println(millis() - start);
}
}
}
void disp(int a, int b, int c, int d) {
int data[4] = {a, b, c, d};
for (int dig = 0; dig <= 3; dig++) {
for (byte seg = 0; seg < 7; ++seg) {
setRegisterPin(digit[seg], !seven_seg_digits[data[dig]][seg]);
// digitalWrite(digit[seg], !seven_seg_digits[data[dig]][seg]);
}
writeRegisters();
digitalWrite(num[dig], HIGH);
delayMicroseconds(100);
digitalWrite(num[dig], LOW);
}
}
//set all register pins to LOW
void clearRegisters() {
for (int i = numOfRegisterPins - 1; i >= 0; i--) {
registers[i] = HIGH;
}
}
//Set and display registers
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters() {
digitalWrite(RCLK_Pin, LOW);
for (int i = numOfRegisterPins - 1; i >= 0; i--) {
digitalWrite(SRCLK_Pin, LOW);
int val = registers[i];
digitalWrite(SER_Pin, val);
digitalWrite(SRCLK_Pin, HIGH);
}
digitalWrite(RCLK_Pin, HIGH);
}
//set an individual pin HIGH or LOW
void setRegisterPin(int index, int value) {
registers[index] = value;
}
void serialEvent(){
minute = Serial.parseInt();
second = Serial.parseInt();
th = Serial.parseInt();
counting = Serial.parseInt();
settime = 0;
while(Serial.available()){
int dummy = Serial.read();// statement
}
}
====Update:2016/08/28====
Video:
2015年4月5日 星期日
AFE4400 血氧計 ver2.0
第二版改的點主要是增加大容量的LED decoupling cap,然後Pin改用1.27mm的減少長度
同時把接點改成SMD並且放到背面
Code的部分則是新增了控制的面板,專門控制LED 亮度,Gain,還有AFE內部的參數