วันศุกร์ที่ 1 มีนาคม พ.ศ. 2556

General Servo Controller by PIC (CCS Compiler)

     General Servo Controller by PIC (CCS Compiler)


              คือปกติแล้วในการ Control Servo Motor นั้นเราต้องป้อนพัลส์ไปยังขา Signal ของ Servo Motor ครับ ซึ่งพัลส์นั้นจะมีความกว้างตั้งแต่ 0.5mS - 1.5mS. ครับโดยที่ 0.5mS นั้น Servo Motor จะหมุ่นมาที่ -90 องศาครับส่วน 1.5mS. นั้นจะหมุนไปที่ +90 องศา ถ้าพัลส์ปกติ (1.0mS)ก็จะหมุนมาที่ 0 องศา ครับ ดังนั้นการเขียนโปรแกรมให้ Servo ทำงานได้ต่อเนื่องนั้นต้องเขียนให้การทำงานในส่วนของ Servo เป็น Background Process ครับ คือโปรแกรมของผมจะเขียนโดยให้ Interrupt Timer เป็น Background Process แทนครับ มาดูวีดีโอที่ผมทดลอง Simulate กันครับว่ามอเตอร์นั้นทำงานอย่างไร



              ความสามารถของ Lib คือต่อ Servo เข้าขาไหนก็ได้ของ PIC แค่เป็นขาที่สามารถเป็น output ได้เป็นพอครับ
กำหนดค่าในโปรแกรมนิดหน่อยก็ใช้งานได้แล้วครับ เดี๋ยวมาดูโค้ดกันก่อนครับ
 
/*
Name : General Servo Controller.
Compiler Support : CCS C Compiler.
Designed by : Wittawat Sompong @ RMUTI
Software use timer_1 and CCP1 in MCU.
*/
#include <16f877.h>
#fuses HS,NOLVP,NOWDT,NOPROTECT
#use delay(clock=20M)

//-------------------------General config----------------------------------//
#define SERVO_MAX 5 //Max of Server connector
#define SERVO_MAX_VALUE 2500 //Max of pulse width micro sec(uS)
#define SERVO_MIN_VALUE 500 //Min of pulse width micro sec(uS)

typedef struct tServo{
volatile unsigned pin;
volatile unsigned Active;
volatile unsigned int16 value;
}Servo;

//------------------------Start Prototype-----------------------------------//
void ServoActive(unsigned chanel,unsigned vPin,unsigned int16 vValue);
void ServoValue(unsigned chanel,unsigned int16 value);//value is uS.
//------------------------End of Prototype---------------------------------//

//------------------------Servo gobal variable----------------------------//
signed ServoCnt=0;
Servo nServo[SERVO_MAX];

//------------------------Servo background task use CCP1 interrupt---------//
#INT_CCP1
void ServoTask()
{
//if enc of servo count ,reset timer1.
if(ServoCnt<0){
set_timer1(0);
}else{
//if server pin is active set output servo pin to low.
if(nServo[ServoCnt].Active)
output_low(nServo[ServoCnt].pin);
}
ServoCnt++;
if(ServoCnt<SERVO_MAX)
{
//set interrupt to next servo time.
CCP_1 = get_timer1()+nServo[ServoCnt].value;
//if servo pin is active set output servo pin to high.
if(nServo[ServoCnt].Active)
output_high(nServo[ServoCnt].pin);
}else{
//set fist chanel to start scan.
CCP_1 = get_timer1()+100;
ServoCnt = -1;
}
}

/*
ServoActive(c,p,v)
set pin 'p' to connect servo chanel 'c' and set pulse width 'v' uS.

Example : ServoActive(0,PIN_A0,1500);
set PIN_A0 to connect servo at chanel '0' and set pulse width 1500 uS.
*/
void ServoActive(unsigned chanel,unsigned vPin,unsigned int16 value)
{
nServo[chanel].pin = vPin;
nServo[chanel].value = ((value*5)/8);
nServo[chanel].Active = 1;
}
/*
ServoValue(c,v)
Set servo chanel 'c' to pulse width 'v' uS.
Example : ServoValue(0,2400);
set servo chanel '0' to pulse width 2400 uS. (2.4mS)
*/
void ServoValue(unsigned chanel,unsigned int16 value)
{
if(value>SERVO_MAX_VALUE)
value=SERVO_MAX_VALUE;
if(value<SERVO_MIN_VALUE)
value=SERVO_MIN_VALUE;

if (chanel>=SERVO_MAX)
chanel=SERVO_MAX-1;

nServo[chanel].value = ((Value*5)/8);
}
void main()
{
unsigned i;
//-----------------------------------------Setup timer1 to servo task-----------------------------//
setup_timer_1 (T1_INTERNAL|T1_DIV_BY_8);
setup_ccp1 (CCP_COMPARE_INT);
enable_interrupts(GLOBAL);
enable_interrupts(INT_CCP1);
//-----------------------------------------------------------------------------------------------//
//Add pin_d0 to connect servo chanel '0'
ServoActive(0,PIN_D0,1500);
ServoActive(1,PIN_D1,1500);
ServoActive(2,PIN_B0,1500);
ServoActive(3,PIN_B1,1500);
delay_ms(1000);
while(true)
{
for(i=0;i<4;i++)
{
ServoValue(i,1000);
//delay_ms(200);
}
delay_ms(1000);
for(i=0;i<4;i++)
{
ServoValue(i,1500);
//delay_ms(200);
}
delay_ms(1000);
for(i=0;i<4;i++)
{
ServoValue(i,2000);
//delay_ms(200);
}
delay_ms(1000);
for(i=0;i<4;i++)
{
ServoValue(i,1500);
//delay_ms(200);
}
delay_ms(1000);
}
}


                   หลักๆที่ท่านจะได้ใช้คือ ServoActive() ครับเป็นฟังก์ชั่นที่เอาไว้เพิ่มหรือกำหนดว่าเราจะต่อขาอะไรเข้ากับ Servo
                  ตัวอย่างเช่น ผมต้องการต่อขา PIN_D0 เข้า Servo ช่องที่ 0 และตั้งให้พัลส์ที่ขาออก 1.5mS 
ผมก็เขียนว่า ServoActive(0,PIN_D0,1500); ถ้าผมต้องการเปลี่ยนองศาการหมุนของมัน
ไปเป็น +90 องศา ก็จะเขียน ServoValue(0,1000);

                   การใช้งานเบื้องต้นมีเท่านี้ครับ ใช้ง่ายครับ แต่โค้ดต้นฉบับเองผมได้ดูมาจาก Arduino 
และดัดแปลงมาเขียนบน AVR Studio และก็แปลงมาเป็น CCS อีกที
เดี๋ยวตั้วหน้าจะเอาเวอร์ชั่น AVR มาให้ครับ พอดียังไม่ได้ลงโปรแกรม AVR Studio ครับเลยยังไ่ม่มีเวลาทดสอบ

                  ส่วนไกล้ๆงานย่าโมโรโบคอนปีนี้ เดี๋ยวจะเอาโค้ดโปรแกรมเซ็นเซอร์ตรวจจับเส้น
ที่เท่ไม่หยอกและบางคนอาจจะคิดไม่ถึงมาให้ดูกันครับ 
ส่วนโปรแกรมนี้ท่านไหนสงสัยส่วนไหน หรือมีอะไรติชม ก็ยินดีครับ


ปล.ผมคอมเม้นในโค้ดเป็นภาษาอังกฤษนะ อาจะดูกระด้างไปหน่อย ครั้งหลังจะปรับปรุงให้ดีกว่านี้ครับ ;)

ขอบคุณครับ
โอ.... ;D

10 ความคิดเห็น:

  1. ผมเอาโค็ดไปคอมไพล์ดูมันerror เยอะเลยอ่ะครับ มันผิดตรงไหนบ้างอ่ะครับ รบกวนหน่อยน่ะครับกำลังศึกษาการเขียนccsอยู่ด้วยครับ

    ตอบลบ
    คำตอบ
    1. ลองก็อปปี้โค้ดไปสร้างในโปรเจ็คใหม่นะครับ
      พอดีผมสร้างใน MPLAB มันจะเปิดบนโปรแกรม CCS เลยไม่ได้ครับ

      ลบ
    2. สอบถามหน่อยน่ะครับแล้วสร้างในMPLAB แล้วทำไมมันถึงเปิดในCCS เลยไม่ได้อ่ะครับ
      คือว่า ผมต้องเขียนใหม่ในccs อย่างนั้นหรือป่าวครับ แล้วโค็ดมันเหมือนกันเลยใช่ไหมครับ
      รบกวนคุณพี่หน่อยน่ะครับ กำลังศึกษาอยู๋ครับ

      ลบ
    3. คือเวลาที่ MPLAB มันสร้างโปเจ็คขึ้นมามันจะตั้งค่าส่วนของการ Compiler ไม่เหมือน CCS ครับ เวลาจะเอาโค้ดไปใช้งานให้ก็อปเอาโค้ดทั้งหน้าไปวางในโปรเจ็คใหม่ได้เลยครับ
      ไม่ก็ลง MPLAB เหมือนผมเลยครับ แก้ไขนิดหน่อย
      อีกวิธีคือลบไฟลโปรเจ็คของ CCS ออกแล้วเปิดแค่ไฟล์ .C ของโปรแกรมได้เลยครับจะคอมไพล์ได้เหมือนกัน

      ลบ
  2. ครับตอนนี้คอมไพล์ได้แล้วครับ ขอบคุณน่ะครับ

    ตอบลบ
  3. ถ้าผมจะทำให้มอเตอร์หมุนที่45องศา ผมต้องแก้ต้องไหนอ่ะครับ

    ตอบลบ
    คำตอบ
    1. ปกติ Servo จะหมุนมา 0 องศาเมื่อปล่อยพัลส์ 1.5ms จะหมุนมา +90 องศาเมื่อพลัส์กว้าง 1ms
      จะหมุนไป -90 องศา ที่ 2.0ms ถ้าต้องการให้หมุนไป 45 องศาจะต้องเอามาคำนวนเอาครับ
      1500+(500*(45/90))
      1500-(500*(45/90))

      ประมาณนี้ครับ
      ในโปรแกรมผมไม่ได้เผื่อคาบเวลาเอาไว้ เวลาจะผิดพลาดเล็กน้อยนะครับ

      ลบ
  4. โทษน่ะครับ พี่มีfacebook หรือmsn ป่าวครับ เผื่อผมอยากจะรู้เรื่องเกี่ยวกับไมโครได้สอบถามอ่ะครับ พอดีกำลังศึกษาทำโปรเจคอ่ะครับ

    ตอบลบ
  5. ครับแอดไปแล้วน่ครับ อติชา บุญสุวรรณ ขอบคุณน่ะครับ

    ตอบลบ