หลังจากได้ลองค้นดูว่ายังมี 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 ออกไปยังตำแหน่งที่เราต้องการให้มันติดสว่าง ซึ่งจะมีค่าดังต่อไปนี้
เราเลือกประกาศเป็นค่าคงที่โดยใช้ key word เป็น const เพื่อบอกให้ compiler รู้ว่าค่าใน array เหล่านี้จะไม่มีการเปลี่ยนแปลงค่า ดังนั้น compiler สามารถเก็บค่าเหล่านี้ไว้ใน Flash memory ได้ ทำให้ประหยัด RAM ไปด้วยครับ
จากนั้นเราก็มาเขียนฟังก์ชั่นที่จะส่งค่าเหล่านี้ออกไปแสดงบน 7-segment แต่ละหลักได้โดยอาศัย shiftOut() ที่ Pinguino มีเตรียมไว้ให้ใช้อยู่แล้ว ซึ่งจะได้เป็นฟังก์ชั่นดังต่อไปนี้ครับ
และเพื่อให้การเขียนโค้ดง่ายยิ่งขึ้นเราก็จะมีฟังก์ชั่นที่ช่วยแยกตัวเลขที่นับได้ออกเป็นหลักหน่วย หลักสิบ หลักร้อย และหลักพัน เพื่อแสดงผล โดยอาศัยการหารกับหลักนั้นๆ และการหารที่เก็บเฉพาะเศษที่เหลือเท่านั้น(modulus, %) ซึ่งจะได้เป็นฟังก์ชั่นดังต่อไปนี้ครับ
คราวนี้โค้ดตัวอย่างของเราจะทำการแสดงตัวเลขนับค่าเพิ่มขึ้นทุกๆ 500 ms และเราจะใช้ฟังก์ชั่น millis() มาช่วยในการจับเวลาที่จะเพิ่มค่าขึ้น ดังนั้นเราต้องการตัวแปรเพิ่มเติมอีกเพื่อเก็บค่าเวลา ณ ปัจจุบันและค่าเวลาที่ผ่านมา กับตัวแปรไว้นับเลข โดยเราจะประกาศตัวแปรดังนี้
ในฟังก์ชั่น setup() เราก็กำหนดให้พินที่ควบคุม 74HC595 ที่เรา define ไว้ให้เป็นเอ้าต์พุต และกำหนดค่าเริ่มต้นให้แก่ตัวแปรจับเวลาดังนี้ครับ
สุดท้ายในฟังก์ชั่น loop() เราก็เพียงแต่คอยเพิ่มค่าทุกๆ 500 ms แล้วเรียกฟังก์ชั่นช่วยเหลือเพื่อแสดงตัวเลขออกไปเท่านั้นเองครับ โดยโค้ดตัวเต็มจะเป็นดังนี้นะครับ
/* 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);
}
ไม่มีความคิดเห็น:
แสดงความคิดเห็น