網頁修改時間:2015/10/31
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
有購買商品的使用者,網頁中所需相關資料已放置於雲端硬碟,請自行下載使用!
- { Raspberry Pi }:{ 3V3 整合型 LCD }/codes/RaspberryPi/IIC_CGRAM/IIC_Numeric/
- { Arduino }:{ 5V 整合型 LCD }/codes/Arduino/
- { 單晶片 }: { 5V 整合型 LCD }/codes/AT89S51/KeilC/Numeric_IIC_Demo/
其餘的使用者,程式碼複製貼上使用 (單晶片程式碼在此不提供)!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
*********************************************************************************
整合型 LCD請至露天賣場訂購:
- {3V3} 整合型{4/8BIT,IIC,4SPI}1602英文字型藍底白字LCD螢幕(附排針)-適用於樹莓派,微控制器
. - {5V}整合型{4/8BIT,IIC,4SPI}1602英文字型藍底白字LCD螢幕(附排針與可變電阻)-可用於微控制器
賣場所賣的整合型 LCD 跟市面上常用的 16 x 2 LCD 不同,可使用 4/8 bit、I2C 和 SPI 三種通訊方式來做控制 ( 預設的控制模式是 I2C 通訊 ),由於控制命令與格式都是相同的,因此下面自定字元的說明與程式碼的講解,觀念上都是相同的。如果想要自己定義顯示的字元或是圖型的話,可以參考接下來的說明。
自訂 LCD 字型或圖案 ( KS0066i ):
LCD 裡面的每一個字型,都是侷限在一個 5 x 8 的像素矩陣。像素矩陣的每一個點,可以想像就是一個 LED:亮為 1,暗為 0。基本上,一些通用的字型與圖形 ( ASCII Code ) 都已內建在其中,要取出只要給定 ASCII Code 馬上就可以將這些內建的字元或圖形取出。
但是若是 ASCII Code 或是 LCD 內建的字型沒有辦法顯示出使用者想要的字元或是圖形時,那麼就必須自己創造一個出來!
打開整合型 LCD 的資料手冊第 18 頁 (表 11,KS0066i-0A 字型檔表 ),就可以看到全部支援的字元與圖形
S0066i-0A 字型檔表 |
S0066i-0A 字型檔表 - 左上角放大 |
名稱解釋:
- CGRAM ( Character Generation RAM )
將字型資料寫入到 CGRAM,就可以使用使用者自訂的字元或是圖形 - DDRAM ( Display Data RAM )
儲存顯示的資料,最多 80 x 8 bits ( 80 個字元 )
如何自訂呢 ? 首先,先創建一個 5 x 8 大小的表格,然後依照自己心中想要的字元或是圖形,將其描繪並填滿在表格的欄位中;填顏色的填入數字 1,沒填顏色的就填入 0。
為了要將這個自訂的字元或是圖形寫入到 CGRAM 中,必須輸入 8 個 Bytes 的資料到 CGRAM 八個其中的一個位址中。但是上面的字元由 5 個行 (5 行 x 8 列) 組成,為了要讓每一行形成一個 Byte,因此加入了 bit 7、6 和 5 三個虛擬的位元 (bit),輸入 0 或 1 都可以。如此,就可以得到完整的 8 個 Byte 的字元或是圖形資料。
每一個字元或是圖形的資料要輸入到八個 CGRAM 中的其中一個位址,每一個 CGRAM 位址又分為 8 個部分,分別對應到上面自訂字元或是圖形的 8 個 Bytes。選擇一個 CGRAM 位址,輸入自定字元或是圖形 8 個 Bytes 的資料之後,才能從 CGRAM 取出該位址的字元或是圖形顯示在整合型 LCD 上。
同樣的觀念與步驟也同樣適用於其他使用相同 LCD 控制晶片的液晶螢幕。
下面以一個創建數字 2 的例子,建立一個剛剛所說明的一個表格,表格右邊 "HEX" 欄位就是產生的字元 8 個 Byte 資料
自訂數字 2 個字元資料表格 |
自訂字元或圖形資料的輸入:
LCD 完成初始化之後,將模式切換到控制模式 ( RS=0,R/W = 0) 並設定 CGRAM 位址為 0x40 + [ 0x00 ~ 0x07] 其中的一個,最後將 8 個 Bytes 的資料輸入,即完成輸入。最後的資料輸入,可以一次輸入 8 個自定字元或是圖形的資料,不過取決於微控制器或微處理器不同而有所限制。
以 Arduino 為例,寫入 CGRAM 的方法如下程式碼
void writeCGRAM( const unsigned char dp[], unsigned char charlen, int start ) { Wire.beginTransmission(IIC_ADDR_LCD1); // To assign CGRAM start address Wire.write(0x80); // 控制指令 Wire.write( 0x40 + ( ( start - 1 ) << 3 )); // 設置CGRAM ADDRESS,0x40 表示第 0 個 // 將字元或圖形ㄌ要寫入 CGRAM Wire.write(0x40); // 控制指令:表示以下傳輸的 n 個字節是數據 // CGRAM_block 的數目;每一個字元,需要 8-byte 資料 for( int i = 0; i < charlen * 8; i++ ) { Wire.write(*dp); dp = dp + 1; } Wire.endTransmission(); }
其中,
- dp[] : 自定字元或圖形的資料,以 16 進制表示。
- charlen : 一次要輸入的字元或是圖形的數量,最多 3 個字元 ( 也就是 24-byte )。
- start : 字元或是圖形輸入的開始位置,從 1 開始至 8 結束。
void displayCGRAM( unsigned char cgramaddr, int row, int col) { // set cursor position to col, row Wire.beginTransmission(IIC_ADDR_LCD1); Wire.write(0x80); //控制指令 Wire.write( 0x80 + 0x40 * ( row - 1 ) + ( col - 1 ) ); delayMicroseconds(100000); Wire.write(0x40); //控制指令 Wire.write( cgramaddr ); Wire.endTransmission(); }
若要輸入自訂數字 2,依照上面所創建的資料,那麼完整的程式如下:
#include <stdio.h> #include <Wire.h> // 每一個數字由六個 5x8 的區塊構成 const unsigned char CGRAM_block[]={ 0x1F,0x01,0x1F,0x1F,0x10,0x10,0x1F,0x1F, // 自訂數字 2 }; const unsigned char IIC_ADDR_LCD1 = 0x3C; // 函數宣告 void initLCD(); void clearLCD(); void writeCGRAM( const unsigned char dp[], unsigned char charlen); void displayCGRAM( unsigned char cgramaddr, int row, int col); void setup() { Wire.begin(); // 整合型 LCD 初始化 @ I2C 模式 initLCD(); delay(100); // delay 100 ms clearLCD(); delay(100); // delay 100 ms // 寫入自定字元至整合型 LCD @ I2C 模式 writeCGRAM( &CGRAM_block[0], 1, 1 ); // 顯示自訂數字 2 for(int i = 0; i < 16; i++) displayCGRAM( 0x00, 1, i + 1 ); for(int i = 0; i < 16; i++) displayCGRAM( 0x00 * i, 2, i + 1 ); } void loop() { } //***--- 整合型 LCD @ I2C 模式 ---*** void initLCD() { Wire.beginTransmission(IIC_ADDR_LCD1); Wire.write( 0x00 ); // N x commands Wire.write( 0x38 ); // Function set Wire.write( 0x0C ); // Display ON/OFF Wire.write( 0x01 ); // Clear display Wire.write( 0x06 ); // Entry mode set Wire.endTransmission(); } void clearLCD() { Wire.beginTransmission(IIC_ADDR_LCD1); Wire.write( 0x80 ); // One command Wire.write( 0x01 ); // Clear display Wire.endTransmission(); } void writeCGRAM( const unsigned char dp[], unsigned char charlen, int start ) { Wire.beginTransmission(IIC_ADDR_LCD1); // To assign CGRAM start address Wire.write(0x80); // 控制指令 Wire.write( 0x40 + ( ( start - 1 ) << 3 )); // 設置CGRAM ADDRESS // 寫入 CGRAM Wire.write(0x40); // 控制指令 // CGRAM_block 的數目;每一個字元,需要 8-byte 資料 for( int i = 0; i < charlen * 8; i++ ) { Wire.write(*dp); dp = dp + 1; } Wire.endTransmission(); } void displayCGRAM( unsigned char cgramaddr, int row, int col) { // set cursor position to col, row Wire.beginTransmission(IIC_ADDR_LCD1); Wire.write(0x80); // 控制指令 Wire.write( 0x80 + 0x40 * ( row - 1 ) + ( col - 1 ) ); delayMicroseconds(100000); Wire.write(0x40); //控制指令 Wire.write( cgramaddr ); Wire.endTransmission(); }
上傳程式所得到的結果
整合型 LCD @ I2C 模式自訂數字 2 |
接著,繼續上面的函式,我們要用幾個自訂字元來創建跟網頁最上面影片中顯示的漂亮數字!
大型數字拆解:
若仔細觀看影片中的數字顯示,應該不難發現這些數字的組成其實是由 5 種格式 加上一個逗號的像素陣列所構成;其中逗號是用來顯示點號 "." 與分號 ":"
構成大型數字的六個圖形 |
以數字 2 的構成為例,一但要在 LCD 上顯示,就會個佔據 LCD 第一行與第二行各三個 5 x 8 的像素矩陣。
依照上面說明的方式完成0 - 9 每個數字 8-byte 的資料,並且將各個數字組成的像素矩陣編號寫出,就可以得到如下兩個宣告的陣列
// 每一個數字由六個 5x8 的區塊構成 // 這些區塊定義如下: const unsigned char CGRAM_block[]={ 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, // 0,全白, 如同 ASCII 0X20 0X1F,0X1F,0X1F,0X00,0X00,0X00,0X00,0X00, // 1,上黑 0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0X1F, // 2,下黑 0X1F,0X1F,0X1F,0X00,0X00,0X1F,0X1F,0X1F, // 3,上下黑 0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F, // 4, 全黑, 如同 ASCII 0XFF 0X00,0X00,0X00,0X00,0X00,0X0E,0X0E,0X0E, // 5,下大點 }; // Numerics[0-9][]:表示一個數字組成的六個字元 // Numerics[][0-2]:表示數字第一列的三個字元 // Numerics[][3-6]:表示數字第二列的三個字元 const unsigned char Numerics[10][6]={ {4,1,4,4,2,4}, // 0 {1,4,0,2,4,2}, {3,3,4,4,2,2}, {1,3,4,2,2,4}, {4,2,4,0,0,4}, {4,3,3,2,2,4}, {4,3,3,4,2,4}, {1,1,4,0,4,0}, {4,3,4,4,2,4}, {4,3,4,0,0,4}, // 9 };
整合型 LCD 的顯示區域中,螢幕上下各佔 16 個字元 ( 1 - 16 )。因此,劃分這些區域之後,總共可以顯示四個大型數字,每個數字前方的上下各預留一個 5 x 8 的像素矩陣做為顯示點號 "." 與分號 ":" 的區域,由此可以得到下面兩個標記數字該顯示的位置的陣列,總共可以顯示包括點號與分號 8 個資料量
// 數字可以容納四個,位置由 LCD 的 2, 6, 10, 14 起頭 const int nix[] = { 2, 6, 10, 14 }; // . 與 : 位置在 1, 5, 9, 13 const int pix[] = { 1, 5, 9, 13 };
知道上面資訊之後,顯示大型數字的函式就可以撰寫如下
void displayNumeric( const char dp[], const int len ) { int p =0, n = 0; for( int i = 0; i < len; i++ ) { switch(dp[i]) { case 0x2e: // . if(p<n) p = n; // line 1 displayCGRAM( 0x00, 1, pix[p] ); // line 2 displayCGRAM( 0x05, 2, pix[p] ); p++; break; case 0x3A: // : if(p<n) p = n; // line 1 displayCGRAM( 0x05, 1, pix[p] ); // line 2 displayCGRAM( 0x05, 2, pix[p] ); p++; break; case 0x20: // space // line 1 for( int f = 0; f < 3; f++ ) { displayCGRAM( 0x00 , 1, nix[n] + f ); } // line 2 for( int f = 3; f < 6; f++ ) { displayCGRAM( 0x00, 2, nix[n] + f - 3 ); } n++; break; case 0x30: // 0 case 0x31: // 1 case 0x32: // 2 case 0x33: // 3 case 0x34: // 4 case 0x35: // 5 case 0x36: // 6 case 0x37: // 7 case 0x38: // 8 case 0x39: // 9 // line 1 for( int f = 0; f < 3; f++ ) { displayCGRAM( Numerics[ dp[i] - 0x30 ][f] , 1, nix[n] + f ); } // line 2 for( int f = 3; f < 6; f++ ) { displayCGRAM( Numerics[ dp[i] - 0x30 ][f], 2, nix[n] + f - 3 ); } n++; break; } } }
完整的程式 ( 一些函式的內容已在上面寫出,這邊省略,請自行補上 )
Numerics.ino
#include <stdio.h> #include <Wire.h> // 每一個數字由六個 5x8 的區塊構成 // 這些區塊定義如下: const unsigned char CGRAM_block[]={ 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, // 0,全白, 如同 ASCII 0X20 0X1F,0X1F,0X1F,0X00,0X00,0X00,0X00,0X00, // 1,上黑 0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0X1F, // 2,下黑 0X1F,0X1F,0X1F,0X00,0X00,0X1F,0X1F,0X1F, // 3,上下黑 0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F, // 4, 全黑, 如同 ASCII 0XFF 0X00,0X00,0X00,0X00,0X00,0X0E,0X0E,0X0E, // 5,下大點 }; // Numerics[0-9][]:表示一個數字組成的六個字元 // Numerics[][0-2]:表示數字第一列的三個字元 // Numerics[][3-6]:表示數字第二列的三個字元 const unsigned char Numerics[10][6]={ {4,1,4,4,2,4}, // 0 {1,4,0,2,4,2}, {3,3,4,4,2,2}, {1,3,4,2,2,4}, {4,2,4,0,0,4}, {4,3,3,2,2,4}, {4,3,3,4,2,4}, {1,1,4,0,4,0}, {4,3,4,4,2,4}, {4,3,4,0,0,4}, // 9 }; // 數字可以容納四個,位置由 LCD 的 2, 6, 10, 14 起頭 const int nix[] = { 2, 6, 10, 14 }; // . 與 : 位置在 1, 5, 9, 13 const int pix[] = { 1, 5, 9, 13 }; const unsigned char IIC_ADDR_LCD1 = 0x3C; // 函數宣告 void initLCD(); void clearLCD(); void writeCGRAM( const unsigned char dp[], unsigned char charlen); void displayCGRAM( unsigned char cgramaddr, int row, int col); void displayNumeric( const char dp[], const int len ); void setup() { Serial.begin(9600); Wire.begin(); // 整合型 LCD 初始化 @ I2C 模式 initLCD(); delay(100); // delay 100 ms clearLCD(); delay(100); // delay 100 ms // 寫入自定字元至整合型 LCD @ I2C 模式 // Note: 一次輸入太多自定字元會有輸入不完全的情況出現 // 所以適量的將自定字元陣列多次的輸入,然後再將其顯示在 LCD 上做確認 writeCGRAM( &CGRAM_block[0], 3, 1 ); writeCGRAM( &CGRAM_block[24], 3, 4 ); } char nums[8]=""; void loop() { // 顯示自定字元在LCD上,確認自定字元已經正常的輸入到為控制裡 for(int i = 0; i < 6; i++) displayCGRAM( (0x01 * i), 1, i + 1 ); for(int i = 0; i < 6; i++) displayCGRAM( (0x01 * i), 2, i + 1 ); delay(1500); clearLCD(); // 顯示大型數字空白、:、.、0 - 9 displayNumeric( "....", 4 ); delay(1500); clearLCD(); displayNumeric( "::::", 4 ); delay(1500); clearLCD(); for( int i = 0; i < 10; i++ ) { snprintf(nums, 8, "%d%d%d%d", i, i, i, i); displayNumeric( nums, 4 ); delay(1500); clearLCD(); } displayNumeric( " ", 4 ); delay(1500); clearLCD(); } //***--- 整合型 LCD @ I2C 模式 ---*** void initLCD() { // ... 省略 ... } void clearLCD() { // ... 省略 ... } void writeCGRAM( const unsigned char dp[], unsigned char charlen, int start ) { // ... 省略 ... } void displayCGRAM( unsigned char cgramaddr, int row, int col) { // ... 省略 ... } //***--- 大型數字顯示函式 ---*** void displayNumeric( const char dp[], const int len ) { // ... 省略 ... }
連接 { 5V } 整合型 LCD,上傳程式執行的結果,如下影片
單晶片與樹莓派測試的結果影片:
同樣的方式,很容易地可以將大型數字顯示的方式在樹莓派與單晶片中實現!
* 樹莓派 ( 每一個硬體版本都適用 )
樹莓派使用 {3V3} 的整合型 LCD,接線相對簡單,不需要裝設可變電阻調整螢幕亮度,而且因為提供了整合型 LCD 函式庫的關係,自定字元或圖形資料的輸入很容易不需要再撰寫,只需要直接呼叫即可
IIC_Numeric.c
/******************************************************************************* * * IIC_Numeric.c * * Author: ruten.proteus * Date: 2015/08/21 * * compile: sudo g++ JLC1602A4IIC.o IIC_Numeric.c -lwiringPi -o iic_numeric * * 說明:using hardware IIC of Raspberry Pi * 使用自定顯示大型數字 * ******************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <wiringPi.h> #include "JLX1602A4IIC.h" // 每一個數字由六個 5x8 的區塊構成 // 這些區塊定義如下: const unsigned char CGRAM_block[]={ 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, // 0,全白, 如同 ASCII 0X20 0X1F,0X1F,0X1F,0X00,0X00,0X00,0X00,0X00, // 1,上黑 0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0X1F, // 2,下黑 0X1F,0X1F,0X1F,0X00,0X00,0X1F,0X1F,0X1F, // 3,上下黑 0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F,0X1F, // 4, 全黑, 如同 ASCII 0XFF 0X00,0X00,0X00,0X00,0X00,0X0E,0X0E,0X0E, // 5,下大點 }; // Numerics[0-9][]:表示一個數字組成的六個字元 // Numerics[][0-2]:表示數字第一列的三個字元 // Numerics[][3-6]:表示數字第二列的三個字元 const unsigned char Numerics[10][6]={ {4,1,4,4,2,4}, {1,4,0,2,4,2}, {3,3,4,4,2,2}, {1,3,4,2,2,4}, {4,2,4,0,0,4}, {4,3,3,2,2,4}, {4,3,3,4,2,4}, {1,1,4,0,4,0}, {4,3,4,4,2,4}, {4,3,4,0,0,4}, }; // // 數字可以容納四個,位置由 LCD 的 2, 6, 10, 14 起頭 const int nix[] = { 2, 6, 10, 14 }; // . 與 : 位置在 1, 5, 9, 13 const int pix[] = { 1, 5, 9, 13 }; const unsigned char IIC_ADDR_LCD1 = 0x3C; const int display = 1; // display on/off const int cursor = 0; // cursor on/off const int blink = 0; // blink on/off JLX1602A4IIC lcd1 = JLX1602A4IIC( IIC_ADDR_LCD1, display, cursor, blink ); void displayNumeric( const char dp[], const int len ); int main(void) { char nums[8]=""; lcd1.clear(); // Wrtie customized font to CGRAM // // 4: 要輸入多少的自訂字元。 // 這不是陣列長度值,但每一個字元表示陣列大小以 8 的倍數成長 // ex. CGGAM_data 大小為 32,表示輸入字元有 4 個,最大輸入不能超過 4 // |_| lcd1.writeCGRAM( &CGRAM_block[0], 4, 1 ); //usleep(10000); lcd1.writeCGRAM( &CGRAM_block[32], 2, 5 ); while(1) { // LCD 顯示數字 0 - 9 // 顯示自定字元在LCD上,確認自定字元已經正常的輸入 for(int i = 0; i < 6; i++) lcd1.displayCGRAM( (0x01 * i), 1, i + 1 ); for(int i = 0; i < 6; i++) lcd1.displayCGRAM( (0x01 * i), 2, i + 1 ); delay(1500); lcd1.clear(); // 顯示大型數字空白、:、.、0 - 9 displayNumeric( "....", 4 ); delay(1500); lcd1.clear(); displayNumeric( "::::", 4 ); delay(1500); lcd1.clear(); for( int i = 0; i < 10; i++ ) { snprintf(nums, 8, "%d%d%d%d", i, i, i, i); displayNumeric( nums, 4 ); delay(1500); lcd1.clear(); } displayNumeric( " ", 4 ); delay(1500); lcd1.clear(); } return 0; } // 每一個數字佔據六個字元位置(上三個、下三個) // 1 3 1 3 1 3 1 3 // 1 3 1 3 1 3 1 3 // "下大點" 和 "上下大點" 只能顯示在標示 1 的地方 // // CGRAM_block[0-4] 只能顯示在標示 3 的位置 // CGRAM_block[5-6] 只能顯示在標示 1 的位置 volatile int len; void displayNumeric( const char dp[], const int len ) { int p =0, n = 0; //printf("len = %d\n", len); for( int i = 0; i < len; i++ ) { switch(dp[i]) { case 0x2e: // . if(p<n) p = n; // line 1 lcd1.displayCGRAM( 0x00, 1, pix[p] ); // line 2 lcd1.displayCGRAM( 0x05, 2, pix[p] ); p++; break; case 0x3A: // : if(p<n) p = n; // line 1 lcd1.displayCGRAM( 0x05, 1, pix[p] ); // line 2 lcd1.displayCGRAM( 0x05, 2, pix[p] ); p++; break; case 0x20: // space // line 1 for( int f = 0; f < 3; f++ ) { lcd1.displayCGRAM( 0x00 , 1, nix[n] + f ); } // line 2 for( int f = 3; f < 6; f++ ) { lcd1.displayCGRAM( 0x00, 2, nix[n] + f - 3 ); } n++; break; case 0x30: // 0 case 0x31: // 1 case 0x32: // 2 case 0x33: // 3 case 0x34: // 4 case 0x35: // 5 case 0x36: // 6 case 0x37: // 7 case 0x38: // 8 case 0x39: // 9 // line 1 for( int f = 0; f < 3; f++ ) { lcd1.displayCGRAM( Numerics[ dp[i] - 0x30 ][f] , 1, nix[n] + f ); } // line 2 for( int f = 3; f < 6; f++ ) { lcd1.displayCGRAM( Numerics[ dp[i] - 0x30 ][f], 2, nix[n] + f - 3 ); } n++; break; } } }
編譯之後執行 ( sudo ./iic_numeric ) 的結果,如下影片
* 單晶片
硬體線路可以自行構建單晶片最小系統 ( 看這篇網頁中的線路 ),或是購買賣場"單晶片燒錄套件",在 Keil C 開啟專案 "Numeric_IIC_Demo.uvproj" 編譯之後燒錄 hex 至單晶片中,就可以得到與下面影片中一樣的執行結果
結論:
這篇網頁主要是為了顯示紫外線強度所寫的網頁,但是用途不只用在這!使用者可以使用在任何需要顯示大型數字的情況下,配合單一字元顯示的函式 ( DisplayChar*** ),就可以做到與網頁最上方參可影片中的結果,這部分可以看接下來的一篇 "{ 樹莓派 + Arduino } 紫外線強度偵測 ( 使用大型數字顯示 )"
<< 整合型 LCD 部落格相關網頁 >>
請問編碼方式跟一般iic一樣嗎?
回覆刪除我用我的顯示竟然是亂碼
請問你有stdio.h的載點嗎??
一般使用iic控充版的LCD與網頁中使用的整合型LCD是不一樣的,(因為它使用IIC通訊的PORT擴充晶片模擬 4/8-bit的LCD通訊 )。
刪除如果不是使用賣場整合型LCD,只有自定字元的程式碼是可以使用與參考的,概念一樣!其他的,不適用!