[toc] ## Test stand 影片介紹 [類似的1](https://www.youtube.com/watch?v=-yq1EmTkBCs&t=271s&pp=ygUXcm9ja2V0IG1vdG9yIHRlc3Qgc3RhbmQ%3D) [類似的2](https://www.youtube.com/watch?v=LyU8Yo3oiW4&t=447s&pp=ygUXcm9ja2V0IG1vdG9yIHRlc3Qgc3RhbmQ%3D) ## Progress/ Difficulty ### 結構 訂單皆已送出 2023/7/22 完成組裝 2023/7/27 ### PCB PCB1 送出 2023/7/22 ### Code [Github](https://github.com/Herokroos/Product-design) 檔案建立 2023/7/22 ### Integrated Test [Video](https://youtu.be/qLWEzkJWCpg) ### Difficulty 2023/7/23 原本選的`STM32L010F4P6`的 **`Flash(16KB)`** 跟 **`RAM(2KB)`** 不夠,因此需要先把程式完成,查看所需大小再替換換新的MCU。後來決定使用STM32F103C8這款MCU。他有 ## 組別 - 工程組 設計、製作test stand - 公關組 IG帳號經營 shopee帳號建立(目前不確定) 與其他團體接洽(目前已知 ISP 屏中社團 台東高中生 建中航空社) - 美宣組 製作相關介紹影片(以全英文為主) 產品介紹影片製作 Fusion 360 Animation + 實際測試影片 產品使用影片製作 Fusion 360 Animation + 操作步驟 ## 發想 Amateur rocketeers要自己做出穩定的推力量測裝置實屬不容易,因此想開發一款可靠性高且平價的test stand :::warning :warning: [Warning, do not click this, Pls](https://youtu.be/bhh-pXDzqJA) ::: ![](https://hackmd.io/_uploads/HykLAOfMa.jpg) ## Requirements/ Limitations 設計一款test stand,適用於小型motor,具 **推力量測及資料紀錄功能** 推力範圍限制:最大不可超過10KG ## Specification DAQ - MCU - AD-DC (HX711) - SD Card connector - Reset button - Tare button - Start button - Power Supply Indicator - SD Card Status Indicator - Buzzer ## Architecture ### Flow chart ![](https://hackmd.io/_uploads/ByA_FQtF3.png) ## Operating steps |時間戳記| 實體操作 | MCU事件控制 | 蜂鳴器狀態指示 | LED指示燈 | |:---:|:------------------------:|:----------------:|:--------------:|:---------:| | | 硬體組裝 | --- | --- | --- | | | 記憶卡插入 | --- | --- | --- | | | 電池上電 | --- | --- | --- | | | 系統測試(測試sd卡讀的到) | SD卡寫入測試訊息 | Pattern 0 |---| | | motor置入 | Load cell測試 | --- | LED blinks | | | 點火頭置入 | --- | --- | --- | | | 扣重 | HX711讀值歸零 |--- | LED blinks and off | |T-10 | 倒數計時開始 | Timer initialize | Pattern 1 | --- | |T-0 | 點火 | MOSFET高電平/資料記錄開始| Pattern 2 | --- | |T+2 | --- | MOSFET低電平 | --- | --- | |T++ | --- | 資料寫入SD卡 | --- | --- | |T+10 | --- | 資料記錄結束 | Pattern 3 | --- | |T+20 | 系統結束操作 | --- | Pattern 4 | --- | | | 電池移除 | --- | --- | --- | | | 收拾 | --- | --- | --- | ## Component development ### Thrust range > 10kg ### Load cell > [10kg load cell](https://cdn.sparkfun.com/datasheets/Sensors/ForceFlex/TAL220M4M5Update.pdf?_gl=1*1rga2nj*_ga*MTA0NTA0NjkzOS4xNjg3NzkwNDcy*_ga_T369JS7J9N*MTY4ODg5ODYxNS4xLjAuMTY4ODg5ODYxNS4wLjAuMA..) ### Hardware Development 結構件: >2020鋁型材 (3DPRT-MAKER創客專賣店) >160mm 數量4 >木芯板 (木百貨) >200 * 300 * 18 mm 數量1 3D列印件: > 固定件 * 2 固定件: >Hex Head Screws (3DPRT-MAKER創客專賣店) >內六角 M5 * 40 數量8 > >Phillips Screws/ Rounded Head Screws (商品不含運滿50元才出貨) >十字 M4 * 6 數量2 >十字 M4 * 20 數量2 >十字 M5 * 30 數量4 > >Socket Head Cap Screw (3DPRT-MAKER創客專賣店) >內六角螺絲 M4 * 8 數量16 > >T-slot Nut (3DPRT-MAKER創客專賣店) >T型螺母 M4 數量16 > >Hex Standoff, Male-Female >六角黃銅螺柱 M4 * 10(內牙螺) * 6(外螺牙) 數量4 > >--- >Spacer Support for PCB (商品不含運滿50元才出貨) >六角黃銅螺柱 M3 * 10 數量4 >十字 M3 * 8 數量4 ## DAQ Software&Hardware Configuration ### Private user code ```c /* create a function in order to delay */ void delay_ms(uint32_t target) { __HAL_TIM_SET_COUNTER(&htim2, 0); while(__HAL_TIM_GET_COUNTER(&htim2) < target) { // waiting counter to count to target } } /* create a function in order indicate the stauts of the loadcell */ void LC_func(uint32_t times){ for (int i =0;i<= times;i++ ){ HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);// high level delay_ms(200); HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);// low level delay_ms(200); } HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);// low level delay_ms(1800); } ``` ### Timer #### Timer Configuration :::info :bulb: Using Timer2; APB1 timer clocks 記數單位設定為1000ms ![](https://hackmd.io/_uploads/BJFY6_L5h.png) Timer clock frequency(Hz) = 8MHz Prescaler = 8000 - 1 Counter Period = 10000 8MHz/8000 * 1000 = 1Hz = 1000ms ::: #### Basic code ```c /* create a function to count time*/ void delay_ms(int target) { __HAL_TIM_SET_COUNTER(&htim2, 0); HAL_TIM_Base_Start(&htim2); while(__HAL_TIM_GET_COUNTER(&htim2) < target) { // waiting counter to count to target } } /* init the TIM */ static void MX_TIM2_Init(void){ /* USER CODE BEGIN TIM2_Init 2 */ HAL_TIM_Base_Start(&htim2); // start the TIM /* USER CODE END TIM2_Init 2 */ } ``` --- ### printf ```c /* USER CODE BEGIN 4*/ int __io_putchar(int ch) { ITM_SendChar(ch); return ch; } ``` --- ### LED #### GPIO Configuration :::info :bulb: GPIO **`GPIO_Output`** GPIO output level **`Low`** GPIO mode **`Output Push Pull`** GPIO Pull-up/ Pull-down **`No push-up and no pull-down`** Maximum output speed **`Low`** User Lable **`LED`** ::: #### Basic Code ```c /* in main.h */ #define LED_Pin GPIO_PIN_2 #define LED_GPIO_Port GPIOA /* in main.c */ while(1){ HAL_GPIO_TogglePin(LED_GPIO_Port, LED_PIN);// 翻轉狀態 HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);// high level HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);// low level } ``` ### Buzzer #### GPIO Configuration :::info :bulb: GPIO **`GPIO_Output`** GPIO output level **`Low`** GPIO mode **`Output Push Pull`** GPIO Pull-up/ Pull-down **`No push-up and no pull-down`** Maximum output speed **`Low`** User Lable **`Buzzer`** ::: | 時間戳記 | Pattern | High level |Low level|extra| |:-------------------------------:|:-------:|:----------:|:------:|:---:| | When the SD Card can't be read | 0 | 400ms | 200ms |High level 400ms| | At T-10(Start button is pressed) | 1 | 500ms | 500ms |10times| | At T-0 | 2 | 1000ms | 9000ms| | | At T=10 | 3 | 200ms | 800ms | | | At T=20 | 4 | 2000ms | | | #### Code ```c /* in main.h */ #define Buzzer_Pin GPIO_PIN_0 #define Buzzer_GPIO_Port GPIOB /* in main.c */ while(1){ /* pattern 0 */ HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// high level delay_ms(400); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET);// low level delay_ms(200); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// high level delay_ms(400); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// low level /* pattern 1 */ for(int p1 = 0; p1 < 10; p1++){// repeats 10 times HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// high level delay_ms(500); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET);// low level delay_ms(500); } /* pattern 2 */ HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// high level delay_ms(1000); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET);// low level delay_ms(9000); /* pattern 3 */ HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// high level delay_ms(200); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET);// low level delay_ms(800); /* pattern 4 */ HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);// high level delay_ms(2000); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET);// low level } ``` --- ### Button #### Configuration :::info :bulb: 1. **Tare button** GPIO **`GPIO_Input`** GPIO mode **`Input mode`** GPIO Pull-up/ Pull-down **`No push-up and no pull-down`** User Lable **`Tare`** 2. **Start button** GPIO **`GPIO_Input`** GPIO mode **`Input mode`** GPIO Pull-up/ Pull-down **`No push-up and no pull-down`** User Lable **`SWpin`** ::: #### Code ```c /* in main.h */ #define Tare_Pin GPIO_PIN_10 //tare button #define Tare_GPIO_Port GPIOA #define SWpin_Pin GPIO_PIN_1 // start button #define SWpin_GPIO_Port GPIOA /* in main.c */ /* USER CODE BEGIN PV */ int Tare_button_state = 0; int Start_button_state = 0; /* USER CODE END PV */ while(1){ Tare_button_state = HAL_GPIO_ReadPin(Tare_GPIO_Port, Tare_Pin); if(Tare_button_state == GPIO_PIN_RESET){// low level //tare } Start_button_state = HAL_GPIO_ReadPin(SWpin_GPIO_Port,SWpin_Pin); if(Start_button_state == GPIO_PIN_RESET){// low level //sequence start } } ``` --- ### SD CARD #### Configuration :::info :bulb: **SD CARD configuration** 1. Set the SD CARD `format` to **FAT32**, `allocation unit size` **4096** ![](https://hackmd.io/_uploads/rk9Nc6g33.png) if the allocation unit size does not have the option `4096`, you may follow steps below to change it - Win+R, enter `diskmgmt.msc` - Select and right click the micro sd card, click the **Format** - Select the `file system` **FAT32**, `allocation unit size` **4096** - Apply ::: :::info 1. SPI1 Mode **`Full duplex Master`** 2. select one pin GPIO **`GPIO_Output`** GPIO mode **`Push-Pull`** User_Lable: **`SD_CS`** 3. **MIddleware** >>FAT32 --> User define --> Enable **`USE_LFN`** with `Enabled with static working buffer on the BSS` --> Set **`MAX_SS`** `4096` --> Generate Code 4. Include **Library** into STM32CUBEIDE [fatfs_sd.h](https://raw.githubusercontent.com/eziya/STM32_SPI_SDCARD/master/Old_STM32F1/Inc/fatfs_sd.h) [fatfs_sd.c](https://raw.githubusercontent.com/eziya/STM32_SPI_SDCARD/master/Old_STM32F1/Src/fatfs_sd.c) 6. **Modifications** Modify the File **`stm32l0xx.it.c`** **`user_diskio.c`** See the code at [here](https://embetronicx.com/tutorials/microcontrollers/stm32/stm32-sd-card-interfacing-with-example/) ::: #### Code in main.c ```c #include "fatfs.h" #include "fatfs_sd_card.h" #include "string.h" #include "stdio.h" #include "stdbool.h" float Thrust; int main(void){ process_SD_card(); while(1){ ... /* SD writing */ fres = f_mount(&FatFs, "", 1); //1=mount now if (fres != FR_OK) { printf("No SD Card found : (%i)\r\n", fres); break; } printf("SD Card Mounted Successfully!!! data coming in!!!\r\n"); fres = f_open(&fil, "data.txt", FA_WRITE | FA_READ | FA_CREATE_ALWAYS); if(fres != FR_OK) { printf("File creation/open Error : (%i)\r\n", fres); break; } //write the data printf("Writing data!!!\r\n"); f_puts("Confirmation SD card open successfully", &fil); //close your file f_close(&fil); printf("Closing File!!!\r\n"); /* unmount SD card*/ f_mount(NULL, "", 0); printf("SD Card Unmounted Successfully!!!\r\n"); } } void process_SD_card( void ){ FATFS FatFs; //Fatfs handle FIL fil; //File handle FRESULT fres; //Result after operations char buf[100]; do { //Mount the SD Card fres = f_mount(&FatFs, "", 1); //1=mount now if (fres != FR_OK) { printf("No SD Card found : (%i)\r\n", fres); break; } printf("SD Card Mounted Successfully!!!\r\n"); //Read the SD Card Total size and Free Size FATFS *pfs; DWORD fre_clust; uint32_t totalSpace, freeSpace; f_getfree("", &fre_clust, &pfs); totalSpace = (uint32_t)((pfs->n_fatent - 2) * pfs->csize * 0.5); freeSpace = (uint32_t)(fre_clust * pfs->csize * 0.5); printf("TotalSpace : %lu bytes, FreeSpace = %lu bytes\n", totalSpace, freeSpace); //Open the file fres = f_open(&fil, "data.txt", FA_WRITE | FA_READ | FA_CREATE_ALWAYS); if(fres != FR_OK) { printf("File creation/open Error : (%i)\r\n", fres); break; } printf("Writing data!!!\r\n"); //write the data f_puts("Confirmation SD card open successfully", &fil); //close your file f_close(&fil); printf("Closing File!!!\r\n"); } while( false ); //We're done, so de-mount the drive f_mount(NULL, "", 0); printf("SD Card Unmounted Successfully!!!\r\n"); } ``` #### Reference [Reference](https://embetronicx.com/tutorials/microcontrollers/stm32/stm32-sd-card-interfacing-with-example/) [FAT32 functions](http://elm-chan.org/fsw/ff/00index_e.html) --- ### HX711 [Github](https://github.com/PCov3r/HX711-STM32-Library/tree/main) [flaot to string](https://www.796t.com/content/1541228343.html) [enable the printf in stm32CubeIDE](https://blog.csdn.net/sudaroot/article/details/105099807) #### Configuration :::info :bulb:q 1. GPIO **`GPIO_Output`** GPIO mode **`No push-up and no pull-down`** User_Lable: **`PD-SCK`** 2. GPIO **`GPIO_Input`** GPIO mode **`No push-up and no pull-down`** User_Lable: **`DAT`** ::: #### Calibration :::info :bulb: calibrate the coef by adjusting the x in **`hx711_coef_set(&loadcell, x);`** that **hx711_weight** = 0 ::: ```C /* in main.c*/ #include "hx711.h" hx711_t loadcell; float Thrust; . . int main() { hx711_init(&loadcell, PD-SCK_GPIO_Port, PD-SCK_Pin, DAT_GPIO_Port, DAT_Pin); hx711_coef_set(&loadcell, x); // read afer calibration, x varies with different loadcell hx711_tare(&loadcell, 10); // tare the value while (1) { HAL_Delay(500); Thrust = hx711_weight(&loadcell, 10); } } ``` #### Code ```C /* in hx711.c*/ /* add code below before hx711_delay_us */ static inline void __nop(void) { __asm__ __volatile__("nop"); } /* in main.c*/ #include "hx711.h" hx711_t loadcell; float Thrust; . . int main() { hx711_init(&loadcell, PD-SCK_GPIO_Port, PD-SCK_Pin, DAT_GPIO_Port, DAT_Pin); hx711_coef_set(&loadcell, x); // read afer calibration, x varies with different loadcell hx711_tare(&loadcell, 10); // tare the value while (1) { /* use it only when adjusting the coef HAL_Delay(500); */ Thrust = hx711_weight(&loadcell, 10); } } ``` ## PCB Design PCB (DAQ) ~~STM32L010F4P6~~ [STM32F103C8T6 datasheet](https://www.st.com/resource/en/datasheet/stm32f103c8.pdf) [STM32F103C8T6 schematic reference1](https://stm32-base.org/assets/pdf/boards/original-schematic-STM32F103C8T6-Blue_Pill.pdf) [STM32F103C8T6 schematic reference2](https://kicad-info.s3.dualstack.us-west-2.amazonaws.com/original/3X/e/4/e4c88b48af7bf832b11c87d979695b311abeaeb4.svg) [STM32F103C8T6 schematic reference3](https://i.stack.imgur.com/db32S.png) [HX711 datasheet](https://cdn.sparkfun.com/datasheets/Sensors/ForceFlex/hx711_english.pdf) [HX711 schematic](https://image.easyeda.com/components/5a7e011054ba4e0d9779a664469bc3ab.png) [SD CARD schematic](https://i.stack.imgur.com/mRfRK.jpg) [Voltage Regulator](https://img-blog.csdnimg.cn/20190225095242384.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1hMX19NQVg=,size_16,color_FFFFFF,t_70) [CH340 schematic reference(web)](http://nicecircuits.com/ch340g-usb-to-rs232-ttl-module-schematic-d-sun-v3-0/) [CH340 schematic reference(github)](https://github.com/NiceCircuits/modules_from_china/tree/master/CH340G_D-SUN-V3.0) ## Debug [terminal](http://www.embedded-communication.com/en/misc/printf-with-st-link/) [float printf](https://forum.digikey.com/t/easily-use-printf-on-stm32/20157) ## System integration test 測試自製motor ## 已知支出 / 產品內容物 | 品項名稱 | 數量 | 價錢 | 小計 | |:----------------:|:----:|:----:|:----:| | 18mm 木芯板 | 1 | 71 | 71 | | 2020鋁型材 | 4 | 62 | 248 | | 3D列印件(固定板) | 2 | | | | M4 T型螺母 | 16 | 3 | 48 | | M4*8內六角螺絲 | 16 | 2 | 32 | | M5*40內六角螺絲 | 8 | 5 | 40 | | M4*6十字螺絲 | 2 | 1 | 2 | | M4*20十字螺絲 | 2 | 2 | 4 | | M5*30十字螺絲 | 4 | 3 | 12 | | M4六角黃銅螺柱 | 4 | 3 | 12 | | M3六角黃銅螺柱 | 4 | | | | M3*6十字螺絲 | 4 | | | | PCB | 1 | | | | Load cell | 1 | | | ## 未來規劃 短期目標(9月前): 功能測試 中期目標(學測前): 產品試用 最終目標(學測前): 進行販售