เมนู

วันอังคารที่ 12 กรกฎาคม พ.ศ. 2559

Pinguino กับ LCD Adaptor Plate I2C


               บทความครั้งนี้ผมจะเขียนถึงการใช้งาน LCD Adaptor Plate I2C หรือบางทีก็เรียกว่า I2C Convertor Module for LCD1602/2004 ซึ่งรูปร่างหน้าตาของมันก็จะอยู่ในรูปที่ 1 เจ้าตัวนี้นั้นถูกออกแบบมาเพื่อให้สามารถใช้สายสัญญานเพียงสองเส้นก็สามารถสื่อสารและแสดงข้อความบนจอ LCD ขนาด 16x2 หรือ 20x4 ได้แล้ว จากเดิมที่ต้องใช้อย่างน้อย 6 เส้นถึงจะสื่อสารกันได้  อีกทั้งราคาที่ถูกมากจึงได้รับความนิยมสูง โดยตัว I2C converter นี้จะมีอยู่หลายเวอร์ชัน ซึ่งแต่ละเวอร์ชันก็จะมี I2C address ไม่เหมือนกัน ข้อมูลเพิ่มเติมสามารถหาอ่านได้จากที่นี่ครับ ค่อนข้างละเอียดดีทีเดียว
รูปที่ 1 LCD Adaptor Plate I2C

               จากการดูและเปรียบเทียบแล้วตัวที่ผมมีอยู่นั้นมี หมายเลข I2C address เป็น 0x27 เมื่อรู้ดังนี้แล้วก็เริ่ม wiring สายจาก I2C convertor ไปที่ตัวบอร์ด Pinguino 8 ซึ่งก็จะมีเพียงแค่ 4 เส้นเท่านั้น คือ Vdd, Gnd, SCL, SDA
ซึ่งก็จะมี label พิมพ์ติดไว้อยู่แล้วทั้งบน I2C convertor และ Pinguino 8 โดยเมื่อต่อเสร็จแล้วก็จะได้ตามรูปที่ 2 ครับ
รูปที่ 2 เชื่อมต่อกับ Pinguino 8
และในส่วนของโค้ดที่จะเขียนนั้นง่ายและสั้นมากครับโดยเราเพียงต้อง initialize เจ้า I2C convertor ว่าต่ออยู่กับจอ LCD ขนาดเท่าไหร่ 16x2 หรือ 20x4 และกำหนดหมายเลข address ให้ตรงกับของ I2C convertor เท่านั้นเองซึ่งตัวที่ผมใช้คือ 0x27 โดยโค้ดจะเป็นดังนี้ครับ

1:  lcdi2c.init(16,2,0x27);  
2:  lcdi2c.backlight();  
3:  lcdi2c.printf("Hello Thailand");  

               ในบรรทัดแรกเป็นการ initialize อย่างที่ได้อธิบายด้านบน ส่วนบรรทัดถัดมาเป็นการสั่งให้ไฟ back light สว่างขึ้นมา และบรรทัดสุดท้ายก็ให้ส่งข้อความ Hello Thailand ออกมาแสดงครับ เมื่อเราสั่งคอมไพล์และโปรแกรมลงตัวไมโครคอนโทรลเลอร์แล้วก็จะจะจะ……..อ้าว! ทำไมไม่มีอะไรเกิดขึ้นเลย ต่อสาย SCL กับ SCA  สลับกันหรือเปล่า ? ก็ถูกนี่ งั้นโค้ดต้องผิดแน่นอนเลย!!!!!


               นั่นคือประสบการณ์ครั้งแรกของผมกับ Pinguino กับ I2C converter for LCD ครับ ผมใช้เวลาอยู่หลายวันหาข้อมูลจากอินเตอร์เน็ทก็หาไม่ค่อยได้ สุดท้ายผมหาเจอ schematic หรือ ใน Arduino forum นี่แหละจำไม่ค่อยได้แล้วครับ ประกอบกับนั่งอ่าน library ของ Pinguino เองจนพบว่าในไฟล์ที่ชื่อ lcdi2c.h ที่อยู่ในโฟล์เดอร์ ‘C:\pinguino-11\p8\include\pinguino\libraries’ นั้น define ขาที่ต่อกับ PCF8574 ไม่ตรงกันโดยของเดิมจะเป็น

1:  #define LCD_BL     PCF8574_data.bits.bit0     // P0  
2:  #define LCD_RS     PCF8574_data.bits.bit1     // P1  
3:  #define LCD_RW     PCF8574_data.bits.bit2     // P2  
4:  #define LCD_EN     PCF8574_data.bits.bit3     // P3  

ผมจึงแก้ไขใหม่ให้ตรงกับตัว I2C convertor for LCD ที่ผมมีอยู่โดยแก้เป็นของใหม่ดังนี้ครับ

1:  #define LCD_BL     PCF8574_data.bits.bit3     // P0  
2:  #define LCD_RS     PCF8574_data.bits.bit0     // P1  
3:  #define LCD_RW     PCF8574_data.bits.bit1     // P2  
4:  #define LCD_EN     PCF8574_data.bits.bit2     // P3  

หลังจาก save file แล้ว ทำการคอมไพล์ใหม่และโปรแกรมลงไมโครคอนโทรลเลอร์อีกครั้ง คราวนี้…..ทำงานได้แล้วครับ เย้ๆ ลองดูจากวิดีโอดูนะครับ ส่วนข้างล่างนี้เป็นโค้ดทั้งหมดนะครับ


1:  /*-----------------------------------------------------  
2:  Author: --<Ekkachai Muangrodpai>  
3:  Board:  Pinguino8 + I2C LCD board.  
4:  Date: 2016-03-20  
5:  Description:  
6:  - display message on LCD through I2C adaptor.  
7:  -----------------------------------------------------*/  
8:  /*  
9:    Note: must change the definition in 'lcdi2c.h' to match the hardware. Like following:    
10:  #define LCD_BL     PCF8574_data.bits.bit3     // P0  
11:  #define LCD_RS     PCF8574_data.bits.bit0     // P1  
12:  #define LCD_RW     PCF8574_data.bits.bit1     // P2  
13:  #define LCD_EN     PCF8574_data.bits.bit2     // P3  
14:   */  
15:  void setup() {  
16:    // put your setup code here, to run once:  
17:    lcdi2c.init(16,2,0x27);  
18:    lcdi2c.backlight();  
19:    lcdi2c.printf("Hello Thailand");    
20:  }  
21:  void loop() {  
22:    // put your main code here, to run repeatedly:  
23:  }  



ของแถมครับ จาก link ข้างบนผมเห็นมีตัวอย่างของ Arduino ที่ใช้ Serial รับค่า string จากคอมพิวเตอร์แล้วเอามาแสดงผลบนจอ LCD ที่ต่อผ่าน I2C adaptor for LCD ซึ่งน่าสนุกดีผมจึงลองเขียนด้วย Pinguino ดูบ้างโดยใช้ฟังก์ชันจากบทความนี้และจากบทความที่ผ่านมาเรื่อง Pinguino สื่อสารผ่าน Com Port ก็ได้มาเป็นโค้ดที่แสดงข้างล่างต่อไปนี้ครับลองทดลองกันดูนะครับ
1:  /*-----------------------------------------------------  
2:  Author: --<Ekkachai Muangrodpai>  
3:  Board:  Pinguino8 + I2C convertor for LCD board + USB-to-Serial.  
4:  Date: 2016-07-11  
5:  Description:  
6:  - Get string from computor through terminal program, then display on LCD.  
7:  -----------------------------------------------------*/  
8:  int i;  
9:  void setup() {  
10:   Serial.begin(9600);    
11:   lcdi2c.init(16, 2, 0x27);         
12:   // ------- Quick 3 blinks of backlight -------------  
13:   for(i = 0; i< 3; i++)  
14:   {  
15:    lcdi2c.backlight();  
16:    delay(250);  
17:    lcdi2c.noBacklight();  
18:    delay(250);  
19:   }  
20:   lcdi2c.backlight(); // finish with backlight on   
21:   //-------- Write characters on the display ------------------  
22:   lcdi2c.setCursor(0,0);   
23:   lcdi2c.printf("Hello, World!....");  
24:   delay(1000);  
25:   lcdi2c.setCursor(0,1);  
26:   lcdi2c.printf("Hi Your Pinguino");  
27:   delay(1000);   
28:  // Wait and then tell user they can start the Serial Monitor and type in characters to  
29:  // Display. (Set Serial Monitor option to "No Line Ending")  
30:   lcdi2c.clear();  
31:   lcdi2c.setCursor(0,0); //Start at character 0 on line 1  
32:   lcdi2c.printf("Use Serial Mon");  
33:   lcdi2c.setCursor(0,1);  
34:   lcdi2c.printf("Type to display");    
35:  }  
36:  void loop() {  
37:    // when characters arrive over the serial port...  
38:    if (Serial.available()) {     
39:     delay(100);          // wait a bit for the entire message to arrive      
40:     lcdi2c.clear();  
41:     // read all the available characters  
42:     while (Serial.available() > 0) {      
43:      lcdi2c.write(Serial.read());          // display each character to the LCD  
44:     }  
45:    }  
46:  }  

วันเสาร์ที่ 9 กรกฎาคม พ.ศ. 2559

Pinguino กับ LCD Keys pad shield part 2


               จากบทความที่แล้วเราสามารถติดต่อกับ LCD shield และแสดงข้อความออกที่หน้าจอได้แล้ว ในบทความต่อเนื่องชิ้นนี้เราจะมาเขียนโค้ดเพื่อให้ LCD Keys pad shield ทำงานได้เหมือนอย่างเดโมของ Arduino ที่แสดงใน link ของ shield ในบทความที่ผ่านมา ซึ่งนั่นรวมถึงการอ่านค่าจาก keys ผ่านทาง ADC โมดูล และการอัพเดทเวลาทุกๆ 1 วินาทีแล้วแสดงผล ซึ่งเดี๋ยวเราจะมาดูกันทีละส่วนครับ

               จาก schematic ของ LCD Keys pad shield เราจะเห็นว่ามีสวิตซ์กด(keys) อยู่ทั้งหมด 6 สวิตซ์ โดย 5 ใน 6 สวิตซ์ต่อเข้ากับวงจรแบ่งแรงดันและแรงดันเอ้าต์พุตต่อเข้ากับ analog input(A0) เพราะจำนวน I/O ของ Arduino มีจำกัดหากต่อแต่ละสวิตซ์เข้า I/O จะต้องใช้ถึง 5 I/O แต่หากใช้ตัวต้านทานต่อเป็นวงจรแบ่งแรงดันร่วมกับ ADC ก็จะลดจำนวน I/O ลงได้มาก ส่วนอีกสวิตซ์จะเป็น RESET ครับ


               สำหรับ Pinguino นั้นมี library สำหรับอ่านค่าจาก ADC โมดูลที่เหมือนกับของ Arduino เป๊ะแถมความละเอียดยังเป็น 10 บิตเท่ากันอีกด้วย นั่นหมายความว่าเราสามารถ copy โค้ดเดโมของ Arduino มาใช้ใน Pinguino ได้เลย ง่ายดีไหมละครับ โดยโค้ดในส่วนการอ่านค่าสวิตซ์จะเป็นดังนี้ครับ

1:  int adc_key_in = 0;  
2:  #define btnRIGHT 0  
3:  #define btnUP   1  
4:  #define btnDOWN  2  
5:  #define btnLEFT  3  
6:  #define btnSELECT 4  
7:  #define btnNONE  5  

8:  int read_LCD_buttons()  
9:  {  
10:   adc_key_in = analogRead(A0);   // read the value from the sensor  
11:   if (adc_key_in < 50)  return btnRIGHT;   
12:   if (adc_key_in < 195) return btnUP;   
13:   if (adc_key_in < 380) return btnDOWN;   
14:   if (adc_key_in < 555) return btnLEFT;   
15:   if (adc_key_in < 790) return btnSELECT;    
16:   return btnNONE; // when all others fail, return this...  
17:  }  


              เริ่มต้นจากการประกาศตัวแปรชื่อ adc_key_in ไว้สำหรับรับค่าจากการอ่านผลลัพธ์ของการแปลง A/D โดยในฟังก์ชัน read_LCD_buttons() จะมีการเรียกใช้ analogRead(A0) ซึ่งจะส่งค่าผลลัพธ์ของการแปลง A/D ของช่อง A0  มาเก็บไว้ในตัวแปรที่กล่าวข้างต้น จากนั้นจึงเปรียบเทียบค่า แล้วส่งผลลัพธ์ที่ถูกต้องกลับไปให้ฟังก์ชัน main ต่อไป โดยผลลัพธ์ที่จะส่งกลับไปก็คือตัวเลขที่ถูก define เอาไว้ก่อนแล้วเพื่อให้ง่ายในการเขียน หรืออ่านโค้ด ส่วนค่าตัวเลขที่นำมาเปรียบเทียบกับค่าที่อ่านจาก ADC นั้นเคยอ่านเจอว่าเจ้าของได้คำนวณ และวัดแรงดันตกคร่อมจริงเพื่อทดสอบ จากนั้นก็มีบวกค่าความคลาดเคลื่อนเข้าไปอีกค่าละประมาณ 50 จึงได้เป็นตัวเลขเหล่านี้ออกมา

             เมื่อมีฟังก์ชันอ่านค่าจากสวิตซ์แล้ว เราก็มาเขียนโค้ดในส่วนของ main(หรือ loop())กัน ซึ่งก็จะเป็นเพียงการเรียกใช้ฟังก์ชัน read_LCD_buttons() แล้วเขียนข้อความออกไปที่จอ LCD ให้ตรงกับสวิตซ์ที่กด( หรือตรงกับค่าที่ได้รับกลับมาหลังจากเรียกใช้ฟังก์ชัน read_LCD_buttons())เท่านั้นเอง โดยโค้ดในส่วนนี้จะเป็นดังนี้นะครับ


1:  lcd_key = read_LCD_buttons(); // read the buttons  
2:   switch (lcd_key)        // depending on which button was pushed, we perform an action  
3:   {  
4:    case btnRIGHT:  
5:     {  
6:     lcd.printf("RIGHT ");  
7:     break;  
8:     }  
9:    case btnLEFT:  
10:     {  
11:     lcd.printf("LEFT  ");  
12:     break;  
13:     }  
14:    case btnUP:  
15:     {  
16:     lcd.printf("UP  ");  
17:     break;  
18:     }  
19:    case btnDOWN:  
20:     {  
21:     lcd.printf("DOWN ");  
22:     break;  
23:     }  
24:    case btnSELECT:  
25:     {  
26:     lcd.printf("SELECT");  
27:     break;  
28:     }  
29:     case btnNONE:  
30:     {  
31:     lcd.printf("NONE ");  
32:     break;  
33:     }  
34:   }  


               อันสุดท้าย  ในตัวอย่างของ Arduino จะเห็นว่ามีตัวเลขที่เพิ่มค่าทุกๆวินาทีแสดงอยู่ด้วย ซึ่งในโค้ดเดโมจะมีการเรียกใช้ฟังก์ชัน millis() ซึ่งจะเป็นฟังก์ชันที่คืนค่าที่เพิ่มขึ้นทุกๆ 1 วินาที( millisecond ) กลับมาให้ เมื่อเราหารค่าทีได้คืนกลับมาด้วย 1000 เราก็จะได้ตัวเลขที่จะแสดงผลทุกๆ 1 วินาที ซึ่งโค้ดก็จะเป็นดังตัวอย่างข้างล่างนี้


1:  lcd.setCursor(9,1);      // move cursor to second line "1" and 9 spaces over  
2:  lcd.printf("%u", millis()/1000);   // display seconds elapsed since power-up  

               เมื่อเราเข้าใจทุกส่วนแล้วเราก็เอามารวมกันก็จะได้เป็นโค้ดเดโมที่ทำงานกับ LCD Keys pad shield ได้เหมือนกับ Arduino ทุกอย่างเลยครับ โค้ดตัวเต็มจะอยู่ข้างล่างนี้นะครับ แล้วลองดูวิดีโอผลลัพธ์การทำงานได้เลยครับ


1:  /*-----------------------------------------------------  
2:  Author: --<Ekkachai Muangrodpai>  
3:  www.picgetstart.blogspot.com  
4:  Date: 2016-07-09  
5:  Board:  Pinguino 8 by Jimmy + LCD Keypads Shield V.1  
6:  Description:  
7:  -Display a message on LCD Keypads Shield, and also read a keys through analog AN0.  
8:  -At the same time, display the second time too.  
9:   * LCD RS pin to digital pin 5  
10:   * LCD E pin to digital pin 4  
11:   * LCD D4 pin to digital pin 24  
12:   * LCD D5 pin to digital pin 18  
13:   * LCD D6 pin to digital pin 17  
14:   * LCD D7 pin to digital pin 16  
15:   * LCD R/W pin to ground  
16:   note:  
17:   - don't use lcd.print() and lcd.printf() in the same program.  
18:  -----------------------------------------------------*/  
19:  #define BACK_LIGHT  2    //LCD back light control by pin2  
20:  // define some values used by the panel and buttons  
21:  int lcd_key   = 0;  
22:  int adc_key_in = 0;  
23:  #define btnRIGHT 0  
24:  #define btnUP   1  
25:  #define btnDOWN  2  
26:  #define btnLEFT  3  
27:  #define btnSELECT 4  
28:  #define btnNONE  5  
29:  // read the buttons  
30:  int read_LCD_buttons()  
31:  {  
32:   adc_key_in = analogRead(A0);   // read the value from the sensor   
33:   if (adc_key_in < 50)  return btnRIGHT;   
34:   if (adc_key_in < 195) return btnUP;   
35:   if (adc_key_in < 380) return btnDOWN;   
36:   if (adc_key_in < 555) return btnLEFT;   
37:   if (adc_key_in < 790) return btnSELECT;    
38:   return btnNONE; // when all others fail, return this...  
39:  }  
40:  void setup( void) {  
41:    // put your setup code here, to run once:  
42:    pinMode(BACK_LIGHT, OUTPUT);  
43:    digitalWrite(BACK_LIGHT, HIGH);  
44:    // initialize the library with the numbers of the interface pins    
45:    lcd.pins(5, 4, 24, 18, 17, 16, 0, 0, 0, 0); // RS, E, D4 ~ D8    
46:    // set up the LCD's number of columns and rows:   
47:    lcd.begin(16, 2);  
48:    // Print a message to the LCD.  
49:    lcd.clear();  
50:    lcd.setCursor(0,0);  
51:    lcd.printf("Push the buttons"); // print a simple message  
52:  }  
53:  void loop( void ) {  
54:   lcd.setCursor(9,1);      // move cursor to second line "1" and 9 spaces over  
55:   lcd.printf("%u", millis()/1000);   // display seconds elapsed since power-up  
56:   lcd.setCursor(0,1);      // move to the begining of the second line  
57:   lcd_key = read_LCD_buttons(); // read the buttons  
58:   switch (lcd_key)        // depending on which button was pushed, we perform an action  
59:   {  
60:    case btnRIGHT:  
61:     {  
62:     lcd.printf("RIGHT ");  
63:     break;  
64:     }  
65:    case btnLEFT:  
66:     {  
67:     lcd.printf("LEFT  ");  
68:     break;  
69:     }  
70:    case btnUP:  
71:     {  
72:     lcd.printf("UP  ");  
73:     break;  
74:     }  
75:    case btnDOWN:  
76:     {  
77:     lcd.printf("DOWN ");  
78:     break;  
79:     }  
80:    case btnSELECT:  
81:     {  
82:     lcd.printf("SELECT");  
83:     break;  
84:     }  
85:     case btnNONE:  
86:     {  
87:     lcd.printf("NONE ");  
88:     break;  
89:     }  
90:   }    
91:  }  


วันพฤหัสบดีที่ 7 กรกฎาคม พ.ศ. 2559

Pinguino กับ LCD Keys pad shield part 1


               วันนี้ผมตั้งใจจะนำเสนอการใช้ Pinguino 8 บอร์ดเชื่อต่อกับจอ LCD โดยผมเลือกที่จะใช้ LCD Keys Pad Shield เพราะความสะดวก สามารถเสียบลงบนตัว Pinguino 8 ได้เลย  หาซื้อได้ง่าย และยังราคาถูกอีกด้วย ผมคิดว่าถูกกว่า และสะดวกกว่า ซื้อแล้วมา wiring สายเองเสียอีกครับ ผู้อ่านหลายๆท่านอาจจะมีอยู่แล้วกับตัวก็ได้ หรือถ้าใครยังไม่มีก็ลอง search หา ลองซื้อมาเล่นดูนะครับ ตัวที่ผมจะใช้จะมีหน้าตาประมาณในรูปข้างล่างนี้เลยครับ


รูปที่ 1 LCD Key pad shield ที่ใช้

คราวนี้เมื่อเราจะใช้งานเจ้า shield ตัวนี้เราก็จำเป็นจะต้องมี schematic รวมถึงตำแหน่งขาที่มันจะเชื่อมต่อกับบอร์ด Pinguino 8 ของเราเสียก่อนจึงจะสามารถเขียนโปรแกรมเพื่อใช้งานมันได้ ซึ่งผมใช้ schematic จากที่นี้ครับ
http://www.dfrobot.com/wiki/index.php?title=Arduino_LCD_KeyPad_Shield_(SKU:_DFR0009)
และอันนี้ก็ diagram ของมันครับ
ซึ่งใน link ข้างบนนั้นนอกจาก schematic แล้วยังมีโค้ดตัวอย่างที่ใช้กับ Arduino ให้อีกด้วยครับ ซึ่งเราสามารถ copy แล้วเอามา modify เพียงเล็กน้อยก็สามารถใช้งานกับบอร์ด Pinguino 8 ได้แล้วครับ

               หลังจากเราได้ schematic กับ pin diagram ของเจ้า LCD Key pad shield มาแล้ว เราก็ต้องมาดูว่าเจ้า Pinguino 8 นั้นมี pin number อะไรบ้างและมีการจัดเรียงบนบอร์ดอย่างไร  อันดับแรกคือ pin number ของ Pinguino ซึ่งใช้ PIC18F45K50 เราสามารถดูได้จาก link ต่อไปนี้ครับ หรือจะดูที่รูปที่ 2 เลยก็ได้ครับ

รูปที่ 2 Pinguino pin number
               จากรูปที่ 2 จะเห็นว่า Pinguino ได้กำหนดขาต่างๆของ PIC18F45K50 ไว้เป็นหมายเลขเพื่อให้เรียกใช้งานได้สะดวกคล้ายกับ Arduino ตัวอย่างเช่น ขา RB0 ก็จะเป็นขาหมายเลข 0 ขา RB1 ก็จะเป็นขาหมายเลข 1
ไล่เรียงกันไป ซึ่งแต่ละขาก็จะมีความสามารถแตกต่างกันไป คราวนี้พอผมเอามาทำเป็นบอร์ด Pinguino 8 แล้วพยายามจัดเรียงขาให้ได้ใกล้เคียงกับ Arduino ตำแหน่งขามันเลยไม่ได้เรียงกันเป็นลำดับเหมือนกับ Arduino ซึ่งอันนี้เป็นสิ่งที่ทำให้สับสนได้ง่ายโดยเฉพาะผู้เริ่มต้น แม้แต่กับตัวผมเองเมื่อแรกเริ่มก็งงจนเขียนโค้ดผิดแล้วงมหาสาเหตุอยู่หลายวันทีเดียว ดังนั้นที่บอร์ด Pinguino 8 ผมจึงมีเขียนหมายเลขกำกับเอาไว้ที่แต่ละขาเพื่อให้ง่ายเวลาใช้งานและเขียนโปรแกรม รูปที่ 3 และรูปที่ 4 แสดงตัวเลขกำกับแต่ละขาครับ

รูปที่ 3 pin number ฝั่ง digital

รูปที่ 4 pin number ฝั่ง analog

ทีนี้เมื่อเราพิจารณา pin diagram และ schematic ของ LCD Key pad shield กับหมายเลขกำกับบนบอร์ด Pinguino 8 ก็จะสามารถสรุปการเชื่อมต่อได้ดังต่อไปนี้ครับ
LCD Shield         Pinguino 8
D4                          24
D5                          18
D6                          17
D7                          16
RS                          5
E                            4
Back light              2
             Keys                       8 หรือ A0
               เมื่อเรารู้หมายเลขขาที่ใช้ในการเชื่อต่อแล้วเราก็สามารถเริ่มเขียนโค้ดเพื่อแสดงข้อความบนจอ LCD ได้แล้วครับ เริ่มต้นจากการ define ขา back light ก่อนเพื่อให้ง่ายในการเขียนโค้ด และ IDE รู้จักและเพิ่มในส่วนออโต้คอมพลีตให้เราด้วย 


 #define BACK_LIGHT  2    //LCD back light control by pin2  

และเราจะกำหนดขา back light ให้เป็นเอ้าต์พุท และสั่งให้เป็น on โดยส่ง logic high ออกไป ด้วยคำสั่ง


 pinMode(BACK_LIGHT, OUTPUT);  
 digitalWrite(BACK_LIGHT, HIGH);  

ถัดมาเราจึงทำการ initialize LCD ด้วยคำสั่ง

 lcd.pins(5,4,24,18,17,16,0,0,0,0);  //RS,E,D4,D5,D6,D7 in 4 bit mode  

ซึ่งค่าพารามิเตอร์ที่ส่งให้ฟังก์ชันจะเป็นหมายเลข I/O ของ Pinguino ที่เชื่อมต่อกับจอ LCD โดยตัวแรกจะเป็นขา RS, E, และตามมาด้วยขาดาต้า D4-D7 ตามลำดับ นี่เป็นในกรณีที่เชื่อมต่อจอ LCD ในแบบ 4 bit mode นะครับดังนั้นพารามิเตอร์ที่เหลือจึงใส่ค่าเป็น 0 สี่ตัว 


ต่อมาเราจำเป็นต้องกำหนดว่า LCD ที่เรากำลังใช้งานอยู่นั้นเป็นชนิดใด 16x2 หรือ 20x4 โดยใช้คำสั่งต่อไปนี้ครับ

 lcd.begin(16,2);              //collumn, row  

เมื่อมาถึงตรงนี้เราก็สามารถเริ่มใช้งานจอ LCD ได้แล้ว โดยผมจะทำการเคลียร์หน้าจอเสียก่อน จากนั้นจึงกำหนดให้เคอร์เซอร์ไปที่ตำแหน่งเริ่มต้นของแถวแรกซึ่งก็คือตำแหน่ง 0,0 แล้วจึงส่งข้อความออกไปแสดงดังตัวอย่างโค้ดข้างล่างนี้ครับ


 lcd.clear();  
 lcd.setCursor(0,0);              //collumn 0, first row  
 lcd.printf("Hello World!....");  

และนี่คือตัวอย่างโค้ดทั้งหมดครับ


1:  /*-----------------------------------------------------  
2:  Author: --<Ekkachai Muangrodpai>  
3:  Date: 2016-07-07  
4:  Board:  Pinguino 8 + LCD Key pad shield v1  
5:  Description: Display 'Hello World!' on LCD  
6:  LCD Shield           Pinguino 8  
7:  D4                   24  
8:  D5                   18  
9:  D6                   17  
10:  D7                  16  
11:  RS                  5  
12:  E                   4  
13:  Back light          2  
14:  -----------------------------------------------------*/  
15:  #define BACK_LIGHT  2    //LCD back light control by pin2  
16:  void setup() {  
17:    // put your setup code here, to run once:  
18:    pinMode(BACK_LIGHT, OUTPUT);  
19:    digitalWrite(BACK_LIGHT, HIGH);  
20:    lcd.pins(5,4,24,18,17,16,0,0,0,0);  //RS,E,D4,D5,D6,D7 in 4 bit mode  
21:    lcd.begin(16,2);              //collumn, row  
22:    lcd.clear();  
23:    lcd.setCursor(0,0);              //collumn 0, first row  
24:    lcd.printf("Hello World!....");  
25:  }  
26:  void loop() {  
27:    // put your main code here, to run repeatedly:  
28:  }  

เพิ่มเติม

วันอังคารที่ 5 กรกฎาคม พ.ศ. 2559

Pinguino สื่อสารผ่าน USB และ Com Port

               บทความนี้จะเขียนถึงการสื่อสารระหว่าง Pinguino บอร์ดกับคอมพิวเตอร์ โดยเรามีตัวเลือกว่าจะใช้ USB โมดูลในตัว PIC18F45K50 emulate เป็น com port สื่อสารกับคอมพิวเตอร์ผ่านทางโปรแกรมเทอร์มินอลต่างๆ  หรือจะใช้โมดูล USART ในตัวไมโครคอนโทลเลอร์สื่อสารแทนก็ทำได้ นอกจากนี้หากต้องการ USART มากกว่าหนึ่งโมดูลก็สามารถใช้ Software USART ที่มีเตรียมไว้ให้กับขา I/O อื่นๆได้อีก เดี๋ยวเรามาลองดูกันทีละโมดูลกันนะครับ

                USB CDC (Communication Device Class) คือการให้ USB ทำตัวเป็นตัวเชื่อมต่อสื่อสารแบบต่างๆ(https://en.wikipedia.org/wiki/USB_communications_device_class) แต่ที่ส่วนใหญ่เข้าใจกันก็คือ USB จำลองเป็น com port เมื่อเชื่อมต่อกับคอมพิวเตอร์ โดยใน Pinguino จะมีฟังก์ชันที่ช่วยในการใช้งาน USB CDC อยู่พอสมควร สิ่งที่เราต้องทำคือแค่เรียกใช้งานเท่านั้น ลองดูตัวอย่างโค้ดดังต่อไปนี้นะครับ

1:  void setup() {  
2:    // put your setup code here, to run once:  
3:    pinMode(USERLED,OUTPUT);    
4:  }  

5:  void loop() {  
6:    // put your main code here, to run repeatedly:  
7:     digitalWrite(USERLED, HIGH);  
8:     CDC.printf("On\n\r");  
9:     delay(1000);  

10:    digitalWrite(USERLED,LOW);  
11:    CDC.printf("Off\n\r");  
12:    delay(1000);  
13:  }  

               ตัวอย่างโค้ดนี้จะเหมือนกับในบทความที่ผ่านมาโดยสั่งให้ USER LED ติด และ ดับ ทุกๆ 1 วินาทีแล้วผมทำการเพิ่มให้มีการส่งข้อความว่า “On” เมื่อ USER LED ติดสว่าง และคำว่า “Off” เมื่อ USER LED ดับ จากบอร์ด Pinguino ไปยังคอมพิวเตอร์ผ่านทางสาย USB ที่เชื่อต่อนะแหละครับ โดยทางฝั่งคอมพิวเตอร์ผมก็ใช้โปรแกรมเทอร์มินอลมาอ่านหรือรับค่าแสดงข้อความ โดยสามารถกำหนด baud rate เท่าไหร่ก็ได้เพราะตัว USB จะจัดการให้เอง สังเกตนะครับว่าผมเพียงแต่เรียกใช้ฟังกชัน CDC.printf() เท่านั้นไม่จำเป็นต้องเซ็ทอัพโมดูล USB ใดๆก่อนเลยค่อนข้างสะดวกมากครับ ลองดูวิดีโอประกอบด้านล่างได้ครับ



               USART ( Universal Synchronous Asynchronous Receiver Transmitter ) เป็นโมดูลสื่อสารแบบอนุกรมที่นิยมมากแบบหนึ่งสำหรับไมโครคอนโทรลเลอร์ ใช้ติดต่อสื่อสารกับอุปกรณ์หรือเครื่องมือต่างๆได้มากมาย เช่น Bluetooth, RF, และอื่นๆ รวมถึงใช้สื่อสารกับคอมพิวเตอร์ได้อีกด้วย โดยก่อนเริ่มสื่อสารนั้นจำเป็นต้องกำหนด baud rate หรือความเร็วในการสื่อสารให้ตรงกันทั้งสองฝ่ายเสียก่อน โดยในตัวอย่างต่อไปนี้จะเซ็ทอัพให้ Pinguino สื่อสารกับคอมพิวเตอร์ที่ baud rate เท่ากับ 9600 bits per second ไม่มี hardware flow control ดาต้าบิทเท่ากับ 8 ไม่มี parity และมีเพียง 1 stop bit. โดยสามารถดูได้จากตัวอย่างข้างล่างนี้ครับ


1:  void setup() {  
2:    // put your setup code here, to run once:  
3:    pinMode(USERLED, OUTPUT);  
4:    Serial.begin(9600);  
5:  }  
6:  void loop() {  
7:    // put your main code here, to run repeatedly:  
8:     digitalWrite(USERLED, HIGH);  
9:     Serial.printf("LED On\n\r");  
10:    delay(1000);  

11:    digitalWrite(USERLED, LOW);  
12:    Serial.printf("LED Off\n\r");  
13:    delay(1000);  
14:  }  
              
              จากโค้ดตัวอย่างจะเห็นว่าเราเพียงจำเป็นต้องเซ็ท baud rate ที่เราต้องการในส่วน setup() ก่อนเริ่มใช้งาน USART โดยเรียกใช้ฟังก์ชัน Serial.begin() หลังจากนั้นเราก็สามารถใช้งานฟังก์ชัน Serial.printf() ในการส่งข้อความขึ้นไปยังคอมพิวเตอร์ผ่านทาง USART ได้แล้ว ตัวอย่างนี้จะเหมือนกับตัวอย่างแรกเกือบทั้งหมดเพียงเปลี่ยนมาใช้ USART แทน CDC เท่านั้น  ในการทดสอบเราจำเป็นต้องมี usb-to-serial มาต่อเข้ากับขา Tx และ Rx ของบอร์ด Pinguino ดังแสดงในรูปข้างล่างนี้นะครับ แล้วเราก็ใช้โปรแกรมเทอร์มินอล connect เข้ากับ com port ของ usb-to-serial นั้นๆก็จะสามารถเห็นข้อความ “LED On” และ “LED Off” สลับกันตามจังหวะการติด ดับ ของ USER LED  ลองดูวิดีโอดูครับ


รูป บอร์ด Pinguino เชื่อมต่อกับ USB-to-Serial



               Software Serial เป็นการใช้ขา I/O ของไมโครคอนโทลเลอร์มาทำงานให้เหมือนขา Tx และ Rx ของ USART บางครั้งก็เรียกว่า Bit Bang Serial  โดยทั่วไปในไมโครคอนโทลเลอร์ตัวเล็กๆ หรือไมโครคอนโทลเลอร์รุ่นเก่าๆ จะมี USART เพียงแค่ตัวเดียว แต่บางครั้งงานที่เรากำลังทำอยู่นั้นจำเป็นต้องใช้ USART มากกว่าหนึ่ง จะเปลี่ยนไมโครคอนโทลเลอร์เป็นตัวที่ใหญ่ขึ้นก็เปลืองและไม่ง่ายนัก Software Serial จึงเป็นทางออกที่น่าจะเหมาะสมกว่า แต่มันก็มีข้อจำกัดของมันเช่น ใช้กับการสื่อสารที่ baud rate สูงมากไม่ค่อยได้ ต้องคำนวณคาบเวลาของแต่ละบิต ครึ่งบิต ให้แม่นยำและเขียนโปรแกรมให้ถูกต้องด้วย ซึ่งก็ค่อนข้างยากและเสียเวลามากพอสมควร
                ใน Pinguino นี้ได้จัดเตรียมไลบรารี่ Software Serial ไว้ให้เราเรียกใช้งานได้อย่างง่ายดาย เราเพียงแค่ต้องกำหนดว่าจะใช้ PORT ใด และขาไหนให้เป็นขา Tx และ Rx รวมถึงค่า baud rate ที่ต้องการไว้ที่ส่วนบนของโปรแกรมที่เรากำลังจะเขียนดังตัวอย่างต่อไปนี้ ที่จะใช้ PORTB ขา RB4 เป็น Tx และขา RB5 เป็น Rx โดยกำหนด baud rate ไว้ที่ 9600 bits per second ดังตัวอย่างข้างล่างนี้

 #define SWBAUDRATE 9600// or 57600, 38400, 19200, 9600, 4800  
 // other baudrates 115200 2400 1200 were tried but did not work perfectly   
 #define _SW_PORT _PORTB // Transmit pin port and pin  
 #define TXDpin 4   
 #define RXDpin 5   
 #define SW_PORT_TXDpin PORTBbits.RB4   
 #define SW_TRIS_TXDD TRISBbits.TRISB4   
 #define SW_PORT_RXDpin PORTBbits.RB5   
 #define SW_TRIS_RXDD TRISBbits.TRISB5   
               
              ถัดมาก็จำเป็นต้องกำหนดให้ขา Tx เป็นเอ้าพุตเพื่อให้สามารถ on/off (bit bang) pin เพื่อให้สามารถส่งดาต้าออกไปจากไมโครคอนโทลเลอร์ได้ และกำหนดค่าเริ่มต้นของทั้งขา Tx และ Rx ให้เป็น high( 1 ) ก่อนดังตัวอย่างข้างล่างนี้ครับ ซึ่งเซ็ทอยู่ใน setup() ฟังก์ชัน


 SW_TRIS_TXDD = 0;  
 SW_PORT_TXDpin = 1;  
 SW_TRIS_RXDD = 1;  

หลังจากนั้นเราก็สามารถเรียกใช้งานฟังก์ชันของ Software Serial ได้อย่างง่ายดายเหมือนฟังก์ชัน Serial ในตัวอย่างที่สองที่ผ่านมาได้ ลองดูตัวอย่างโค้ดทั้งหมดได้ครับ


1:  #define SWBAUDRATE 9600// or 57600, 38400, 19200, 9600, 4800  
2:  // other baudrates 115200 2400 1200 were tried but did not work perfectly   
3:  #define _SW_PORT   _PORTB      // Transmit pin port and pin  
4:  #define TXDpin   4  // or 0, 2, 6  
5:  #define RXDpin   5  // or 1, 3, 7  
6:  #define SW_PORT_TXDpin   PORTBbits.RB4  // or 0, 2, 6  
7:  #define SW_TRIS_TXDD    TRISBbits.TRISB4 // or 0, 2, 6  
8:  #define SW_PORT_RXDpin   PORTBbits.RB5  // or 1, 3, 7  
9:  #define SW_TRIS_RXDD    TRISBbits.TRISB5 // or 1, 3, 7  

10:  void setup() {  
11:    SW_TRIS_TXDD = 0;  
12:    SW_PORT_TXDpin = 1;  
13:    SW_TRIS_RXDD = 1;  
14:    pinMode(USERLED, OUTPUT);  
15:  }  

16:  void loop() {   
17:    digitalWrite(USERLED, HIGH);  
18:    SwSerial.printf("USER LED On\n\r");  
19:    delay(1000);  
20:    digitalWrite(USERLED, LOW);  
21:    SwSerial.printf("USER LED Off\n\r");  
22:    delay(1000);  
23:  }  


USB-to-Serial ต่อเข้ากับขา 4,5 (Pinguino) หรือขา 8,9(Arduino)