เมนู

วันศุกร์ที่ 12 สิงหาคม พ.ศ. 2559

Pinguino กับ 7-segment บน Multifunction Shield


               หลังจากได้ลองค้นดูว่ายังมี shield อะไรเก็บไว้อยู่บ้างก็เจอว่ายังมีตัว Multifunction Shield ที่ดูน่าสนใจเอามาเขียนโปรแกรมกับบอร์ด Pinguino 8 ที่ดูน่าสนใจที่สุดบนบอร์ดก็ต้องเป็นเจ้า 7-segment 4 หลักที่เชื่อมต่ออยู่กับ IC serial-to-parallel 74HC595 เมื่อพอลองหาข้อมูลจากเว็ปดูก็ไปได้ข้อมูลจากลิ้งค์ข้างล่างนี้ 
https://wiki.eprolabs.com/index.php?title=Multi-functional_Learning_Board_for_Arduino
รูปที่ 1 Schematic ส่วนของ 7-Segment กับ 74HC595
รูปที่ 2 หมายเลขพินของบอร์ด Pinguino 8
              พอดูที่ schematic จะเห็นว่า 7-segment 4 หลักที่อยู่บนตัว shield นั้นจะมี IC 74HC595 จำนวน 2 ตัวต่อ drive อยู่ โดยตัวแรก( U2) จะเป็นตัวเลือกว่าจะให้ 7-segment หลักไหนแสดงผล ส่วนตัว U3 จะเป็นตัวขับให้แสดงเป็นตัวเลขต่างๆ  อินพุตจะเริ่มจากตัว U2 โดยขา SDI (ขา data)จะต่ออยู่กับพิน 8 ของ Arduino ส่วนขา SFTCLK(ขา clock)จะต่อกับพิน 7 และสุดท้ายขา LCHCLK(ขา latch)จะต่อกับพิน 4 ทีนี้เมื่อเรารู้ตำแหน่งที่เชื่อต่อกับ Arduino แล้ว เมื่อเราต้องการใช้บอร์ด Pinguino 8 แทนเราก็ต้องมาดูว่าที่ตำแหน่งเดียวกันนั้นบนบอร์ด Pinguino 8 เป็นพินหมายเลขอะไร จากในรูปที่ 2 จะเห็นว่าเป็นพินหมายเลข 5, 16, และ 24 ตามลำดับ ดังนั้นเพื่อให้ง่ายในการจำและเขียนโค้ดเราจึงจะ define พินทั้งสามนี้ไว้ดังนี้

1:  /* Define shift register pins used for seven segment display */  
2:  #define LATCH_DIO   24  
3:  #define CLK_DIO     16  
4:  #define DATA_DIO    5  

               จากนั้นเราก็ต้องมากำหนดค่าคงที่ที่เราจะส่งออกไปแล้วทำให้ 7-segment ติดสว่างแสดงเป็นตัวเลข 0-9 เมื่อเราพิจารณาที่ schematic โดยเฉพาะที่ U3 ซึ่งต่อเข้ากับ 7-segment ที่ตำแหน่ง a-h ตามลำดับแล้วโดยเมื่อเราส่ง logic 0 ออกไปที่พินใดๆ(a-h) ก็จะทำให้ segment นั้นๆติดสว่าง(เป็น common Anode) ยกตัวอย่างเช่นต้องการให้เลข 0 ติดสว่างจะต้องให้ logic 0 ที่พิน a, b, c, d, e, f และให้ logic 1 ที่พิน g กับ h และค่า binary นี้จะถูกส่งออกไปทีละบิต โดยถ้ายึดตามโค้ดตัวอย่างของ Arduino ที่เลือกส่งบิต MSB(Most Significant Bit) ออกไปก่อนเราก็จะได้ค่าเป็น 0xC0  และหมายเลขอื่นๆก็ใช้วิธีคิดแบบเดียวกันครับ โดยค่าคงที่ทั้งสิบตัวจะมีค่าเป็นดังนี้

 /* Segment byte maps for numbers 0 to 9 */  
 const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};  

และค่าคงที่สำหรับการเลือกว่าจะให้หลักใดติดสว่างก็ใช้วิธีคิดแบบเดียวกันเพียงแต่คราวนี้เราต้องส่ง logic 1 ออกไปยังตำแหน่งที่เราต้องการให้มันติดสว่าง ซึ่งจะมีค่าดังต่อไปนี้


 /* Byte maps to select digit 1 to 4 */  
 const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};  

เราเลือกประกาศเป็นค่าคงที่โดยใช้ key word เป็น const เพื่อบอกให้ compiler รู้ว่าค่าใน array เหล่านี้จะไม่มีการเปลี่ยนแปลงค่า ดังนั้น compiler สามารถเก็บค่าเหล่านี้ไว้ใน Flash memory ได้ ทำให้ประหยัด RAM ไปด้วยครับ

               จากนั้นเราก็มาเขียนฟังก์ชั่นที่จะส่งค่าเหล่านี้ออกไปแสดงบน 7-segment แต่ละหลักได้โดยอาศัย shiftOut() ที่ Pinguino มีเตรียมไว้ให้ใช้อยู่แล้ว ซึ่งจะได้เป็นฟังก์ชั่นดังต่อไปนี้ครับ


1:  /* Wite a decimal number between 0 and 9 to one of the 4 digits of the display */  
2:  void WriteNumberToSegment(byte Segment, byte Value)  
3:  {  
4:    digitalWrite(LATCH_DIO,LOW);   
5:    shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);  
6:    shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );  
7:    digitalWrite(LATCH_DIO,HIGH);    
8:  }  
             
               และเพื่อให้การเขียนโค้ดง่ายยิ่งขึ้นเราก็จะมีฟังก์ชั่นที่ช่วยแยกตัวเลขที่นับได้ออกเป็นหลักหน่วย หลักสิบ หลักร้อย และหลักพัน เพื่อแสดงผล โดยอาศัยการหารกับหลักนั้นๆ และการหารที่เก็บเฉพาะเศษที่เหลือเท่านั้น(modulus, %) ซึ่งจะได้เป็นฟังก์ชั่นดังต่อไปนี้ครับ


1:  /* Write a decimal number between 0 and 9999 to the display */  
2:  void WriteNumber(int Number)  
3:  {  
4:    WriteNumberToSegment(0 , Number / 1000);  
5:    WriteNumberToSegment(1 , (Number / 100) % 10);  
6:    WriteNumberToSegment(2 , (Number / 10) % 10);  
7:    WriteNumberToSegment(3 , Number % 10);  
8:  }  

               คราวนี้โค้ดตัวอย่างของเราจะทำการแสดงตัวเลขนับค่าเพิ่มขึ้นทุกๆ 500 ms และเราจะใช้ฟังก์ชั่น millis() มาช่วยในการจับเวลาที่จะเพิ่มค่าขึ้น ดังนั้นเราต้องการตัวแปรเพิ่มเติมอีกเพื่อเก็บค่าเวลา ณ ปัจจุบันและค่าเวลาที่ผ่านมา กับตัวแปรไว้นับเลข โดยเราจะประกาศตัวแปรดังนี้


1:  unsigned long Cur_ms_Count;      // Stores the current time in ms  
2:  unsigned long Last_ms_Count;     // Stores the last time in ms the counter was last updated  
3:  unsigned int Count;              // Stores the value that will be displayed  

ในฟังก์ชั่น setup() เราก็กำหนดให้พินที่ควบคุม 74HC595 ที่เรา define ไว้ให้เป็นเอ้าต์พุต และกำหนดค่าเริ่มต้นให้แก่ตัวแปรจับเวลาดังนี้ครับ


1:  void setup() {  
2:    pinMode(25,INPUT);    //turn off buzzer first  
3:   /* Set DIO pins to outputs */  
4:   pinMode(LATCH_DIO,OUTPUT);  
5:   pinMode(CLK_DIO,OUTPUT);  
6:   pinMode(DATA_DIO,OUTPUT);    
7:   /* Initiliase the registers used to store the current time and count */  
8:   Cur_ms_Count = millis();  
9:   Last_ms_Count = 0;  
10:   Count = 0;    
11:  }  

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


/*-----------------------------------------------------
Author:  --<Ekkachai Muangrodpai>
Date: 2016-08-12
Description: Display and update a number on 7-Segment 
      every 500 ms.
-----------------------------------------------------*/
/* Define shift register pins used for seven segment display */
#define LATCH_DIO     24
#define CLK_DIO       16
#define DATA_DIO      5
 
/* Segment byte maps for numbers 0 to 9 */
const byte SEGMENT_MAP[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};
/* Byte maps to select digit 1 to 4 */
const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};

unsigned long Cur_ms_Count;  // Stores the current time in ms
unsigned long Last_ms_Count;  // Stores the last time in ms the counter was last updated
unsigned int  Count;   // Stores the value that will be displayed

/* Wite a decimal number between 0 and 9 to one of the 4 digits of the display */
void WriteNumberToSegment(byte Segment, byte Value)
{
  digitalWrite(LATCH_DIO,LOW); 
  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_MAP[Value]);
  shiftOut(DATA_DIO, CLK_DIO, MSBFIRST, SEGMENT_SELECT[Segment] );
  digitalWrite(LATCH_DIO,HIGH);    
}

/* Write a decimal number between 0 and 9999 to the display */
void WriteNumber(int Number)
{
  WriteNumberToSegment(0 , Number / 1000);
  WriteNumberToSegment(1 , (Number / 100) % 10);
  WriteNumberToSegment(2 , (Number / 10) % 10);
  WriteNumberToSegment(3 , Number % 10);
}
void setup() {
    pinMode(25,INPUT);        //turn off buzzer first
   
  /* Set DIO pins to outputs */
  pinMode(LATCH_DIO,OUTPUT);
  pinMode(CLK_DIO,OUTPUT);
  pinMode(DATA_DIO,OUTPUT); 
  
  /* Initiliase the registers used to store the current time and count */
  Cur_ms_Count = millis();
  Last_ms_Count = 0;
  Count = 0;    
}

void loop() {   
  /* Get how much time has passed in milliseconds */
  Cur_ms_Count = millis();
  
  /* If 100ms has passed then add one to the counter */
  if(Cur_ms_Count - Last_ms_Count > 500)
  {
    Last_ms_Count = Cur_ms_Count;
    
    if(Count < 9999)
    {
      Count++;
    } else
    {
      Count = 0;
    }
  }
  
  /* Update the display with the current counter value */
  WriteNumber(Count);  
}




ไม่มีความคิดเห็น:

แสดงความคิดเห็น