發表文章

目前顯示的是 1月, 2020的文章

ESP32學習筆記-OTA 注意事項

圖片
這篇主要真對這幾天要使用ESP32開發專案,將examples中直直制專案內朽發現的問題,以及解決的方法 undefined reference to `_binary_ca_cert_pem_start 一開始移植後遇到這個問題,經過搜尋以及嘗試後解決方法如下:        將範例中的server_certs及裡面的ca_certpem 一起複製到自己的專案 打開main.資料夾中的CMakeLists.txt,加入" set(COMPONENT_EMBED_TXTFILES ${IDF_PROJECT_PATH}/server_certs/ca_cert.pem) " E (86336) esp_ota_ops: not found otadata 解決方法法就是 make menuconfig->partition Table->勾選Factory app,  two OTA definitions

ESP32學習筆記-常見的系統API

這篇做一個紀錄,將常用的系統API紀錄在這邊  esp_restart(): 系統軟體重起功能,  esp_chip_info() 得到chip的相關數據,使用方法: /* Print chip information */ esp_chip_info_t chip_info; esp_chip_info( & chip_info); printf( "This is ESP32 chip with %d CPU cores, WiFi%s%s, " , chip_info.cores, (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "" , (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "" ); printf( "silicon revision %d, " , chip_info.revision); printf( "%dMB %s flash \n " , spi_flash_get_chip_size() / ( 1024 * 1024 ), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external" );   vTaskDelay(1000 / portTICK_PERIOD_MS) 這個比較偏FreeRTOS的東西,不過在這邊先做紀錄  

C語言筆記-用結構體讓函式可以返回多個資料

C與言的函式無法回傳一個以上的值,不過可以透過回傳一個結構來完成: 範例: #include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct { double width,height; }size_s; size_s width_height ( char * papertype){ return ! strcasecmp(papertype, "A4" ) ? (size_s){.width = 210 ,.height = 297 } : ! strcasecmp(papertype, "Letter" ) ? (size_s){.width = 216 ,.height = 279 } : ! strcasecmp(papertype, "Legal" ) ? (size_s){.width = 2216 ,.height = 356 } : (size_s){.width = NAN,.height = NAN}; } int main ( void ) { size_s a4size = width_height( "A4" ); printf( "width=%g,height=%g \n " ,a4size.width,a4size.height); } 透過 condition?iftrue:else的格式來取代switch,而且也可以放在return後面 "21centry c"一書的作者很提倡這種風格。 除了用結構體之外,也可以用指標透過參數在函式內修改來完成: void width_height ( char * papertype, double * width, double * height); 這種風格是我常用的方法,也是最常見的格式,不過很容易混淆輸入跟輸出。

C語言筆記-結構體的初始化

圖片
一般程式常看到這種結構的初始化方式: direction_s upright={NULL,0,1,1,0}; direction_s upright = { NULL , 0 , 1 , 1 , 0 }; 這種填充式的結構初始化很糟糕,因為必須要記住所有的結構成員順序,這種方式很不人性化 初始化應該使用上標籤: #include <stdio.h> #include <stdlib.h> typedef struct { int one; double two,three,four; }n_str; n_str d = { 100 , .four = 10 , .two = 30 , }; int main ( void ) { printf( "%d %g %g %g" ,d.one,d.two,d.three, d.four); } 從上面的程式碼中可以看到初始化結構成員,順序不用與聲明的一致,編譯器也是可以成功編譯 未聲明的原素初始化為0,沒有初始過的都是設為0 可以混和聲明 在"21 century c"中有這個範例可以參考: #include <stdio.h> #include <stdlib.h> typedef struct { char * name; int left,right,up,down; }direction_s; void this_row (direction_s d); void draw_box (direction_s d); int main ( void ) { direction_s D = {.name = "left" ,.left = 1 }; draw_box(D); D = (direction_s){ "upper right" ,.up = 1 ,.right = 1 }; draw_box(D); draw_box((direction_s){}); return 0 ; } void this_row

C語言筆記-用__VA_ARGS__ 完成free_all() 函式向量化

free()是一個長見的函式,不過他一次只能接受一個參數 因此常常在函式尾巴必須加上一堆釋放記憶體的工作: free(ptr1); free(ptr2); free(ptr3); 這樣的程式碼很不美觀,很冗長,寫成這樣: free_all(ptr1,ptr2,ptr3); 完成方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> #include <stdlib.h> #define Fn_apply(type,fn,...){\ void *stopper_for_apply=(int[]){0};\ type **list_for_apply=(type*[]){__VA_ARGS__,stopper_for_apply};\ \ for(int i=0;list_for_apply[i]!=stopper_for_apply;i++)\ fn(list_for_apply[i]);\ } #define Free_all(...) Fn_apply(void, free,__VA_ARGS__); int main ( void ) { int * x = malloc( 1000 ); int * y = malloc( 1000 ); int * z = malloc( 1000 ); Free_all(x,y,z); } 第5行:     提高安全性, 第6行:     需要一個終止符,卻保不與任何使用中的指標匹配,包括任何的NULL指標。 因此我們使用複合常量形式定義醫包含整數的陣列,並定義一個指向這個陣列的指標。 for迴圈的終止條件所觀察的是指標本身,而不是他指向的東西

C語言筆記-用__VA_ARGS__ 製作Foreach

很常看到陣列或是結構內使用複合常量,例如: char ** strings = ( char * []){ "one" , "two" } 現在將它放入一個For迴圈中。循環得第一部分聲明了這個字串數組,然後開始便歷整個陣列,直到最後的NULL標記。 #include #include typedef char * string; int main ( void ) { string str = "thresad" ; for (string * list = (string[]){ "111" ,str, "ropw" , NULL }; * list; list ++ ) printf( "%s " , * list); } 這樣的程式碼不易閱讀,很雜,所以用宏定易簡化: #include #include typedef char * string; #define Foreach_string(iterator,...) for(string *iterator=(string[]){__VA_ARGS__,NULL};*iterator;iterator++) int main ( void ) { string str = "two" ; Foreach_string(i, "one" ,str, "three" ){ printf( "%s " , * i); } } 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-用__VA_ARGS__ 完程多列表的宏定義

如果現在想要發送兩個任意長度列表,可以這樣做 假設現在程式顯示一個訊息,同時將一個機器獨的錯誤碼發送到日誌: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> #include <stdlib.h> #define fileprintf(...) fprintf(stderr,__VA_ARGS__) #define doubleprintf(human,machine) do{\ printf human;\ fileprintf machine;\ }while(0) int main ( void ) { int x =- 1 ; if (x < 0 ) doubleprintf(( "x is negative(%d) \n " ,x),( "NEGVAL:x=%d \n " ,x)); } 他會被拓展成: 1 2 do {printf ( "x is negative (%d) \n " , x); fileprintf ( "NEGVAL: x=%d \n " , x);} while ( 0 ); 下面試另一個例子: 給出兩列R和C,每個單元(i,j)保持Ri Cj的乘積,此城市的核心是matrix_cross宏 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <stdio.h> #include <stdlib.h> #include <math.h> #define make_a_list(...) (double[]){__VA_ARGS__,NAN} #define matrix_cross(list1,list2) matrix_cross_base(make_a_list list1,\ make_a_list list2) void

C語言筆記-透過 __VA_ARGS__ 達成可變參數的宏定義

圖片
      C語言中,可改變長度的函式很容易發生問題(之後提到) 不過要做到可改變參數的宏定義式很簡單的,關鍵字是:   __VA_ARGS__ 期展開的結果是給定的原素集合 舉例: #include <stdio.h> #include <stdlib.h> #define forloop(i,loopmax,...) for(int i=0;i<loopmax;i++)\ {__VA_ARGS__} int main ( void ) { int sum = 0 ; forloop(i, 10 ,sum += i;printf( "sum to %i:%i \n " ,i,sum);); } 輸出結果為: 不過實戰上不會這樣使用。 可參考這一篇: isnan與宏定義來做一個可調整輸入參數的功能