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];



2016年4月20日 星期三

學習筆記 MODBUS

MODBUS Application Protocol

Application Layer Messaging Protocol

是應用層的通訊協定,提供 Client/Server 通訊在兩個裝置或網路之間。一般用在 Serial Line 的傳輸上面,後來也有發展出 TCP/IP 的應用。

在1979年創立的標準,為 de facto 工業標準,常用在各種自動化設備之間的通訊。

MODBUS 是 Request/Reply Protocol ,答詢模式的協定,利用 Function Code 指定不同的行為。 Function Code 是組成 PDU的要素,用來建立架構進行 MODBUS 的 Transaction

MODBUS Communication Stack


Example of MODBUS Network Architecture

MODBUS 透過 Gateway 可用在不同網路間的連接,一對一的連接可以用 RS232,一對多用RS485,有多個 Client 可用 TCP/IP, Gateway 可用來做封包的轉送用來連接的不同類型的網路。

HMI:人機界面, PLC:邏輯控制器

 MODBUS Protocol Description

PDU( Protocol Data Unit)獨立於底層的通訊層,與傳遞的方式無關,PDU 被用來指定封包的功能和MODBUS SLAVE 的行為。

ADU( Application Data Unit)用來指定到不同的匯流排(buses)或網路,定址到某個 BUS上的指定的 Slave Address。

Address 的內容為一個 byte,定址的使用範圍從0到255,0為廣播位址(broadcast),1到127一般可用位址,128到255保留。通常 MODBUS Address 在裝置上事先分配好了,也可以由自己設定想要的 slave address。





MODBUS Slave device 

Delta(台達電子) 

在 MODBUS 網路上以Master/Slaver架構運作,除了Master裝置以外其餘的一個或多個設備皆為 Slave Device,也就是在MODBUS的網路上,只會允許一個Master裝置的存在,這是在spec終究規範好的,否則的話如果有兩個master同時發出request的訊號,會造成網路上的衝突,發生不可預期的反應。

PLC ( Programmable Logic Controller)
可程式邏輯控制器

PC可以用 RS232 或 RS485 與PLC相連進行設定和編程,預設通訊格式為 (ASCII, 9600, 7, E, 1),與PC相連時,PC 端為 Master 而 PLC 端為 Slave。

載入程式後,PLC透過設定好的程式,PLC 端主動或被觸發動作產生 MODBUS 的指令傳送給 BUS 上的某個 MODBUS Slave。


TC ( Temperature Controller)
溫度控制器

在 MODBUS 上作為 MODBUS Slave 的角色



學習筆記 UART PC16550D Universal Asynchronous Receiver/Transmitter

UART

UART(Universal Asynchronous Receiver/Transmitter)
通用非同步接收發送機,是硬體的一部分,將資料由序列通訊與並列通訊作傳輸轉換。UART通常用在與其他通訊界面的連接上,如RS232、RS485。

是對應各種非同步串行通信口的接口標準和匯流排標準,它規定了通信口的電氣特性、傳輸速率、連接特性和接口的機械特性等內容。

實際上是屬於通信網路中的實體層(Physical Layer)的概念,即電氣特性,與通信協定沒有直接關係。而通信協定,是屬於通信網路中的資料鏈結層(Data Link Layer)的概念,規範了被傳送資料的格式。

COM 是 PC(個人計算機)上,非同步串行通信口的簡寫。由於歷史原因,IBM的PC外部接口配置為RS232,成為實際上的PC界默認標準,最早就是由 IBM 所使用,所以後來繼續沿用,現在 PC 機的 COM 均為 RS232。若配有多個非同步串行通信口,則分別稱為COM1、COM2... 。在裝置管理員中可以找到。


與同步傳輸的差異在於 Clock 信號的有無,在傳遞訊號時會用起始位元來表示資料訊框的開始,以結束位元當作資料的終止,結束位元可能會有不同個數的選擇,則依據不同的鮑率需要選擇不同的結束位元數目,一般以資料傳輸位元在小於4%的畸變的考量下去決定最高的鮑率和結束位元數目。

USART
在 UART 上追加同步方式。

PC16550D

TI(Texas Instruments, 德州儀器)的 UART晶片,帶有FIFO功能。


UART演進

16550 可以選擇是否要ENABLE FIFO,切換有無FIFO的模式。Mode 16450和 Mode FIFO,在1645並沒有FIFO的功能。 16550加了FIFO,有16 bytes 緩衝,即深度16 bytes,寬8 bits。
(資料來源:wiki )

Basic Configuration

用在 CPU BUS和通訊界面之間互相的連接,此處的 DATA BUS為 8 bits的匯流排,為 Intel 8086/8088(16位元CPU)所使用,利用 8 bits BUS  並列讀寫 D0 到 D7 八個位元,將串列換成序列資料到傳輸介面。

相對來說,8 個位元的並列傳輸要傳輸 8 bits 的資料只需要一個 tick 的時間,串列傳輸卻需要重複傳輸八次,需要八倍的時間也就是八個 tick 的時間,光是效率上就差了八倍。但是就距離而言,串列傳輸的傳送長度比並列傳輸要大得多,因為在並列傳輸上,每條信號線到達目的端時間點可能不同,或者有不同的相位差,造成信號的偏差,所以一般並列式傳輸的距離較短。

圖中 EIA-DRIVERS 可以為 RS232或RS485 由DRIVER的類型決定,DRIVER晶片轉換PC16550D的 TTL 電壓到interface對應的電壓範圍進行通訊。

PC16550D腳位

資料傳輸

D0-D7 並列 資料(parallel)
SIN串列資料(serial)
SOUT

WR/RD 讀寫控制(PIN方向)

晶片選擇

CS0/CS1/CS2
有三條線,代表最多可以有2的3次方,即8個不同裝置


MODEM控制

RI (鈴聲指示)
DCD(載波偵測)
DSR
CTS(清除以傳送)
DTR
RTS(準備傳送)

現在通常已經沒有一定要實作的必要,但是都會保留下來。還是可以當作判斷有沒有在進行通訊中。

中斷信號

INTR

DMA信號

TXRDY
RXRDY


Register 位址選擇

A0/A1/A2
ADS

Address 就根據 IO base加上相對的暫存器位置。


PC16550D Function Block Diagram

左邊區塊為晶片的邏輯控制,Register Address 的選擇和讀寫的控制。

中間為 Register 的種類,如 Line Control, Divisor Latch, Modem Control, Interrupt Enable, FIFO Control 控制類型的,和狀態讀取的 Line Status, Modem Status, Interrupt ID,還有接受和傳送用的Register, Receiver Buffer, Transmitter Holding。 

右上接收的移位暫存器,接收完畢後送到Receiver Buffer 然後Data Ready旗標 ,右中為傳送的移位暫存器,







各暫存器(Register)種類

利用 Address Line 可以定址到不同 Register 進行讀寫,如 address 0 同時是接收(RBR)和發射(THR)的暫存器,可是進行 Read 和 Write 不同行為,卻是對應到兩個不同暫存器。還有另一個位元 DLAB為1時,定址到 address 0 也會對應到不同暫存器 Divisor Latch(LS,MS)。在最一開始設定暫存器時,需要注意當時寫入的是哪個暫存器。

以下是各暫存器內容



Registers Addressing






中斷(INTERRUPT)控制

當有中斷信號產生時,原本執行中的行程被中斷,必須要處理中斷服務常式內的程序,等到 ISR 執行完後返回原本中斷的地方,繼續當初正在執行的動作。


當各種 interrupt 有被致能時,只要對應的 Register 行為產生,INTR pin就會發出 interrupt信號,譬如說 Receiver Buffer Register 接收滿了,對應的 Interrupt Data Ready(DR) 中斷信號就會產生。

由於晶片上只有一個 INTR 的腳位,只要有任何中斷信號發生,INTR pin 信號就會舉起,等等待 CPU 執行對應的動作 INTR 電壓準位才會降下,像是讀取 RBR,硬體動作就會自動將 INTR 內容清除為 0。為了知道中斷信號產生時,這個信號是從誰而來,每個中斷信號會分到不同的優先權等級,代表不同類型的行為。

分成四個等級,如接收錯誤、接收完成、發送、MODEM控制。