# 國立臺灣大學賽車隊軟體研發日誌-BMS/MUX_ADC_NTC ##### 組別: 動力組 ##### 負責人: 李星辰 ##### 次系統: BMS ##### 次系統編號: *填入次系統編號* ##### 軟體名稱: MUX_ADC_NTC ##### 軟體編號: *填入軟體編號* ##### 存放位置: *加入軟體存放位置超連結* ##### 開始設計日期: 2022/07/22 ##### 版本: 1.0 ##### 更動時間: 2022/07/29 ##### 組長檢核: *填入組長檢核者* ##### 組長檢核日期: *填入組長檢核日期* ##### 技術長檢核: *填入技術長檢核* ##### 技術長檢核日期: *填入技術長檢核日期* --- ## 完整工程目標 > 監測電池各個 Segment 電極處的溫度並回傳值給 Master Board ## 程式架構 > 執行順序: MUX選擇通訊通道 → ADC讀電壓值 → 計算電阻 → 回傳溫度 ## 使用的函式庫 > [Arduino.h & math.h](https://www.arduino.cc/reference/en/) > [Wire.h](https://www.arduino.cc/reference/en/language/functions/communication/wire/) > [ADS1x15.h by RobTillaart](https://github.com/RobTillaart/ADS1X15) ## 演算法參考資料 > [TCA9548A I2C Multiplexer Module](https://www.instructables.com/TCA9548A-I2C-Multiplexer-Module-With-Arduino-and-N/) > [Thermistors and NTC Thermistors](https://www.electronics-tutorials.ws/io/thermistors.html) > [NTC Thermistor Beta](https://www.ametherm.com/thermistor/ntc-thermistor-beta) > [Calculating Temperature from Resistance](https://www.northstarsensors.com/calculating-temperature-from-resistance) ## 測試環境 > 填入測試環境(有用到的軟體以及版本) ##### 電腦硬體:ROG ZEPHYRUS GA401 ##### 作業系統: Windows 10 家用版 21H2 ##### 編譯器版本(python版本): Arduino IDE 1.8.15 ##### 其他硬體 > MCU: Arduino Nano > MUX: TCA9548A I2C MUX > ADC: Ads1115 > NTC: NXFT15XH103FA2B100 > [NTC DataSheet](https://www.mouser.tw/datasheet/2/281/1/NXFT15XH103FA2B100-2936858.pdf) --- ## 2.0板內容 - 各元件API整理/編寫 #### MUX 我們選的MUX( TCA9548A )在使用上非常簡單,因此只需要包含ADDRESS以及CHANNEL就可以了。 ```cpp= // 宣告MUX類別 class MUX { public: // __init__ MUX() : _ADDR(0x70), _Channel(0) { //預設位址、預設通道 set_channel(); } MUX(uint8_t ADDR) : _ADDR(ADDR), _Channel(0) { //有更改位址、預設通道 set_channel(); } MUX(uint8_t ADDR, int CH) : _ADDR(ADDR), _Channel(CH) { //有更改位置、有其他預設通道 set_channel(); } // public var // func //啟動MUX bool begin(); bool begin(uint8_t ADDR); //設置通道 void set_channel(); void set_channel(uint8_t CH); //回傳是否啟動 bool operator bool (){ return _Active; } private: bool _Active = false; uint8_t _ADDR; uint8_t _Channel; }; ``` #### NTC 將所有跟熱敏電阻有關的變數全部提取+整理。 ```cpp= //宣告NTC物件 class NTC { public: // init // default Resistor: 10k, Temp: 25C NTC() : _R(10000), _T(25), _val(25), _V(2.5), _ratio(0.1) {} NTC(double R) : _R(R), _V(2.5), _val(0), _ratio(0) { R2T(); } // set vary type of var void set_ratio(double ratio); // Use for val->V void set_val(int16_t val); // Set value void set_R(double R); // Set resistance void set_V(double V); // Set Voltage void set_T(double T); // Set Temp //Transform value to Voltage void val2V(); void val2V(double ratio); // transform Resistor to Temp void R2T(); void R2T(char* a); // transform Voltage to Resistor void V2R(); void V2R(double Vref); void V2R(double Vref, double RX); // get each datas int16_t get_val() { return _val; } double get_Resistor() { return _R; } double get_Temp() { return _T; } double get_Voltage() { return _V; } void show(); private: double _ratio; // val to V ratio int16_t _val; // value double _R; // Resistance double _V; // Voltage double _T; // Temp }; ``` #### Timer 因為會需要定時回傳/檢查數據,乾脆直接把定時器寫成一個簡單的物件,方便後續的定時。 ```cpp= class Timer { public: //init Timer() : _start_time(0), _current_time(0), _time_gap(1000), _difference(0) {} Timer(long int gap) : _start_time(0), _current_time(0), _time_gap(gap), _difference(0) {} void begin(); // 開始計時 void set_time_gap( long int g ); //設定定時間格 bool check_time(); //確認計時 long int get(); //回傳經過秒數 private: long int _start_time; long int _current_time; long int _difference; long int _time_gap; }; ``` ## 2.0版測試結果 尚未測試,但編譯器有過 + 是拿原本程式碼改的,問題應該不大。 會在測試後補上結果 ## 2.0版改進方向 > ADC整理: 他有夠難設定 > 希望目標: 可以依照Segment回傳,設定電壓輸入參考腳位 > ADC函式庫看要不要改成 Adafruit 的 --- ## 1.0 版內容 - MUX 多工器 選擇/切換通訊通道 - ADC 類比/數位轉換器 一對四 - 熱敏電阻/溫度轉換函式 #### MUX ##### 用途 MUX(數據多工器)用於減少讀取數值所需要的腳位數量,要讀取n個輸入,只需要$log_2(n)$個腳位。本次使用的MUX使用I2C通訊界面來處理不同訊號輸入。I2C MUX通常用於避免擁有相同I2C位址的芯片互相衝突。 ##### 使用原因 在EP4使用的電池,會需要處理8組電池 Segment,每組電池需要量測12個點,總共96個量測點,同時電池Segment之間會需要做隔離。ver 1.0採用的ADC每顆可以轉換4個不同輸入源,同時可以設定四組不同的位址,在沒有使用MUX的情況下最多可以量測16比不同數據,遠遠不到96組,同時又要滿足隔離的條件,因此需要8通道的MUX。 ##### 接線 ![image alt](https://i.imgur.com/NPVF4ZC.png) TCA9548A的腳位配置非常簡單,SDA與SCL分別對應Master Board的SDA/SCL腳位,A0~A2用來設置MUX的通訊位址,剩餘的腳位用來接上要通訊的芯片就接好了 ![](https://i.imgur.com/Ba6OEWk.png) ##### 使用方式 TCA9548A的使用方式非常簡單,只需要將要通訊的通道寫道MUX裡面即可。 ex: 想要與Channel 0通訊,只要寫入 B00000001 (0x01)就行 ```cpp= void TCA9548A(uint8_t bus) { Wire.beginTransmission(0x70); // TCA9548A address is 0x70 Wire.write(1 << bus); // send byte to select bus Wire.endTransmission(); } ``` #### ADC ##### 用途 ADC( Analog Digital Convertor )是一種可以將類比訊號轉換成數位形式的芯片,透過量測輸入電壓與參照電壓之間的比例,在比較之後將轉換的數值傳給控制器 ##### 使用原因 Arduino雖然自帶讀取類比輸入的腳位,但要讀取96組數據還遠遠不夠,因此需要外接可以讀取多筆輸入的ADC ##### 接線 ![](https://i.imgur.com/Q2zrKOo.png) 基本上就是看到甚麼就接什麼東西,比較需要注意的是ADDR腳位的連接,ADDR是用來設定通訊位址的。設定方式如下: ![](https://i.imgur.com/b523O2t.png) ##### 使用方法 Adafruit有已經寫好的函式庫,所以不需要特別去處理通訊資料傳輸接收。 基本上會用到幾個函式: - 宣告 宣告ADS系列的芯片物件 ```cpp= ADS1115 ADS(0x48); // 宣告一個 ADS1115的芯片,並且設定他的通訊位址 ADS.begin(); // 啟用 ADS芯片 ADS.setGain(0); // 設定參照電壓 6.144 volt ADS.setDataRate(7); // 設定通訊速率 fast ADS.setMode(0); // 設定讀取模式 continuous mode ``` - 讀值 ```cpp= float f = ADS.toVoltage(1); //宣告數值電壓轉換參數 int16_t _val[ 4 ] = { 0 }; //宣告各腳位讀值 float Voltage[ 4 ] = { 0 }; //宣告各腳位電壓 for( int i = 0; i < 4; i++ ){ _val[i] = ADS.readADC( i ); //讀取各個腳位的值 Voltage[ i ] = _val[ i ] * f; //將讀值轉換成電壓 } ``` #### NTC ##### 用途 NTC是熱敏電阻的一種分類,國高中物理有教,電阻的電阻值會隨著環境溫度的上升而下降,但一般電阻的下降值並不明顯,熱敏電阻就是一種電阻值會隨著環境溫度改變產生明顯變化的電阻。 一般熱敏電阻有兩種,NTC&PTC NTC電阻的電阻值會隨著溫度的上升而下降,PTC的電阻值則會歲著溫度的上升而上升 FASE官方的規定寫說硬體電路的元件不可以使用PTC元件,這點要注意。 ##### 使用原因 需要測量電芯溫度 ##### 計算方式 熱敏電阻有一個很重要的參數: $\beta$ $\beta_{T_1/T_2}=\frac{ln( \frac{R_1}{R_2} )}{ (\frac{1}{T_1}-\frac{1}{T_2})}$ $\beta_{T_1/T_2}$代表著NTC電組值在溫度$T_1$與$T_2$的差異,也就是說,只要有在某個溫度的電阻值以及他的$\beta$值,就可以推出NTC在另一個溫度的電阻值,有了兩點的數值之後,就可以得到電組-溫度的曲線圖,就可以推出電阻值在不同溫度的近似值,誤差範圍在0.1~0.3℃之間。 ##### 計算過程 ###### NTC電組溫度換算 點進[DataSheet](https://www.mouser.tw/datasheet/2/281/1/NXFT15XH103FA2B100-2936858.pdf),可以看到官方有給在25℃時的電阻值與四組$\beta$,也就是說,我們可以得出這個NTC在五個溫度時的電阻值,已知NTC的電阻與溫度關係大致與$R=ne^{kT}$相符,因此我們可以由五個已知點做近似得出這家NTC的$R(T)$。計算過程與公式圖表都在以下檔案中: <iframe src="https://docs.google.com/spreadsheets/d/e/2PACX-1vT1_jw1NvYORTYyy9T1VZfOTvfp1JZaqIfKHyfn_5nw46MufquIWuzLDA1k_EtVouV-Bkf1yPb0VTwH/pubhtml?gid=1112537462&amp;single=true&amp;widget=true&amp;headers=false" width = "105%" height = 450></iframe> [待補]() ###### NTC電組測量 ![](https://i.imgur.com/xFs3gDO.png) 上圖為一個分壓電路,根據分壓電路計算,可以得出NTC的電阻值$R=R_X\bullet( \frac{V_{in}-V_{out}}{V_{in}} )$ 其中$V_{in}$為輸入電壓,$V_{out}$為分壓電路分出來的電壓。 ##### 程式 ```cpp= //雖說Arduino語法語C++類似,但常用函式庫並沒有通用 #include<math.h> //< functions > //Natural log 自然對數計算 Arduino沒有內建的ln() double ln( float N ) { return double( log(N) / log(M_E) ); } //R to Kelvin Temp 電阻值轉絕對溫度 double R2K( double R ) { return -( ln( R / pow(10, 8) ) ) / 0.031; } //R to C 電阻值轉攝氏溫標 double R2C( double R ) { return -( ln( R / 20796 ) ) / 0.031; } //V to R 依照不同測試條件輸入不同參數 float V2R( float v ) { return 10000 * float ( (5 - v) / v ); } float V2R( float v, float Vref ) { return 10000 * float ( (Vref - v) / v ); } float V2R( float v, float Vref, float Rx ) { return Rx * float ( (Vref - v) / v ); } ``` ## 1.0版測試結果 > 測試方式: 電池接負載量測電池升溫狀況 > 數據格式: csv > 記錄方式: 將Serial輸出格式調整為csv,結束測量的同時將數據複製儲存,以利後續處理。 > 輸出數據: [MUX_ADC.csv](https://docs.google.com/spreadsheets/d/1NBPP9Wy_1shrK7nx-FktpjB3s1GwmS8JT5EraRn-_Mc/edit?usp=sharing) ![](https://i.imgur.com/QajbO27.png) ## 1.0版改進方向 > 為了方便維護以及簡化主程式,之後要把程式寫成一個個物件以及簡化需要的參數。此外,之後可能會使用不同型號的ADC,所以需要因應不同芯片對程式碼做調整,挑選芯片時就會查找有沒有對應的函式庫。 :::warning 填寫完請將此表的超連結(github上的)放至[這裡](https://docs.google.com/spreadsheets/d/1slk_8V2VJco42WuU0_OY8UjR3JOtOSg_u7ZOxh3JsI0/edit#gid=0) :::