Sensor Kamera CMUcam3
May 5, 2011 23 Comments
Tujuan dari proyek CMUcam adalah untuk memberikan kemampuan visi sederhana untuk embedded system kecil dalam bentuk sebuah sensor cerdas. CMUcam3 memperluas atas gagasan ini dengan menyediakan fleksibel dan mudah untuk menggunakan lingkungan pengembangan open source yang melengkapi platform perangkat keras biaya rendah. CMUcam3 ini berbasis ARM7TDMI sepenuhnya programmable embedded computer vision sensor. Prosesor utama adalah LPC2106 NXP terhubung ke kamera CMOS sensor Omnivision modul. Custom C code dapat dikembangkan untuk CMUcam3 menggunakan port dari GNU toolchain bersama dengan satu set library open source dan program contoh. Pemrograman menggunakan port serial port tanpa perangkat eksternal tabahan.
Modul embedded vision sensor berbasis Omnivision CMOS camera dan mikrokontroler ARM7TDMI (Philips NXP LPC2106).
Spesifikasi:
– Programmable dan open source.
– RGB, resolusi CIF (352×288).
– Slot untuk MMC/SD card dengan FAT16 driver.
– 4 port servo controller.
– Kecepatan image processing 26 fps (frame/second).
– Kompresi JPEG software.
– Lua light-weight language interpreter.
– Raw images dumps melalui port serial.
– Mampu membuat histogram.
– Tersedia keluaran video analog B/W (PAL or NTSC).
– FIFO image buffer untuk image processing dengan resolusi tinggi.
– Antarmuka serial UART TTL & RS-232.
– Mendukung Teleos 802.15.4, antarmuka jaringan Wireless Mote.
Untuk melakukan pemrograman software bisa didownload di link berikut. http://cmucam.org/wiki/Software. Jika menggunakan Windows dan saat proses installasi CygWin terdapat masalah, maka installer CygWin bisa didownload dari situsnya langsung http://cygwin.com/setup.exe.
Kelengkapan Software untuk melakukan programming pada CMUcam3
Windows: Cygwin-Installer (with packages), arm-gcc, Philips-Flash utility, .NET Runtime, CMUcam3 frame grabber
Linux: arm-gcc compiled tar, LPC-isp Flash Utility
Source Code
Pada situs http://cmucam.org/wiki/Downloads terdapat CC3 Source Tree yang bisa kita gunakan sebagai acuan dasar. Jadi kita tinggal mengedit saja sesuai keperluan.
CMUcam2 pada CMUcam3
CMUcam3 dapat diisi dengan menggunakan CMUcam2 Emulation HEX file (http://cmucam.org/attachment/wiki/Downloads/cmucam2_lpc2106-cmucam3.hex?format=raw) agar mempunyai kemampuan seperti CMUcam2. Untuk mengetes firmware tersebut bisa digunakan CMUcam2 GUI (http://www.cs.cmu.edu/~cmucam2/CMUcam2GUI.zip) yang berbasis java. Emulator java sendiri bisa didownload pada situs berikut. http://www.oracle.com/technetwork/java/javase/downloads/index.html.
Compile Source Code
Untuk mengedit file.c bisa menggunakan wordpad. Setelah semua software kelengkapan telah terinstall dengan baik, maka kita bisa langsung mencoba untuk mengkompail source code CC3 Source. Berikut urutan langkah-langkah untuk mengkompail file yang ada pada CC3 Source folder Project:
1. Jalankan CygWin (windows, console pada linux)
2. Ketik “cd alamat_direktori_project_yang dipilih”. Enter.
3. Ketik “make”, enter. Jika terdapat error, cobalah untuk mengulangi langkah 2 dengan mengganti alamat direktori project menjadi alamat dari folder CC3, enter. Lalu ketik “make”, enter. Setelah selesai, kembali ke langkah 2 untuk mengkompail file terpilih pada folder Project. Jika berhasil, maka pada folder yang terpilih akan ada file yang berekstensi .hex yang akan dimasukan ke dalam CMUcam3.
Memasukan .Hex pada CMUcam3
Pertama, matikan CMUcam3 lalu nyalakan kembali sambil menekan pushbutton yang terdapat pada modul beberapa saat. Jika CMUcam3 sudah siap diprogram maka 2 led akan menyala hijau dan merah. Buka software Philips-Flash utility. Pastikan pilih COM yang akan digunakan. Klik Erase. Lalu pilih juga file .hex yang akan ditanam pada CMUcam3 dan Upload to flash. Setelah selesai, matikan CMUcam3 dan nyalakan kembali agar CMUcam3 keluar dari keadaan siap diprogram menjadi menjalankan program.
Interface CMUcam3 dengan Mikrokontroler
CMUcam3 memiliki pin UART yang tentunya bisa kita manfaatkann untuk berkomunikasi dengan mikrokontroler. Disana terdapat koneksi dengan mode RS232 atau TTL. Jika menggunakan mode RS232 maka kita tinggal mengkoneksikannya dengan conector DB9 pada CMUcam3. Akan tetapi, jika menggunakan mode TTL maka ada jumper yang harus dilepas dan hati-hati jika mengkoneksikan CMUcam3 dengan pin TTL ini karena UART dari ARM yang rawan terbakar. Perhatikan level tegangan dan konsumsi arus antara CMUcam3 dan mikrokontroler yang digunakan. Disarankan gunakan saja RS232 karena koneksi terproteksi oleh IC MAX232 yang terdapat pada modul CMUcam3.
Berikut contoh program untuk CMUcam3 yang bisa digunakan untuk deteksi warna yang bisa terkoneksi ke mikrokontroler lain.
________________________________________________________
#include <stdio.h>
#include <stdlib.h>
#include <cc3.h>
#include <cc3_ilp.h>
#include <cc3_color_track.h>
#include <cc3_color_info.h>
#include <cc3_frame_diff.h>
void simple_track_color(cc3_track_pkt_t *t_pkt);
void simple_get_mean (cc3_color_info_pkt_t * s_pkt);
int main(void) {
cc3_color_info_pkt_t s_pkt;
uint8_t data;
uint32_t threshold;
int32_t tmp;
cc3_track_pkt_t t_pkt;
uint32_t x0, y0, x1, y1;
cc3_frame_diff_pkt_t fd_pkt;
cc3_uart_init (0, CC3_UART_RATE_115200,
CC3_UART_MODE_8N1, CC3_UART_BINMODE_TEXT);
cc3_camera_init ();
cc3_camera_set_resolution(CC3_CAMERA_RESOLUTION_LOW);
cc3_pixbuf_frame_set_subsample(CC3_SUBSAMPLE_NEAREST, 2, 1);
// init pixbuf with full size width and height
x0 = 0;
x1 = cc3_g_pixbuf_frame.raw_width;
y0 = 0;
y1 = cc3_g_pixbuf_frame.raw_height;
fd_pkt.coi = 1;
fd_pkt.template_width = 8;
fd_pkt.template_height = 8;
t_pkt.track_invert = false;
t_pkt.noise_filter = 0;
cc3_pixbuf_frame_set_roi (x0, y0, x1, y1);
// Load in color tracking parameters
t_pkt.lower_bound.channel[0] = 168;
t_pkt.upper_bound.channel[0] = 240;
t_pkt.lower_bound.channel[1] = 29;
t_pkt.upper_bound.channel[1] = 36;
t_pkt.lower_bound.channel[2] = 14;
t_pkt.upper_bound.channel[2] = 18;
//set servo awal posisi
cc3_gpio_set_servo_position(0,128);
while(true) {
simple_track_color(&t_pkt);
data = getchar();
if(data==’x’)
{
printf(“%c”,t_pkt.centroid_x);
}
else if(data==’y’)
{
printf(“%c”,t_pkt.centroid_y);
}
else if(data==’d’)
{
printf(“%c”,(uint8_t)t_pkt.int_density/10);
}
else if(data==’r’) // L R
{
t_pkt.lower_bound.channel[0] = getchar();
}
else if(data==’s’) // H R
{
t_pkt.upper_bound.channel[0] = getchar();
}
else if(data==’g’) // L G
{
t_pkt.lower_bound.channel[1] = getchar();
}
else if(data==’h’) // H G
{
t_pkt.upper_bound.channel[1] = getchar();
}
else if(data==’b’) // L B
{
t_pkt.lower_bound.channel[2] = getchar();
}
else if(data==’c’) // H B
{
t_pkt.upper_bound.channel[2] = getchar();
}
else if(data==’p’)
{
printf(“\n centroid=[%d,%d] bounding box=[%d,%d,%d,%d] num pix=[%d] density=[%d] \n”,
t_pkt.centroid_x, t_pkt.centroid_y,
t_pkt.x0,t_pkt.y0,t_pkt.x1,t_pkt.y1,
t_pkt.num_pixels, t_pkt.int_density );
}
else if(data==’w’)
{
printf(“\n R=[%d,%d] G=[%d,%d] B=[%d,%d] \n”,
t_pkt.lower_bound.channel[0],t_pkt.upper_bound.channel[0],
t_pkt.lower_bound.channel[1],t_pkt.upper_bound.channel[1],
t_pkt.lower_bound.channel[2],t_pkt.upper_bound.channel[2]);
}
else if(data==’a’)
{
// init pixbuf with width and height
cc3_pixbuf_load ();
threshold = 30;
// set window to 1/2 size
x0 = cc3_g_pixbuf_frame.x0 + cc3_g_pixbuf_frame.width / 4;
x1 = cc3_g_pixbuf_frame.x1 – cc3_g_pixbuf_frame.width / 4;
y0 = cc3_g_pixbuf_frame.y0 + cc3_g_pixbuf_frame.width / 4;
y1 = cc3_g_pixbuf_frame.y1 – cc3_g_pixbuf_frame.width / 4;
cc3_pixbuf_frame_set_roi (x0, y0, x1, y1);
// call get mean
simple_get_mean (&s_pkt);
// set window back to full size
x0 = 0;
x1 = cc3_g_pixbuf_frame.raw_width;
y0 = 0;
y1 = cc3_g_pixbuf_frame.raw_height;
cc3_pixbuf_frame_set_roi (x0, y0, x1, y1);
// fill in parameters and call track color
tmp = s_pkt.mean.channel[0] – threshold;
if (tmp < 16)
tmp = 16;
if (tmp > 240)
tmp = 240;
t_pkt.lower_bound.channel[0] = tmp;
tmp = s_pkt.mean.channel[0] + threshold;
if (tmp < 16)
tmp = 16;
if (tmp > 240)
tmp = 240;
t_pkt.upper_bound.channel[0] = tmp;
tmp = s_pkt.mean.channel[1] – threshold;
if (tmp < 16)
tmp = 16;
if (tmp > 240)
tmp = 240;
t_pkt.lower_bound.channel[1] = tmp;
tmp = s_pkt.mean.channel[1] + threshold;
if (tmp < 16)
tmp = 16;
if (tmp > 240)
tmp = 240;
t_pkt.upper_bound.channel[1] = tmp;
tmp = s_pkt.mean.channel[2] – threshold;
if (tmp < 16)
tmp = 16;
if (tmp > 240)
tmp = 240;
t_pkt.lower_bound.channel[2] = tmp;
tmp = s_pkt.mean.channel[2] + threshold;
if (tmp < 16)
tmp = 16;
if (tmp > 240)
tmp = 240;
t_pkt.upper_bound.channel[2] = tmp;
}
else
{
printf(“n”);
}
}
}
void simple_track_color(cc3_track_pkt_t *t_pkt)
{
cc3_image_t img;
img.channels = 3;
img.width = cc3_g_pixbuf_frame.width;
img.height = 1; // image will hold just 1 row for scanline processing
img.pix = cc3_malloc_rows (1);
if (img.pix == NULL) {
return;
}
cc3_pixbuf_load ();
if (cc3_track_color_scanline_start (t_pkt) != 0) {
while (cc3_pixbuf_read_rows (img.pix, 1)) {
// This does the HSV conversion
// cc3_rgb2hsv_row(img.pix,img.width);
cc3_track_color_scanline (&img, t_pkt);
}
}
cc3_track_color_scanline_finish (t_pkt);
free (img.pix);
return;
}
void simple_get_mean (cc3_color_info_pkt_t * s_pkt)
{
cc3_image_t img;
img.channels = 3;
img.width = cc3_g_pixbuf_frame.width;
img.height = 1; // image will hold just 1 row for scanline processing
img.pix = malloc (3 * img.width);
cc3_pixbuf_load ();
if (cc3_color_info_scanline_start (s_pkt) != 0) {
while (cc3_pixbuf_read_rows (img.pix, 1)) {
cc3_color_info_scanline (&img, s_pkt);
}
cc3_color_info_scanline_finish (s_pkt);
}
free (img.pix);
}
______________________________________________________________
Keterangan instruksi untuk interfacing dengan CMUcam3 dari program di atas.
‘x’ –> jika mikrokontroler mengirim nilai ascii dari huruf x , CMUcam3 akan mengirim balasan hex titik tengah koordinat sumbu x warna yang terdeteksi.
‘y’ –> jika mikrokontroler mengirim nilai ascii dari huruf y , CMUcam3 akan mengirim balasan hex titik tengah koordinat sumbu y warna yang terdeteksi
‘d’ –> jika mikrokontroler mengirim nilai ascii dari huruf d , CMUcam3 akan mengirim balasan hex nilai density yaitu nilai kepadatan pixel warna yang terdeteksi dibagi 10.
‘r’ –> jika mikrokontroler mengirim nilai ascii dari huruf r ,dilanjutkan dengan nilai hex filter warna merah (0-255) minimum.
‘s’ –> jika mikrokontroler mengirim nilai ascii dari huruf s , dilanjutkan dengan nilai hex filter warna merah (0-255) maximum.
‘g’ –> jika mikrokontroler mengirim nilai ascii dari huruf g , dilanjutkan dengan nilai hex filter warna hijau (0-255) minimum.
‘h’ –> jika mikrokontroler mengirim nilai ascii dari huruf h , dilanjutkan dengan nilai hex filter warna hijau (0-255) maximum.
‘b’ –> jika mikrokontroler mengirim nilai ascii dari huruf b , dilanjutkan dengan nilai hex filter warna biru (0-255) minimum.
‘c’ –> jika mikrokontroler mengirim nilai ascii dari huruf c, dilanjutkan dengan nilai hex filter warna biru (0-255) maximum.
‘p’ –> jika mikrokontroler mengirim nilai ascii dari huruf p, maka CMUcam3 akan mengirim ascii centroid=[%d,%d] bounding box=[%d,%d,%d,%d] num pix=[%d] density=[%d]
‘w’ –> jika mikrokontroler mengirim nilai ascii dari huruf w, maka CMUcam akan mengirim ascii R=[%d,%d] G=[%d,%d] B=[%d,%d] yaitu nilai filter warna yang digunakan.
‘a’ –> jika mikrokontroler mengirim nilai ascii dari huruf a, CMUcam3 akan meng-grab warna yang ada dihadapannya dan digunakan sebagai warna yang difilter atau dideteksi selanjutnya.
Untuk mengujinya bisa juga dihubungkan dengan hyperterminal pada PC.
Berikut link untuk mendownload .hex dari program di atas. http://www.mediafire.com/file/fo8jtyjwu7w77dr/simple-track-color-wangready.wordpress.com_lpc2106-cmucam3.hex
______________________________________________________________
Berikut contoh schematic rangkaian interface CMUcam3 dengan mikrokontroler atmega128 11.0592MHz + LCD 2×16 yang berkomunikasi menggunakan UART RS232
______________________________________________________________
Contoh program dengan CVAVR untuk mendeteksi adanya warna yang difilter
/*****************************************************
Chip type : ATmega128
Program type : Application
Clock frequency : 11.059200 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 1024
*****************************************************/
#include <mega128.h>
#include <delay.h>
// Alphanumeric LCD Module functions
#asm
.equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 8
char rx_buffer0[RX_BUFFER_SIZE0];
#if RX_BUFFER_SIZE0<256
unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
#else
unsigned int rx_wr_index0,rx_rd_index0,rx_counter0;
#endif
// This flag is set on USART0 Receiver buffer overflow
bit rx_buffer_overflow0;
// USART0 Receiver interrupt service routine
interrupt [USART0_RXC] void usart0_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0[rx_wr_index0]=data;
if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
if (++rx_counter0 == RX_BUFFER_SIZE0)
{
rx_counter0=0;
rx_buffer_overflow0=1;
};
};
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART0 Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0[rx_rd_index0];
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#asm(“cli”)
–rx_counter0;
#asm(“sei”)
return data;
}
#pragma used-
#endif
// USART0 Transmitter buffer
#define TX_BUFFER_SIZE0 8
char tx_buffer0[TX_BUFFER_SIZE0];
#if TX_BUFFER_SIZE0<256
unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;
#else
unsigned int tx_wr_index0,tx_rd_index0,tx_counter0;
#endif
// USART0 Transmitter interrupt service routine
interrupt [USART0_TXC] void usart0_tx_isr(void)
{
if (tx_counter0)
{
–tx_counter0;
UDR0=tx_buffer0[tx_rd_index0];
if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
};
}
#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART0 Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter0 == TX_BUFFER_SIZE0);
#asm(“cli”)
if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
{
tx_buffer0[tx_wr_index0]=c;
if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
++tx_counter0;
}
else
UDR0=c;
#asm(“sei”)
}
#pragma used-
#endif
// Standard Input/Output functions
#include <stdio.h>
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Port E initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTE=0x00;
DDRE=0x00;
// Port F initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTF=0x00;
DDRF=0x00;
// Port G initialization
// Func4=In Func3=In Func2=In Func1=In Func0=In
// State4=T State3=T State2=T State1=T State0=T
PORTG=0x00;
DDRG=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
ASSR=0x00;
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// OC1C output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare C Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// Timer/Counter 3 initialization
// Clock source: System Clock
// Clock value: Timer 3 Stopped
// Mode: Normal top=FFFFh
// Noise Canceler: Off
// Input Capture on Falling Edge
// OC3A output: Discon.
// OC3B output: Discon.
// OC3C output: Discon.
// Timer 3 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare C Match Interrupt: Off
TCCR3A=0x00;
TCCR3B=0x00;
TCNT3H=0x00;
TCNT3L=0x00;
ICR3H=0x00;
ICR3L=0x00;
OCR3AH=0x00;
OCR3AL=0x00;
OCR3BH=0x00;
OCR3BL=0x00;
OCR3CH=0x00;
OCR3CL=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// INT3: Off
// INT4: Off
// INT5: Off
// INT6: Off
// INT7: Off
EICRA=0x00;
EICRB=0x00;
EIMSK=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
ETIMSK=0x00;
// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud rate: 115200
UCSR0A=0x00;
UCSR0B=0xD8;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x05;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
// LCD module initialization
lcd_init(16);
// Global enable interrupts
#asm(“sei”)
//delay, menunggu cmucam3 benar-benar aktif
delay_ms(1000);
//setting nilai filter RGB
//deeteksi warna Dark orange (web colour) : http://en.wikipedia.org/wiki/Orange_%28colour%29
//centre RGB (255,140,0)
putchar(‘r’);
putchar(245); // set nilai red minimum
putchar(‘s’);
putchar(255); // set nilai red maksimum
putchar(‘g’);
putchar(130); // set nilai green minimum
putchar(‘h’);
putchar(150); // set nilai green maksimum
putchar(‘b’);
putchar(0); // set nilai blue minimum
putchar(‘c’);
putchar(10); // set nilai blue maksimum
while (1)
{
// Place your code here
//meminta nilai density dari CMUCAM3 dan menampilakan hasilnya pada LCD atmega128
putchar(‘d’);
if(getchar() > 0)
{
lcd_clear();
lcd_gotoxy(0,1);
lcd_putsf(“warna terdeteksi”);
}
else
{
lcd_clear();
lcd_gotoxy(0,1);
lcd_putsf(“tidak ada warna terdeteksi”);
}
delay_ms(300);
};
}
______________________________________________________________
Daftar Pustaka