Basic Microcontroller Programming


การทำงานกับข้อมูลระดับบิตในภาษาซี

โพสต์11 ธ.ค. 2555 20:50โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 06:48 ]




การทำงานกับข้อมูลระดับบิตในภาษาซี


    โดยทั่วไปแล้ว งานเขียนโปรแกรมกับไมโครคอนโทรลเลอร์ งานหลักๆ ก็คือ การสั่ง ON-OFF บิตที่ต้องการบิตใดบิตหนึ่ง ในรีจิสเตอร์ นับว่า เป็นความโชคดีที่ภาษาซี มีการกระทำทางบิต ให้มาแล้ว โดยที่เราไม่ต้องไปกระทำทางภาษา Assembly (ซึ่งเข้าใจยากกว่า) เรามาทำความเข้าใจวิธีการกระทำทางบิต ด้วย Operation แบบต่างๆ ในภาษาซีกันครับ 

a | b  (Bitwise Or) 

เป็นการ OR logic กัน อันนี้ จำง่ายๆ บิตไหน ตรงกัน OR กัน จะได้ 1 เมื่อบิตใด บิตหนึ่งมีค่าเป็น "1" ตัวอย่าง   0x56 | 0x32 ได้ 0x76 เพราะว่า

  0 1 0 1 0 1 1 0 <----  0x56
| 0 0 1 1 0 0 1 0 <----- 0x32
  --------------------
  0 1 1 1 0 1 1 0 <---- 0x76

เรามักใช้ในกรณีที่ต้อง ON บิตใดบิตหนึ่ง หรือหลายๆบิต ในรีจิสเตอร์ที่เราต้องการ ตัวอย่างการนำไปใช้งาน เราเรียกว่า การเซทบิต
PORTA |= 0x80; // ทำให้บิตที่ 7 มีค่าเป็น 1 (บิตอื่นๆเหมือนเดิม ไม่ได้รับผลกระทบ)
หรือ 
PORTA |= (1<<n);  // โดยที่ n คือ ลำดับของบิต ตั้งบิต 0 จนถึงบิตสูงสุดของ PORTA มีค่าเป็น 1 เฉพาะตำแหน่ง 


a & b  (Bitwise And) 

เป็นการ And logic กัน อันนี้ ก็ไม่ยาก เจอบิตใด บิตหนึ่งเป็ศูนย์ ผลลัพธ์ออกมาเป็นลอจิก "0" ตัวอย่าง 0x56 & 0x32 ได้ 0x12  เพราะว่า

   0 1 0 1 0 1 1 0 <----  0x56
& 0 0 1 1 0 0 1 0 <----  0x32
   ----------------------
   0 0 0 1 0 0 1 0 <----  0x12

เรามักใช้ในกรณีต้องการเช็ค ว่า บิตนั้น เป็น "1" หรือไม่ ตัวอย่างการนำไปใช้งาน
if( (PORTA & 0x81) == 0 )  // เงืื่อนไขนี้ ทำการเช็คบิต 7 และบิต 0 ว่าเป็น 1 หรือไม่ ถ้าไม่เป็น 1 ทั้งคู่ให้กระทำอะไรบางอย่าง 
* จำไว้ว่า ต้องใส่วงเล็บ & logic ก่อน นำมาเปรียบเทียบกับ 0 ก่อนนะครับ อันนี้เป็นตกม้าตาย มาหลายคนแหละ เพราะลำดับความสำคัญ มันไม่เท่าก้ัน  เราเลยต้องใส่วงเล็บ ให้ Compiler เข้าไปคิดให้วงเล็บก่อน แล้วค่อยมาเปรียบเทียบกับศูนย์ อีกที 

หรือเรามักพบในตัวอย่างในการเช็คบิต nibble ( 4 บิตบน หรือ 4 บิตล่าง) ว่าเป็น 1 หมดหรือเปล่า หรือว่าเป็น 0 หมดไหม เช่น
if ((PORTA & 0xF0) == 0xF0) // ทำให้ 4 บิตล่างเป็นศูนย์หมด แล้วทำการเช็คว่า 4 บิตบนเป็น 1 หมดหรือเปล่า จึงเข้าเงือนไข

หรือบางที เราใช้ในการเคลียร์บิต นั้นๆ 
PORTA &= ~(1<<n);  //  โดยที่ n คือ ลำดับของบิต ตั้งแต่บิต 0 จนถึงบิตสูงสุดของ PORTA มีค่าเป็น 0 เฉพาะตำแหน่ง


a ^ b  (Bitwise Exclusive or)

ท่องกันไว้เลยครับ  "เหมือนกันเป็นศูนย์ ต่างกันเป็นหนึ่ง"  ตัวอย่าง 0x56 ^ 0x32 ได้ผลลัพธ์ 0x64 เพราะว่า

   0 1 0 1 0 1 1 0  <----  0x56
^  0 0 1 1 0 0 1 0  <----  0x32
  ----------------------
   0 1 1 0 0 1 0 0  <----  0x64

Exclusive or นี้ มีประโยชน์มากเลยกับงานไมโครคอนโทรลเลอร์ เรามักใช้ในการกลับบิตไปมา โดยที่เราไม่ต้องสนใจว่า บิตปัจจุบัน มันเป็น หนึ่ง หรือ ศูนย์อยู่ รู้เพียงอย่างเดียว ถ้ากระทำการ Exclusive or แล้ว บิตมันจะกลับสภาวะตรงกันข้ามทันที ตัวอย่างการนำไปใช้งาน

PORTA ^= 0x80;  // จะทำให้บิต 7 สลับกลับไปมา (บิตอื่นๆ ไม่ได้รับผลกระทบ)
หรือ 
PORTA ^= (1<<n); // โดยที่ n คือ ลำดับของบิต ตั้งบิต 0 จนถึงบิตสูงสุดของ PORTA 


~a (Bitwise Complement)

อันนี้ ทำหน้าที่ กลับบิต ให้ตรงกันข้าม จากหนึ่งเป็นศูนย์ หรือ จากศูนย์เป็นหนึ่ง ดังตัวอย่าง ข้างล่างนี้

~ 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0
   -------------------------------------------
   1 1 1 1 1 1 1 1 1 0 1 0 1 0 0 1

จะเห็นได้ว่า ทุกบิต ถูกกลับบิตหมดเลย  ในการนำไปใช้งานจริง เราสามารถประยุกต์การใช้งานร่วมกับ & logic จะมีประโยชน์มากยิ่งขึ้น ดูตัวอย่างครับ
PORTA &= ~0x80; // ทำให้บิต 7 เป็นศูนย์
หรือ 
PORTA &= ~(1<<n);  // โดยที่ n คือ ลำดับของบิต ตั้งแต่บิต 0 จนถึงบิตสูงสุดของ PORTA กลับบิตเฉพาะตำแหน่ง 

หลายๆ คนคงสับสนว่า เจ้า  (1<<n) มันคืออะไร ไม่ใช่การเปรียบเทียบมากกว่า หรือน้อยกว่า นะครับ แต่เป็นการเลื่อนบิต เรามาดูหลักการมันก่อน 

<< (Shift Bit Left)

คือการทำให้ลำดับบิตเลื่อนไปทางซ้ัาย แล้วนำศูนย์มาต่อบิตทางขวามือ เช่นถ้าเราต้องการเลื่อนข้อมูล PORTA = 0x06 ไปทางซ้าย 2 บิต จะได้ว่า

     0 0 0 0 0 1 1 0    <----  0x06
0 0 0 0 0 1 1 0 _ _   <----  0x06<<2
     ----------------------
     0 0 0 1 1 0 0 0    <----  0x18

ในทางตรงกันข้าม เราสามารถเลื่อนบิตไปทางขวาได้เช่นกัน โดยใช้เครื่องหมายตรงกันข้ามกับ เลื่อนบิตไปทางซ้าย 

>> (Shift Bit Right)

จะทำให้ลำดับบิตเลื่อนไปทางขวา แล้วนำศูนย์มาต่อบิตทางซ้ายมือ เช่นถ้าเราต้องการเลื่อนข้อมูล PORTA = 0x06 ไปทางขวา 2 บิต จะได้ว่า
     0 0 0 0 0 1 1 0       <----  0x06
     _ _ 0 0 0 0 0 1 1 0 <----   0x06>>2
     ----------------------
     0 0 0 0 0 0 0 1       <----  0x01


แต่เท่าที่พบเห็นส่วนมาก การใช้ Shift bit left หรือ Shift bit right เราจะนำ 0x01<<n เลื่อนไปเป็นจำนวน n บิต แล้วนำไป &= หรือ |= กับข้อมูลเดิม เพื่อให้เกิดผลกับบิตในตำแหน่ง n ที่ต้องการ เหมือนตัวอย่าง ที่ยกให้เห็นข้างต้น 

สรุปกันอีกครั้ง ตัวอย่างที่พบเห็นบ่อยๆ ในการเขียนโปรแกรมภาษาซีในการกระทำข้อมูลกับบิตในไมโครคอนโทรลเลอร์ 

การเซตบิต (Set Bit)
uint8_t a = 0x08;   /* 00001000 */
                    /* เซต บิตที่2 */
a |= (1<<2);        /* 00001100 */

การเคลียร์บิต (Clear Bit)
uint8_t a = 0x0F;  /* 00001111 */
                   /* เคลียร์บิตที่2 */
a &= ~(1<<2);      /* 00001011 */

uint8_t a = 0x0F;      /* 00001111 */
                       /* เคลียร์บิตที่1 และบิตที่2 */
a &= ~((1<<2)|(1<<1)); /* 00001001 */

การกลับบิต (Toggle Bit)
uint8_t a = 0x0F; /* 00001111 */
                  /* สลับบิืตที่2 */
a ^= (1<<2);      /* 00001011 */
a ^= (1<<2);      /* 00001111 */

ทั้งหมดนี้ เป็นเพียงพื้นฐานนะครับ ยังมีรูปแบบอื่นๆ อีกมากมาย แต่ก็จะใช้รูปแบบพื้นฐานเหล่านี้ประกอบกัน หากเราพบเห็นโค๊ดของคนอื่น เราก็จะได้เข้าใจ และัสามารถแก้ไข หรือนำไปประยุกต์ใช้ได้ต่อไป หวังว่า คงได้รับประโยชน์กันบ้างนะครับ 

รายการหน้าเว็บย่อย



ความแตกต่างของ Arduino platform กับ microcontroller อื่นๆ

โพสต์9 ธ.ค. 2555 18:52โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 06:56 ]

C Programming Tutorial

ความแตกต่างของ Arduino platform กับ microcontroller อื่นๆ

Arduino Duemilanove 2009b
บอร์ด Arduino Duemilanove 2009b : http://en.wikipedia.org/wiki/File:Arduino_Duemilanove_2009b.jpg
    ในมุมมองของผู้เล่นซึ่งเพิ่งผ่านไปไม่นาน ก็จะอธิบายแบบน้องใหม่เหมือนกัน เพราะเพิ่งเล่น microcontroller (MCU) มาไม่นาน เข้าใจสภาพตอนเป็นน้องใหม่ได้ดี เพราะไม่ค่อยรู้เรื่องเหมือนกัน ตอนเริ่มใหม่ศัพย์ต่างๆที่ผู้รู้พูดมา งงไปหมด??? ก่อนจะเข้าไปถึงว่า อะไรต่างกับอะไรอย่างไร เรามาเข้าใจความรู้พื้นฐานของการใช้ MCU กันก่อนดีกว่า เมื่อมีพื้นฐานที่แน่นแล้ว จะได้ไม่มั่วหรือเข้าใจผิด     เริ่มว่า การใช้ microcontroller ไหนก็ตาม เราก็ต้องมีบอร์ดที่เราจะใช้มัน ซึ่งบนบอร์ด จะมี MCU จะเป็นตัวใหนก็ตาม เช่น PIC, Atmel หรือ พวก MCS 51 ฯ 
    เมื่อมีบอร์ดแล้ว ก่อนที่เราจะใช้มัน เราก็ต้องเขียนโปรแกรมขึ้นมา บน PC โดยบน PC นี้ก็จะมีอุปกรณ์ ( โปรแกรม หรือที่เรียกว่า Integrate Development Environment == IDE ) ให้เราเขียน เช่นบน PIC ก็จะมีโปรแกรมที่ชื่อ MPLab ใน Atmel ก็จะมี Atmel Studio 6 (AS6) ให้เรามาใช้เพื่อพัฒนา สิ่งที่เราอยากจะให้ mcu มันทำงานให้เรา โดยเราจะเขียนโปรแกรมขึ้นมา จะด้วยภาษาอะไรก็ตาม เช่น ภาษา C, Pascal หรือ ภาษา Basic ฯ

    และ ไอ้เจ้า IDE นี้ แท้จริงแล้ว มันก็คือโปรแกรมที่เขาทำมาให้เราใช้ เพื่อความสดวก ในการพัฒนาโปรแกรม ตัวมันเองก็ถูกพัฒนามาด้วยการเขียนด้วยภาษาอะไรก็ได้ เช่น มันถูกพัฒนามาด้วย ภาษา C เช่น AS6 หรือ จะเป็นภาษา pascal ( Delphi )  หรือจะเป็น Java ( Arduino) ก็ได้ รูปร่างหน้าตามันขึ้นกับบริษัทที่เขาออกแบบมา มันไม่ได้แตกต่างไปเลย ว่ามันจะถูกพัฒนาด้วยอะไร ท้ายสุดมันก็คือตัวอำนวยความสะดวกให้เรา เพื่อให้เราได้มาซึ่ง hex file และไม่ต้องไปยึดมั่นถือมั่นว่า มันต้องเขียนด้วยภาษาอะไร ช่างหัวมัน เราไม่ต้องไปสนใจมันเลย เพราะเขาทำมาให้เราใช้ แบบที่ว่าเราบอกความแตกต่างไม่ได้ ( ในแง่ความสดวก หรือ ความเร็ว) ยกเว้นหน้าตาที่ออกมาให้เราใช้ 
ARDUINO IDE
ที่มารูป : http://en.wikipedia.org/wiki/File:Arduino_1.0_IDE,_Ubuntu_11.10.png
    เมื่อเราเขียนโปรแกรม( ซึ่งเป็นภาษาที่มนุษย์อ่านรู้เรื่อง) ขึ้นมาแล้ว เราก็ต้องเปลี่ยน ( Compile ) ให้เป็นภาษาเครื่อง เพื่อ MCU จะได้เอาไปทำงานตามที่เราต้องการ เมื่อ compile เสร็จแล้วก็จะได้โปรแกรมที่เป็น ภาษาเครื่องขึ้นมา ที่เราเรียก file ที่ได้มาว่า hex file เมื่อได้มาแล้ว เราก็ต้องเอา ภาษาเครื่อง ( hex file ) นี้ ไปบรรจุเข้าไปในหน่วยความจำของ MCU ที่อยู่บนตัวบอร์ดที่เราใช้ กรรมวิธีการเอาไปลงบน MCU อันนี้เขาเรียกว่า "burn" hex file ( คือเผามันเข้าไปใน mcu ) หรือ จะเรียกว่า "flash" hex file ( ก็คือการเอาภาษาเครื่องเข้าไปอยู่ในหน่วยความจำชนิด flash ) หรือจะเรียกว่า "program" hex file เข้าไปใน flash memory ( หมายเหตุ flash memory นี้คือหน่วยความจำที่เขาเรียกว่า nonvolatile แปลว่า เขียนเข้าไปแล้ว แม้จะปิดไฟ ข้อมูลก็จะไม่หายไปจากตัว mcu ฉนั้น เราถึงปิดเปิดเครื่อง มันก็จะยังทำหน้าที่เดิมที่เราเขียนเข้าไปให้มันทำงานให้เรา ) กรรมวิธีในการที่จะ "burn" หรือ "flash" หรือจะ "program" hex file นี้ เราก็ต้องอาศัยอุปกรณ์ hardware ที่เขาเรียกว่า programmer ซึ่งเป็นอุปกรณ์ต่างหาก ที่ผู้จะใช้ mcu ต้องจัดหามา ในวงการของ PIC อุปกรณ์ตัวนี้ก็มีอยู่หลายตัว มีเด่นๆสองสามตัว เช่น PICKit 2 และ PICKit3 เป็นต้น ในสาย Atmel ก็จะมี programmer อยู่หลายตัวมาก ทั้งที่ฟรีและไม่ฟรี ที่เด่นๆ และล่าสุด ก็เห็นจะมี AVRISP MK II และ AVR Dragon programmer นี้ ราคาของ programmer นี้จะไม่ถูกเลย ลองค้นหาสอบถามได้จาก google ก็จะเห็นราคาต่างๆ ตัว programmer นี้จะอยู่ตรงกลางระหว่าง PC ( ที่เราพัฒนาโปรแกรม) และ ตัวบอร์ดที่เราต้องการจะพัฒนาให้ทำงานตามที่เราต้องการ กล่าวคือ มันเป็นคนกลางในการจัดการบรรจุ hex file โดยไปเอามาจาก PC แล้วส่งไปยัง flash memory ของ MCU โดยจะมีสายต่อจาก 
PC(hex file)==>programmer==>MCU board 
PICKIT3 : Programmer ของค่ายไมโครชิพ สำหรับโปรแกรม Flash ลง PIC
เมื่อเราได้โปรแกรม และ compile ให้ได้เป็นภาษาเครื่องแล้ว เราก็ยังต้องอาศัย programmer โดยจะไปคว้า hex file ที่ได้จากโปรแกรม IDE ( เช่น MPLab หรือ AVR Studio/Atmel Studio ) เพื่อส่ง hex file นี้ ผ่าน programmer ไปยัง developement board ของเรา ดัง diagram ข้างบน แค่นี้ mcu มันก็จะทำงานให้เราตามที่เราต้องการ ( หากเราเขียน สั่งมันได้ถูกต้อง )นี่คือ หลักการทั่วไปของทั้ง PIC , Atmel or MCS 51 และอื่นๆ     มาถึง Arduino ต่างจาก PIC หรือตัวอื่นๆอย่างไร ก็จะเกร่นสักเล็กน้อยว่า หน่วยความจำที่เราจะบรรจุ hex file เข้าไปใน MCU นั้น มันมีอยู่สองแบบ คือ หน่วยคำจำที่โปรแกรมของเราเข้าไปอยู่ ซึ่งจะไปอยู่ส่วนล่างสุดของ หรือที่เรียกว่า program Section และอีกส่วนหนึ่งที่ปลายสุดโต่งบนสุดของ program memory นี้ ส่วนนี้มันจะทำหน้าที่พิเศษ ที่เขาเรียกว่า bootloader Section ในส่วนนี้ มันเป็นที่อยู่ของ โปรแกรมพิเศษที่เรียกว่า bootloader     ขอท้าวความกลับไปที่ programmer ที่ว่ามีหลายตัว ตัว programmer มันเองจะทำหน้าที่เอา hex file เข้าไปวางใน flash memory ของ mcu และที่น่าปวดหัว ก็คือ วิธีการเอา hex file ไปวางนี้ แต่ละ programmer มันก็มีวิธีการวางที่มีรายละเอียดและการส่งต่างกันไป ดังนั้น เพื่อให้ง่ายขึ้น เขาจึงพัฒนา bootloader program ขึ้นมา ซึ่งจะทำให้การบรรจุ hex file เข้า MCU ได้ง่ายขึ้น bootloader คืออะไร มันคือโปรแกรมซึ่งส่วนใหญ่ไม่ใหญ่โตมากนัก ที่ทำหน้าที่ทันทีที่เปิดเครื่อง http://www.cs.tau.ac.il/telux/lin-club_files/linux-boot/slide0002.htm http://www.engineersgarage.com/tutorials/bootloader-how-to-program-use-bootloader เมื่อ mcu ที่มีโปรแกรมชนิดที่เขาเรียกว่า bootloader แล้ว เราก็สามารถติดต่อกับ MCU โดยไม่ต้องอาศัย programmer เลย เราสามารถติดต่อจาก PC โดยใช้ผ่าน serial communication เข้าไปยัง MCU เลย     สรุปย่อๆได้ว่า พอเรามี bootloader บรรจุเข้าไปใน MCU ของเราแล้ว เราจะสามารถ "burn" หรือจะ "flash" หรือจะ "program" hex file จาก PC ผ่านไปยัง MCU ได้เลย โดยไม่ต้องอาศัย programmer เลย ใช่แค่ serial communication เท่านั้น นี่คือ ลักษณะหนึ่งของบอร์ด arduino ซึ่งใช้ chip ของ Atmel กล่าวคือ ตัว MCU จะมีโปรแกรม bootloader ใส่เข้ามาให้เรียบร้อยแล้ว ( ทำให้เราประหยัดค่า programmer) 
AVR Boot Loader
ที่มารูป : http://www.scienceprog.com/usb-bootloaders-for-avr-microcontrollers/
    อีกสิ่งหนึ่งที่เป็นจุดดึงดูดให้คนหันมาใช้ arduino มากก็คือ เขาให้ library เข้ามาใช้มากมาย ทำให้สามารถพัฒนาสิ่งที่เราอยากจะทำ จะใช้ ได้ง่าย หากดูจากสิ่งที่ผู้คนพัฒนาบน arduino นั้น จะเห็นว่ามีคนคิดประดิษฐ์ทำส่งของต่างๆแยะมาก คิดว่าขีดจำกัดที่พวกเราชอบพูดกันเหลือเกิน ก็คือการที่เราขาดองค์ความรู้ของตัวเราเรื่องที่เราต้องการจะทำมากกว่า และไม่ต้องกลัวว่า arduino จะรองรับไม่ได้ ควรจะห่วงว่า ตนเองมีความรู้หรือศาสตร์ในเรื่องนั้นๆ พอที่จะพัฒนาเรื่องที่เราอยากทำได้หรือเปล่ามากกว่า มีตัวอย่างมากมายที่เขาใช้ความรู้หรือศาสตร์ต่างๆมาพัฒนาบน arduino ซึ่งองค์ความรู้ของศาสตร์นั้นๆต่างหาก ที่เราต้องศึกษา เพราะเห็นในนี้ เอะอะก็บอกว่า mcu 8 bit จะรองรับไม่ได้ ( ก็คงมีบ้าง แต่น่าจะไม่มากนัก )     ฉนั้นในระดับเราๆ หรืออย่างในระดับใน e2day นี้ อย่าห่วงว่า arduino หรือ PIC 8 bit จะรองรับไม่ได้ ในความเห็นผม พวกที่บ่นนั้นเพราะพื้นความรู้หรือศาสตร์ ที่จะเอามาพัฒนาประยุกต์ใช้ของเขาเหล่านั้น ไม่พอมากกว่า ดูได้จากผลงานที่ออกมาแสดงใน arduino มีมากมายมหาศาล และศาสตร์ที่เป็นพื้นฐานที่เขาเอามาพัฒนาของให้เราใช้หรือเล่นนั้นๆ ไม่ใช่เบาๆเลย ยกต้วอย่างเล่นๆ ครับลองไปดูโครงการอันนี้ซึ่งไม่ใช่เล่นเลย และเขาใช้ arduino มาพัฒนา และไม่เพียงแค่นั้น แถมเขาเปิดให้เราหมดเลย http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/step7/Oscilloscope-Triggering/ มันมีทางเลือกให้ ทั้ง PIC & Atmelและต้วอื่นๆ แต่ในความเห็นผม arduino เป็นการเริ่มที่ง่ายและสะดวก โดยเฉพาะน้องใหม่ที่มันจะทำให้ผู้เริ่ม ได้ลุกขึ้นและเดินได้เร็วกว่าวิธีอื่น เมื่อคล่องแล้ว จะกลับมาดูว่าการลุกนั่ง เดินหรือวิ่งนั้น มันมีวิธีการกรรมวิธีหรือที่มาทีไปอย่างไรภายหล้ง ก็ย่อมได้ เห็นรูป pic เลียนแบบ Arduino แสดงว่า มันคงดีพอสมควร ทำให้นึกถึงประโยคที่เขาว่า
Imitation is the sincerest form of flattery
http://www.phrases.org.uk/meanings/imitation-is-the-sincerest-form-of-flattery.html แปลเป็นไทยน่าจะได้ว่า "การเลียนลอกแบบเป็นการแสดงความซูฮกกันแบบสุดๆเลย" ( ถึงได้เลียนแบบไง )     สรุปว่า Arduino คือ การเอา Atmel chip คือต้ว Atmega 168/328 มาบรรจุ bootloader ซึ่งทำให้การ burn หรือ flash หรือจะ program ภาษาเครื่อง (hex file ) ง่ายขึ้น ยิ่งไปกว่านั้น ยังมีสิ่งอำนวยความสดวก ในเรื่อง library ให้ใช้มากมาย มีคนทำและเอามาเปิดให้เราได้ศึกษา ลอก ก๊อป หรือให้เอาไปใช้อย่างกว้างขวาง
AVR + Boot Loader = Arduino
หวังว่า คงพอจะทำให้เข้าใจดีขึ้นและมีประโยชน์บ้าง
เครดิต Samira

รายการหน้าเว็บย่อย

การเขียนโปรแกรม C18 แบบเป็นโครงสร้าง

โพสต์19 เม.ย. 2555 05:31โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:04 ]



การเขียนโปรแกรม C18 แบบเป็นโครงสร้าง    

โดยทั่วไปแล้ว ถ้าโปรเจคไมโครคอนโทรลเลอร์ของเราไม่ได้มีขนาดใหญ่มากนัก หรือว่าเป็นงานเฉพาะที่ทำครั้งเดียว ไม่ได้ต้องทำกันบ่อย เรามักจะเขียนโปรแกรมของเราให้มีเพียงไฟล์ main.c เพียงไฟล์เดียวแล้วรวมโค๊ดทุกอย่างไว้ใน main.c แต่ในกรณีที่เราต้องการที่จะสร้างโปรเจคของเราให้มีการแยก header file (*.h) และ Source file (*.c)  ออกจากกัน เพื่อประโยชน์ในการแก้ไข หรือเพื่อนำไปใช้กับโปรเจคอื่นๆ ได้ เราจะต้องสร้างและทำการเขียนโปรแกรมแยกออกเป็นโครงสร้าง (Structure Programming) วันนี้เราจะมาเรียนรู้การเขียนโปรแกรมแบบเป็นโครงสร้าง ผ่านตัวอย่างง่ายๆ ต่อไปนี้ 

ตัวอย่างนี้ จะเป็นโปรเจคง่ายๆ เป็นการแสดงไฟติดดับสลับกัน โดยผ่านการกดปุ่ม button 1 ตัว เพื่อเป็นตัวทำหน้าที่ให้หลอด LED ติดดับสลับกัน 


เครื่องมือ 
-MPLAB V8.83 หรือสูงกว่า 
-C18 Complier v3.35 หรือ สูงกว่า
-PIC18F458 


สร้างโปรเจคด้วย MPLAB โดยเปิดโปรแกรม MPLAB ขึ้นมา แล้วไปที่เมนู Project>ProjectWizard
ขั้นที่1 - เลือก PIC18F458
ขั้นที่2 - เลือก C18 complier 
ขั้นที่3 - ตั้งชื่อโปรเจคของเรา Project.mcp
ขั้นที่4 - เพิ่มไฟล์ C:\MCC18\lkr\18f458_g.lkr (บางเวอร์ชั่น 18f458.lkr) เข้าไปในโปรเจค
ขั้นที่5 - เสร็จสมบูรณ์ กด Finish 

จะได้โปรเจคว่างเปล่า หน้าตาโปรแกรม (คล้ายๆดังรูป)


อันดับแรกเลย การที่เราจะเขียนโปรแกรมให้ไมโครคอนโทรลเลอร์ของเราทำงานได้นั้น จะต้องมีการตั้งค่าเริ่มต้น หรือกำหนดค่าเริ่มต้น เช่น กำหนดหน้าที่การทำงานของแต่ละขาของไมโครคอนโทรลเลอร์ ว่าจะให้ทำงานในโหมด เอาท์พุต หรือว่า อินพุต และการกำหนดค่าเริ่มต้นของความถี่ในการทำงาน และการเปิด ปิด โหมดต่างๆ ที่เกี่ยวข้องกับงานของเรา ในที่นี้ เราจะมาสร้างไฟล์ที่ทำหน้าที่เป็นการกำหนดค่าเริ่มต้นให้โปรเจคของเรา เราจะให้ไฟล์ชื่อ system.h เก็บค่าเริ่มต้นเหล่านั้น 

ไปที่เมนู File>New สร้างไฟล์เปล่าๆ ขึ้นมา แล้ว เขียนโปรแกรม เพื่อกำหนดค่าเริ่มต้นให้กับไมโครคอนโทรลเลอร์ ในที่นี้ โค๊ดที่เราสร้าง จะเป็นโค๊ดที่อยู่ข้างนอก void main(void) ซึ่งในตัวอย่างนี้ ค่าที่สามารถสร้างได้ นอก void main(void) ก็คือ มาโคร #pragma config นั่นเอง เพราะฉะนั้นจะได้ โค๊ด ภายในไฟล์ system.h ดังนี้ 

#pragma config OSC = HS,OSCS = OFF
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF

หมายเหตุ : ในไฟล์ต่างๆ พยายามเคาะ enter บรรทัดสุดท้าย ให้ว่างๆ ไว้ สักบรรทัดเป็นอย่างน้อย เพราะอาจจะทำให้เรา Complie ไม่ผ่าน แล้วหาไม่เจอ ตรงนี้ให้ระวังด้วยครับ 

ทำการบันทึกไฟล์ system.h ไว้ในโฟลเดอร์เดียวกันกับที่เราสร้างโปรเจค (ไว้ที่เดียวกันกับไฟล์ Project.mcp นั่นแหละ) 
ที่เมนู File>New สร้างไฟล์เปล่าๆ ขึ้นมา เราจะให้ไฟล์นี้เป็นไฟล์ ที่ฟังก์ชั่น main( ) เริ่มต้นทำงาน โดยเขียนโค๊ดเริ่มต้นดังนี้ 

#include <p18cxxx.h>
#include "system.h"


void main(void)
{
while(1)
{
}
}

จากนั้นบันทึกไว้เป็นไฟล์ main.c (เพื่อสื่อความหมายว่า main ฟังก์ชั่น อยู่ที่ไฟล์นี้) จุดสังเกต เราจะพบว่าในไฟล์ main.c นี้ จะมีการ  นำไฟล์ system.h ( ดัวยคำสั่ง #include "system.h" )เข้ามาร่วมในไฟล์ main.c ด้วย นั่นหมายความว่า โค๊ดที่เราเขียนไว้ที่ไฟล์ system.h จะถูกนำมาแปะไว้ที่ไฟล์ main.c ก่อนขึ้นฟังก์ชั่น void main(void) และอยู่หลัง #include <p18cxxx.h>

ที่ Source Files ให้ทำการ Add File main.c เข้าไป แล้วให้ทำการ build project ดูก่อน เพื่อให้มั่นใจว่า ไม่ได้เกิด Error ขึ้นในขั้นตอนนี้ ถ้าทุกอย่างถูกต้อง เพื่อนๆ จะต้องได้คำว่า BUILD SUCCEEDED ที่หน้าต่าง build แท๊ป output (ถ้าเกิด BUILD FAILED ให้ทำการแก้ไข ตาม บรรทัดที่แจ้งเตือน) 

ถ้าทุกอย่างเรียบร้อย เราจะมาเริ่มทำการเขียนโค๊ดไฟกระพริบ ก่อน โดยเราจะให้ ขา PB0 ทำหน้าที่เป็นเอาท์พุต และให้หลอด LED ที่ต่ออยู่ที่ขานี้ กระพริบติดดับสลับกัน เมื่อเราได้แนวคิดแล้ว ให้ทำการสร้างไฟล์ขึ้นมา เพื่อทำหน้าที่ควบคุมการติดดับของหลอด LED  และเพื่อให้สื่อความหมายของไฟล์นี้ เราจะตั้งชื่อไฟล์ว่า LED ให้เพื่อนๆ สร้างไฟล์ LED.c ขึ้นมาโดยไปที่เมนู File>New แล้วเขียนโค๊ด 

#include <p18cxxx.h>

void InitialiseLED(void)
{
TRISB = TRISB & 0xFE;  // PB0 as output pin
}

void LED_Off(void)
{
PORTB &= (~0x01); // Turn off LED
}

void LED_On(void)
{
PORTB |= 0x01;  // Turn on LED

}

จากนั้น เราจะทำการสร้างไฟล์ ที่เป็น header file ชื่อ LED.h ของไฟล์ LED.c เพื่อทำการประกาศฟังก์ชั่นโปรโตไทป์ ก่อนการเรียกใช้งานฟังก์ชั่น ที่เมนู File>New สร้างไฟล์ขึ้นมา แล้วทำการ ก๊อปปี้ชื่อฟังก์ชั่นไปไว้ในไฟล์ LED.h โดยมีคำว่า extern นำหน้า ซึ่งบอกให้คอมไพล์เลอร์ทราบว่า ชื่อฟังก์ชั่นนี้อยู่ที่ไฟล์อื่น ไม่ได้อยู่ที่ไฟล์ LED.h จริง ฉะนั้นในไฟล์ LED.h จะต้องเขียนโค๊ดเป็นดังนี้

extern void InitialiseLED(void);
extern void LED_Off(void);
extern void LED_On(void);

ทำการบันทึกไฟล์ LED.h จากนั้นกลับไปที่ไฟล์ main.c ทำการเพิ่ม #include "LED.h" ไว้ที่หัวของไฟล์ เพื่อบอกให้คอมไพล์เลอร์ทราบว่าให้นำ LED.h เข้ามาร่วมด้วยที่ไฟล์ main.c และทำการเรียกฟังก์ชั่นที่เราสร้างไว้ที่ไฟล์ LED.c ซึ่งได้แก่ฟังก์ชั่น 

InitialiseLED();
LED_Off();
LED_On();

เข้ามาทำงานในไฟล์ main.c ดังนั้นที่ไฟล์ main.c เราจะได้ว่า 

#include <p18cxxx.h>
#include "system.h"
#include "LED.h"


void main(void)
{
InitialiseLED();
LED_Off();
LED_On();
while(1)
{
}
}

ลองทำการกดปุ่ม Build All เพื่อนๆ จะพบว่า เกิด Error ขึ้น เพราะ Linker ไม่สามารถที่จะหาตัวฟังก์ชั่นที่เราเรียกมาใช้ได้ เราจะต้องทำการนำไฟล์ที่เป็นที่อยู่ของฟังก์ชั่นดังกล่าวเข้ามาในโปรเจคเราซะก่อน โดยการทำการคลิกขวาที่ Source Files แล้ว Add File แล้ว เลือกไฟล์ LED.c กด OK เราจะได้ Source File เพิ่ม ดังภาพ แล้วลอง Build All อีกครั้ง จะได้ BUILD SUCCEEDED แสดงว่าทุกอย่างถูกต้องแล้ว 



หากเราพิจารณา โดยที่ยังไม่ต้องเบิร์นโค๊ดเรา ลงไปที่ไมโครคอนโทรลเลอร์ เราก็อาจจะพิจารณาได้ว่า หลอด LED ที่ต่ออยู่ที่ขา PB0 ของไมโครคอนโทรลเลอร์ จะติดค้างอยู่ ที่ PB0 หากเราต้องการให้เกิดการติดดับสลับกัน เราก็แค่ให้ฟังก์ชั่น LED_On() และ LED_Off() วางสลับกัน ก็น่าจะทำให้หลอดไฟ LED ติดดับสลับกันได้ แต่ ด้วยความถี่ที่สูงมาก ทำให้สายตาของเราไม่สามารถแยกความแตกต่างได้ สิ่งที่เราต้องการก็คือ ควรจะมีการหน่วงเวลา เพื่อทำให้สายตาของเราแยกแยะความแตกต่างได้ ดังนั้น เราจึงควรที่จะสร้างฟังก์ชั่นหน่วงเวลาขึ้นมา หรือที่นิยมเรียกกันว่า delay ขึ้นมาใช้งาน ในการสร้างฟังก์ชั่น delay เราก็จะทำคล้ายๆ กับที่เราสร้างฟังก์ชั่น LED เหมือนกัน ให้เพื่อนๆ ลองสร้างไฟล์ delay.h และ delay.c ขึ้นมา (เรื่องการคำนวณ delay สามารถดูได้จากตอนที่ผ่านไปแล้ว ได้ครับ คลิก

โค๊ดของ delay.c
#include <delays.h>

void delay_ms(unsigned int ms)
{
    while(ms--)
    {
        Delay1KTCYx(5); 
    }

}


และ delay.h

extern void delay_ms(unsigned int ms);

สุดท้ายเราต้องการฟังก์ชั่นที่ควบคุมการกดปุ่ม ในที่นี้ผมจะสร้างไฟล์ button.c เพื่อทำหน้าที่กำหนดขาเริ่มต้นเพื่อทำหน้าที่รับค่าการกดปุ่ม และ ฟังก์ชั่นคืนค่าการกดปุ่ม ผมทำการสร้างไฟล์ button.c ดังนี้

#include <p18cxxx.h>

void InitialiseButton(void)
{
    TRISB = TRISB & 0xFF;  // PB1 as input
}


char PushButton(void)
{
    if(PORTB & 0x02){
        return 1;
    }else{
        return 0;    
    }
}

และเช่นเดิม ผมต้องแยกไฟล์ button.h เพื่อเก็บฟังก์ชั่นโปรโตไทป์ ออกมา จะได้ไฟล์ button.h ที่มีโค๊ดดังนี้

extern void InitialiseButton(void);
extern char PushButton(void);

แล้วก็อย่าลืม เพิ่มไฟล์ *.h เข้าไปที่หัวไฟล์ของ main.c ในขณะที่ *.c เราจะ add file เข้าที่ source files ดังภาพ 


ทำการ Build All โปรเจคอีกครั้ง ต้อง BUILD SUCCEEDED ถ้าไม่ได้ ให้ทำการแก้ไข อย่าลืมเรื่องการเคาะ Enter ไว้ที่บรรทัดสุดท้าย ในแต่ละไฟล์ด้วย (สงสัยจะเป็น bug ของ IDE หรือเปล่าไม่แน่ใจ )

ทำการต่อวงจรในโปรแกรมจำลองการทำงาน Proteus โดยให้ Processor Clock Frequency มีค่าเท่ากับ 20MHz ทดลองกดปุ่ม ดูผลการทำงานของโปรแกรม 




ปล. บางรูปอาจจะไม่สัมพันธ์กับคำบรรยายในบางรูป แต่ขอให้ทำตามคำแนะนำที่ให้ไว้ครับ 

รายการหน้าเว็บย่อย


การตั้งค่า Delay ใน MPLAB C18 C Complier Libraries

โพสต์27 ม.ค. 2555 09:57โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:04 ]




การตั้งค่า Delay ใน MPLAB C18 C Complier Libraries

ในการใช้งาน Library ของ MPLAB C18 C Complier ในส่วนของ delay function ซึ่งถูกประกาศไว้ในไฟล์ delay.h  มีการใช้งานดังนี้ 

อันดับแรก ทำการ #include <delays.h> เข้ามาไฟล์ของเรา เพื่อร่วมในการ complie ก่อน โดยทำการประกาศ directive ไว้

ที่หัวของไฟล์ ต่อจาก header ไฟล์ p18cxxx.h

#include <p18cxxx.h>
#include <delays.h>

ภายในไฟล์ delays.h ประกอบไปด้วย

การประกาศฟังก์ชั่น 
void Delay1TCY( void );
void Delay10TCYx( unsigned char unit );
void Delay100TCYx( unsigned char unit );
void Delay1KTCYx( unsigned char unit );
void Delay10KTCYx( unsigned char unit );

คำอธิบาย 
ตัวอักษร 'x' แทนความหมายการคูณ ด้วย parameter ที่เราใส่เข้าไปในแต่ละฟังก์ชั่น 
ตัวอักษร 'TCY' แทนความหมาย รอบคำสั่ง 'instruction cycle' 
ค่าของ unit คือค่าที่เราต้องการให้เกิดการหน่วงเวลา โดยค่า unit มีค่าอยู่ระหว่าง 1 ถึง 255 

ตัวอย่างการคำนวณ 
หากเราต้องการที่จะหน่วงเวลา 5 ms เราจะต้องหาค่า unit หรือค่าตัวคูณกับ TCYx ที่อยู่ระหว่าง 1 ถึง 255 เพื่อเป็น parameter ของฟังก์ชั่น delay แต่เนื่องจาก PIC ทำงาน 4 clock ต่อ 1 คำสั่ง เพราะฉะนั้น เราจะต้องหาว่า ต้องใช้กี่ Cycle ถึงจะทำให้ PIC ไปทำการเรียกใช้คำสั่ง NOP() (คือไม่ทำอะไร เรียกเฉยๆ) กี่ครั้ง ถึงจะได้ 5 ms 

มาถึงตรงนี้ อาจจะงงๆ สักหน่อย ยกสมการมาใช้เลยหล่ะกัน 

TCY = (TimeDelay * Fosc) / 4
TCY = (5ms * 20MHz) / 4
TCY = 25,000

แต่เนื่องจาก unit มีค่าได้ไม่เกิน 255 เพราะฉะนั้น เราต้องตัวคูณหน้าชื่อฟังก์ชั่น delay ที่ทำให้ TCY = 25,000 ในที่นี้ ผมเลือก 1K
จะได้ว่า 1K x 25 จะได้  25,000 เพราะฉะนั้น 

Delay1KTCYx(25); จึงมีค่าเท่ากับ หน่วงเวลา 5 ms 

แล้วถ้าผมต้องการ หน่วงเวลา 500ms หล่ะ จะได้เท่าไหร่ ???

คำตอบก็คือ Delay10KTCYx(250); ครับ 

พูดง่ายๆ ก็คือ เลือกฟังก์ชั่นที่ต้องการ เพื่อไม่ให้ unit มีค่าเกิน 255 เพื่อให้ได้ TCY ที่เราต้องการ 

หมายเหตุ หากเราใส่ค่า unit เท่ากับ 0 มิได้หมายความว่า จะหน่วงเวลาเท่ากับ 0 วินาที นะครับ ถ้าเราใส่ unit เท่ากับ 0 ที่ฟังก์ชั่น delay ใดๆ 

จะเท่ากับ unit = 256 คูณกับฟังก์ชั่น delay เช่น Delay1KTCYx(0) จะเท่ากับหน่วงเวลาไป 2,560 cycles
ฟังก์ชั่นอื่นๆ ที่เหลือ ก็คำนวณเหมือนๆ กัน 

ปล. อาจจะมีคำถามว่า 20MHz มาจากไหน อันนี้ ก็มาจากบอร์ดทดลองของเราเลย ว่าตอนนี้ ใส่ Crystal เข้าไปค่าเท่าไหร่ ทั้งนี้ ต้องไม่เกินค่าที่ระบุ

ไว้ใน ดาต้าชีทด้วยนะครับ 

ตัวอย่างโค๊ดไฟกระพริบ ติดดับสลับกัน 500ms หรือ ครึ่งวินาที ของ PIC18F458 

#include <p18cxxx.h>
#include <delays.h>

#pragma config WDT = OFF
#pragma config OSC = HS // High speed crystal  on board 20MHz
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config LVP = OFF

void main(void)
{
TRISB = 0x00;
PORTB = 0x00;
while(1)
{
PORTB = 0x01;
Delay10KTCYx(250);
PORTB = 0x00;
Delay10KTCYx(250);
}

}


 
 

แล้ว ถ้าเราต้องการเอามาเขียนเป็น function หล่ะ (เพื่อให้เกิดความยืดหยุ่นในการนำไปใช้งาน) ก็ไม่ยากครับ 

นี่เป็นฟังก์ชั่นหน่วงเวลา แบบ millisecond (หนึ่งในพันวินาที) 
void delay_ms(unsigned int ms)
{
    while(ms--)
    {
        Delay1KTCYx(5);    
    }    

}

หวังว่า คงไม่ งง นะครับ ว่า Delay1KTCYx(5);   มาจากไหน ^^ 

รายการหน้าเว็บย่อย


C18 - Storage Class

โพสต์11 ม.ค. 2554 06:45โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:03 ]



C18 - Storage Class
Storage  class  ของตัวแปร  เป็นสิ่งที่ใช้ในการบอกให้ Compiler รู้ว่าจะต้องจัดเก็บตัวแปรที่ตามหลังมาอย่างไร  ซึ่งมีผลถึง
  • การคงอยู่ของข้อมูลของตัวแปรนั้น ๆ เช่น  อยู่ตลอดเวลาหรืออยู่เฉพาะบางเวลา
  • ขอบเขตของการอ้างถึงหรือมองเห็นของตัวแปรนั้น ๆ  ว่าสามารถจะเรียกใช้ได้ที่ใดได้บ้าง  และโดย functions ใดได้บ้าง

ทำไมต้องมี  Storage  class  ???

     เนื่องจากภาษาซีเอื้ออำนวยให้สามารถเขียนโปรแกรมและคอมไพล์เป็นส่วนย่อย ๆ ก่อนที่จะนำมาลิงค์เป็นโปรแกรมใหญ่ ภาษาซียอมให้ตั้งชื่อตัวแปรซ้ำกันได้ในต่างฟังก์ชัน  ดังนั้นส่วน storage class  จะช่วยให้ compiler รู้ว่าควรจะจัดการกับตัวแปรต่าง ๆ อย่างไรจึงจะตรงกับความต้องการในการใช้งานของโปรแกรมเมอร์และหลีกเลี่ยงความผิดพลาดต่าง ๆ ที่อาจเกิดขึ้นได้

     ใน C18 complier ของ MPLAB รองรับ ANSI standard storage classes ตัวแปร เช่นกัน ได้แก่ auto , extern, register, static และ typedef  ซึ่งแต่ละคำ มาจากคำว่า 
  • auto ย่อมาจาก automatic
  • extern ย่อมาจาก external 
  • static
  • register
 
 



รูปแบบการใช้ ตัวแปร Storage Class

ตัวบ่งบอกStorage_Class ชนิดตัวแปร ตัวแปร


ตัวแปรแบบ Automatic
    โดยปกติ ตัวแปรที่ประกาศภายใน function จะเป็นตัวแปร automatic ทุกตัว ไม่เว้นกระทั่งภายใน function main() เมื่อ function ทำงานสิ้นสุดลง ตัวแปรภายใน function ก็จะหมดหน้าที่ลง ถูกทำลายไปโดยอัตโนมัติ หรือที่เราเรียกว่า ตัวแปรแบบ local นั่นแหละ เราสามารถประกาศตัวแปร พวกนี้ โดยใส่คำว่า auto นำหน้าตัวแปร หรือไม่้ใส่ก็ได้ ซึ่งการประกาศตัวแปรพวกนี้ จะไม่ได้ถูกตั้งค่าเริ่มต้นให้ เราจะต้องตั้งค่าเริ่้มต้นเอาเอง และค่าเริ่มต้น ที่ไม่ได้กำหนด ก็ไม่ใช่ค่าศูนย์ เสีียด้วย เพราะฉะนั้น ตรงนี้ให้ระวังไว้  พิจรณา ตัวอย่าง 



ตัวแปร external หรือตัวแปร extern
เป็นลักษณะการแก้ปัญหา การประกาศตัวแปร ที่เป็น global ที่มีชื่อซ้ำกัน แต่อยู่กันคนละไฟล์ ในโปรเจคเดียวกัน ถ้าเราไม่ได้ใช้ keyword extern ในการแก้ปัญหานี้ เวลาที่คอมไำพล์จะไม่มีปัญหา แต่เวลาที่ linker จะต้องเอาแต่ละไฟล์ที่โปรเจคอ้างถึง จะเกิดปัญหาแจ้ง error message ออกมา 

ตัวแปร static 
    ตัวแปรใดๆ ที่ถูกระบุว่าเป็น static ตัวแปรนี้ จะมีความพิเศษคือ จะสามารถคงค่าล่าสุดไว้ภายในไฟล์ที่ถูกประกาศไว้ การทำการกำหนดค่าเริ่มต้นจะมีผลแค่ครั้งแรกที่ตัวแปรนี้ถูกเรียกใช้เท่านั้น หากมีการเรียกใช้อีกครั้ง การกำหนดค่าเริ่มต้นจะไม่มีผลใดๆ เรามักใช้ตัวแปร static ในฟังก์ชั่น เพื่อที่จะคงค่าของตัวแปรไว้ เพราะว่า เมื่อฟังก์ชั่นใดๆ ถูกเรียกใช้ หลังจากฟังก์ชั่นทำงานเสร็จแล้ว จะทำให้ตัวแปรที่ถูกประกาศอยู่ภายในฟังก์ชั่นถูกทำลายทิ้ง ยกเว้นตัวแปร static ที่ยังคงค่าไว้ 

ตัวแปร register 
    เราใช้การระบุ register หน้าตัวแปรทีเป็นตัวแปร local ที่เราต้องการให้เก็บค่าตัวแปรนั้นไว้ที่ register แทนที่เราจะเก็บไว้ที่ RAM นั่นหมายความว่า ขนาดของตัวแปรจะมีขนาดใหญ่เท่ากับขนาดของรีจิสเตอร์ (โดยทั่วไปก็ 1 word) และไม่สามารถใช้การอ้างอิงแบบแอดเดรสได้ (ไม่สามารถใช้ & หน้าตัวแปรได้) เพราะมันไม่ได้มีที่อยู่ในหน่วยความจำนั่นเอง  เรามักใช้ register หน้าตัวแปรที่เราต้องการให้มีการเข้าถึงอย่างรวดเร็ว เช่น ตัวแปร counter ที่เก็บค่าการนับ แต่ทั้งนี้ ทั้งนั้นไม่ใช่ว่าเราจะสามารถประกาศตัวแปรที่เป็น register ได้ทุกตัวที่เราต้องการ เพราะขึ้นอยู่กับฮาร์ดแวร์ของระบบและกฏของ complier นั้นๆ ด้วย 

ดูรูปประกอบ เพื่อความเข้าใจครับ 

Storage Class

MPLAB C18 - ชนิดของตัวแปร

โพสต์13 ต.ค. 2552 00:54โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:02 ]


MPLAB C18 - ชนิดของตัวแปร

เหมือนๆกับทุก complier ที่จะต้องมีตัวแปร เช่นเดียวกัน C18 complier มีตัวแปรทั้งที่เป็นชนิด char ,integer, float, double
นี่ก็เป็นเรื่องเบสิคทั่วๆำไป ที่ผู้ที่ต้องการเขียนโปรแกรมจะต้องรู้เกี่ยวกับชนิดของตัวแปรในภาษานั้น และขอบเขตของตัวแปรนั้นๆ ที่สามารถทำได้ เพราะถ้าหากเรากำหนดตัวแปร ตัวแปรหนึ่งแล้วไปเก็บค่าที่เกินขอบเขตของตัวแปรตัวนั้น จะเกิดอาการ overflow คือค่าที่เก็บจะย้อนกลับมาที่ค่าเริ่มต้นของมัน 

ตัวอย่างเช่น เรากำหนดให้ตัวแปร A เป็นตัวแปร  unsigned char แล้วให้ A เก็บค่าการนับอะไรก็ตาม เมื่อ A เก็บค่าการนับสะสมไปเรื่อยๆ เมื่อค่า A มีค่าไปจนถึงค่า 255 พอเราทำการบวกค่า A หรือเพิ่มค่า A ขึ้นไปอีกหนึ่งค่า ค่า A หลังจากการบวก เพิ่มค่า จะกลับกลายเป็น A = 0 เพราะว่า unsigned char สามารถเก็บค่าได้สูงสุด แค่ 255 เท่านั้น 

เราสามารถสร้างตัวแปร แล้วกำหนดชนิดตัวแปร ให้สามารถเก็บค่า ค่าหนึ่งๆ โดยเราต้องพิจารณาขอบเขต Minimum และ Maximum ที่เป็นไปได้ ตามตาราง 2-1 ข้างล่างนี้


สำหรับจำนวนตัวเลขที่เป็นทศนิยมแล้ว ใน MPLAB C18 เราสามารถใช้ได้ทั้งตัวแปรที่เป็นชนิด float และ double ตามตาราง 2-2 ข้างล่างนี้


รายการหน้าเว็บย่อย



MPLAB C18 - รูปแบบการ Include file

โพสต์13 ต.ค. 2552 00:52โดยวิสิทธิ์ แผ้วกระโทก   [ อัปเดต 18 ม.ค. 2557 07:03 ]



MPLAB C18 - รูปแบบการ Include file

การ Include  header file เข้ามาร่วมกันด้วยใน project ของเรา จะมีด้วยกัน อยู่ 2 รูปแบบ คือ 
  1. แบบ System Header File 
  2. แบบ User Header File 
ซึ่งทั้งสองแบบ ทำงานต่างกันดังนี้ 

แบบ System Header File จะเป็นการ Include File จาก Folder ที่เก็บไลบรารี หลักของ Complier ซึ่งเป็น Folder ที่ถูกระบุไว้ที่ระบบ รูปแบบการอ้างอิง #include <filename> เมื่อ Complier ทำการแปลข้อความบรรทัดนี้ Complier จะืำทำการดึงไฟล์ที่อยู่ใน Folder ของโปรแกรมภาษาที่เราใช้เขียน

 
 


แบบ User Header File จะเป็นการ Include File จาก Folder เดียวกับที่เราเก็บ source file ที่เรากำลัีงเขียนอยู่นี้ เข้ามาร่วมในการคอมไำพล์ด้วย รูปแบบการเรียกใช้ คือ #include "filename" 

ทั้งสองรูปแบบต่างกัน หลังคำสั่ง #include 

รายการหน้าเว็บย่อย


1-7 of 7