2018年3月2日 星期五

{單晶片} TCS34725 顏色感測器取色與 APA102 RGB LED 顯色測試

網頁最後修改時間:2018/03/02

延續上一篇使用 Arduino UNO 將取得的彩色紙顏色用WS2812 / APA102 全彩 LED 顯示後,這一篇改用單晶片 ( AT89S52 ) 作為主控制器,將取得的彩色紙顏色用 APA102 全彩 LED 做顯示。

/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
在網頁結尾處,特別也提供函式庫封裝後之簡化版 (不需要整合型 LCD) 的 Keil C51 範例程式碼,可自行修改或是燒錄事先已編譯好的 Hex 檔,只需要有 AT89S52* 和 APA102 全彩 LED ... 等即可;詳情請看電路圖中的描述。
* 基本上,主控制器的晶片選擇可由專案檔以及 Config.h 檔案中自行設置,8051 / 8052 / STC89C52 ... 系列的都可以;詳情看程式碼一節的說明。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*

簡介:
相比於 Arduino,會想用 51 單晶片作為顏色感測器 TCS34725 與 APA102 的人,應該是有點自虐傾向吧 ? 除了一般 51 系列的單晶片沒有內建 I2C 硬體通訊外,APA102、TCS725 和整合型 LCD 的驅動函式庫也沒有,根本有點自找麻煩!

還好,這幾個因為對於通訊時間上的要求並不強烈,所以還算好處理!加上有幾個 (例如,APA102 和整合型 LCD ) 早先在部落格已經撰寫過驅動程式,所以只要整合進來,基本上就可以使用。比較麻煩的是 TCS34725,除了手邊沒有驅動程式外,I2C 底層通訊程式必須重新撰寫來一併適用於整合型 LCD;由於我所使用的單晶片沒有內建 I2C 硬體通訊,所以採用 Bit-Banging 的方式來作,TCS34725 驅動部分則是參考 Arduino 版本的函式庫。

按鈕的部分採用的接線方式與 Arduino 版本的不同,但都是按下後開始動作。

TCS34725 顏色感測器取得的原始 RGB 三個數值,會經過 Gamma 2.5 的校正**產生新的 RGB 數值給 APA102 顯示用,除非需要得知這幾個數值,否則可省略使用整合型 LCD,要不就自己再實現 UART 通訊的部分。

** 了解Gamma Correction

最後一點,確認線路與程式燒錄沒問題的情況之下,若是直接以燒錄器的電源驅動整個線路而動作不正常,請先改用外接電源釐清是否為 TCS34725 參數設定的問題,避免問題其實只是電流不足造成。

參考接線圖:
TCS34725 單晶片版本參考接線圖
實際完成的接線,如下所示
TCS34725 單晶片版本的實際接線完成照片
上面照片裡那根小圓柱,是 APA102 套上珍奶的吸管後灌入熱熔膠完成的;通過這樣的方式,比用肉眼直接看更容易看出 RGB 混色之後的結果,而且也方便攝影與拍照。

電路用到的主要零件可以看下面的列表。A 項:所列兩種單晶片都有經過測試,動作正常;D 項:除非需要輸出資料,否則可不用或是改用 UART 輸出。
*********************************************************************************
主要零件:
*********************************************************************************

程式碼說明:
程式碼依據 A 項的不同,Keil C51 專案的設定與 Config.h 需要作一些修改 (詳情請自行下載程式碼對照),才能輸出相對應的燒錄 Hex 檔。

以 AT89S52 專案裡的 Config.h 為例
ColorLEDAPA102_AT89S52, Config.h, Line 20 - 44
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//#define STC

#ifdef STC
 #include <STC89C5xRC.H>  // 使用 STC-ISP 燒錄安裝支援 STC 晶片之後的標頭檔
#else 
 #include "reg52.h"       // 使用 Keil C51 既有的標頭檔
#endif

// 板載 LED
sbit BUILTIN_LED = P2^0;  // for STC89C52 開發板
sbit STARTBTN    = P2^7;  // active-low, internal pull-up required

// pins for I2C bus
sbit SDA   = P1^6;
sbit SCL   = P1^7;
// TCS34725
#define TCS34725_ADDRESS   (0x52) // 8-bit iic address
// IIC LCD
#define IICLCD_ADDRESS     (0x78) // 8-bit iic address

// pins for APA102
sbit Di = P2^1;
sbit Ci = P2^2;
// APA102 LED 的數量
#define NUM_LEDS 1

Line 20 決定使用的晶片形式,取消註解則會使用 STC89S52 晶片的設定;Line 29 只適用於 STC89C52 開發板,AT89S52 套件沒有這顆 LED;Line 30 按鈕的接腳定義;Line 33 - 34 軟體 I2C 所使用的通訊接腳定義;Line 36, 38 是整合型 LCD 與 TCS34725 的 I2C 位址;Line 41 - 42 定義了 APA102 的通訊接腳;Line 44 定義所使用的 APA102 數量,預設只使用 1 顆,但不管使用幾顆,APA102 都會顯示同一種顏色設定值。

除了 Config/ 目錄下的 Config.h 作為組態之用外,Driver/ 目錄下的檔案主要是零件的函式庫標頭檔,用法看 Source/ 目錄下的 colorledapa102.c 就會清楚;所以接下來就以此檔案為主來分段說明。
ColorLEDAPA102_AT89S52, colorledapa102.c, Line 24 - 70
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <stdio.h>
#include <math.h>
#include "Config.h"
#include "apa102.h"
#include "tcs34725.h"
#include "lcd.h"
#include "I2C.h"
#include "Delay.h"

// our RGB -> eye-recognized gamma color
unsigned char code gammatable[] = {
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,
 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,
 0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x04,
 0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,
 0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,
 0x0A,0x0A,0x0A,0x0B,0x0B,0x0B,0x0C,0x0C,0x0D,0x0D,
 0x0E,0x0E,0x0E,0x0F,0x0F,0x10,0x10,0x11,0x11,0x12,
 0x12,0x13,0x13,0x14,0x15,0x15,0x16,0x16,0x17,0x17,
 0x18,0x19,0x19,0x1A,0x1B,0x1B,0x1C,0x1D,0x1D,0x1E,
 0x1F,0x1F,0x20,0x21,0x22,0x22,0x23,0x24,0x25,0x25,
 0x26,0x27,0x28,0x29,0x2A,0x2A,0x2B,0x2C,0x2D,0x2E,
 0x2F,0x30,0x31,0x32,0x33,0x34,0x34,0x35,0x36,0x37,
 0x38,0x39,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,
 0x43,0x44,0x45,0x47,0x48,0x49,0x4A,0x4B,0x4D,0x4E,
 0x4F,0x50,0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5B,
 0x5C,0x5D,0x5F,0x60,0x62,0x63,0x64,0x66,0x67,0x69,
 0x6A,0x6C,0x6D,0x6F,0x70,0x72,0x73,0x75,0x77,0x78,
 0x7A,0x7B,0x7D,0x7F,0x80,0x82,0x84,0x85,0x87,0x89,
 0x8A,0x8C,0x8E,0x90,0x91,0x93,0x95,0x97,0x99,0x9B,
 0x9C,0x9E,0xA0,0xA2,0xA4,0xA6,0xA8,0xAA,0xAC,0xAE,
 0xB0,0xB2,0xB4,0xB6,0xB8,0xBA,0xBC,0xBE,0xC0,0xC2,
 0xC5,0xC7,0xC9,0xCB,0xCD,0xCF,0xD2,0xD4,0xD6,0xD8,
 0xDB,0xDD,0xDF,0xE2,0xE4,0xE6,0xE9,0xEB,0xED,0xF0,
 0xF2,0xF5,0xF7,0xFA,0xFC,0xFF
};

// LCD 顯示用
char code lcdmsg[][17] = {
 " COLOR SENSING  ",
 "  push button ->",
 "  Found sensor  ",
 "No TCS34725 foud"};

bit trigger = 0;

Line 24 - 31 宣告使用到的標頭檔;Line 34 - 61 定義一個存放在 ROM 的 unsigned char 陣列(因為直接在程式裡作計算所產生的陣列會超出 RAM 的大小限制,所以陣列中的數值是預先用 EXCEL 算出來再產生的,計算的方式看上面提供的連結);Line 64 - 68 這個二維字元陣列,是預先將需要輸出到整合型 LCD 的字串提出來儲存到 ROM 裡去,這樣可以節省 RAM 使用的大小;Line 70 是作為按鈕按下後是否有效的旗標,只有 trigger  = 1 才會開始顏色的擷取。

接著說明主程式的部分。主程式一開始會進行按鈕、整合型 LCD、APA102 和 TCS34725 的初始化動作,APA102 和 TCS34725 不管之前的狀態為何?在此步驟完成後,都會強制關閉,然後進入到無窮循環的部分。

在無窮循環裡,程式會一直檢查按鈕的狀態,直到按鈕的按下狀態被確認有效後,程式就會啟動 TCS34725 開始檢測物體的表面顏色,所得到的 RGB 原始數據值為 16-bit,但 APA102 只能接收 8-bit 數據,所以必須先經過處理為 8-bit 資料才能使用 (此時所得到的 8-bit 數據,其實就可以直接將數值進行輸出顯示),只不過在這邊程式會再作一個 Gamma 校正的動作 (使用者可以在測試的時候去切換這部分,看看實際顯示輸出時有什麼不同)。最後,在整合型 LCD 上顯示輸出到 APA102 的 RGB 值,完成一個測試的循環。
ColorLEDAPA102_AT89S52, colorledapa102.c, Line 72 - 146
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
void main(void)
{
 unsigned short red, green, blue, clear; // 16-bit
 unsigned long sum;   // 32-bit
 float r, g, b;
 char buf[17];
 
 //** 初始化 **
 STARTBTN = 1;    // 設定此接腳為輸入
 // LCD
 lcd_init();
 DelayMs(100);
 lcd_clear();
 DelayMs(100);
 lcd_displayChar( 1, 1, lcdmsg[0], 16 );
 // APA102
 apa102_init();
 // TCS34725
 if( tcs34725_init( TCS34725_INTEGRATIONTIME_154MS, TCS34725_GAIN_1X ) ) {
  lcd_displayChar( 2, 1, lcdmsg[2], 16 );
  tcs34725_setInterrupt( true );  // turn off LED
 } else {
  lcd_displayChar( 2, 1, lcdmsg[3], 16 );
  while(1);  // halt!
 }
 DelayMs(2000);
 lcd_displayChar( 2, 1, lcdmsg[1], 16 );
 
 // turn off APA102
 apa102_ledshow();
 
 for(;;) {
  
  // button debounced
  if( STARTBTN == 0 ) {  // pressed
   DelayMs( 60 );  // 60ms
   if( STARTBTN == 0 ) {
    trigger = 1;
   } else {
    trigger = 0;
   }
  }
  
  if( trigger == 1 ) {  // 開始檢測顏色
   
   clear = 0; red = 0; green = 0; blue = 0; sum = 0;
   r = 0.0; g = 0.0; b = 0.0;
   
   trigger = 0;
   
   tcs34725_setInterrupt( false );  // turn on LED
   DelayMs( 160 );   
   tcs34725_getRawData( &red, &green, &blue, &clear );
   tcs34725_setInterrupt( true );  // turn off LED
   
   // 輸出轉換為 8-bit 的 RGB 值
   sum = clear;
   r = red;    r /= sum;
   g = green;  g /= sum;
   b = blue;   b /= sum;
   r *= 256; g *= 256; b *= 256;
   
   // 輸出 gamma 補正的顏色值
   apa102_setRGBall( gammatable[(int)r], gammatable[(int)g], gammatable[(int)b] );
   // APA102 顯色
   apa102_ledshow();
  
   // LCD 顯示顯色資料
   sprintf(buf, "   CLEAR:%-5d  ", clear  );
   lcd_displayChar( 1, 1, buf, 16 );
   sprintf( buf, " R%-3d G%-3d B%-3d ", (int)gammatable[(int)r], (int)gammatable[(int)g], (int)gammatable[(int)b] );
   lcd_displayChar( 2, 1, buf, 16 );
  }
 }
}

從無窮迴圈開始,Line 106 - 113 偵測按鈕是否被使用者按下,並且簡單的去除抖動;Line 115 一但確認按鈕動作有效,進入檢色與顯色的過程;過程一開始,設定 Line 120 trigger 旗標回原狀,接著 Line 122 打開 TCS34725 模組上的 LED 燈,LED 會照亮模組上方的物體一段時間 (Line 123) 後,進行檢色取得該物體表面顏色的 RGBC 原始數值 (Line 124),最後關閉 TCS34725 模組的 LED 燈 (Line 125);RGBC 原始數據經過 Line 128 - 132 的簡單計算,轉換為 8-bit 的原始數據;將 8-bit RGB 原始數據代入到 gammatable 陣列中,得到 Gamma 2.5 校正之後的結果,並以此結果作為引數代入到 APA102 顏色設定的函式裡,以此作為 Line 137 顯示的顏色;Line 140 - 141 將原始數據中的 Clear 值,顯示在整合型 LCD 的第一行;Gamma 2.5 校正之值,Line 142 - 143 顯示在整合型 LCD 的第二行,完成一次檢色顯色的動作。

/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 程式碼下載:
下面兩個下載的壓縮檔,都包含了 A 項所描述的兩種單晶片的專案檔,裡面也包含了編譯後的 Hex 檔可以直接用來燒錄。

測試影片:
影片中所展示的就是上面程式碼下載的 "影片版"。影片中可以很明顯地看出檢色與顯色的速度與效果,而且也不需事前作白平衡校正 (TCS3200 需要),非常容易使用!

結論:
影片看起很流暢,但實際上並不是一次就一鏡到底,而是經過幾次的預演與挑選適當的彩色紙才如此順利。首先,攝影機的設定影響 APA102 (中間那支小圓柱) 與整合型 LCD 是否能清楚顯示辨識之後的顏色與文字 (試著用相機對日光燈照就會了解),而這也跟所處環境中的光線來源與強弱有關;其次是 TCS34725 積分時間與增益這兩個參數的設定,而這也跟環境光有關係,影響顏色辨識的準確性。

上述問題決定了之後,要考慮的就是彩色紙在測試時放置的高低距離。因為是用手拿彩色紙做測試,所以影片中所選擇的這幾張色紙,是選能在相同測試距離下 ( <5mm ) 容易辨識出來的 (其他的當然也可以成功辨識,只不過影片拍攝時還要特別去記每一個色紙的距離,要拍很久且麻煩 !),因為 TCS34725 所處環境下的光線條線或多或少都互影響測試的結果。

說了一堆好像很複雜的樣子!其實只要實際動手做一遍,不需要人講也會知道上面這些會影響檢色的因素是什麼?

實際應用時,建議固定物體與 TCS34725 的檢測距離以及所處環境的光線強度,然後再以實際測試結果調整積分時間與增益這兩個參數,直到結果符合期望值!

如果有檢測顏色的需求,相信 TCS34725 顏色感測器是一個很好的選擇!

<< 部落格相關文章 >>

沒有留言:

張貼留言