2017年7月24日 星期一

# include

Marco #include

GCC documents > Computed Includes

在程式中常用到的
#include "stdio.h"
是 marco 的用法,是complie的時候,preprocessor會去處理,將 include的文件,在敘述中展開。
被稱為 computed include.

#if SYSTEM_1
# include "system_1.h"
#elif SYSTEM_2
# include "system_2.h"
#elif SYSTEM_3
…
#endif


使用 include 的時候,會根據雙引號與角括號的不同,以對應的規則去搜尋包含的文件名稱。
雙引號優先以source code當前的目錄做搜尋,角括號則以環境參數所預設的 include路徑為主。
#include "file"
#include <file>

include 用來包含 header file
頭文件中可以用來包含的函式的宣告,可以將一份宣告透過共用於多個文件。
當被用到的函式,也是其他程式中很常被呼叫的,就可以宣告在頭文件中。
可以避免像是同樣的函式在每份源文件中宣告出錯,修改函式也只需要一次。

2017年7月17日 星期一

序列傳輸 - 序列埠通訊

Serial Communication串列傳輸




Introduction 


一般的嵌入式系統泛指由 IC 和 CPU 互聯電路所共同組成的系統,其中目標包含內部獨立的電路可以交換、傳遞彼此的資訊,必須能夠透過共同的通訊協定來溝通。 所以為了使各種元件或 IC 可以順利溝通,出現了各種不一樣的通訊協定,可以達到資料交換的目的。 一般而言,會將通訊類型分成兩大類,並列式(parallel)和序列式傳輸(serial)。

Parallel v.s. Serial


並列式傳輸是可以同時間傳送多個位元,常見的匯流排(bus)是 8 ,16 或更多線所組成。

序列式傳輸則是一個時間點只會送出一個位元,將位元依序送出,最少可以只用一條線,常見的應用一般不使用超過四條線。

Asynchronous Serial


經過長時間的發展,已經有各種序列式的通訊協定出現,可以適用各種不同嵌入式系統所需的條件。如 USB 和 乙太網路都是比較常見的通訊方式。 其他常見的序列式介面包含 SPI、I2C 。

序列傳輸又可以分成兩類,同步(Synchronous)與非同步(Asynchronous)。

同步傳輸的序列介面,除了資料線以外,會多一條線作為傳輸時脈(Clock)信號,如此一來只要是在此序列同步傳輸的匯流排上的裝置,都可以參考同一個 clock 做資料同步。

非同步傳輸則是沒有額外的訊號線作為傳輸時脈的用途,這代表必須要用其他的方式來使得傳輸更可靠。

Rules of Serial

非同步序列的傳輸,有很多種的規則,必須要透過規範的機制,來使得傳輸更加可靠,才不會造成資料丟失或者資料錯誤的情況發生。

這個機制需要透過額外的資訊來實現

Data bits,
Synchronization bits,
Parity bits,
Baud rate.

這個機制的調整彈性相當的大,並且沒有辦法連續的一直送出資料,而是將資料分成很多的小訊框在送出,這個機制下最重要的是確保通訊的兩方要在同樣通訊協定的配置下。


https://learn.sparkfun.com/tutorials/serial-communication 


2017年7月7日 星期五

malloc() 動態設置記憶體


int *ptr = malloc(sizeof(int));

void *malloc(size_t size)

size 所需記憶體區塊大小的byte數

回傳值是指向所指定的記憶體區塊的指標,失敗的話回傳NULL


#include <stdio.h>
 #include <stdlib.h> 

int main(void) 
  int *ptr = malloc(sizeof(int));
  printf("空間位置:%p\n", ptr);
  printf("空間儲存值:%d\n", *ptr);
  *ptr = 200;
  printf("空間位置:%p\n", ptr);
  printf("空間儲存值:%d\n", *ptr);
  free(ptr);
  return 0;
}


執行結果:

空間位置:0xb27010 
空間儲存值:0 
空間位置:0xb27010 
空間儲存值:200

如果使用了 malloc 分配動態記憶體,可是卻沒有使用 free 歸還記憶體,可能會發生記憶體用盡的情況。

陣列在使用的時候,必須事先決定好陣列的大小,有時候一開始不知道會使用多大的陣列,或是希望由使用者來自定大小,就可以使用動態記憶體配置,加上指標來實作。

int *arry = malloc(1000 * sizeof(int));

此行分配了 1000 個 int 大小的空間,並傳回空間的第一個位址配置後的空間資料是未知的。可以使用 calloc() 來宣告空間配置。

int *arry = calloc(1000, sizeof(int));

分配了 1000 個 int 大小的空間,並將空間裡的所有值初始化成 0。在使用 malloc 或是 calloc 進行記憶體配置,在不使用時,應該使用 free() 釋放記憶體。



參考:
https://openhome.cc/Gossip/CGossip/MallocFree.html


2017年7月5日 星期三

使用 sprintf 將字串組合

格式


int sprintf (char * str, const chat * format, ...);

sprintf 格式的組成和 printf 的使用一樣,不一樣的是可以將 C 的字串組合後,藉由指向 char 的 pointer str 存入 buffer 內容中。

要注意這裡使用的 buffer 應該要夠大,才能夠放進組合後整個字串的大小。


str:指向 buffer 的 pointer,用來儲存字串。大小應該要足夠存放運算結果的字串。

format:與 printf 的格式相同, %d, %x, %s, ...

Return Value:函數前面的型態是 int,代表回傳值會是一個 int ,如果函數執行成功,會回傳寫進的字元的總數


---------------------
#include <stdio.h>

char buffer[20];  // the number of result that both added cant larger than 20 bytes
char string[] = "TEXT";
int number = 1234;


main()
{
  sprintf( buffer, "%s, + %d \n" , string, number);
  printf("print result : %s \n",buffer);

  return 0;
}



--------------------

另外看 printf 的格式有哪些


#include <stdio.h> 

 int main() 
{
  printf ("Characters: %c %c \n", 'a', 65); 
  printf ("Decimals: %d %ld\n", 1977, 650000L);  
  printf ("Preceding with blanks: %10d \n", 1977); 
  printf ("Preceding with zeros: %010d \n", 1977); 
  printf ("Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100); 
  printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416); 
  printf ("Width trick: %*d \n", 5, 10); 
  printf ("%s \n", "A string"); return 0; 
}
D:\cp\code>gcc printf.c -o printf 

D:\cp\code>printf 
Characters: a A 
Decimals: 1977 650000 
Preceding with blanks:            1977 
Preceding with zeros: 0000001977 
Some different radixes: 100 64 144 0x64 0144 
floats: 3.14 +3e+000 3.141600E+000 
Width trick: 10 A string
符號說明範例
c字元 (char)a
d整數 (Decimal integer)372
i整數 (Decimal integer) (同 d)372
f浮點數 (Floating Point)372.56
e科學記號 (Scientific notation)3.7256e+2
E科學記號 (Scientific notation)3.7256E+2
g取浮點數或科學記號當中短的那個372.56
G取浮點數或科學記號當中短的那個372.56
o八進位 (Octal Integer)735
s字串 (String)372
u無號數 (unsigned integer)372
x十六進位 (Hexadecimal integer)3fb
X十六進位 (Hexadecimal integer)3FB
p指標位址B800:0000
n不列印, 用來取得目前輸出長度%n
%印出 % 符號%%


參考


http://programmermagazine.github.io/201401/htm/article2.html







BLE B-001 藍芽模組 (buletooth 4.0)

BLE


概述


使用 TI 的 CC2541F256 晶片 的射頻模組,有低功耗的藍芽版本和體積較小等優點,可以用來實現手機與藍芽模組通訊,模組與模組的點對點通訊。


規格


腳位圖


Command Set

  指令集分成兩類,一類是設置的指令,另一類是用來查看參數。 在要進入設置模式以前,要注意模組的連線配置:同時將腳位 RTS(P0_0) 和 CMD(P0_1) 拉 LOW 電位。

Command Format

與一般藍芽模組不同,不是使用常見的 AT指令,而是WEBEE自己設的 FA格式。

  所有的設置指令格式為: 0xFa + TYPE + DATA_Length + DATA + 0xAA, Frame 的開頭是 FA,TYPE 是類型, DATA_Length 是資料長度, AA 是 Frame 的結尾,用來告知接收端結束。  

指令種類

設定的指令集


切換 peripheral 腳色

切換 Central 腳色

修改 Baud Rate

設置連接對象的位址
  傳的 DATA 是目標的 mac address(6 Bytes),設置成 00 00 00 00 00 00 00 00 00 00 00 00 (全0) 的時候,模組會預設連接第一個搜尋到的藍芽裝置(出廠預設)

設定廣播間隔

設定連接參數

設定模組的名稱

設定廣播報文中的資訊

設定模組掃描周邊的藍芽裝置

設定模組停止掃描

設定模組重啟

設定模組回復出場設置


查看參數的指令集


查看指令的內容包含查看當前的角色, Baud Rate,廣播間隔,連接間隔,廣播名稱。查看模組訊息的指令格式為 FB + TYPE + 00 + AA


查看當前的角色

獲取模組的 Baud Rate

查看目前連接目標的位址

查看模組本身的藍芽位址

獲取當前的廣播間隔

獲取當前的連接參數

查看模組的名稱











2017年6月26日 星期一

ESP8266 ESP-01 WiFi 模組

術語與縮寫

WiFi

Wireless Fidelity

UART


Universal Asynchronous Receiver & Transmitter

P2P


Point to Point

TCP

Transmission Control Protocol

IP

Internet Protocol

WPA

WiFi Protected Access

WPS

WiFi Protected Setup



ESP8266/ESP-01 簡介



ESP8266 是低功耗的 UART-WiFi 透傳模組,特色是體積小而且低功耗,適用移動裝置或物聯網的設計,可將嵌入式的裝置連到 WiFi 無線網路,進行 Internet 或 LAN 通訊,實現聯網功能。

Features 特色


支援無線 802.11 b/g/n 標準
支援 STA/AP/STA+AP 三種工作型態
內建 TCP/IP stack,支援多路 TCP Client 連線
支援 Socket AT 指令
支援 UART/GPIO
3.3V 單電源供應

主要功能

ESP8266可以實現的主要功能包括:串列埠透傳,PWM 調控,GPIO控制。

串列埠透傳:資料傳送,傳送的可靠性好,最大的傳送速率為:460800bps。
PWM 調控:燈光調節,三色LED 調節,電機調速等。
GPIO控制:控制開關,繼電器等。

工作型態


電腦用 COM port 與 ESP8266 模組連接,透過 UART 兩者之間通訊。由電腦端可以發送 AT command 進行設定。ESP8266 預設的 baudrate 為 9600,8,n,1。

ESP8266模組支援 STA/AP/STA+AP 三種工作型態。

STA 型態:ESP8266模組通過路線器連線互聯網,手機或電腦通過互聯網實現對裝置的遠端控制。
 AP 型態:ESP8266模組作為熱點,實現手機或電腦直接與模組通訊,實現區域網路無線控制。
 STA+AP 型態:兩種型態的共存型態,即可以通過互聯網控制可實現無縫切換,方便作業。


測試方法



電腦和手機端要當作伺服器端(SERVER),讓模組作為客戶端(CLIENT)發送請求連線與進入通訊埠(PORT),需要下載 TCP 的除錯軟體。也要將模組切換 STA/AP,以做 server/client 之間的切換。



Fig.1 系統架構圖

1. ESP8266 模組當作 Server ,PC 當作 Client:
將模組用 AT command 設定為 AP 型態,用PC連上 ESP8266 模組的 WiFi ,並在 PC 端開啟 TCP 測試的應用程式,連接ESP8266的 IP 位址和通訊埠。

2. PC 當 Server,ESP8266 當 Client:
在 PC 端開啟 WIFI熱點,讓模組可以連入。在電腦端使用 TCP/IP server 的應用程式建立 Server,等待模組連線至電腦的熱點,連上WIFI熱點並取得 IP後,模組使用 CIPSEND的指令進入傳透模式,將被傳送的資料寫入模組的 UART port 即開始傳送資料,可以在這裡建立使用者互相通訊的模式。

3.手機端當作 server ,ESP8266 當 Client:
與第二點相同,用手機開啟 TCP的應用程式,等待模組的連入並建立連線。


透傳型態測試


大致上模組進行連線通訊的流程

供電並致能以後,執行 AT 指令

AT+CWMODE=3
AT+RST

AT+CIPMODE=1 //設定透傳型態

// 模式可以設定後,連上AP點的網路,開啟TCP連線


AT+CWLAP                            //列出目前可用的AP點
AT+CWJAP=“SSID”,”PWD” //加入指定的 AP

/*  連上WIFI,有網路以後就可以做為 Client 連上 TCP Server,相反的模組也可以自己當 server  */

AT+CIFSR                               //抓取IP位址,檢查是否連接到 IP

AT+CIPSTART=“TYPE”,”ADDR”,”PORT”
 //建立TCP/UDP連線,指定 Server 的 IP 位址,和通訊埠


AT+CIPSTATUS


AT+CIPSEND //開始傳送,CIPMODE=1並且作為用戶端,進入透傳型態

AT+CIPSEND=<LENGTH>  //LENGTH 決定要傳送的 Bytes 數



建立 TCP SERVER


AT+CIPMUX=1
AT+CIPSERVER=1

只要兩行指令就將伺服器建立起來了,這時候會不知道 SERVER 的 IP 位址是多少,可以再用 CIFSR 來看,預設的通訊埠為 333。

所以在將 server 建立之前先設定 STA使用的 IP位址,在 server 建立的同時設定通訊埠。

AT+CIPSTA_CUR="192.168.94.87"
AT+CIPMUX=1
AT+CIPSERVER=1,9487

AT+CIFSR  //查看 IP 及 STAIP,MAC
AT+CIPSTA_CUR?  //查看 STAIP, Gateway



2017年6月20日 星期二

typedef的用法

typedef 與 #define 類似,但是 #define 是做字串直接的替換,typedef 像是幫型態類別重新取名。

typedef
1.一次宣告多個指標型態的物件
2.typedef 用在 struct,以往每在宣告 struct 的新物件時,都要帶上 struct
3.用 typedef 來定義與平台無關的型態
4.為複雜的宣告定義一個新的簡單的別名



1.不僅僅是簡單的替換。可以作為同時宣告多個指標的物件。
char* pa, pb;

typedef char* PCHAR;
PCHAR pa, pb;


#define char* PCHAR
PCHAR pa, pb;
//實際上變成只有 pa 是指標型態
//char* pa; char pb;


2.

struct tagPOINT1
{
int x;
int y;
};

struct tagPOINT1 p1;

- - - - - - -

typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1;

3.

typedef int number_max;

有個變數只用來存 2 byte的大小,想要換平台,改用更大的型態,這樣原本宣告的新名稱不用變動。

typedef DWORD number_max;


4. 複雜宣告的簡化

void (*b[10])(void(*)());

typedef void(*pFunParam)();
typedef void(pFunx)(pFunParam);

簡化後
pFunx b[10];