Electoday 4.0

ไมโครคอนโทรลเลอร์ => Other MCUs => Topic started by: Chunate on September 30, 2013, 04:56:35 pm

Title: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: Chunate on September 30, 2013, 04:56:35 pm
ผมทำโปรเจคจบเสดแล้ว  ตอนทำเล่ม อาจารย์เห็น โค้ด แล้วเค้าบอกให้มาแก้โดยการ ย่อโค้ดได้มั้ย  ผม ไม่ค่อยเก่งคับ เลย เขียน ตรง ๆ พี่ ๆ ในนี้ มีใครช่วยหน่อยครับ ย่อโค้ด หรือใช้เทคนิคอะไร แนะนำหน่อยครับ

ใกล้ผ่านแล้ว  เป็นโค้ด สั่งงานมอเตอร์ 2 ตัว หน่วงเวลาหยุดครับ แล้ว จะมีมอเตอร์อีก 1 ตัว หยุดโดย ใช้ เซนเซอร์

Code: [Select]
#include <reg51.h>
#include <stdio.h>

sbit DCCR=P0^0; // DC Chanal Right
sbit DCCL=P0^1; // DC Chanal Left
sbit DCTG=P0^2; // DC Transfer Right
sbit DCTB=P0^3; // DC Transfer Left
sbit DCFU=P0^4; // DC Floor UP
sbit DCFD=P0^5; // DC Floor DOWN
sbit sen1=P1^0; //
sbit sen2=P1^1; //
sbit sen3=P1^2; //
sbit sen4=P1^3; //
sbit sen5=P1^4; //
sbit sen6=P1^5; //
sbit sen7=P1^6; //
sbit sen8=P1^7; //

void init_time0(void){
ET0=1;   //Enable Timer 0 Interrupts
TR0=1;   //Start Timer 0 Running
EA=1;   // Start Interrupt Enable
}


void delay(unsigned int n){
int x,y;
for(x=0;x<n;x++){
for(y=0;y<150;y++){

}
}       


void main(){
 
char a;
TR1=1;   // Timer1 Disable
TMOD=0x21;    // Set Timer1 as Mode 2
TH1=0xFD;   // Set buad rate 9600 bps
SCON=0x50; //registor control serial port   // Uart Enable and Set Uart as Mode1
DCFU=0;
DCFD=0;
DCCR=0;
DCCL=0;
DCTB=0;
DCTG=0;
sen1=1;
sen2=1;
sen3=1;
sen4=1;
sen5=1;
sen6=1; sen7=1; sen8=1;

 

while(1){
a=_getkey();
switch(a){


//////////////// /////////////
case 'A':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen2==0);
DCCL=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
break;

case 'a':

do{
DCCL=1;}
while(sen2==0);
DCCL=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;


break;

case 'B':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen3==0);
DCCL=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
break;

case 'b':
do{
DCCL=1;}
while(sen3==0);
DCCL=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;

break;

case 'C':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen4==0);
DCCL=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;

break;

case 'c':
do{
DCCL=1;}
while(sen4==0);
DCCL=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;

break;
 
case 'D':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen5==0);
DCCR=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCL=1;}
while(sen1==0);

DCCL=0;

break;

case 'd':
do{
DCCR=1;}
while(sen5==0);
DCCR=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen1==0);
DCCL=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;

break;

case 'E':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen6==0);
DCCR=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCL=1;}
while(sen1==0);

DCCL=0;

break;

case 'e':
do{
DCCR=1;}
while(sen6==0);
DCCR=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen1==0);
DCCL=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;

break;

case 'F': 
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen7==0);
DCCR=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCL=1;}
while(sen1==0);

DCCL=0;

break;

case 'f':
do{
DCCR=1;}
while(sen7==0);
DCCR=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen1==0);
DCCL=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;

break;

case 'G':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCR=1;}
while(sen8==0);
DCCR=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;
delay (1000);
do{
DCCL=1;}
while(sen1==0);

DCCL=0;

break;

case 'g':
do{
DCCR=1;}
while(sen8==0);
DCCR=0;
delay (1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
  delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
do{
DCCL=1;}
while(sen1==0);
DCCL=0;
delay (1000);

DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay (3500);
DCTB=0;

break;
   ////////////Floor 2
case 'H':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFU=1;
delay (8000);
DCFU=0;
delay (1000);
DCTG=1;
delay(3500);
DCTG=0;
delay(1000);
DCFD=1;
delay(2500);
DCFD=0;
delay(1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8500);
DCFD=0;
delay (1000);
break;

case 'h':
DCFU=1;
delay(8000);
DCFU=0;
delay(1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8000);
DCFD=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;

break;

case 'I':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);

DCFU=1;
delay (8000);
DCFU=0;
delay (1000);
do{
DCCL=1;}
while(sen2==0);
DCCL=0;
delay (1000);
DCTG=1;
delay(3500);
DCTG=0;
delay(1000);
DCFD=1;
delay(2500);
DCFD=0;
delay(1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8500);
DCFD=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;

break;

case 'i':
DCFU=1;
delay(8000);
DCFU=0;
delay(1000);
do{
DCCL=1;}
while(sen2==0);
DCCL=0;
delay(1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8000);
DCFD=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);
DCFD=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;

break;

case 'J':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);

DCFU=1;
delay (8000);
DCFU=0;
delay (1000);
do{
DCCL=1;}
while(sen3==0);
DCCL=0;
delay (1000);
DCTG=1;
delay(3500);
DCTG=0;
delay(1000);
DCFD=1;
delay(2500);
DCFD=0;
delay(1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8500);
DCFD=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;

break;

case 'j':

DCFU=1;
delay(8000);
DCFU=0;
delay(1000);
do{
DCCL=1;}
while(sen3==0);
DCCL=0;
delay(1000);
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8000);
DCFD=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;
delay (1000);
DCTG=1;
delay (3500);
DCTG=0;
delay (1000);
DCFD=1;  
delay (3000);DCFD=0;delay (1000);


DCTB=1;
delay(3500);
DCTB=0;

break;

case 'K':
DCTG=1;  
delay (3500);
DCTG=0;
delay (1000);
DCFU=1;
delay (3000);
DCFU=0;
delay (1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);

DCFU=1;
delay (8000);
DCFU=0;
delay (1000);
do{
DCCL=1;}
while(sen4==0);
DCCL=0;
delay (1000);
DCTG=1;
delay(3500);
DCTG=0;
delay(1000);
DCFD=1;
delay(2500);
DCFD=0;
delay(1000);
DCTB=1;
delay(3500);
DCTB=0;
delay (1000);
DCFD=1;  
delay (8500);
DCFD=0;
delay (1000);
do{
DCCR=1;}
while(sen1==0);
DCCR=0;

break; 


}
}
}




โค้ด มี ประมานนี้ แต่เคสเยอะมากเพราะต้องทำงานหลายช่อง โพสหมดไม่ได้ เกินกำหนด อักษรครับ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on September 30, 2013, 05:17:06 pm
เอาโค้ดไปโพสที่ http://pastebin.com/ (http://pastebin.com/) ก็ได้ครับแล้วเอาลิงค์มาแปะ
ถ้าการทำงาน มันซ้ำๆ กันไปมา ทำเป็น function อีก function ก็ได้ครับ ไม่จำเป้นต้องมี main loop อย่างเดียว แล้วก็เรียก function นั้นมาทำงาน... อ่ะคับ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: wozniak on October 01, 2013, 10:35:31 am
เมื่อมี Code ที่ทำงานซ้ำๆมากๆ ขอแนะนำให้ดูเรื่อง การเขียน Macro และการสร้า่ง function หรือ subroutine จะช่วยได้

หากเป็นเรื่อง Macro ลองศึกษาได้จากที่นี่ครับ http://www.cprogramming.com/tutorial/cpreprocessor.html
ในหัวข้อเรื่อง Macro โดย Macro ทำตัวเป็นการแทนที่คำสั่งลงไป เวลาใช้ก็ตั้งชื่อให้สื่อกับความหมายในการสร้าง Macro นั้นได้ก็จะทำให้ดูง่ายขึ้นบ้าง (หลีกเลี่ยงการตั้งชื่อแบบ MAC_01 , MAC_02 มันไม่สื่อ) และมักนิยมตั้งชื่อของ Macro ให้เป็นตัวใหญ่กัน
อย่างไรก็ตาม Macro จะยังไม่มีประสิทธิภาพนักกับเรื่องของการทำ Code (แค่เขียน Code สั้นลงบ้าง)
จากกรณี Code ข้างบน อาจเขียน Macro ทำเป็นตัวอย่างสักตัว เพื่อ Guide ให้นะ ที่เหลือลองคิดต่อเอา

Code: [Select]
#include <stdio.h>

#define PULSE_TRIGGER(pbit,ton,toff)  { pbit=1; delay(ton); pbit=0; delay(toff); }
...

เวลาใช้ก็่เขียนเพียง
...
   case 'A' :
PULSE_TRIGGER(DCTG,3500,1000); // PLUSE at DCTG
PULSE_TRIGGER(DCFU,3000,1000);        // PLUSE at DCFU
PULSE_TRIGGER(DCTB,1000,3500);        // PLUSE at DCTB
...

หากลองมาดูเรื่อง function หรือ subroutine ก็ลองอ่านได้จากที่นี่
http://en.wikipedia.org/wiki/Subroutine#C_and_C.2B.2B_examples
http://www.thepmk.ac.th/kum/tc/programming_c_7.pdf

การสร้า่ง subroutine หรือ function จะได้่ประสิทธิภาพกว่าการใ้ช้ Macro แค่วางแผนการรับส่ง ตัวแปรต่างๆให้เหมาะสม
และควรตั้งชื่อให้สื่อกับความหมายใน subroutine นั้นด้วยก็จะดีมาก (หลีกเลี่ยงการตั้งชื่อแบบ sub_01 , sub_02 เช่นกัน) และใน C มักนิยมใช้ Underscore (คือ _ แทน space ในชื่อ )
จริงๆ จาก Code ข้างบน delay ก็เป็น subroutine อย่างหนึ่ง
และจากกรณี Code ข้างบน อาจเขียน function ทำเป็นตัวอย่างสักตัวเพื่อ Guide ให้ ที่เหลือก็ลองคิดต่อเอาเองเช่นกัน

Code: [Select]
...
void pulse_trigger_DCTG(unsigned ton,unsigned toff)
{
    DCTG = 1;
    delay(ton);
    DCTG = 0;
    delay(toff);
}
...
เวลาใช้ก็่เขียนเพียง
...
   case 'A' :
pulse_trigger_DCTG(3500,1000);
...
   case 'B' :
pulse_trigger_DCTG(3500,1000);
...
   case 'C' :
pulse_trigger_DCTG(3500,1000);
...
   case 'D' :
pulse_trigger_DCTG(3500,1000);
...
   case 'E' :
pulse_trigger_DCTG(3500,1000);
...

ค่าที่ส่งมันซ้ำๆ ก็อาจเขียนร่วมกันให้สั้นได้อีก ก็ใช้ Macro และ function ร่วมกันไปเช่น

Code: [Select]
...
#define   FIX_PULSE_TRIGGER_DCTG { pulse_trigger_DCTG(3500,1000); }
...
   case 'A' :
FIX_PULSE_TRIGGER_DCTG;
...
   case 'B' :
FIX_PULSE_TRIGGER_DCTG;
...
   case 'C' :
FIX_PULSE_TRIGGER_DCTG;
...
   case 'D' :
FIX_PULSE_TRIGGER_DCTG;
...
   case 'E' :
FIX_PULSE_TRIGGER_DCTG;

ทั้งนี้ก็สามารถใช้ทั้งสองอย่างร่วมด้วยช่วยกันได้ ก็จะได้ประโยชน์อย่างเต็มที่เลย

แนะนำเพิ่มอีกนิด สามารถ เพิ่ม function หรือ subroutine ได้อีก แม้จะมีการเรียกเพียงครั้งเดียวก็ตาม ทั้งนี้เพื่อเป็นการอธิบาย ให้สื่อความว่าทำอะไร ใน function นั้น (เพราะ function ย่อมจะต้องมีชื่อ) เช่้นการ Initialize เป็นต้น
ดังนั้น ใน main อาจให้ดูง่ายๆก็ทำได้โดยใส่ function เพิ่มเข้่าไป ก็เหมือนเป็นการ อธิบายว่า main นั้นทำอะไรบ้างแล้วเช่น

Code: [Select]
...
void initialize(void )
{
   DCFU = 0;
   DCFD = 0;
  ....
}
void process_motor_program_A(void )

   ....
}
void process_motor_program_a(void )
{
  ....
}
...

void main(void )
{
    char a;

    initialize();
    while(1) {
         a = _getkey();
         switch (a) {
                   case 'A' :
                         process_motor_program_A();
                         break;
                   case 'a' :
                         process_motor_program_a();
                         break;
                   ....
         }
     }
}   


ลองศึกษาและแก้ไขด้วยตนเองนะครับ อยากให้ทำเองมากกว่านะ จะได้ประสบการณ์ที่ดี
แก้ไขด้วยตนเองได้ ตอบอาจารย์ได้ และน่าจะไม่ยากลำบากอะไร ในเรื่องย่อ Code นี้
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 01:00:38 pm
อย่างตามที่ท่าน wozniak ว่าในเคสนี้ก็ทำ macro อย่างเดียวก็ได้ครับ การทำงานอาจจะเร็วกว่า(ถ้าเขียนโค้ดไม่ผิดน่ะ)

ปล.อยากเห็นโค้ดที่เหลือเลยให้เค้าโพสทั้งหมดดีกว่า อ่ะครับ
เช่น สงสัยว่าโค้ดนี้เอาไว้ทำอะไร...
Code: [Select]
void delay(unsigned int n){
  int x,y;
    for(x=0;x<n;x++){
      for(y=0;y<150;y++){
    }
  }
}
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: ROM on October 01, 2013, 03:18:50 pm
สงสัยว่าโค้ดนี้เอาไว้ทำอะไร...
Code: [Select]
void delay(unsigned int n){
  int x,y;
    for(x=0;x<n;x++){
      for(y=0;y<150;y++){
    }
  }
}

คงเป็น Soft delay ในการ วน Loop เพื่อให้ MCU หน่วงเวลาออกไป โดยให้ MCU มานับตัวแปร x,y เล่น
http://geniusdevils.com/2013/03/1-millisecond-delay-in-8051-c-program/
ซึ่งเป็นการเขียน function หน่วงเวลาแบบง่ายๆ อาจไม่ค่อยแม่นยำนัก แต่ก็ง่ายในการทำงานในการหน่วงเวลา

การเขียนแบบนี้บน PC (เดาจาก Signature ของท่านเว่า GNU/Linux User เป็นกลุ่ม PC ) คงจะไม่ค่อยเห็นใครเขียนแบบนี้ เพราะมี function ให้ใช้ อย่าง sleep หรือ delay เลย เนื่องเพราะมี library ให้พร้อมมาจาก OS เลยได้ใช้ง่ายๆ
แต่ใน Micro controller ที่มักไม่ค่อยมี OS อะไรกับเขา (มีก็อาจใช้ และติดตั้งไม่ง่ายนัก หรือไม่พอลงกับ MCU ได้)
มักต้องมาเขียนมาทำทุกอย่างเองสารพัดโดยลำพัง มี Lib มาจาก Compiler ก็นิดๆหน่อยๆ ต้องไปหาเอาเองจากพวกข้างนอกมาใช้ ใช้ได้มั้งไม่ได้มั้ง สุดแท้แต่จะแปลงกันมา ดังนั้นอย่าแปลกใจครับ หากเห็นเขียน Code กันแปลกๆ สำหรับพวก embedded เล็กๆ อย่าง MCU พวกนี้ ยิ่ง 8 bit นี้ บางตัว malloc ยังทำไม่ได้เลย resource น้อยเกิน อะไรๆ ก็เลยลำบาก  :'(
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 03:56:49 pm
สงสัยว่าโค้ดนี้เอาไว้ทำอะไร...
Code: [Select]
void delay(unsigned int n){
  int x,y;
    for(x=0;x<n;x++){
      for(y=0;y<150;y++){
    }
  }
}

คงเป็น Soft delay ในการ วน Loop เพื่อให้ MCU หน่วงเวลาออกไป โดยให้ MCU มานับตัวแปร x,y เล่น
http://geniusdevils.com/2013/03/1-millisecond-delay-in-8051-c-program/
ซึ่งเป็นการเขียน function หน่วงเวลาแบบง่ายๆ อาจไม่ค่อยแม่นยำนัก แต่ก็ง่ายในการทำงานในการหน่วงเวลา
แต่ตัว MCU ยังทำงานอยู่น่ะ(ประมาณยังคำนวณตัวเลข(ALU)) มันไม่ได้แบบ NOP จริงๆ หรือผมเข้าใจอะไรผิดหว่า = ="
http://www.keil.com/forum/2938/ (http://www.keil.com/forum/2938/)
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: ROM on October 01, 2013, 04:10:34 pm
Code: [Select]
แต่ตัว MCU ยังทำงานอยู่น่ะ(ประมาณยังคำนวณตัวเลข) มันไม่ได้แบบ NOP จริงๆ หรือผมเข้าใจอะไรผิดหว่า = ="
http://www.keil.com/forum/2938/

MCU ยังทำงานครับ แต่นับตัวแปรเล่นอยู่ ส่วนจะได้เวลาในการทำงานเท่าใด ก็คงดูที่ asm listing ว่ามี คำสั่งภาษา assembly อะไรบ้่าง ทำไปกี่รอบ แล้วเอาไปคำนวณดู ซึ่งอาจเกิดจากปัจจัยหลายอย่าง ในการเกิดคำสั่งของ asm นี้ โดยอาจเกี่ยวข้องกับ compiler ในแต่ละ version การตั้ง optimizer หรือ อื่นๆ หรือถ้าจะให้ชัดเจนไปคงต้องเขียน assembly ในส่วน delay นี้เอาเองครับ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 04:19:18 pm
Code: [Select]
แต่ตัว MCU ยังทำงานอยู่น่ะ(ประมาณยังคำนวณตัวเลข) มันไม่ได้แบบ NOP จริงๆ หรือผมเข้าใจอะไรผิดหว่า = ="
http://www.keil.com/forum/2938/

MCU ยังทำงานครับ แต่นับตัวแปรเล่นอยู่ ส่วนจะได้เวลาในการทำงานเท่าใด ก็คงดูที่ asm listing ว่ามี คำสั่งภาษา assembly อะไรบ้่าง ทำไปกี่รอบ แล้วเอาไปคำนวณดู ซึ่งอาจเกิดจากปัจจัยหลายอย่าง ในการเกิดคำสั่งของ asm นี้ โดยอาจเกี่ยวข้องกับ compiler ในแต่ละ version การตั้ง optimizer หรือ อื่นๆ หรือถ้าจะให้ชัดเจนไปคงต้องเขียน assembly ในส่วน delay นี้เอาเองครับ
ผมว่ามันไม่จำเป็นน่ะครับ มันเปลืองทรพยากร
USING NOP IN C...
http://www.keil.com/support/docs/2315.htm
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: ROM on October 01, 2013, 04:30:36 pm
Quote
ผมว่ามันไม่จำเป็นน่ะครับ มันเปลืองทรพยากร
USING NOP IN C...
http://www.keil.com/support/docs/2315.htm

แล้ว ต้องใช้  _nop_ (); เท่าไหร่ครับ ถึงจะ delay ได้นานๆ
อย่างสัก 10  millisecond ครับ ที่เขาเขียนนับตัวแปรก็ด้วยเรื่องนี้ครับ
เพราะ _nop_(); มัน delay ได้สั้นมาก
ลองดู
http://www.keil.com/support/man/docs/is51/is51_nop.htm
มันใช้  delay แค่ 1 cycle ของ MCU เองนะ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 04:32:52 pm
Quote
การเขียนแบบนี้บน PC (เดาจาก Signature ของท่านเว่า GNU/Linux User เป็นกลุ่ม PC ) คงจะไม่ค่อยเห็นใครเขียนแบบนี้ เพราะมี function ให้ใช้ อย่าง sleep หรือ delay เลย เนื่องเพราะมี library ให้พร้อมมาจาก OS เลยได้ใช้ง่ายๆ
แต่ใน Micro controller ที่มักไม่ค่อยมี OS อะไรกับเขา (มีก็อาจใช้ และติดตั้งไม่ง่ายนัก หรือไม่พอลงกับ MCU ได้)
มักต้องมาเขียนมาทำทุกอย่างเองสารพัดโดยลำพัง มี Lib มาจาก Compiler ก็นิดๆหน่อยๆ ต้องไปหาเอาเองจากพวกข้างนอกมาใช้ ใช้ได้มั้งไม่ได้มั้ง สุดแท้แต่จะแปลงกันมา ดังนั้นอย่าแปลกใจครับ หากเห็นเขียน Code กันแปลกๆ สำหรับพวก embedded เล็กๆ อย่าง MCU พวกนี้ ยิ่ง 8 bit นี้ บางตัว malloc ยังทำไม่ได้เลย resource น้อยเกิน อะไรๆ ก็เลยลำบาก  :'(
GNU/Linux ไม่ได้มีแต่ใน PC น่ะครับ(แอบเศร้า) :'(
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 04:34:50 pm
Quote
ผมว่ามันไม่จำเป็นน่ะครับ มันเปลืองทรพยากร
USING NOP IN C...
http://www.keil.com/support/docs/2315.htm

แล้ว ต้องใช้  _nop_ (); เท่าไหร่ครับ ถึงจะ delay ได้นานๆ
อย่างสัก 10  millisecond ครับ ที่เขาเขียนนับตัวแปรก็ด้วยเรื่องนี้ครับ
เพราะ _nop_(); มัน delay ได้สั้นมาก
ลองดู
http://www.keil.com/support/man/docs/is51/is51_nop.htm
มันใช้  delay แค่ 1 cycle ของ MCU เองนะ
คำตอบอยู่ใน link แรกแล้วครับ = =" หรือว่าไม่ใช่หว่า
Code: [Select]
#include <intrins.h>

void DelayMS(unsigned char ms)
{
unsigned long us = 1000*ms;

while (us--)
  {
  _nop_();
  }
}
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: ROM on October 01, 2013, 04:49:57 pm
GNU/Linux ไม่ได้มีแต่ใน PC น่ะครับ(แอบเศร้า) :'(
ผมหมายถึงประเภท Computer มากกว่านะครับ อาจรวมไปถึง embedded linux และอื่นๆ ด้วยครับ
ที่ไม่ค่อยมีข้อจำกัดอะไรนัก ทั้งเร็ว ทั้งแรง resource มาก ขออภัยอาจจะใช้คำไม่ถูก อย่าเศร้าน่า  :)
แต่ขอแยกกันกับ MCU เพราะเล็กกว่ามาก ข้อจำกัดมากกว่า และที่กล่าวอาจก็จะอ้างอิงกับ 8 bit บางตัวด้วยซ้ำนะครับ
เศร้ากว่ากันเยอะ  :'(

Quote
ผมว่ามันไม่จำเป็นน่ะครับ มันเปลืองทรพยากร
USING NOP IN C...
http://www.keil.com/support/docs/2315.htm

แล้ว ต้องใช้  _nop_ (); เท่าไหร่ครับ ถึงจะ delay ได้นานๆ
อย่างสัก 10  millisecond ครับ ที่เขาเขียนนับตัวแปรก็ด้วยเรื่องนี้ครับ
เพราะ _nop_(); มัน delay ได้สั้นมาก
ลองดู
http://www.keil.com/support/man/docs/is51/is51_nop.htm
มันใช้  delay แค่ 1 cycle ของ MCU เองนะ
คำตอบอยู่ใน link แรกแล้วครับ = =" หรือว่าไม่ใช่หว่า
Code: [Select]
#include <intrins.h>

void DelayMS(unsigned char ms)
{
unsigned long us = 1000*ms;

while (us--)
  {
  _nop_();
  }
}

มันก็มี ตัวแปรชื่อ us ให้ MCU คอยนับอยู่นี่ครับ MCU ก็นับตัวแปรเล่นเหมือนกัน ก็ใช้ resource เหมือนกัน
แม้จะเขียนต่างกันไปบ้าง แต่หลักการก็คล้ายๆกัน
ผมก็เลยยังสงสัยว่า ท่านงงตรงไหน ? หรือผมพลาดตรงไหน ?
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 05:13:39 pm
GNU/Linux ไม่ได้มีแต่ใน PC น่ะครับ(แอบเศร้า) :'(
ผมหมายถึง Computer มากกว่านะครับ อาจรวมไปถึง embedded linux ด้วยครับ
ขออภัยอาจจะใช้คำไม่ถูก อย่าเศร้าน่า
แต่ขอแยกกันกับ MCU เพราะเล็กกว่า ที่กล่าวอาจจะอิงกับ 8 bit ด้วยซ้ำนะครับ

Quote
ผมว่ามันไม่จำเป็นน่ะครับ มันเปลืองทรพยากร
USING NOP IN C...
http://www.keil.com/support/docs/2315.htm

แล้ว ต้องใช้  _nop_ (); เท่าไหร่ครับ ถึงจะ delay ได้นานๆ
อย่างสัก 10  millisecond ครับ ที่เขาเขียนนับตัวแปรก็ด้วยเรื่องนี้ครับ
เพราะ _nop_(); มัน delay ได้สั้นมาก
ลองดู
http://www.keil.com/support/man/docs/is51/is51_nop.htm
มันใช้  delay แค่ 1 cycle ของ MCU เองนะ
คำตอบอยู่ใน link แรกแล้วครับ = =" หรือว่าไม่ใช่หว่า
Code: [Select]
#include <intrins.h>

void DelayMS(unsigned char ms)
{
unsigned long us = 1000*ms;

while (us--)
  {
  _nop_();
  }
}

มันก็มี ตัวนับ us อยู่นะครับ MCU ก็นับตัวแปรเล่นเหมือนกัน ก็ใช้ resource เหมือนกัน
ผมไม่เข้าใจ ว่าท่านงงอะไร ?
จะว่านับก็ได้ครับ แต่เวลาใน asm จริงๆ มันไม่เหมือนกันน่ะครับ ผมอธิบายตามที่ผมเข้าใจก่อนน่ะ
จากโค้ดของ NOP
ใน loop while
เซ็ตค่า us แล้วจะมีการเช็ค us ว่าเป็น 0 รึเปล่า แล้วทำการลดค่า us โดย 1 ประมาณ us-1 แล้วทำการ NOP แล้วมาเช็คใหม่
ใน asm ก็ประมาณ 4 instuction(เซ็ต us ผมไม่นับเพราะอยู่นอกลูป)

ถ้าเป้น for loop ดังเดิม
- ตัวแปรเพิ่ม
ให้ x=0,y=0 ประมาณ 2 instuction(นับแต่ y ก็ 1 instuction เพราะมีการกำหนดใหม่ทุกครั้ง (mov))
เช็ค x<n และ y<150 ประมาณ 2 instuction + jump อีก 2 instuction
x++,y++ ประมาณ 2 instuction
รวม 1+2+2+2 = 7

ค่าต่างๆ เป็นค่าประมาณน่ะครับ

ส่วนที่มันเหมือนกันนี่ไปไม่ถูกเลย lolz
http://stackoverflow.com/questions/17896714/why-would-introducing-useless-mov-instructions-speed-up-a-tight-loop-in-x86-64-a (http://stackoverflow.com/questions/17896714/why-would-introducing-useless-mov-instructions-speed-up-a-tight-loop-in-x86-64-a)
เจอลิงค์ที่อธิบายที่ดีกว่า http://www.win.tue.nl/~aeb/comp/8051/set8051.html#51nop (http://www.win.tue.nl/~aeb/comp/8051/set8051.html#51nop) เผื่อมีคนมาอ่าน
เข้าว่าโดยพื้นฐาน การทำงานน่าจะเหมือนกันน่ะครับ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 05:28:37 pm
Quote
ผมหมายถึงประเภท Computer มากกว่านะครับ อาจรวมไปถึง embedded linux และอื่นๆ ด้วยครับ
ที่ไม่ค่อยมีข้อจำกัดอะไรนัก ทั้งเร็ว ทั้งแรง resource มาก ขออภัยอาจจะใช้คำไม่ถูก อย่าเศร้าน่า  :)
แต่ขอแยกกันกับ MCU เพราะเล็กกว่ามาก ข้อจำกัดมากกว่า และที่กล่าวอาจก็จะอ้างอิงกับ 8 bit บางตัวด้วยซ้ำนะครับ
เศร้ากว่ากันเยอะ  :'(
embedded linux ที่นี่ ไม่มี 8 bit บ้างรึครับ?  เศร้า :'(
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: JENG on October 01, 2013, 05:46:32 pm
คุยไรกันครับนี่ ...  ;D
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: ROM on October 01, 2013, 05:47:51 pm
Quote
embedded linux ที่นี่ ไม่มี 8 bit บ้างรึครับ?  เศร้า
ท่านนี่เศร้าง่ายนะ 8 bit ก็มีสิครับ สมัยก่อนผมก็ใช้อยู่ แต่ตอนนี้ ผมหมายถึง MCU เล็กๆกว่านั้นครับ
ที่ไม่มี resource อะไรมาก ทำอะไรก็ไม่ค่อยได้มากนักนะ

จะว่านับก็ได้ครับ แต่เวลาใน asm จริงๆ มันไม่เหมือนกันน่ะครับ ผมอธิบายตามที่ผมเข้าใจก่อนน่ะ
จากโค้ดของ NOP
ใน loop while
จะมีการเช็ค us ว่าเป็น 0 รึเปล่า แล้วทำการลดค่า us โดย 1 ประมาณ us-1 แล้วทำการ NOP แล้วมาเช็คใหม่
ใน asm ก็ประมาณ 3 instuction

ถ้าเป้น for loop ดังเดิม
- ตัวแปรเพิ่ม
ให้ x=0,y=0 ประมาณ 2 instuction
เช็ค x<n และ y<150 ประมาณ 2 instuction + jump อีก 2 instuction
x++,y++ ประมาณ 2 instuction

ส่วนที่มันเหมือนกันนี่ไปไม่ถูกเลย lolz
http://stackoverflow.com/questions/17896714/why-would-introducing-useless-mov-instructions-speed-up-a-tight-loop-in-x86-64-a (http://stackoverflow.com/questions/17896714/why-would-introducing-useless-mov-instructions-speed-up-a-tight-loop-in-x86-64-a)
เข้าว่าโดยพื้นฐาน การทำงานน่าจะเหมือกันน่ะครับ

พยายามจะทำให้ท่านเข้่าใจนะ บางที ผมอาจใช้คำว่า เหมือนบ้าง คล้ายบ้าง อย่าเพิ่งสับสนนะ
คือทั้ง 2 code เป็นการ delay ทั้งคู่ก็เหมือนกันนะ ใช้ตัวแปรนับเหมือนกัน (แม้อาจมีความแตกต่างในการมาคำนวณก่อน แต่สุดท้ายก็เกิดการนับ ) และก็อาจจะได้ ชุดคำสั่งของ asm แตกต่างกันอยู่บ้างครับ ผมก็เลยไม่รู้ว่าเป็นประเด็๋นสำหรับท่านตรงไหนหรือเปล่าครับ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 05:49:18 pm
ถ้ายังไม่เข้าใจก็
ลองเขียน for loop ประมาณหลักล้านๆ ลูป
แล้วเปรียบเทียบ
NOP ในลูป while สัก ล้านๆ ลูปดู แล้วดูว่า
อันไหนใช้ทรัพยากรเยอะกว่า? เอาผลมาดูด้วยน่ะครับ ผมก็อยากรู้เหมือนกัน
Quote
พยายามจะทำให้ท่านเข้่าใจนะ บางที ผมอาจใช้คำว่า เหมือนบ้าง คล้ายบ้าง อย่าเพิ่งสับสนนะ
คือทั้ง 2 code เป็นการ delay ทั้งคู่ก็เหมือนกันนะ ใช้ตัวแปรนับเหมือนกัน (แม้อาจมีความแตกต่างในการมาคำนวณก่อน แต่สุดท้ายก็เกิดการนับ ) และก็อาจจะได้ ชุดคำสั่งของ asm แตกต่างกันอยู่บ้างครับ ผมก็เลยไม่รู้ว่าเป็นประเด็๋นสำหรับท่านตรงไหนหรือเปล่าครับ
ครับ ผลลัพธ์ไม่ต่างครับ แต่ทรัพยากรที่ใช้ ต่างครับ
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: ROM on October 01, 2013, 05:53:57 pm
ถ้ายังไม่เข้าใจก็
ลองเขียน for loop ประมาณหลักล้านๆ ลูป
แล้วเปรียบเทียบ
NOP ในลูป while สัก ล้านๆ ลูปดู แล้วดูว่า
อันไหนใช้ทรัพยากรเยอะกว่า? เอาผลมาดูด้วยน่ะครับ ผมก็อยากรู้เหมือนกัน
Quote
พยายามจะทำให้ท่านเข้่าใจนะ บางที ผมอาจใช้คำว่า เหมือนบ้าง คล้ายบ้าง อย่าเพิ่งสับสนนะ
คือทั้ง 2 code เป็นการ delay ทั้งคู่ก็เหมือนกันนะ ใช้ตัวแปรนับเหมือนกัน (แม้อาจมีความแตกต่างในการมาคำนวณก่อน แต่สุดท้ายก็เกิดการนับ ) และก็อาจจะได้ ชุดคำสั่งของ asm แตกต่างกันอยู่บ้างครับ ผมก็เลยไม่รู้ว่าเป็นประเด็๋นสำหรับท่านตรงไหนหรือเปล่าครับ
ครับ ผลลัพธ์ไม่ต่างครับ แต่ทรัพยากรที่ใช้ ต่างครับ

ผมไม่ได้อยากรู้นะครับ พยายามช่วยท่านและอธิบายให้ ตามที่ท่านสงสัยเฉยๆครับ  ;D
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 05:56:15 pm
ถ้ายังไม่เข้าใจก็
ลองเขียน for loop ประมาณหลักล้านๆ ลูป
แล้วเปรียบเทียบ
NOP ในลูป while สัก ล้านๆ ลูปดู แล้วดูว่า
อันไหนใช้ทรัพยากรเยอะกว่า? เอาผลมาดูด้วยน่ะครับ ผมก็อยากรู้เหมือนกัน
Quote
พยายามจะทำให้ท่านเข้่าใจนะ บางที ผมอาจใช้คำว่า เหมือนบ้าง คล้ายบ้าง อย่าเพิ่งสับสนนะ
คือทั้ง 2 code เป็นการ delay ทั้งคู่ก็เหมือนกันนะ ใช้ตัวแปรนับเหมือนกัน (แม้อาจมีความแตกต่างในการมาคำนวณก่อน แต่สุดท้ายก็เกิดการนับ ) และก็อาจจะได้ ชุดคำสั่งของ asm แตกต่างกันอยู่บ้างครับ ผมก็เลยไม่รู้ว่าเป็นประเด็๋นสำหรับท่านตรงไหนหรือเปล่าครับ
ครับ ผลลัพธ์ไม่ต่างครับ แต่ทรัพยากรที่ใช้ ต่างครับ

ผมไม่ได้อยากรู้นะครับ พยายามช่วยท่านและอธิบายให้ ตามที่ท่านสงสัยเฉยๆครับ
ครับผม  ;D
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: Lastman on October 01, 2013, 10:31:13 pm
สวัสดี จขกท.

ผมมีเรื่องจะเล่าสู่กันฟัง.....ตามประสาคนเขียนโปรแกรมมาก่อนอ่ะนะ อาจจะ
ไม่เก่งมาก แต่ระดับ level น่าจะพอสอน จขกท.ได้บ้าง

เรื่องแรก...
ผมเห็น code ท่านแล้ว ถ้าผมเป็นอ.ที่สอนท่านคงปวดตับเช่นกัน  :P
ปรัชญาการมีเครื่องคอมพิวเตอร์ หรือเครื่องคิดเลขทรงประสิทธิภาพนี้ก็เพราะว่า
มันเก่งในเรื่องที่ต้องคำนวน (งานโพรเซส) หรือการทำงานซ้ำๆ (งานรูทีน) ครับ
งานพวกนี้เครื่องมันเก่ง ที่จริงมนุษย์ก็ทำได้ครับ แต่มนุษย์ขี้เกียจ และผิดพลาดบ่อย
เค้าเลยต้องโยนให้เครื่องมันทำให้

ดังนั้นถ้าโจทย์บอกว่า จงพิมพ์ "ฉันรักเธอ" 1000 ครั้ง
คนที่ใช้เครื่องเป็นเค้าจะสั่งวนลูป 1000 รอบ จบแล้ว...ง่ายไหม ?
 
แต่ถ้าเป็น จขกท. คง copy + paste "ฉันรักเธอ" 1000 บรรทัดแทนซะละมั๊ง ::)

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

=============================================

ต่อมา เรื่องที่สอง
จากปัญหาข้างต้น ทำให้ต้องเข้าใจว่า ที่จริงแล้ว คือเราต้องแบ่งโปรแกรมออกเป็นส่วนย่อย
(เรียกว่า sub routine) แล้วเรียกใช้บ่อยๆ เช่น

printf("ฉันรักเธอ")

ก็สร้างเป็น function ไว้
void i()
{ printf("ฉันรักเธอ"); }


เวลาเรียกใช้ ก็เขียนแค่ i(); 1000 ครั้งก็จบแล้ว
ถึงแม้ว่าจะคล้ายๆ การ copy + paste คำสั่ง printf("ฉันรักเธอ") พันบรรทัด,
แต่ภาพรวมมันสั้นกว่า แถมยังประหยัดหน่วยความจำเยอะนะครับ เพราะ "ฉันรักเธอ" มีแค่บรรทัดเดียว
ที่เหลือคือร่างแยก 1000 ครั้ง ไม่เหมือน printf("ฉันรักเธอ") ตรงๆ พันบรรทัดนะ อันนี้กินเนื้อที่โปรแกรมเยอะกว่า

==========================================================

เรื่องที่สาม
อย่าไปงงกับเรื่อง macro หรือ Compiler Directive
อย่าไปคิดว่า macro เขียนแทน funtion ได้ ทำงานได้เหมือนกัน...

พวกมือใหม่มักจะเข้าใจอย่างนั้น ที่จริงต้องบอกว่ามันคล้ายกัน
แต่ทางปรัชญาการเขียนโปรแกรม มันมีความแตกต่างกันมากทีเดียว

การสร้าง macro หรือการใช้ compiler directive เช่น #define มาสร้างโปรแกรมย่อย
แทนการใช้ function ถือว่าผิดเกณฑ์อย่างร้ายแรง มันแทนกันได้แต่ไม่เหมาะสม

compiler directive คือ "pre processor"  (แปลว่าให้ทำ.....ก่อน ก่อนการเอาไปประมวลผล)
หรือก็คือ มันจะกระทำตามคำสั่ง macro ที่วางไว้ก่อน ก่อนที่จะเอา source code ที่ได้นั้น
ไปเข้ากระบวนการ compile เพื่อสร้างโปรแกรมเพื่อรันในสถาปัตยกรรมนั้นๆต่อไป

เราวาง macro เพื่อให้มันทำงานสักอย่างหนึ่งตอนนั้น แต่ตัวผู้เขียนโปรแกรมเองก็ไม่รู้ว่าเป็นค่าอะไร
(แต่รู้ว่าต้องทำแน่ๆ) ก็เช่น
- ให้ใส่เลขเวอร์ชั่น ตามวันเวลาที่เขียนโปรแกรมเสร็จ ซึ่งไม่รู้เหมือนกันว่าจะเสร็จวันไหน กี่โมง ก็เลยว่า macro เอาไว้
- การให้ compile ตาม speed X'tal ที่มีตอนนั้น ซึ่งไม่รู้เหมือนกันว่าตอน compile จะไปใช้ speed อะไร ก็เลยวาง macro เอาไว้
- การย้าย source code ให้ไปรันที่ต่างสถาปัตยกรรม รู้แน่ๆ ว่ามี int ให้ใช้ แต่ไม่รู้ว่า สถาปัตยกรรมนั้นจะใช้ int ที่ 2 byte หรือ 4 byte หรือ 8 byte ก็เลยวาง macro ไว้
- ฯลฯ

จะสังเกตุได้ว่า macro จะถูกวางไว้ก่อน แล้วอ้างอิงกับมันเสมือนว่าเป็นค่าหนึ่ง แต่ก็ไม่รู้ว่าจะเป็นค่าอะไร
ดังนั้นจึงวางค่าคงที่ ที่แน่นอนใน source code ขณะนั้นๆ ไม่ได้  นั่นจึงเป็นที่มาของ macro

แล้วคุณสามารถเขียน macro แทน function ได้ไหม?
ตอบว่า "ได้" แต่ไม่ควร .... เพราะการนำ macro มา reuse ใช้ในระดับ  source code นั้นทำได้ยาก
อีกทั้ง macro ไม่ได้ถูกออกแบบมาให้เขียน function ที่ซับซ้อน จึงไม่เหมาะ
macro เป็นความสามารถพื้นฐานของ compiler ภาษาซี แต่บางภาษาไม่มี

macro คือ preprosessor ถ้าตั้งเงื่อนไขดีๆ มันสามารถช่วยในการย้ายสถาปัตยกรรมได้โดยง่าย (Portability)
เช่นเขียน library บน PC แต่เอาไปใช้ใน AVR, PIC ,ARM ได้ง่ายๆ แทบไม่ต้องเขียนใหม่
ยกตัวอย่าง int

C# = 64 bit
AVR int = 8 bit
ARM  int = 32 bit


file ใน csharp.h
#define int int64_t

file ใน avr.h
#define int int8_t

file ใน arm.h
#define int int32_t

เพียงแค่นี้ ไม่ว่าเราจะไปใช้ สถาปัตยกรรมไหน
เพียงแค่เรียก int มันจะใช้ตรงตามสถาปัตยกรรมนั้น ขอแค่ include ให้ตรงกับสถาปัตยกรรมนั้นๆ
หลักการนี้เป็นหลักการง่ายๆ ที่ใช้ port พวก linux ที่รันบน x86 ไปรันบน ARM (คนละสถาปัตยกรรมกันเลย)
หรือรันบน powerPC หรือรันบน playstation , XBOX ฯลฯ

ยิ่งถ้าวางคู่กับ ตัว compiler directive อื่นๆ จะทำให้การ compile นั้น จะได้ code native ที่
เหมาะสมกับสถาปัตยกรรมนั้นๆ มาก อุปมาเหมือน สั่งตัดเสื้อผ้า มันจะเข้ากับหุ่นเป๊ะเลย ต่างจากไปซื้อเสื้อผ้าโหลจากโรงงาน
ก็จะมีหลวมบ้าง คับบ้าง ประมาณนั้น

การเขียน macro ถ้าเขียนเทพๆ วางผังดีๆ ใช้่คู่กับ editor ดีๆ เช่นพวก VIM
บางทีเราเอาโปรแกรมที่มีโครงสร้างคล้ายๆ ซี เช่น pascal มาใส่คำสั่งเปลี่ยนรูปใน VIM ไม่กี่ที
แล้วใส่ macro ไป เผลอๆ source code ภาษา pascal อันนั้น เมื่อสั่ง compile ดันผ่านได้ด้วยนะเออ... ทำเป็นเล่นไป... ::)

จำไว้ว่า ถ้าต้องการโปรแกรมย่อย ก็ให้เขียนโปรแกรมย่อย (sub routine)
ถ้าต้องการปรับแต่ง code ณ เวลาจะ compile ก็ให้ใช้ Macro
เพื่อการ reuse ในระดับ source code ที่ค่อนข้างมั่นใจได้มากกว่า

ในการ reuse บนระดับ computer ทั่วไป สมัยนี้เรามักจะใช้เทคนิคที่เรียกว่า OOP (แทบจะเป็นสวรรค์สำหรับใครหลายๆคน)
นั่นคือการ reuse ประเภทหนึ่ง แต่เป็นการ reuse ระดับ "object" ซึ่งจะมี overhead สูงมาก กว่าจะใช้งานสัก funtion นึง(method)
มันจะไปเรียก ญาติโกโหติกา ลูกหลานเหลนโหลนมาประชุมแรมกันอย่างพร้อมหน้า แล้วก็เรียกใช้งาน  เราลดเวลาการพัฒนาได้เยอะขึ้นแต่แลก
กับหน่วยความจำที่เสียไป แต่ด้วย computer สมัยนี้ประสิทธิภาพสูงมาก จึง dont' care!

แต่บน MCU ทรัพยากรมันน้อยมาก เราทำอย่างนั้นไม่ค่อยได้  แต่เราจะทำการ reuse ระดับ "source code" ค่อนข้างบ่อย
ถ้า source code ที่จะ reuse ทำงานไม่เป็นเอกเทศ จะทำงานที ต้องไปเทียบค่ากับ macro
หรือยึดติดแบบ macro จะทำให้ reuse ได้ยาก เผลอๆ เขียนใหม่เร็วกว่า ด้วยประการฉะนี้... :)
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: JENG on October 01, 2013, 11:21:15 pm
สวัสดี จขกท.

ผมมีเรื่องจะเล่าสู่กันฟัง.....ตามประสาคนเขียนโปรแกรมมาก่อนอ่ะนะ อาจจะ
ไม่เก่งมาก แต่ระดับ level น่าจะพอสอน จขกท.ได้บ้าง

เรื่องแรก...
ผมเห็น code ท่านแล้ว ถ้าผมเป็นอ.ที่สอนท่านคงปวดตับเช่นกัน  :P
ปรัชญาการมีเครื่องคอมพิวเตอร์ หรือเครื่องคิดเลขทรงประสิทธิภาพนี้ก็เพราะว่า
มันเก่งในเรื่องที่ต้องคำนวน (งานโพรเซส) หรือการทำงานซ้ำๆ (งานรูทีน) ครับ
งานพวกนี้เครื่องมันเก่ง ที่จริงมนุษย์ก็ทำได้ครับ แต่มนุษย์ขี้เกียจ และผิดพลาดบ่อย
เค้าเลยต้องโยนให้เครื่องมันทำให้

ดังนั้นถ้าโจทย์บอกว่า จงพิมพ์ "ฉันรักเธอ" 1000 ครั้ง
คนที่ใช้เครื่องเป็นเค้าจะสั่งวนลูป 1000 รอบ จบแล้ว...ง่ายไหม ?
 
แต่ถ้าเป็น จขกท. คง copy + paste "ฉันรักเธอ" 1000 บรรทัดแทนซะละมั๊ง ::)

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

=============================================

ต่อมา เรื่องที่สอง
จากปัญหาข้างต้น ทำให้ต้องเข้าใจว่า ที่จริงแล้ว คือเราต้องแบ่งโปรแกรมออกเป็นส่วนย่อย
(เรียกว่า sub routine) แล้วเรียกใช้บ่อยๆ เช่น

printf("ฉันรักเธอ")

ก็สร้างเป็น function ไว้
void i()
{ printf("ฉันรักเธอ"); }


เวลาเรียกใช้ ก็เขียนแค่ i(); 1000 ครั้งก็จบแล้ว
ถึงแม้ว่าจะคล้ายๆ การ copy + paste คำสั่ง printf("ฉันรักเธอ") พันบรรทัด,
แต่ภาพรวมมันสั้นกว่า แถมยังประหยัดหน่วยความจำเยอะนะครับ เพราะ "ฉันรักเธอ" มีแค่บรรทัดเดียว
ที่เหลือคือร่างแยก 1000 ครั้ง ไม่เหมือน printf("ฉันรักเธอ") ตรงๆ พันบรรทัดนะ อันนี้กินเนื้อที่โปรแกรมเยอะกว่า

==========================================================

เรื่องที่สาม
อย่าไปงงกับเรื่อง macro หรือ Compiler Directive
อย่าไปคิดว่า macro เขียนแทน funtion ได้ ทำงานได้เหมือนกัน...

พวกมือใหม่มักจะเข้าใจอย่างนั้น ที่จริงต้องบอกว่ามันคล้ายกัน
แต่ทางปรัชญาการเขียนโปรแกรม มันมีความแตกต่างกันมากทีเดียว

การสร้าง macro หรือการใช้ compiler directive เช่น #define มาสร้างโปรแกรมย่อย
แทนการใช้ function ถือว่าผิดเกณฑ์อย่างร้ายแรง มันแทนกันได้แต่ไม่เหมาะสม

compiler directive คือ "pre processor"  (แปลว่าให้ทำ.....ก่อน ก่อนการเอาไปประมวลผล)
หรือก็คือ มันจะกระทำตามคำสั่ง macro ที่วางไว้ก่อน ก่อนที่จะเอา source code ที่ได้นั้น
ไปเข้ากระบวนการ compile เพื่อสร้างโปรแกรมเพื่อรันในสถาปัตยกรรมนั้นๆต่อไป

เราวาง macro เพื่อให้มันทำงานสักอย่างหนึ่งตอนนั้น แต่ตัวผู้เขียนโปรแกรมเองก็ไม่รู้ว่าเป็นค่าอะไร
(แต่รู้ว่าต้องทำแน่ๆ) ก็เช่น
- ให้ใส่เลขเวอร์ชั่น ตามวันเวลาที่เขียนโปรแกรมเสร็จ ซึ่งไม่รู้เหมือนกันว่าจะเสร็จวันไหน กี่โมง ก็เลยว่า macro เอาไว้
- การให้ compile ตาม speed X'tal ที่มีตอนนั้น ซึ่งไม่รู้เหมือนกันว่าตอน compile จะไปใช้ speed อะไร ก็เลยวาง macro เอาไว้
- การย้าย source code ให้ไปรันที่ต่างสถาปัตยกรรม รู้แน่ๆ ว่ามี int ให้ใช้ แต่ไม่รู้ว่า สถาปัตยกรรมนั้นจะใช้ int ที่ 2 byte หรือ 4 byte หรือ 8 byte ก็เลยวาง macro ไว้
- ฯลฯ

จะสังเกตุได้ว่า macro จะถูกวางไว้ก่อน แล้วอ้างอิงกับมันเสมือนว่าเป็นค่าหนึ่ง แต่ก็ไม่รู้ว่าจะเป็นค่าอะไร
ดังนั้นจึงวางค่าคงที่ ที่แน่นอนใน source code ขณะนั้นๆ ไม่ได้  นั่นจึงเป็นที่มาของ macro

แล้วคุณสามารถเขียน macro แทน function ได้ไหม?
ตอบว่า "ได้" แต่ไม่ควร .... เพราะการนำ macro มา reuse ใช้ในระดับ  source code นั้นทำได้ยาก
อีกทั้ง macro ไม่ได้ถูกออกแบบมาให้เขียน function ที่ซับซ้อน จึงไม่เหมาะ
macro เป็นความสามารถพื้นฐานของ compiler ภาษาซี แต่บางภาษาไม่มี

macro คือ preprosessor ถ้าตั้งเงื่อนไขดีๆ มันสามารถช่วยในการย้ายสถาปัตยกรรมได้โดยง่าย (Portability)
เช่นเขียน library บน PC แต่เอาไปใช้ใน AVR, PIC ,ARM ได้ง่ายๆ แทบไม่ต้องเขียนใหม่
ยกตัวอย่าง int

C# = 64 bit
AVR int = 8 bit
ARM  int = 32 bit


file ใน csharp.h
#define int int64_t

file ใน avr.h
#define int int8_t

file ใน arm.h
#define int int32_t

เพียงแค่นี้ ไม่ว่าเราจะไปใช้ สถาปัตยกรรมไหน
เพียงแค่เรียก int มันจะใช้ตรงตามสถาปัตยกรรมนั้น ขอแค่ include ให้ตรงกับสถาปัตยกรรมนั้นๆ
หลักการนี้เป็นหลักการง่ายๆ ที่ใช้ port พวก linux ที่รันบน x86 ไปรันบน ARM (คนละสถาปัตยกรรมกันเลย)
หรือรันบน powerPC หรือรันบน playstation , XBOX ฯลฯ

ยิ่งถ้าวางคู่กับ ตัว compiler directive อื่นๆ จะทำให้การ compile นั้น จะได้ code native ที่
เหมาะสมกับสถาปัตยกรรมนั้นๆ มาก อุปมาเหมือน สั่งตัดเสื้อผ้า มันจะเข้ากับหุ่นเป๊ะเลย ต่างจากไปซื้อเสื้อผ้าโหลจากโรงงาน
ก็จะมีหลวมบ้าง คับบ้าง ประมาณนั้น

การเขียน macro ถ้าเขียนเทพๆ วางผังดีๆ ใช้่คู่กับ editor ดีๆ เช่นพวก VIM
บางทีเราเอาโปรแกรมที่มีโครงสร้างคล้ายๆ ซี เช่น pascal มาใส่คำสั่งเปลี่ยนรูปใน VIM ไม่กี่ที
แล้วใส่ macro ไป เผลอๆ source code ภาษา pascal อันนั้น เมื่อสั่ง compile ดันผ่านได้ด้วยนะเออ... ทำเป็นเล่นไป... ::)

จำไว้ว่า ถ้าต้องการโปรแกรมย่อย ก็ให้เขียนโปรแกรมย่อย (sub routine)
ถ้าต้องการปรับแต่ง code ณ เวลาจะ compile ก็ให้ใช้ Macro
เพื่อการ reuse ในระดับ source code ที่ค่อนข้างมั่นใจได้มากกว่า

ในการ reuse บนระดับ computer ทั่วไป สมัยนี้เรามักจะใช้เทคนิคที่เรียกว่า OOP (แทบจะเป็นสวรรค์สำหรับใครหลายๆคน)
นั่นคือการ reuse ประเภทหนึ่ง แต่เป็นการ reuse ระดับ "object" ซึ่งจะมี overhead สูงมาก กว่าจะใช้งานสัก funtion นึง(method)
มันจะไปเรียก ญาติโกโหติกา ลูกหลานเหลนโหลนมาประชุมแรมกันอย่างพร้อมหน้า แล้วก็เรียกใช้งาน  เราลดเวลาการพัฒนาได้เยอะขึ้นแต่แลก
กับหน่วยความจำที่เสียไป แต่ด้วย computer สมัยนี้ประสิทธิภาพสูงมาก จึง dont' care!

แต่บน MCU ทรัพยากรมันน้อยมาก เราทำอย่างนั้นไม่ค่อยได้  แต่เราจะทำการ reuse ระดับ "source code" ค่อนข้างบ่อย
ถ้า source code ที่จะ reuse ทำงานไม่เป็นเอกเทศ จะทำงานที ต้องไปเทียบค่ากับ macro
หรือยึดติดแบบ macro จะทำให้ reuse ได้ยาก เผลอๆ เขียนใหม่เร็วกว่า ด้วยประการฉะนี้... :)

ข้อมูลแน่น แถมคัดกรองมาเป็นอย่างดี ... ;D
Title: Re: ช่วยย่อโค้ดหน่อยครับ ภาษาซี เขียนใน Keil
Post by: s4m3l0 on October 01, 2013, 11:56:21 pm
สวัสดี จขกท.

ผมมีเรื่องจะเล่าสู่กันฟัง.....ตามประสาคนเขียนโปรแกรมมาก่อนอ่ะนะ อาจจะ
ไม่เก่งมาก แต่ระดับ level น่าจะพอสอน จขกท.ได้บ้าง

เรื่องแรก...
ผมเห็น code ท่านแล้ว ถ้าผมเป็นอ.ที่สอนท่านคงปวดตับเช่นกัน  :P
ปรัชญาการมีเครื่องคอมพิวเตอร์ หรือเครื่องคิดเลขทรงประสิทธิภาพนี้ก็เพราะว่า
มันเก่งในเรื่องที่ต้องคำนวน (งานโพรเซส) หรือการทำงานซ้ำๆ (งานรูทีน) ครับ
งานพวกนี้เครื่องมันเก่ง ที่จริงมนุษย์ก็ทำได้ครับ แต่มนุษย์ขี้เกียจ และผิดพลาดบ่อย
เค้าเลยต้องโยนให้เครื่องมันทำให้
level นี้คงต้องเป็น อ. สอนใจมหาลัยแล้วล่ะ  ;D
ตอนเห็นโค้ดผมก็ปวดตับเหมือนกัน แต่ไม่ใช่พวก function น่ะ เป็นพวก Indent style พอเห็นนี่ไม่อยากดูโค้ดเลยถึงกับิด VIM เลยทีเดียว!!
เรื่อง macro vs function แถมอีกอัน ฝรั่งเค้าสรุปสั้นๆ ง่ายๆ ดีครับ
http://programmers.stackexchange.com/questions/937/why-arent-macros-included-in-most-modern-programming-languages (http://programmers.stackexchange.com/questions/937/why-arent-macros-included-in-most-modern-programming-languages)