Hello world I am AVR part II
    จากตอนที่ 1 เราได้ทำกาต่อวงจรไฟฟ้าขั้นพื้นฐานเพื่อให้ไมโครคอนโทรลเลอร์ Atmega48 ของเราทำงานได้อย่างที่เราต้อง ซึ่งถ้าเพื่อนๆ ได้ใช้บอร์ดอื่นๆ หรือไอซีเบอร์อื่นๆ ที่ไม่ใช่เบอร์ Atmega48 ก็สามารถทำตามได้ โดยหลักการของไอซีค่าย Atmel แล้ว ก็ไม่ต่างกันมาก

    ในตอนที่ 2 นี้ เราจะมาเริ่มลงมือเขียนส่วนที่เป็น Firmware ของไอซีสมองกลฝังตัว อย่างที่ผมเคยยกตัวอย่างไปแล้วเจ้า Firmware ที่เราจะเขียนนี้ ก็เปรียบเสมือนระบบปฏิบัติการเช่น Windows หรือ Linux ที่เราคุ้นเคยกันนั่นเอง ต่างกันตรงที่ความซับซ้อน และขนาดหน่วยความจำที่ค่อนข้างจำกัดจำเขียด จะประกาศตัวแปรหรือทำอะไร ก็ต้องคอยระมัดระวังรอบคอบ อย่าให้ขนาดโค๊ด (Code size) เกินหน่วยความจำที่ใช้เก็บโค๊ด (Flash memory) ที่อยู่อย่างจำกัด ไม่เหมือนกับคอมพิวเตอร์ที่มีมากมาย ดังนั้นแล้ว การเขียนโค๊ดให้กับไมโครคอนโทรลเลอร์ เป็นเรื่องที่ค่อนข้างจะลำบากสำหรับมือใหม่ ที่ต้องใช้ความระมัดระวังอย่างมาก

แต่ในเบื่องต้น เป้าหมายของเราคือต้องการให้หลอด LED ที่ต่ออยู่กับขา digital output ของไมโครคอนโทรลเลอร์ทำการสั่งให้หลอด LED ติดดับเป็นจังหวะได้ ซึ่งขนาดของโค๊ดกับงานแค่นี้ ไม่น่าจะเกินหน่วยความจำ ฉะนั้นในเบื้องต้น ตัดความกังวลเรื่องขนาดโค๊ดเกินหน่วยความจำไปได้เลย

เอาหล่ะ เรามาเริ่มจากเปิดโปรแกรม Atmel Studio ที่เราได้ติดตั้งกันไปก่อนหน้านี้ขึ้นมาครับ จะปรากฏหน้าต่างดังรูป




    เราจะมาเริ่มสร้างโปรเจคกันก่อน หากใครที่เคยใช้โปรแกรมอย่างเช่นพวก Visual Studio จะพบว่า โปรแกรม Atmel Studio มีลักษณะ IDE ที่คล้ายกันมาก (จริงๆ พื้นฐานก็มาจากที่เดียวกัน)
ก่อนที่เราจะเริ่มสร้างโปรเจคเพื่อเขียนโปรแกรม เราจะต้องทำการออกแบบโค๊ดโปรแกรมของเราให้ทำงานสอดคล้องกับฮาร์ดแวร์ของเราเสียก่อน เราอาจจะออกแบบในกระดาษ โดยเขียนเป็น flow chart หรืออะไรก็ตามแต่ ที่เราถนัด ในที่นี้โปรแกรมของเราไม่ได้ซับซ้อนอะไร ผมเลยขออนุญาตที่จะเขียนบนหน้าเว็บอธิบายหลักการทำงานคร่าวๆ ก็แล้วกัน 

    เป้าหมายของเราก็คิือ เราต้องการให้เกิดการติดดับของหลอด LED ที่ต่ออยู่กับขาของไอซี Atmega48 ขา digital output ขาใดขาหนึ่ง ดังนั้น ก่อนที่เราจะลงมือเขียนโปรแกรมนั้น เราก็ต้องเลือกขาของไอซีที่จะมาทำงานเสียก่อน เนื่องจากงานของเราต้องการให้มีสัญญาณดิจิตอลออกที่ขาใดขาหนึ่ง ผมขอเลือกที่จะใช้ PORTC ก็แล้วกัน (จริงๆ เลือก PORTD หรือ PORTB ก็ไม่ผิด ทำงานได้เหมือนกัน) ให้ย้อนกลับไปที่ดาต้าชีทอีกครั้ง ในหน้าที่เกี่ยวกับ 14.2.1 Configuring the pin อธิบายไว้ดังนี้

หากต้องการควบคุมการทำงานของ Digital I/O แล้ว จะต้องเกี่ยวข้องกับ Register 3 ตัว  (ย้ำนะครับว่า เรากำลังทำงานกับ Digital I/O มันก็เลยมีแค่ 3 Register ที่เกี่ยวข้อง) คือ DDRxn , PORTxn , PINxn โดยที่ 

x คือชื่อ PORT เช่น PORTC ค่า x ก็เท่ากับ C  
n คือตำแหน่งบิต นั้นๆ เช่น bit ที่ 0 ของ PORTC0 ค่า n ก็เืท่ากับ 0 

ที่นี้ ถ้าผมเขียนแบบนี้ PORTC ผมกำลังอ้างถึงค่าที่เก็บได้ 8 บิต (ค่าตั้งแต่ 0-255)
และถ้าผมเขียน PORTC0 ผมกำลังอ้างถึงค่าที่เก็บได้แค่ 1 บิต (มีแค่ 0 กับ 1) 

ศึกษาเรื่องบิตข้อมูลกับ PORT ได้ที่นี่  การทำงานข้อมูลระดับบิตในภาษาซี

กลับมาที่เรื่องที่เราจะกำหนดการทำงานของขา Digigtal I/O ก่อน เนื่องจากขา Digital I/O Port C สามารถทำงานได้แบบ Bi-Directional นั่นแปลว่า มันสามารถทำหน้าที่เป็นได้ทั้ง Input และ Output digital ขึ้นอยู่กับว่าเราจะกำหนดให้มันเป็นอะไร โดยมันจะถูกควบคุมจากรีจิสเตอร์ที่ชื่อ DDRC นั่นเอง 

ในการเซตให้ขาใดขาหนึ่งทำงานเป็น output เราจะกำหนดให้มีค่าเป็น 1 ในทางตรงกันข้าม หากต้องการให้เป็น input เราจะให้เป็น 0 ดังนั้น หากผมกำหนด DDRC |= 0x02; ก็จะมีความหมายดังรูปด้านล่าง

ต่อมาเมื่อเราได้กำหนดหน้าที่ขา Digital ที่จะเป็น output แล้ว หน้าที่ต่อไปก็คือ สั่งให้มี output ออกที่ขานั้นๆ การที่จะสั่งให้มี output ที่เป็นสัญญาณดิจิตอลออกไปที่ขานั้นๆ ได้นั้น ต้องอาศัยรีจิสเตอร์ที่ชื่อ PORTC หากเรากำหนดให้ค่าเป็น 1 ที่บิตใดๆ ในพอร์ตนั้นๆ จะทำให้เกิดสัญญาณดิจิตอล Logic High ออกที่ขานั้น ในทางตรงกันข้ามหากให้บิตใดๆ มีค่าเป็น 0 จะทำให้เกิดสัญญาณดิจิตอลที่เป็น Logic Low ออกที่ขานั้นๆ ซึ่งมีค่าเที่ยบเท่ากับกราวด์ของวงจร