Programming in C
A Framework for Hardware/Software Codesign Hardware/Software Codesign of Embedded Systems Chap_13Lesson01EmsysNewDevProSofTools Microprocessors and Microcontrollers Embedded C Programming MPLAB C18 C Compiler Getting Started Programming the PIC18 Using C Coding The Hitchhiker’s Guide to C Programming on the PIC
Embedded System หมายถึงคอมพิวเตอร์เพื่องานเฉพาะกิจ ที่ Hardware และ Software ของมันถูกออกมาให้สามารถทำงานอย่างใดอย่างหนึ่งเป็น การเฉพาะ เช่นคอมพิวเตอร์ควบคุมการทำงานของลิฟท์ หรือเครื่องซักผ้า เป็นต้น
ตัวอย่างของ Embedded System
ตัวอย่างของ Embedded System
ตัวอย่าง Embedded System
ส่วนแบ่งตลาดของ Embedded System
การออกแบบระบบ Embedded System รวบรวมการทำงาน (Function) ทั้งหมดที่ จำเป็นต้องมีใน Embedded System เช่น อุปกรณ์ต่อพ่วงที่ใช้ควบคุมการทำงานของ เครื่องจักรหรือใช้ติดต่อกับผู้ใช้ วิธีการสื่อสาร ระหว่างไมโครคอนโทรลเลอร์กับอุปกรณ์ต่อพ่วง เช่น I2C, CAN หรือ SPI เป็นต้น แบ่งการทำงานออกเป็นส่วนของ Hardware และส่วนของ Software
ขั้นตอนการออกแบบ Embedded System
การออกแบบ Hardware/Software แยกออกจากกัน การออกแบบระบบ Embedded System โดยแยกการออกแบบ Hardware และ Software ออกจากกันตั้งแต่เริ่มต้น โดยส่วนใหญ่วิศวกรจะออกแบบ Hardware โดยไม่ คำนึงถึงข้อจำกัดของการเขียนโปรแกรม และโปรแกรมเมอร์มักจะไม่มีส่วนร่วมในการออกแบบ Hardware การออกแบบลักษณะนี้ทำให้ไม่สามารถ Trade-off ระหว่าง Hardware และ Software เพื่อให้ได้ผลลัพธ์ที่ดีขึ้น เช่น การย้ายการทำงานบางอย่างของ Software ให้ Hardware ทำงานแทนเพื่อให้ทำงานได้เร็วขึ้น หรือการเขียนโปรแกรมเพื่อทำงานแทน Hardware เพื่อประหยัดต้นทุนและทำให้ Hardware มีขนาดเล็กลงเป็นต้น นอกจากนี้อาจเกิดปัญหาในระหว่างขั้นตอนการรวม Hardware และ Software เข้า ด้วยกัน เช่น Hardware ทำงานช้าเกินไป หรือโปรแกรมใช้หน่วยความจำมากเกินไป ทำให้ ต้องปรับปรุงแก้ไข Hardware หรือ Software ซึ่งทำให้ค่าใช้จ่ายและเวลาเพิ่มขึ้น
Hardware/Software Codesign จากความก้าวหน้าของเทคโนโลยี Application- Specific Integrated Circuits (ASICs) ทำ ให้สามารถออกแบบ IC สำหรับใช้งานเฉพาะ ทำได้อย่าง รวดเร็วและมีราคาถูก สถาปัตยกรรมแบบ RISC ทำให้โปรแกรมทำงานได้เร็ว ขึ้นมาก จนสามารถใช้โปรแกรมทำงานแทน Hardware ได้ ดังนั้นการออกแบบ Embedded System ใน ปัจจุบัน วิศวกรที่ออกแบบ Hardware และ โปรแกรมเมอร์จำเป็นจะต้องทำงานร่วมกันมากขึ้น พิจารณาผลดีผลเสียของการออกแบบ Hardware และ Software เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด
การพัฒนาโปรแกรมโดยใช้ MPLAB X IDE โปรแกรมที่ต้องใช้ MPLAB X IDE (Assembler Only) MPLAB XC (C Compiler) XC8 (PIC10/12/16/18) XC16 (PIC24, dsPIC) XC32 (PIC32)
การพัฒนาโปรแกรม
Window>PIC Memory Views>Configuration Bits
#include <xc.h> // CONFIG1 #pragma config WDTEN = OFF #pragma config STVREN = ON #pragma config XINST = OFF #pragma config CP0 = OFF // CONFIG2 #pragma config FOSC = HSPLL #pragma config FCMEN = ON #pragma config IESO = ON #pragma config WDTPS = 32768 // CONFIG3 #pragma config EASHFT = ON #pragma config MODE = XM16 #pragma config BW = 16 #pragma config WAIT = OFF #pragma config CCP2MX = DEFAULT #pragma config ECCPMX = DEFAULT #pragma config PMPMX = DEFAULT #pragma config MSSPMSK = MSK7 int main(void) { return 0; }
โครงสร้างการเขียนโปรแกรมภาษา C /* Include Files */ #include <p18xxxxx.h> #include … ….. /* Symbol Definitions */ #define MAX 100 #define … …. #pragma config WDTEN = OFF /* Global Variables */ int x,y,z,….. char a, b, c,…… /* Function Declarations */ int Func(char r) { int x,y; …………. return … } …. /* Start of MAIN Program */ void main(void) …………..
โครงสร้างการเขียนโปรแกรมภาษา C /* Include Files */ #include <p18xxxxx.h> #include … ….. /* Symbol Definitions */ #define MAX 100 #define … …. #pragma config WDTEN = OFF /* Global Variables */ int x,y,z,….. char a, b, c,…… Preprocessor Directive ไม่ได้เป็นคำสั่งที่สั่งให้ PIC ทำงาน แต่เป็นคำสั่งที่ใช้ MPLab C18 ทำงานบางอย่างเช่นคำสั่ง #include <p18xxxxx.h> เป็นคำสั่งให้ใส่ข้อมูลที่อยู่ใน p18xxxxx.h ไว้ที่ตำแหน่งของคำสั่ง include #define MAX 100 เป็นคำสั่งให้นำ 100 ไปแทน MAX ทุกครั้งที่เจอ #pragma config … เป็นคำสั่งใช้เลือกชนิดของสัญญาณนาฬิกา หรือใช้สั่งเปิดหรือปิด (Enable/Disable) Watchdog Timer เป็นต้น /* Function Declarations */ int Func(char r) { int x,y; …………. return … } …. /* Start of MAIN Program */ void main(void) …………..
โครงสร้างการเขียนโปรแกรมภาษา C Function ฟังก์ชันในภาษา C แบ่งออกเป็น 2 ชนิดคือ ฟังก์ชัน main เป็นฟังก์ชันที่ถูกเรียกเป็นฟังก์ชันแรกในโปรแกรมภาษา C ทุกโปรแกรมจำเป็นจะต้องมีฟังก์ชัน main เสมอและต้องมีเพียงตัวเดียว ฟังก์ชันย่อย คือฟังก์ชันที่ถูกเรียกโดยฟังก์ชัน main หรือถูกเรียกโดยฟังก์ชันย่อยอื่นๆ การใช้ฟังก์ชันย่อยจะทำให้เขียนโปรแกรมได้ง่ายขึ้น /* Include Files */ #include <p18xxxxx.h> #include … ….. /* Symbol Definitions */ #define MAX 100 #define … …. #pragma config WDTEN = OFF /* Global Variables */ int x,y,z,….. char a, b, c,…… /* Function Declarations */ int Func(char r) { int x,y; …………. return … } …. /* Start of MAIN Program */ void main(void) …………..
โครงสร้างการเขียนโปรแกรมภาษา C /* Include Files */ #include <p18xxxxx.h> #include … ….. /* Symbol Definitions */ #define MAX 100 #define … …. #pragma config WDTEN = OFF /* Global Variables */ int x,y,z,….. char a, b, c,…… /* Function Declarations */ int Func(char r) { int x,y; …………. return … } …. /* Start of MAIN Program */ void main(void) ………….. Local Variable ตัวแปรทุกตัวที่ถูกสร้างอยู่ภายในฟังก์ชัน จะเรียกว่าตัวแปรชนิด Local ตัวแปรชนิด Local ถูกเรียกใช้ได้เฉพาะภายในฟังก์ชันที่มันถูกสร้างเท่านั้น Global Variable ตัวแปรทุกตัวที่ถูกสร้างอยู่ภายนอกฟังก์ชัน จะเรียกว่าตัวแปรชนิด Global ตัวแปรชนิด Global สามารถเรียกใช้โดยฟังก์ชันใดก็ได้ในโปรแกรม
การใช้คำสั่ง #include การเขียนภาษา C เราสามารถแยกเขียน ฟังก์ชัน, ค่าคงที่, หรือตัวแปรต่างๆ ไว้ใน Library หรือในไฟล์ภาษา C อื่นๆ เพื่อ ความสะดวกในการเขียนโปรแกรม การแยกเขียนโปรแกรมออกเป็นหลาย Library หรือไฟล์ จำเป็นจะต้องประกาศ (Declaration) ชื่อฟังก์ชัน, ค่าคงที่และ ตัวแปรเหล่านี้ไว้ใน Header File เราจำเป็นต้องประกาศใช้ header file ที่ ต้องใช้ไว้ในโปรแกรมที่เขียน ตัวอย่างเช่น #include <ชื่อ Header file> หรือ #include “c:\\folder\\header.h” /*demo1.c*/ #include <xc.h> // Header file สำหรับ PIC Device #include <adc.h> // Header file สำหรับฟังก์ชัน ADC #include <delays.h> // Header file สำหรับฟังก์ชัน Delay #include <timers.h> // Header file สำหรับฟังก์ชัน Timer
การใช้คำสั่ง #define เพื่อให้เขียนโปรแกรมได้ง่าย ใน บางครั้งเราอาจจะแทนตัวเลขที่เป็น ค่าคงที่ ด้วยชื่อที่มีความหมาย ในภาษา C เราใช้คำสั่ง #define เพื่อแทนค่าคงที่ด้วยชื่อที่เรา ต้องการ #define NUMBER_OF_LEDS 8 …. void main(void) { shift %=8; } #define NUMBER_OF_LEDS 8 …. void main(void) { shift %=NUMBER_OF_LEDS; }
การใช้คำสั่ง #pragma #pragma config เป็นคำสั่งที่สั่งให้ MPLab C18 ตั้งค่าต่างๆของ PIC #pragma code เป็นคำสั่งที่สั่งให้ MPLab C18 นำ โปรแกรมหรือตัวแปรไปเก็บไว้ในหน่วยความจำโปรแกรม #pragma config FOSC = INTIO67 #pragma config WDTEN = OFF, LVP = OFF, MCLRE = OFF #pragma code int result; int shift; void main(void) { …. }
ฟังก์ชันสามารถถูกเรียกโดยฟังก์ชัน main หรือฟังก์ชันย่อยอื่นๆ ได้ การเขียนโปรแกรมที่ดีจะต้องแบ่งหน้าที่การทำงานของโปรแกรม ออกเป็นการทำงานย่อยหลายๆงาน โดยที่แต่ละงานจะถูกเขียนใน ฟังก์ชัน ฟังก์ชันสามารถถูกเรียกโดยฟังก์ชัน main หรือฟังก์ชันย่อยอื่นๆ ได้ float SinWave(float A, float t); Void SendWave(char x); void main(void) { float t,Output; for(t=0;t<1.0;t+=0.1) Output = SinWave(255.0,t); SendWave(Output); } float SinWave(float A,float t) { return A*sin(2.0*3.14*t); } void SendWave(float x) PORTA = (char) x;
การสร้างฟังก์ชัน returntype คือชนิดของตัวแปรที่ จะส่งคืนจากฟังก์ชัน name ชื่อฟังก์ชัน type var1 ชนิดและชื่อของตัว แปรอินพุทของฟังก์ชัน ชื่อในภาษา C เป็นแบบ case sensitive คือฟังก์ชันหรือตัวแปรที่ มีชื่อเหมือนกันแต่มีตัวอักษรเล็กใหญ่ ไม่เหมือนกันจะหมายถึงคนละฟังก์ชัน หรือคนละตัวแปรเช่น funca, FuncA, funcA returntype name(type var1,type var2,…) { body return A*sin(2.0*3.14*t); }
การสร้างฟังก์ชัน โปรแกรมของฟังก์ชันจะต้องเขียน อยู่ในเครื่องหมายปีกกาเสมอ return เป็นคำสั่งที่ใช้คืนค่าออก จากฟังก์ชัน จะต้องถูกเรียกก่อน ออกจากฟังก์ชันเสมอ ฟังก์ชันที่ไม่มีการคืนค่า ไม่ จำเป็นต้องมีคำสั่ง return และ กำหนดให้ returntype เป็น void returntype name(type var1,type var2,…) { body return A*sin(2.0*3.14*t); }
ต้องประกาศฟังก์ชันก่อนทุกครั้งที่ จะถูกเรียกใช้ float SinWave(float x); Void SendWave(char x); void main(void) { float t,Output; for(t=0;t<1.0;t+=0.1) Output = SinWave(255.0,t); SendWave(Output); }
ชนิดของตัวแปร
การเปลี่ยนชนิดของตัวแปร ถ้าต้องการเปลี่ยนชนิดของตัวแปรจะต้องทำการ cast เสมอ เช่น void SendWave(float x) { PORTA = (char) x; }
Local & Global Variable Local Variable คือตัวแปรที่สามารถใช้ได้ในฟังก์ชันที่มีการประกาศ ไว้เท่านั้น Global Variable คือตัวแปรที่สามารถเรียกใช้ในฟังก์ชันใดๆก็ได้ float SinWave(float x); Void SendWave(void); float x; // x is global variable void main(void) { float x; // x is local variable for(x=0;x<1.0;x+=0.1) Output = SinWave(255.0,x); SendWave(); } void SinWave(float A,float t) { x = A*sin(2.0*3.14*t); // x is global variable } void SendWave(void) PORTA = (char) x; // x is global variable
ตัวแปร Array void main(void) { int LED[] ={ 0b00000001, 0b00000010, TRISAbits.TRISA0=1; TRISD = 0; PORTD = 0; ADCON1 = 0b00001110; ADCON2 = 0b10001010; ADCON0bits.ADON = 1; while(1) { ADCON0bits.GO=1; while(ADCON0bits.GO); result = ADRES; result >>=2; if(result==0) result = 1; PORTD=LED[shift]; shift++; shift %=8; Delay10KTCYx(result); }
การจบคำสั่งและการเขียน comment คำสั่งแต่ละคำสั่งจะต้องต่อด้วยเครื่องหมาย ; เสมอ เช่น int x,y; x = A*sin(2.0*3.14*t); การเขียน comment ทำได้ 2 วิธีคือ // comment ใช้ในกรณีที่ต้องการเขียนเพียงบรรทัดเดียว /* comment ใช้ในกรณีที่ต้องการเขียนหลายบรรทัด */
จงอธิบายการทำงานของโปรแกรม #include <xc.h> void main(void) { char Comm[20]; GetComm(Comm); if(Cmp(Comm,”Left”)) turnLeft(); if(Cmp(Comm,”Right”)) turnRight(); } int Cmp(char *IComm,char *OComm) { int i; for(i=0;;i++) if(IComm[i]!=OComm[i]) return 0; if(IComm[i]==0) return 1; }