發表文章

目前顯示的是 2019的文章

C語言筆記-文本處理(3) 用asprintf strdup 做一個實用的可拓展字串的宏定義

用asprintf()把一段文字添加到另一個字串尾部:   asprintf(&s,%s and other string: %s",s,add); 如果今天很多字串要處理,變成 int num=5,id=27; char *s=strdup("select"); asprintf(&s,"%sscol%i\n",s,num); asprintf(&s,"%sfrom tab\n",s); asprintf(&s,"%swhere person id=%i",s,id); 得到: selectscol5 from tab where person id=27 上面這樣看,除了不整潔 也很厭煩, 也有記憶體洩漏的風險在,因為s的原位址中的對向在asprintf向s提供一個心位置時不會被釋放掉,如果生成的字串數量是未知得,長度也是未知就可以透過宏定義來簡化: #define Sasprintf(write_to, ...){ \ char *tmp_string_for_extend=(write_to); \ asprintf(&(write_to),__VA_ARGS__); \ free(tmp_string_for_extend); \ } int main(void) { int i=666; char *q=NULL; char *k="Jack"; Sasprintf(q,"Hello~~ "); Sasprintf(q,"%s %s Nice to meet you  %d.",q,k,i); printf("%s\n",q); } Sasprintf宏加上strdup,差不多100%的字串處理都能應付了,除了一個下面提到的問題乙級偶爾需要使用free外,可以不必續考慮記憶體的問體。 這個問題是:  如果q沒有初始為NULL或是忘記使用strdup,那麼第一次使用Sasprintf宏將會釋放...

C語言筆記-文本處理(2)常數字串的陷阱,用 strdup 處理

以下程式創了兩個字串: include <stdio .h=""> int main(void) {     char *s1="First";     char *s2;     asprintf(&amp;s2,"Second");     printf("%s\n,s1);     printf("%s\n,s2); } 兩種都產生了一個字串,但編譯器會用不同的方式去處理,如果不熟悉就容易造成錯誤。 "First"就是在一個空間規劃好噁的位置上,S1直接指向這個位址,如此的簡單快速 閱讀程式碼s1跟s2的行為是相同的,但是我們無法修改也不能去釋放s1 如果加上: s2[0]='f'; s1[0]='t';   //錯誤 free(s2); free(s1);    //錯誤 s1指定的內容是絕對唯讀的。 這個錯誤在我一開始踏入這行的時候遇過,被折騰了一下子 有一個簡單的方解決方法:strdup。 這是 POSIX的標準函式,字串複製(string duplicate)的簡寫:  char *s3=strdup("First"); "First"也是以硬編碼的方式寫入,但s3視這個常數字串的一份複製,所以可以自由修改。 用strdup就可以用同一種方式處理自串,不用擔心踩雷。 如果不支援strdup,就用asprintf自己寫一個 char *strdup(char const* in){     if(!in) return NULL;     char *out;     asprintf(&amp;out,"%s",in):     return out; }

C語言筆記-文本處理(1) 善用 asprintf取代sprintf

sprintf應該都不陌生,不過sprintf()使用上世有風險的,它的原型是: int sprintf(char *str,const char *format,...) 也就是說使用前必須先建立好空間,再用sprintf()將內容填入: int temp=10; char str[20]; sprintf(str," %d * %d *= %d",temp,temp,temp*temp); str輸出來看的結果為:10 * 10 = 100 但如果今天temp為10000,輸出就是: 10000 * 10000 = 100000000 則長度超過20,造成over flow的問題 用snprintf/asprintf取代不安全的sprintf才是最好的 #include <stdio.h> void get_strings(char const *in){ char *cmd; int len = strlen("strings ") + strlen(in) + 1;  cmd=(char*)malloc(len); snprintf(cmd, len, "strings %s", in);     printf("cmd:%s\n",cmd); free(cmd); } 用snprintf,需要先確定長度,還需要自己調用malloc 使用asprintf,它會自動調用malloc void get_strings_(char const *in){ char *cmd; asprintf(&cmd, "strings %s", in);     printf("cmd:%s\n",cmd); free(cmd); } --------------------- asprintf跟sprintf很像,區別在於傳入的是字串的位址而不是字串本身, asprintf()會自動分配空間 int asprintf(char **str,char *fmt,...) _...

C語言筆記-探索goto 善用goto

goto在很多交科書上都是建議大家不要使用,不過善用goto可以讓函數更加優雅: double sum_to_first_nan ( double * vector, int vector_size, double * vector2, int vector2_size, int * error) { double sum = 0 ; * error = 1 ; for ( int i = 0 ;i < vector_size;i ++ ) { if (isnan(vector[i])) goto outro; sum += vector[i]; } for ( int i = 0 ;i < vector2_size;i ++ ) { if (isnan(vector2[i])) goto outro; sum += vector2[i]; } * error = 0 ; outro: printf( "the sum until the first nan was:%g \n " ,sum); free(vector); free(vector2); return sum; } 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-強制轉換的重要

在整數相除,沒做強制轉換都會回傳一個整數,這兩條都是正確的: 4/2==2 5/4==1 第二條是容易導致錯誤的地方,有時後趕code很容易忽略到這個錯誤,只要養成一個習慣就好,假設i是整數,則(i+0.0)就可以了,括號很重要! int two=2; 3/(two+0.0)==1.5 3/(2+0.0)==1.5 3/2.0==1.5 2/2.==1.5 也可以用強制轉換的方式: 3/(double)two==1.5 3/(double)2==1, 不過用前面的方式比較有美感,在/後面加上0.0是一種好習慣 但是陣列索引要注意一下,陣列索引只能是整數: 4/(double)2==2.0 //這是正確的 list[4/(double)2]  //編譯器會提出錯誤,解決方法如下: list[(int)(4/(doube)2)] //這是正確的 也可以: int index=4/(double)2; list[index]; 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-malloc前的強制轉換

看別人的程式多少都會看到在malloc前面加上強制轉換:      dlouble * p=(double*)malloc(sizeof(length*(sizeof(double)); 會這樣加是因為早期的malloc回傳値是char*,所以要做強制轉 現在已經不需要加了,因為malloc回傳的是一個void指標,編譯器會自動轉換

C語言筆記-指標(9) 用typedef簡化指標,函數指標

有時候看到複雜類行的指標,可以考慮用typedeg進行簡化 typedef cahr* string; 拿上一篇的範例進行簡化: #include <stdio.h> int main (){ char * list[] = { "first" , "second" , "third" , NULL }; for ( char ** p = list; * p != NULL ;p ++ ) printf( "%s \n " ,p[ 0 ]); } 聲明變的清楚易懂,list就是一個字串陣列 string *p表示p是一個指向字串的指標,所以*p表示一個字串 --------------------------------------------------------- 有一函數:                         double a_fn(int,int); 只要添加星號(括號一定要加,保證優先權),就是描述一個指向這類行的函數指標:                           double (*a_fn_type)(int,int); 前面再加上typedef來定義一種類型:                          typedef double(*a_fn_type)(int,int); 可以把它當成一個類型來使用,聲明一個接受另一個函數做為輸入參數函數:    double apply_a_fn ( a_fn_type f,int first_int,int second_in){         return f(first_in,second_in); 指標其...

C語言筆記-指標(8)指標的運算

    陣列的某個成員可以用陣列的基址加上一個偏移量來表示 聲明一個指標 double *p; 他當做基址,可以向陣列一樣使用偏移量來表示: p[0]為第一個成員,p[1]為第2個成員 以此類推 所以只要有指標的基址跟相鄰成員間的距離就可以當成陣列來使用了。 教科書常出現: p[1]同等於*(p+1) 所以 陣列第一個成員是p[0] ==*(p+0) 以下有三條規則: 可以通過指標形式 double *p,或是靜態/自動形式的double p[10]來聲明陣列 無論哪個,第n+1個陣列成員都是p[n],第一項是0不是1 如果要第n個成員的位址,使用&符號:&p[n] 第一個成員的位址&p[0]==p 簡單的程式範例: #include <stdio.h> int main ( void ){ int evens[ 5 ] = { 1 , 2 , 3 , 4 , 5 }; printf( "the first even number is%i \n " , * evens); int * positive_evens =& evens[ 1 ]; printf( "the first positive even number is%i \n " ,positive_evens[ 0 ]); } --------------小技巧--------------- 在"p+1表示陣列中下一個成員對只(&p[1])"這個規則的基礎下,在下例使用 一個備用指標來指向list的頭,然後p++在陣列中向前遍歷,直到陣咧尾部的NULL標記,從而得到整個陣列的值。 #include <stdio.h> int main (){ char * list[] = { "first" , "second" , "third" , NULL }; for ( char ** p = list; * p != NU...

C語言筆記-指標(7) *號帶來的錯亂

指標的具體涵義取決於生明的方式:   int *i; *i是個整數,所以透過int *i把*i聲名為整數 下列舉出聲名中的*i與聲名外的*i涵義不同: int *i=malloc(sizeof(int));    //正確 *i=23;                                   //正確 int *i=23;                              //錯誤 簡單的說就是: 當用於聲明時,星號表示指標 不用於聲明時,星號表示指標的值            int i=10;            int*j=&i;            int *k=j;           *j=100; 第二行是對的,因為*j是一個聲明,因此表示指標 第三行 *k是一個聲名指標,把他賦值給j是合法的 第四行,*j不在聲明中,因此他表示一個普通整數,然後把100賦值給它(i                 也會隨之改變) 結論: 在聲明中看到*i,表示他是只向某個對向的指標 在非聲明中看到*i,他是指標所指向的值 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-指標(6) 少用malloc來操作記憶體

malloc,讓C語言工程師容易埋下陷阱的程式,要避免malloc的陷阱最好的方式就是避免使用。 需要使用malloc的常見原因: 改變已存在的陣列長度 無法從函數中返回一個陣列 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-指標(5) 用memmove來複製陣列

如果要複製陣列,可以用memmove來完成 #include <assert.h> #include <string.h> int main ( void ){ int abc[] = { 1 , 2 , 4 }; int * copy1,copy2[ 3 ]; copy1 = abc; memmove(copy2,abc, sizeof ( int ) * 3 ); abc[ 0 ] = 5 ; assert(copy1[ 0 ] == 5 ); assert(copy2[ 0 ] == 1 ); } copy2是透過memmove,故abc改變不會影響 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-指標(4)-函數返回的陷阱

圖片
函數可以回傳指標,會有陷阱存在,過往經驗不足的時候也有吃過鱉: #include <assert.h> #include <stdio.h> typedef struct powers{ double base,square,cube; }powers; powers get_power ( double in){ powers out = { .base = in, .square = in * in, .cube = in * in * in }; return out; } int * get_even ( int count){ int out[count]; for ( int i = 0 ;i < count;i ++ ) out[i] = 2 * i; return out; //埋下問題 } int main (){ powers threes = get_power( 3 ); int * evens = get_even( 3 ); printf( "threes:%g \t %g \t %g \n " ,threes.base,threes.square,threes.cube); printf( "evens: %i \t %i \t %i \n " ,evens[ 0 ],evens[ 1 ],evens[ 2 ]); } 執行2次: 原因出函式退出時,陣列內容的內存會被釋放,但指標一然會回傳 不過通常編譯器都會提出警告! 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-指標(3) 結構複製,陣列創造與別名

要複製結構體,只需要一個等號就可以完成。 #include <assert.h> typedef struct { int a,b; double c,d; int * e; }test; int main ( int argc, char ** argv){ test s1 = { .b = 1 , .c = 2 , .d = 3 , .e = ( int []){ 4 , 5 , 6 } }; test s2 = s1; s1.b = 15 ; s1.c = 55 ; s1.e[ 0 ] = 7 ; assert(s2.a == 0 ); assert(s2.b == 1 ); assert(s2.c == 2 ); assert(s2.d == 3 ); assert(s2.e[ 0 ] == 7 ); } 這些斷言都會通過     這個demo可以發現 修改s1.b s1.c並不會影響s的b c值,所以這些數據是創建一份複製。     但是指標的複製仍然是只向原先結構內的數據,所以修改s1.e時s2.e也會跟著改變,解決辦法就是在結構有指標的時候用函數進行複製。 _ 指標指向一個陣列: #include <assert.h> int main (){ int abc[] = { 1 , 2 , 4 }; int * copy = abc; copy[ 0 ] = 5 ; assert(abc[ 0 ] == 5 ); } 指標被修改,則原陣列內容也被修改 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-指標(2) 沒有用malloc的指標

現在要把A設置給B,通常有兩種目的的可能: 把B的值複製給A,此時A做任何改編接不會影響B 把A變成B的別名。此時A做改變B也會改變 所以在寫程式必須明確說明是要複製一份還是創建一個別名。 部使用malloc可以讓程式更靈活: 假設有一個函示: void inc(int *i){         (*i)++; } 一般來說會這樣使用: int *i=malloc(sizeof(int)); *i=10; inc(i); . . . free(i); 善用這種自動分配內存的話可以直接: int i=12; inc(&i); ----------------------------------------------------------------- 邊寫程式,遇到這種把A設至成B的狀況 可以視情況決定是改成別名 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-指標(1)

指標最容易搞混的就是: int array[] int *ptr_array 這兩種之間的差別 int array[10]: 程式會做出已下的行為 在棧上分配一個可以容納10個整數的空間 把array當成一個指標 將指標與分配好的位址綁定   這個空間是由系統自動分配出來的,所以不能改變其大小,如果拖離範圍後被釋放了,依然可以再拿回這個空間。    但array這個指標不能指向其他地方,因為它與分配好的位址是綁定的。 int *ptr_array: 程式指會做一件事,就是將array聲明為一個指標 這個指標沒有綁定任何位址,可以重心只想任何地方,以下都是合法使用:      ptr_array=malloc(sizeof(int)*10);                      or      ptr_array=array; 所以 int array[]和int *ptr_array 是不一樣的,已前看過幾本書都是把它們話上等號 不過在函示傳遞就沒有什麼區別了: int fun(int *ptr_array,int array[]); 本質上他們做的事情都是一樣的 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-const(4) char const **的問題

圖片
#include <stdbool.h> #include <strings.h> bool check ( char const ** in){ return ( ! strcasecmp(in[ 0 ], "123" ) && ! strcasecmp(in[ 1 ], "456" )) || ( ! strcasecmp(in[ 0 ], "abc" ) &&! strcasecmp(in[ 1 ], "def" )); } int test () { char * a[] = { "123" , "456" }; return check( & a[ 0 ]); } 我用Devc++編譯慧無法通過: 需要在這裡做一個類型轉換才行: return check((char const**)&a[0]); 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-const(3) 衝突

在實際操作中會出現const帶出來的問題, 一個const的指標,有時候需要把它當做輸入參數給一個沒有const標記的函示 這時候可以用強制轉換成其他非常數的指標就好: void set(int *a,int *b){     a[0]=1; } int main(void){     int a[10]={};     int const *b=a;     set(a,(int*)b); //這麼一來就可以跳過編譯器給的警告了 } 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記-const(2)

這是一個在網路上或書上常看到的: int const int const* int *const int *const* int const** int const*const* 要讀這種宣告就是由右往左讀: int const=一個常數整數 int const*=指向一個常數整數的指標 int *const=指向一個整數的常數指標 int *const*=一個指向常數指標的指標,常數指標指向一整數 int const**=一個指向指標的指標,指標指向常數整數 int const*const*=一個指向常數指真的指針,常數指針指向常數整數 int const 可以寫成const int

C語言筆記-const(1)

const是一個常見的常數,函數輸入參數如果是非指標的數據,通常就是理解成這數據在此函數中不會被修改,單純做傳遞 如果輸入參數有指標的話就很曖昧了。 在傳遞的指標數據前面加上const做修飾就很容易看出這參數在函示中並不會被修改,這對看code的人來說非常方便,就算未來自己看道也可以很快清楚。 不過還是能透過指標來修改const修飾過的變數: void set(int *a,int const *b){     a[0]=1; } int main(void){     int a[5]={};     int const *b=a;     set(a,b); } 把結果輸出可以看到有const修飾的b也是被修改了

C語言筆記 -避免頭文件(.h)重複包含

如果在a.c中 include 一個a.h 在b.c中include 一個a.h 如果出現編譯錯誤,表示頭文件重複包含了 解決方法有兩個 1.C與言標準提供這個辦法: 在頭文件中加入 #ifndef A_H #define A_H //your code #endif 2.加上pragma once 在頭文件上面加上 #pragma once   這樣編譯器就不會發生二次包含 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記 -用宏定義做一個可返回的斷言

做一個斷言失敗會回傳的宏定義 #include <stdio.h> #include <stdlib.h> #define Claim(assertion,returnval)  if(!(assertion))  \           {fprintf(stderr,#assertion" failed to be true.  \ Return " # returnval"\n");return returnval;} int test(int x,int y){     Claim(x==y,-1);     return 0; } 如果沒有回傳值的函數可以這樣做: void doSomethings(int x,int y) {      Claim(x==y, );      return; } 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C語言筆記 -預處理器的技巧(2)

前偏:C語言筆記 -預處理器的技巧(1) 如果想要將兩個非字串連在一起,可以用兩個#: ## #include <stdio.h> #include <math.h> #define Setup_list(name,...)                                                            \         double *name  ## _list=(double[]){__VA_ARGS__,NAN}; \         int name ##_len=0;                                                                 \         for(name##_len=0;!isnan(name ## _list[name ##_len]);)       \                     name ## _len ++; int main() {     Setup_list(items,1,2,3,6);     double sum=0;   ...

C語言筆記 -預處理器的技巧(1)

圖片
預處理器保留的標記是 # ,有三種用法: 1.標記一個指令 2.輸入的字 字串化 3.連結符號 #用在宏定義中:把輸入參數轉換成一個字串 #include <stdio.h> #include <stdlib.h> #define  Printf_(cmd)   printf(#cmd ":%g\n",cmd); int main(){    double*plist=(double[]){11,22,33};   doublelist[]={55,66,77};         Printf_(sizeof(plist)/(sizeof(double)+0.0));    Printf_(sizeof(list)/(sizeof(double)+0.0)); } 在這裡 #cmd會把cmd轉成字串: 此文章內容參考"21 century c"一書,在此做筆記 如須刪除請告知 謝謝

C與言筆記-宏定義 define 的注意事項與陷阱

這幾篇會對宏定義#define做個筆記: ------------------------------------------------------------------------------------------- 宏定義主要執行文本交換,以下有些陷阱要避開: 陷阱1: #define double(x) 2*x 執行 int main(void) {     printf("double(4):%d\n",double(4)); } 結果為8 -------------------- 執行 int main(void) {     printf("double(1+1):%d\n",double(1+1)); } 結果不會是預期的8而是10 因為替換後變成 printf("double(1+1):%d\n",1+1*8); 為了預防這種錯誤,最好事都加上括號() #define double(x)  (2*x) 最常見的宏定義就是: #define max(a,b)   ((a)>(b)?(a):(b)) --------------------------------------------------------- 陷阱2: 宏定義的兩端要加上大括號{} #define increament(a,b)    \         (a)++;                          \         (b)++; 沒有加大括號,如果把他放在if後面會有此風險: int x=1,y=0; if(x>y)     increament(x,y); 展開的話變成: int x=1,y=0; if(x>y)     (x)++; (y++); 這是一種常見的宏定義陷阱 ----...

isnan與宏定義來做一個可調整輸入參數的功能

#include <math.h> #include <stdio.h> double sum_(double in[]) {     double sum=0;     for( int i=0;! isnan (in[i]);i++)         sum+=in[i];     return sum; } #define sum(...) sum_((double[]){__VA_ARGS__,NAN}) int main(){ double SUM=sum(3,4); printf("3+4=%g\n",SUM); } 再翻以前不知道看哪本書的時候從書上整理下來的code 利用__VA_ARGS__ 讓輸入可以更有彈性 不過這個方法有個問題:     我在幾個IDE中build,都發現isnan在不是double型態的情況下讀到NAN也不會返回正確的值 此文章內容參考"21 century c"一書,在此做筆記  如須刪除請告知 謝謝

ESP32學習筆記(零)-RTOS SDK使用筆記(包含燒錄)

圖片
最近都有用ESP8266 RTOS 怕之後又要花時間記憶怎麼build code跟燒code,在此先記錄一下 1.先到官方文件中提供的網址下載vitualBox: Please download VirtualBox from: https://www.virtualbox.org/wiki/Downloads 2.下載ESP8266_lubuntu_20141021.ova:     http://downloads.espressif.com/FB/ESP8266_GCC.zip --------------------------------------------------------------------------- 載完,配置一下(' 下載的SDK放入共享資料夾)就可以進入了: 1.打開LXterminal: 輸入"./mount.sh",會出現"sudo] password for esp8266:",輸入espressif 2.輸入 "cd Share":(Share為我在配置時設定的共享資料夾) 3.輸入"ls":    -理論上會出現你在共享資料夾放的SDK 4.現在打開sdk:    5.輸入"./gen_misc.sh",畫面會顯示設定: 按照流程自己做設定即可    6.完成畫面: 7.在用官方提供的flashDownloasTool進行燒錄:

筆記-array 刪除

之後要用到的,先在這邊留筆記 int arr[]={1,5,4,3,6,2}; void print_arr(int *arr) { int i=0; for(i=0;i<sizeof(arr);i++) { printf("%d ",arr[i]); } printf("\n"); } int search_data(int *arr,int data) { int i=0; for(i=0;i<sizeof(arr);i++) { if(arr[i]==data) { printf("find it!!\n"); return i; } } printf("\n"); return -1; } int delete_data(int *arr,int index) { int i=0; for(i=index;i<sizeof(arr);i++) { if(i==sizeof(arr)-1) arr[i]=0; else arr[i]=arr[i+1]; } print_arr(arr); } int find(int *arr,int data) { int index=search_data(arr,data); if(index!=-1) { delete_data(arr,index); return 0; } else { printf("can not find it\n"); return -1; } } int main(int argc, char *argv[]) { print_arr(arr); find(arr,6); find(arr,1); find(arr,9); return 0; }

ESP8266 RTOS 筆記(三)-如何在sdk中將.c放入自己的資料夾

圖片
        有時候寫code會想要新增一個資料夾來放自己的 lib 在esp8266中需要一些步驟才能成功編譯 ======================================================== 假設我在我的專案中新增一個資料夾叫做my_lib 在裡面新增一個.c檔跟一個show()函式,build code會出現以下訊息: 很明顯可以看到找不到show()。 解決方法如下: 先打開user資料夾,裡面會有一個Makefile檔案,將Makefile複製到資料夾mylib 打開在mylib資料夾中的Makefile: 在前面的地方會有 將 GEN_LIBS = libuser.a 改成 GEN_LIBS = libmylib.a 接下來打開專案的Makefile 先找到 SUBDIRS= 新增自己新增的資料夾 my_lib 到下面找 COMPONENTS_eagle.app.v6 = 新增  my_lib/libmylib.a 現再進行build code,就可以成功通過了! 自己遇到這問題時,不知道該怎麼處理 直到前陣子自己稍微完一下Makeflie與GCC,對Makefile有稍微了解 所以回頭來看這問題就很自然的從makefile中下手,就設定完成了 最大的原因還是自己經驗不夠,對makefile不熟 技術這條路真的永遠也走不完!!

ESP8266 RTOS 筆記(三)-GPIO(3)_input使用

這篇直接講解怎麼設定esp8266 gpio input 中斷如何使用 實例: void gpio_intr_handler(void) {     _xt_isr_mask(1<<ETS_GPIO_INUM);    //disable interrupt     os_delay_us(20*1000);//delay 20ms     if(!GPIO_INPUT_GET(GPIO_ID_PIN(12)))     {         printf( "\r\n receive gpio12 press!\n" );     }     if(!GPIO_INPUT_GET(GPIO_ID_PIN(13)))     {     printf( "\r\n receive gpio13 press!\n" );     }     if(!GPIO_INPUT_GET(GPIO_ID_PIN(2)))     {     printf( "\r\n receive gpio2 press!\n" );     }     if(!GPIO_INPUT_GET(GPIO_ID_PIN(14)))     {     printf( "\r\n receive gpio14 press!\n" );     }     GPIO_REG_WRITE(             GPIO_STATUS_W1TC_ADDRESS,GPIO_Pin_2|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14 ); //clear interrupt mask     _xt_isr_unmask(1 << ET...

ESP8266 RTOS 筆記(二)-GPIO(2)_OUTPUT設定與介紹

    此章節為記錄 esp8266的gpio output部分 從關方手冊可以看到幾個有關GPIO的registers: Output enable register: GPIO_ENABLE_W1TS Output disable register: GPIO_ENABLE_W1TC Output low level register GPIO_OUT_W1TC   Output high level register GPIO_OUT_W1TS  每個REGISTER皆為16個bits,bit[15:0] 1.GPIO_ENABLE_W1TS: 相對應的bit設為1,此IO的output將至能 例如:   欲將gpio4設為output,則此register設為0x10   欲將gpio5設為output,則此register設為0x20   若希望gpio4與gpio5皆設為output,則此register設為0x30 2.GPIO_ENABLE_W1TC: 關閉output功能, 相對應的bit設為1,此IO的output將被關閉 例如:   欲將gpio4的output失能,則此register設為0x10   欲將gpio5的output失能,則此register設為0x20   gpio4與gpio5的output皆失能,則此register設為0x30 3. GPIO_OUT_W1TC   bit[15:0] output low level bit 設為1則腳位為為High level 例如: gpio4要設為low,則此register設為0x10 4. GPIO_OUT_W1TS  bit[15:0] output high level bit 設為1則腳位為為High level 例如: gpio4要設為high,則此register設為0x10 看完register後再來看一下gpio.h中的一些定義: void gpio_output_conf ( uint32 set_mask, uint32 clear_ma...

ESP8266 RTOS 筆記(一)-GPIO(1)

    此章節為 記錄ESP8266的gpio設定筆記 從gpio.h可以看到GPIO的結構參數,定義很簡單: typedef enum {     GPIO_PIN_INTR_DISABLE = 0,      /**< disable GPIO interrupt */     GPIO_PIN_INTR_POSEDGE = 1,      /**< GPIO interrupt type : rising edge */     GPIO_PIN_INTR_NEGEDGE = 2,      /**< GPIO interrupt type : falling edge */     GPIO_PIN_INTR_ANYEDGE = 3,      /**< GPIO interrupt type : bothe rising and falling edge */     GPIO_PIN_INTR_LOLEVEL = 4,      /**< GPIO interrupt type : low level */     GPIO_PIN_INTR_HILEVEL = 5       /**< GPIO interrupt type : high level */ } GPIO_INT_TYPE ; typedef enum {     GPIO_Mode_Input = 0x0,          /**< GPIO mode : Input */     GPIO_Mode_Out_OD ,               /**< GPIO mode : Output_OD */   ...

RTL8711-sdram使用方法與心得

圖片
       RTL8711使用中,因為需要放幾kb的字串,顧考慮將這些字串放置sdram, 不過使用中遇到些許陷阱,在這裡筆記一下。 一開始按照文件的方式將字串宣告前面加上 SECTION(".sdram.data") Build Code還是出現SRAM不夠,我就好奇,先翻了一下手冊 可以知道: SRAM的address從 0x10000000~0x1006FFFF SDRAM的address從 0x30000000~0x301FFFFF 用&確認字串位址有無在SDRAM,結果如下: e 發現除了testt這個指向char指標有被放在SDRAM,他指向的內容都還是在SRAM 原因在於宣告的方式有問題: _ 這樣宣告只有讓testt這個指向char的指標放在SDRAM裡面,改成這樣即可: 其結果為: 這個問題非常有趣,沒有仔細去處理就是一個問題 應該算是一個本身對C語言不夠精通的關係所導致

ESP32學習筆記(五)-ESP32-IDF 使用官方步驟建置教學

圖片
由於安信可的Aithinker IDE有瑕疵,從git少上 clone下來的無法使用 只好乖乖使用官方的ESP-IDF建置來使用 準備工作: 1.MSY32: 下載 2.TTL轉COMPORT  ---------------------------------------------------------------- 1.下載後將MSY32移出至PC,運行c:\msys32/mingw32.exe 2.輸入 cd c:/msys32/home 4.從github上clone esp-idf下來: - git clone --recursive https://github.com/espressif/esp-idf.git 注意這裡有個 --recursive 選項。 如果你克隆ESP-IDF時沒有帶這個選項,你還需要運行額外的命令來獲取子模塊: cd esp-idf git submodule update --init 5.接下來要設定IDF_PATH: -打開C:\msys32\etc\profile.d -新增一個檔案  export_idf_path.sh( 每次打開msy32窗口都會進入 ) ,  並用 用記事本或notepad+開啟 -在裡面新增:export IDF_PATH="C:/msys32/home/esp-idf" -重新打開msy32.exe,輸入 printenv IDF_PATH 6.創建專案: - cd c:/msys32/home/esp-idf -  mkdir app (建立一個資料夾) - cd app -  cp -r $IDF_PATH/examples/get-started/hello_world . - cd hello_world (也可以直接打開資料夾將example的檔案移出在改名) 7.準備就緒: -到此步驟完成,準備build code,先將開發版或串口接好並確認com port -  cd  c:/msys32/home/esp-idf/app/Hello_World ...