PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   Lỗi lập trình ngôn ngữ cấp cao (http://www.picvietnam.com/forum/forumdisplay.php?f=65)
-   -   Lỗi không ngắt được trong CCS (http://www.picvietnam.com/forum/showthread.php?t=2732)

bazooka2006 21-08-2008 12:23 AM

Lỗi không ngắt được trong CCS
 
Mình viết Ct điều khiển động cơ bước từ máy tính. Cụ thể là điều khiển 1 mâm quay, trên hành trình mâm có công tắc giới hạn, nối vào portB. Cấu trúc ct như sau:
- Phần khai báo biến, mức ưu tiên, RS232...
- Các hàm phát xung cho động cơ (dùng delay_us trong CCS).
- Hàm phục vụ ngắt nối tiếp (INT_RDA): báo ngắt khi có kí tự gởi xuống, ứng với mỗi kí tự thì gọi hàm phát xung tương ứng
- Hàm phục vụ ngắt PortB (INT_RB): khi công tắc báo ngắt thì gọi hàm phát xung.

Ý định của mình là khi gửi kí tự A chẳng hạn, hàm ngắt RDA cho mâm quay trái, gặp công tắc thì hàm ngắt RB cho dừng, delay 1s rồi quay ngược lại 1 góc nào đó.

Mình đã test thử từng phần riêng, là gửi A thì mâm quay trái tốt, tác động bằng tay lên công tắc thì mâm quay ngược lại tốt, nghĩa là đáp ứng ngắt tốt. Nhưng khi đang quay trái mà gặp công tắc thì không ngắt được. phải đến khi thực hiện hết quay trái của ngắt RDA, nếu t/h ngắt RB còn thì nó mới thực hiện ngắt RB.
Lưu ý là mình đã đặt mức ưu tiên ngắt RB cao hơn RDA rồi.

Ở đây mình phán đoán nó bị lỗi như giống như trường hợp cảnh báo "Warning 216 : Interrupts disable during call to prevent re_entrancy:tên hàm"
lỗi này hình như là 1 ngắt có dùng các hàm delay_us, delay_ms mà ở ngoài cũng có 1 hàm delay này đang chạy thì ngắt sẽ bị disable? Đây là link trên CCSInfo, do trình độ AV có hạn nên mình ko hiểu nhiều lắm: http://www.ccsinfo.com/forum/viewtop...er=asc&start=0
Trường hợp của mình là đều dùng Delay_us trong cả 2 ngắt.

Mình chỉ là newbie với PIC, ai có kinh nghiệm có thể giúp mình khắc phục không?

phamminhtuan 21-08-2008 12:36 AM

Bạn có thể post code lên được không, có thể sẽ dễ giải quyết vấn đề hơn, chú ý là ngắt INT_RB là ngắt on change, xử lý không tốt ở đây cũng nảy sinh vấn đề rồi.

bazooka2006 21-08-2008 02:01 AM

Ct của mình dùng đk 1 tay máy 3 trục dùng 3 đcơ bước nên nó dài dòng quá, ban đầu post lên sợ ko ai đọc.
Mình tóm tắt là có 3 motor bước, mỗi cái quay 1 trục, trên hành trình có gắn 3 ctắc để set vị trí home, ctắc nối vào chân ngắt của RB.
Giao tiếp RS232 báo ngắt khi bộ đệm nhận dữ liệu đầy.
Hoạt động: gửi 1 kí tự xuống PIC thì ngắt nối tiếp RDA gọi hàm quay động cơ tương ứng. Gửi kí tự "O" thì ngắt RDA đk 3 trục về vtrí home, bằng cách là khi mỗi trục gặp ctắc, hàm ngắt RB đặt mức ưu tiên cao hơn sẽ ngắt hàm RDA, cho dừng và quay 3 trục về home.
Vấn đề ở đây là ngắt RB ko ngắt đc hàm RDA đang thực thi, nên 3 động cơ không dừng như mong muốn. Nếu ngắt RDA ko chạy thì ngắt RB vẫn hoạt động tốt. Mình cũng thử là cho RB ngắt khi chạy phát xung ngoài hàm main, thì vẫn ko ngắt đc. Trình dịch cảnh báo Warning 216 như mình nói.
đây là code, mọi ngừoi chịu khó xem giúp mình:
Code:

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#priority rb,rda 
#byte porta=0x05         
#byte portb=0x06
#byte portd=0x08

#bit catch=porta.3      // ngo ra nam cham

#bit clock1=porta.2      // Step motor 1
#bit en_step1=porta.1
#bit dir1=porta.0

#bit clock2=portd.7      // step motor 2
#bit en_step2=portd.6
#bit dir2=portd.5

#bit en_step3=portd.3    // step motor 3
#bit dir3=portd.2
#bit clock3=portd.1

int count1;            // bien dem so xung motor1
int16 count2,count3;    //                  motor2 va 3
char ss;


void rotate_high1()    // ham phat xung cho motor 1
{                            // quay toc do cao
clock1=1;
delay_us(30000);
clock1=0;
delay_us(500);
}

void rotate_low1()    // motor 1 toc do thap
{
clock1=1;
delay_us(50000);
clock1=0;
delay_us(500);
}

void rotate_high2()   
{
clock2=1;
delay_us(1000);
clock2=0;
delay_us(100);
}

void rotate_low2()
{
clock2=1;
delay_us(2000);
clock2=0;
delay_us(100);
}

void rotate3()
{
clock3=1;
delay_us(700);
clock3=0;
delay_us(100);
}
//**************************************************
void left_right()        // ham quay motor 1
{
 int tam;
 tam=count1;
 en_step1=1;
 while (count1>0)
  {
  count1--;
  if ((count1>30)&&(count1<(tam-30)))
    {
      rotate_high1();
    }
  else
    {
      rotate_low1();
    }
  }
 count1=0;
 delay_ms(500);
}
//****************************************************
void go_up_down()          // ham quay motor 2
{
  en_step2=1;
  while (count2>0)
  {
    count2--;
    if (dir2==0)
    {
      rotate_low2();
    }
    else
    {
      rotate_high2();
    } 
  }
  count2=0;
  delay_ms(500);
  en_step2=0;
}
//*****************************************************
void in_out()              //  ham quay motor 3
{
    en_step3=1;
    while (count3>0)
      {
      count3--;   
      rotate3();
      } 
    delay_ms(1000);
    en_step3=0;
    count3=0;
}

//*******************************************************

#int_RB
void rb_isr()            // ham phuc vu ngat RB
 {   
  int current;
  int last;
  set_tris_b(0xff);
  current=input_b();
  last=current;
  delay_ms(50);
  set_tris_b(0xff);
  current=input_b();
  if (current==last)         
    {
      clear_interrupt(int_RDA); 
      if (!bit_test(current,4))    // ctac tren mam xoay bao ngat
      { 
        if (home)                    // chi thuc hien khi o che do home:
        {                              // quay mam ben phai 60 do
          en_step1=0;
          count1=70;
          dir1=1;
          en_step1=1;
          while (count1>0)
            {
              count1--;
              if ((count1>30)&&(count1<(70-30)))
              {
                rotate_high1();
              }
              else
              {
                rotate_low1();
              }
            }
            count1=0;
 
          }
      } 
                 
      if (!bit_test(current,5))    // ctac trong bao ngat
      {                         
        en_step3=0;
        delay_ms(500);
        count3=2000;
        dir3=0;
        in_out();
      }
     
      if (!bit_test(current,6))    //ctac tren bao ngat 
      {
        en_step2=0;
        delay_ms(500);
        count2=500;
        dir2=1;
        go_up_down();
        count2=0;
      }
         
      if (!bit_test(current,7))    // cam bien phat hien co vat den
      {
        putc('y');
        delay_ms(10);
      }
    } 
  clear_interrupt(int_RB);
 }

//****************************************************************
#int_RDA                  // ham phuc vu ngat noi tiep
void  RDA_isr()
 {
  delay_us(50);
  ss=getc();
  if (ss=='u')          // di len
    {
      count2=2000;
      dir2=0;
      go_up_down();
      printf("done");
    }
     
  if (ss=='d')            // di xuong
    {
      count2=2000;
      dir2=1;
      go_up_down();
      printf("done");
    }
   
  if (ss=='l')              // quay trai
    {
      count1=70;            //1 lan quay 60 do
      dir1=0;
      left_right();
      printf("done");
    }
   
  if (ss=='r')              // quay phai
    {
      count1=70;
      dir1=1;
      left_right();
      printf("done");
    }   
   
  if (ss=='i')              //di vao
    {
      count3=4000;          //1 lan di chuyen 30mm
      dir3=1;
      in_out();
      printf("done");
    }   
   
  if (ss=='o')              // di ra
    {
      count3=4000;
      dir3=0;
      in_out();
      printf("done");
    } 
   
  if (ss=='#')        // test comm
    {
      putc('!');
      delay_us(100);
    }
   
  if (ss=='O')        // go home: dieu khien tay may
    {                    // ve vi tri home
      home=1;
      count1=100;
      dir1=0;
      left_right();
      count2=2000;
      dir2=0;
      go_up_down();
      count3=2666;
      dir3=1;
      in_out();
      home=0;
    }
 
  if (ss=='1')        // chuong trinh di chuyen cho vat 1
    {
      count2=10000;  // chay xuong
      dir2=1;
      go_up_down();
     
      catch=1;        // gap vat
     
      count2=10000;  // di len
      dir2=0;   
      go_up_down();
     
      count1=102;    // xoay 90 do
      dir1=1;
      left_right();
     
      count3=13333;  // di ra
      dir3=0;
      in_out();
     
      count2=10000;  // ha xuong
      dir2=1;
      go_up_down();
     
      catch=0;        // nha vat
     
      count2=10000;  // di len
      dir2=0;   
      go_up_down();
     
      count1=102;    // xoay 90 do
      dir1=0;
      left_right();
     
      count3=13333;  // di vao
      dir3=1;
      in_out();

  }
  clear_interrupt(int_rda);
 }

void main()

    enable_interrupts(INT_RB|H_TO_L);
    enable_interrupts(GLOBAL);
    ext_int_edge(H_TO_L);
    enable_interrupts(INT_RDA);
    set_tris_d(0x00);
    set_tris_b(0xff);
    set_tris_a(0x00);
    printf("reset");

     
    while (1)
    {
 
    }
}


phamminhtuan 21-08-2008 11:44 AM

Trích:

Nguyên văn bởi bazooka2006 (Post 18287)
Code:

#include <16F877A.h>
...
#priority rb,rda 

...
#int_RB
void rb_isr()            // ham phuc vu ngat RB
 {   
  int current;
  int last;
  set_tris_b(0xff);
  current=input_b();
  last=current;
  delay_ms(50);
  set_tris_b(0xff);
  current=input_b();
  if (current==last)         
    {
      clear_interrupt(int_RDA); 
      if (!bit_test(current,4))    // ctac tren mam xoay bao ngat
      { 
        if (home)                    // chi thuc hien khi o che do home:
        {                              // quay mam ben phai 60 do
          en_step1=0;
          count1=70;
          dir1=1;
          en_step1=1;
          while (count1>0)
            {
              count1--;
              if ((count1>30)&&(count1<(70-30)))
              {
                rotate_high1();
              }
              else
              {
                rotate_low1();
              }
            }
            count1=0;
 
          }
      } 
                 
      if (!bit_test(current,5))    // ctac trong bao ngat
      {                         
        en_step3=0;
        delay_ms(500);
        count3=2000;
        dir3=0;
        in_out();
      }
     
      if (!bit_test(current,6))    //ctac tren bao ngat 
      {
        en_step2=0;
        delay_ms(500);
        count2=500;
        dir2=1;
        go_up_down();
        count2=0;
      }
         
      if (!bit_test(current,7))    // cam bien phat hien co vat den
      {
        putc('y');
        delay_ms(10);
      }
    } 
  clear_interrupt(int_RB);
 }

//****************************************************************
#int_RDA                  // ham phuc vu ngat noi tiep
void  RDA_isr()
 {
  delay_us(50);
  ss=getc();
  if (ss=='u')          // di len
    {
      count2=2000;
      dir2=0;
      go_up_down();
      printf("done");
    }
     
  if (ss=='d')            // di xuong
    {
      count2=2000;
      dir2=1;
      go_up_down();
      printf("done");
    }
   
  if (ss=='l')              // quay trai
    {
      count1=70;            //1 lan quay 60 do
      dir1=0;
      left_right();
      printf("done");
    }
   
  if (ss=='r')              // quay phai
    {
      count1=70;
      dir1=1;
      left_right();
      printf("done");
    }   
   
  if (ss=='i')              //di vao
    {
      count3=4000;          //1 lan di chuyen 30mm
      dir3=1;
      in_out();
      printf("done");
    }   
   
  if (ss=='o')              // di ra
    {
      count3=4000;
      dir3=0;
      in_out();
      printf("done");
    } 
   
  if (ss=='#')        // test comm
    {
      putc('!');
      delay_us(100);
    }
   
  if (ss=='O')        // go home: dieu khien tay may
    {                    // ve vi tri home
      home=1;
      count1=100;
      dir1=0;
      left_right();
      count2=2000;
      dir2=0;
      go_up_down();
      count3=2666;
      dir3=1;
      in_out();
      home=0;
    }
 
  if (ss=='1')        // chuong trinh di chuyen cho vat 1
    {
      count2=10000;  // chay xuong
      dir2=1;
      go_up_down();
     
      catch=1;        // gap vat
     
      count2=10000;  // di len
      dir2=0;   
      go_up_down();
     
      count1=102;    // xoay 90 do
      dir1=1;
      left_right();
     
      count3=13333;  // di ra
      dir3=0;
      in_out();
     
      count2=10000;  // ha xuong
      dir2=1;
      go_up_down();
     
      catch=0;        // nha vat
     
      count2=10000;  // di len
      dir2=0;   
      go_up_down();
     
      count1=102;    // xoay 90 do
      dir1=0;
      left_right();
     
      count3=13333;  // di vao
      dir3=1;
      in_out();

  }
  clear_interrupt(int_rda);
 }

void main()

    enable_interrupts(INT_RB|H_TO_L);
    enable_interrupts(GLOBAL);
    ext_int_edge(H_TO_L);
    enable_interrupts(INT_RDA);
    set_tris_d(0x00);
    set_tris_b(0xff);
    set_tris_a(0x00);
    printf("reset");

     
    while (1)
    {
 
    }
}


Mình có quote cho bạn những đoạn code trên, bạn cần lưu ý những điều sau để tự sửa lại chương trình:
  • Trong PIC16F877A không có ưu tiên ngắt, do đó chỉ dẫn #priority không có tác dụng
  • Khi xảy ra bất kì 1 ngắt nào, thì GIE = 0 để tránh xảy ra các ngắt chồng nhau, nó chỉ được set = 1 khi có lệnh RETFIE, có nghĩa là khi xảy ra 1 ngắt bất kì thì chỉ khi thực hiện xong ngắt đó mới có thể giải quyết ngắt tiếp theo
  • Khi xử lý 1 ngắt, trước khi kết thúc trình phục vụ ngắt, bạn phải xóa cờ ngắt đó bằng lệnh clear_interrupt();, nếu không sau khi thoát ra khỏi ngắt đó, nó sẽ quay trở lại
  • enable_interrupts(INT_RB|H_TO_L); không có OR với H_TO_L, tuy nhiên do giá trị H_TO_L = 0, nên chương trình bạn không bị ảnh hưởng
  • Dưới đây là file list C/ASM đơn giản để bạn thấy rõ điều đó
PHP Code:

#include<16f877a.h>
#use delay(clock=4Mhz)
#use rs232(baud=9600, UART1)
#INT_RDA
void rda(){
   
unsigned char c;
   
getc(); //Lệnh này sau khi đọc xong kí tự, thì cờ ngắt tự động bị xóa
   
output_b(0xAA);
}

#INT_RB
void rb(){
   
output_b(0x55);
   
clear_interrupt(INT_RB);
}

void main(){
   
enable_interrupts(INT_RDA);
   
enable_interrupts(INT_RB);
   
enable_interrupts(GLOBAL);
   
   while(
1);


đây là file list, lược bớt đoạn đầu, là đoạn chỉ lưu các thanh ghi và lựa chọn nhảy đến vị trí các chương trình phục vụ ngắt, không hề có lệnh nào xóa cờ ngắt
PHP Code:

.................... #INT_RDA 
.................... void rda(){ 
....................    
unsigned char c
....................    
getc(); 
003C:  BTFSS  0C.5
003D
:  GOTO   03C
003E
:  MOVF   1A,W
003F
:  MOVWF  28
....................    output_b(0xAA); 
0040:  BSF    03.5
0041
:  CLRF   06
0042
:  MOVLW  AA
0043
:  BCF    03.5
0044
:  MOVWF  06
.................... } 
....................  
0045:  BCF    0C.5
0046
:  BCF    0A.3
0047
:  BCF    0A.4
0048:  GOTO   023
.................... #INT_RB 
.................... void rb(){ 
....................    
output_b(0x55); 
0049:  
BSF    03.5
004A
:  CLRF   06
004B
:  MOVLW  55
004C
:  BCF    03.5
004D
:  MOVWF  06
....................    clear_interrupt(INT_RB); 
004E:  BCF    0B.0 //Chỉ khi có lệnh này, thì cờ ngắt của INT_RB mới được xóa
.................... } 


bazooka2006 21-08-2008 02:48 PM

Trích:

Nguyên văn bởi phamminhtuan (Post 18294)

Trong PIC16F877A không có ưu tiên ngắt, do đó chỉ dẫn #priority không có tác dụng

Cám ơn bạn minhtuan, quả thực trong datasheet 16f87xA ko hề nhắc đến điều này, mình nhầm to chỗ này rồi.
Trích:

Khi xảy ra bất kì 1 ngắt nào, thì GIE = 0 để tránh xảy ra các ngắt chồng nhau, nó chỉ được set = 1 khi có lệnh RETFIE, có nghĩa là khi xảy ra 1 ngắt bất kì thì chỉ khi thực hiện xong ngắt đó mới có thể giải quyết ngắt tiếp theo.
  • Một câu hỏi đặt ra là ngay khi thực hiện ngắt 1, có thể tự set bit GIE lên 1 để nhận các ngắt khác không?
  • Thứ 2 là vấn đề của mình vẫn chưa giải quyết được. Như mình đã nói, mình đã test thử là thay vì cho chạy đcơ trong ngắt RDA, thì mình đưa đoạn đó ra ngoài main(), trong ngắt RDA chỉ set 1 bit cờ rồi thoát. Hàm main sẽ lặp vòng hỏi cờ này, nếu thấy =1 thì cho chạy đcơ. Và, khi đoạn này đang chạy, nếu ctắc báo ngắt RB, vẫn ko thể dừng được, nghĩa là ko thực thi ngắt RB được. Chỉ khi hàm quay đcơ này chạy xong, nếu ngắt RB còn, hay mình tự tác động thì nó ngắt tốt.
  • Và nếu đưa đoạn ct quay đcơ ra ngoài main như trên, thì CCS báo "Warning 216 : Interrupt disable..." như đã nói.
    Có lẽ việc dùng delay_ms/us trong các ISR khi ở ngoài cũng có hàm này đang chạy sẽ thực sự gây bug là disable các ISR chăng?

phamminhtuan 21-08-2008 03:29 PM

Trích:

Nguyên văn bởi bazooka2006 (Post 18299)
Cám ơn bạn minhtuan, quả thực trong datasheet 16f87xA ko hề nhắc đến điều này, mình nhầm to chỗ này rồi.
  • Một câu hỏi đặt ra là ngay khi thực hiện ngắt 1, có thể tự set bit GIE lên 1 để nhận các ngắt khác không?
  • Thứ 2 là vấn đề của mình vẫn chưa giải quyết được. Như mình đã nói, mình đã test thử là thay vì cho chạy đcơ trong ngắt RDA, thì mình đưa đoạn đó ra ngoài main(), trong ngắt RDA chỉ set 1 bit cờ rồi thoát. Hàm main sẽ lặp vòng hỏi cờ này, nếu thấy =1 thì cho chạy đcơ. Và, khi đoạn này đang chạy, nếu ctắc báo ngắt RB, vẫn ko thể dừng được, nghĩa là ko thực thi ngắt RB được. Chỉ khi hàm quay đcơ này chạy xong, nếu ngắt RB còn, hay mình tự tác động thì nó ngắt tốt.
  • Và nếu đưa đoạn ct quay đcơ ra ngoài main như trên, thì CCS báo "Warning 216 : Interrupt disable..." như đã nói.
    Có lẽ việc dùng delay_ms/us trong các ISR khi ở ngoài cũng có hàm này đang chạy sẽ thực sự gây bug là disable các ISR chăng?

  • Dĩ nhiên, nếu bạn cứ set GIE lên, thì ngắt tiếp theo sẽ xảy ra trong khi đang thực thi ngắt cũ, và các giá trị mà CCS lưu lại sẽ bị đè lên bởi cái mới, giá trị con trỏ chương trình lưu lại chính là cái nơi xảy ra ngắt sau, thế nên chắc chắn 1 điều là chương trình của bạn chỉ có thể trở về tại vị trí nằm trong chương trình xử lý ngắt cũ(tại nơi xảy ra ngắt mới), và không thể trở về tại chương trình chính.
  • Việc bạn xác định ngắt RB không xảy ra trong khi động cơ đang quay bạn cần kiểm chứng bằng LED chẳng hạn
  • Còn hàm delay, bạn dịch thử 1 đoạn có delay, xem file list thì thấy rõ ngay, ví dụ bạn xem sau đây nhé, nó chỉ là những dòng lệnh bình thường như bao dòng lệnh khác thôi, chẳng tác động gì tới ngắt cả, thế nên, delay ở đâu cũng thế cả, có ngắt thì phục vụ ngắt.
PHP Code:

.................... #use delay(clock=4Mhz) 

0053:  MOVLW  29
0054
:  MOVWF  04
0055
:  BCF    03.7
0056
:  MOVF   00,W
0057
:  BTFSC  03.2
0058:  GOTO   067
0059:  MOVLW  01
005A
:  MOVWF  78
005B
:  CLRF   77
005C
:  DECFSZ 77,F
005D
:  GOTO   05C
005E
:  DECFSZ 78,F
005F
:  GOTO   05B
0060
:  MOVLW  4A
0061
:  MOVWF  77
0062
:  DECFSZ 77,F
0063
:  GOTO   062
0064
:  GOTO   065
0065
:  DECFSZ 00,F
0066
:  GOTO   059
0067:  BCF    0A.3
0068:  BCF    0A.4
0069:  GOTO   087 (RETURN)
//và
....................    delay_ms(1000); 
0082:  
MOVLW  04
0083:  MOVWF  28
0084:  MOVLW  FA
0085:  MOVWF  29
0086:  GOTO   053
0087:  DECFSZ 28,F
0088:  GOTO   084 

Bạn thấy rõ, CCS C sẽ tính toán các giá trị nạp vào các ô nhớ RAM ở địa chỉ 28 và 29, sau đó nhảy tới chương trình delay ở địa chỉ 53 để thực thi hàm delay, đến khi thực thi xong, thì lại nhảy 87, làm cho xong hết thì ra khỏi delay, bạn thấy đấy, delay chẳng liên quan gì đến xử lý ngắt cả. Bạn hãy viết các chương trình đơn giản hơn để kiểm nghiệm

quangduy 08-09-2008 02:59 PM

code trên không sai nhưng ccsc sai mấy ông mở cái set 16f877a.h ra và coi có set đúng
hay khong tôi từng bị cái này với 16f887.h rồi hầu như ngát RB sai cả sửa lai code theo 16f877a.h thì ok, => phien bản của các cong cụ lạp trình cấp cao chưa chăc hoản toàn đúng ==> khong tin thì sài 16f887 bien dịch mọi phien bản ccsc khác nhau = không chạy RB nếu khong sủa lại 16f887.h

vuxuansyhut 17-05-2010 06:28 AM

mình đang gặp lỗi tương tự như trên. Không thể dùng ngắt rb và Rda trong cùng chương trình. Khi bỏ hoàn toàn ngắt rb thì chương trình chạy bình thường, còn khi thêm vào thì lại không chạy được. Ai đã giải quyết được vấn đề này xin giúp đỡ mình

nguyenung 27-05-2010 05:51 PM

mình dùng ngắt và hàm delay cùng lúc không được. mình lập trình bằng CCS
dùng ngắt timer.Khi có cả delay và timer thì chỉ có "ngắt" chạy còn delay thì hoạt đông không chính xác. Delay_ms(2000) mà đợi tới cả chục giây mới có. Bạn nào biết nguyên nhân không và xin cho cách khắc phục vấn đề trên ( mình muốn dùng cả 2 delay và ngắt timer ). Thanks

tungbka 28-05-2010 01:18 AM

Mình cũng đang viết 1 chương trình điều khiển động cơ 1 chiều, dữ liệu được nhập từ máy tính. Trong chương trình có dùng 3 ngắt là RDA, RB0 và ngắt của timer1 để tạo chu kỳ trích mẫu.
Có điều đáng nói là khi chạy thì chương trình thường bị treo sau khoảng 1-2s. Mình nghĩ là có xung đột về ngắt nên đã disable ngắt RDA sau khi nhận được dữ liệu từ máy tính. Và quả thật sau khi disable thì chương trình chạy ngon.
Tuy nhiên, khi đang chạy mà muốn truyền thêm dữ liệu từ PC xuống để thay đổi các thông số thì lại ko được (Vì đã disable ngắt RDA). Mình đã thử nhiều cách nhưng vẫn không thay đổi được gì.
Mong mọi người cho ý kiến để cải thiện chương trình của mình. Thanks.
Sau đây là chương trình của mình:

Code:

#include <16f877a.h>
#include <def_877a.h>
#include <stdlib.h>
#fuses NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <lcd_lib_4bit.c>
void ht(int16 a);
void init();
void pid();
void nhapheso();
void display(int16 n);
void truyen();
int16 count=0, tocdo=0, C, temp, temp1, k, tocdodat ;
signed int16 e2=0;
signed int16 e1=0;
int16 e_sum=0;
int16 e_del=0;
int16 duty=0;
float Kp=0;
float Ki=0;
float Kd=0;
int flag=0;
float u, T=0.01;

unsigned char text[30], text2[5] ;
unsigned char a1[5], dem=0, i=0, j=0,i1=0;

#INT_RDA
void Receive_isr()
{
text[dem]=getc();
if(text[dem]=='@') //kiem tra dieu kien ket thuc
  {
  flag =1;    //ket thuc nhan, bat co bao
  dem=0;
  }
else dem++;
}
#INT_EXT
void ngatR0()  {
     
      count++;//set_timer0(0);
       
      }
#int_timer1
void Timer11_isr() {                // Ham duoc goi khi TImer1 tran (65535->0)

      set_timer1(53036);
      tocdo= 30*(count + get_timer0());
    // printf("%ld\t",tocdo);
      count = 0;
      set_timer0(0);

    }
void main(){
init();
lcd_putcmd(0x01);
while(true){
truyen();                //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
      pid();
if(RC1==0) set_PWM1_duty(duty);
if(RC1==1) set_PWM1_duty(1023 - duty); 
lcd_putcmd(0x80);
ht(tocdo);
printf("n%4Lu",tocdo);
display(tocdo);

//lcd_putchar("hi");


}
}
void init()
{
  lcd_init();
  nhapheso();
  setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H);  // Timer0 is Counter
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
  setup_ccp1(CCP_PWM);
  setup_timer_2(T2_DIV_BY_4, 255, 1);//4*4*256*1/20000000=204.8us=4.8khz
  set_timer0(0);
  set_timer1(53036);
  enable_interrupts(INT_RTCC);
  enable_interrupts(int_timer1);
  enable_interrupts(int_ext);
  ext_int_edge(L_TO_H);
  enable_interrupts(GLOBAL);
  lcd_putcmd(0x80);
  count=0;
  trisc=0;
  trisd=0;
  trisa=255;
  trisb=1;

  }
void pid(){
  e2 = tocdodat - tocdo;
  e_sum += e2;
//  e_del = e2 - e1;
//  e1 = e2;
  u = u + Kp*e2 + Ki*e_sum*T;
  if (u>24){
  u=24;
  e_sum -=e2;
  }
  if (u<0){
  u = 0;
  e_sum -=e2;
  }
  duty = u*1023/24;
}
void ht(long a) {
    int nghin,tram,chuc,dvi;
    nghin=a/1000;
    tram=(a%1000)/100;
    chuc=(a%100)/10;
    dvi=(a%10);
    lcd_putchar(nghin+48);
    lcd_putchar(tram+48);
    lcd_putchar(chuc+48);
    lcd_putchar(dvi+48);
}
void nhapheso(){
  lcd_putchar("nhap tu PC");
  enable_interrupts(int_rda);
  enable_interrupts(GLOBAL); 
while(!flag) ;

}
void truyen()
{
  enable_interrupts(int_rda);
  enable_interrupts(GLOBAL);     
if(flag){

              //if ((strchr(text,'T')) && (strrchr(text, '@')))
       
                text2[0] = text[0];
                text2[1] = text[1];
                text2[2] = text[2];
                text2[3] = text[3];
                text2[4] = text[4];
                tocdodat = atol(text2);
             
                //----------------------------------------
                  while (text[i] != 'P')
                    i++;
                  while (text[j] != 'I')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  Kp = atof(a1);
               
                  printf("P%f",Kp);
                  delay_ms(100); 
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                  i = j;
                  while (text[j] != 'D')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  Ki = atof(a1);
                  printf("I%f",Ki);
                    delay_ms(100);
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                  i = j;
                  while (text[j] != 'C')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  Kd = atof(a1);
                  printf("D%f",Kd);
                    delay_ms(100);
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                  i = j;
                  while (text[j] != '@')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  C = atol(a1);
                  printf("C%Lu",C);
                  flag=0;
                  i=0; j=0;
                  dem=0;
                  if(C==1) RC1=1;
                  If(C==0) RC1=0;
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                                               
          }
disable_interrupts(int_rda);
disable_interrupts(global);
}
void display(int16 n){
int nghin,tram,chuc,dvi;
nghin = n/1000;
tram = (n%1000)/100;
chuc = (n%100)/10;
dvi = n%10;
PORTB=dvi<<1; RD0=0; delay_ms(1);RD0=1;
PORTB=chuc<<1; RD1=0; delay_ms(1);RD1=1;
PORTB=tram<<1; RC4=0; delay_ms(1);RC4=1;
PORTB=nghin<<1; RC5=0; delay_ms(1);RC5=1;

}


changnhoc123 03-06-2013 10:47 PM

Trích:

Nguyên văn bởi tungbka (Post 36359)
Mình cũng đang viết 1 chương trình điều khiển động cơ 1 chiều, dữ liệu được nhập từ máy tính. Trong chương trình có dùng 3 ngắt là RDA, RB0 và ngắt của timer1 để tạo chu kỳ trích mẫu.
Có điều đáng nói là khi chạy thì chương trình thường bị treo sau khoảng 1-2s. Mình nghĩ là có xung đột về ngắt nên đã disable ngắt RDA sau khi nhận được dữ liệu từ máy tính. Và quả thật sau khi disable thì chương trình chạy ngon.
Tuy nhiên, khi đang chạy mà muốn truyền thêm dữ liệu từ PC xuống để thay đổi các thông số thì lại ko được (Vì đã disable ngắt RDA). Mình đã thử nhiều cách nhưng vẫn không thay đổi được gì.
Mong mọi người cho ý kiến để cải thiện chương trình của mình. Thanks.
Sau đây là chương trình của mình:

Code:

#include <16f877a.h>
#include <def_877a.h>
#include <stdlib.h>
#fuses NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#include <lcd_lib_4bit.c>
void ht(int16 a);
void init();
void pid();
void nhapheso();
void display(int16 n);
void truyen();
int16 count=0, tocdo=0, C, temp, temp1, k, tocdodat ;
signed int16 e2=0;
signed int16 e1=0;
int16 e_sum=0;
int16 e_del=0;
int16 duty=0;
float Kp=0;
float Ki=0;
float Kd=0;
int flag=0;
float u, T=0.01;

unsigned char text[30], text2[5] ;
unsigned char a1[5], dem=0, i=0, j=0,i1=0;

#INT_RDA
void Receive_isr()
{
text[dem]=getc();
if(text[dem]=='@') //kiem tra dieu kien ket thuc
  {
  flag =1;    //ket thuc nhan, bat co bao
  dem=0;
  }
else dem++;
}
#INT_EXT
void ngatR0()  {
     
      count++;//set_timer0(0);
       
      }
#int_timer1
void Timer11_isr() {                // Ham duoc goi khi TImer1 tran (65535->0)

      set_timer1(53036);
      tocdo= 30*(count + get_timer0());
    // printf("%ld\t",tocdo);
      count = 0;
      set_timer0(0);

    }
void main(){
init();
lcd_putcmd(0x01);
while(true){
truyen();                //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
      pid();
if(RC1==0) set_PWM1_duty(duty);
if(RC1==1) set_PWM1_duty(1023 - duty); 
lcd_putcmd(0x80);
ht(tocdo);
printf("n%4Lu",tocdo);
display(tocdo);

//lcd_putchar("hi");


}
}
void init()
{
  lcd_init();
  nhapheso();
  setup_timer_0 (RTCC_DIV_1|RTCC_EXT_L_TO_H);  // Timer0 is Counter
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
  setup_ccp1(CCP_PWM);
  setup_timer_2(T2_DIV_BY_4, 255, 1);//4*4*256*1/20000000=204.8us=4.8khz
  set_timer0(0);
  set_timer1(53036);
  enable_interrupts(INT_RTCC);
  enable_interrupts(int_timer1);
  enable_interrupts(int_ext);
  ext_int_edge(L_TO_H);
  enable_interrupts(GLOBAL);
  lcd_putcmd(0x80);
  count=0;
  trisc=0;
  trisd=0;
  trisa=255;
  trisb=1;

  }
void pid(){
  e2 = tocdodat - tocdo;
  e_sum += e2;
//  e_del = e2 - e1;
//  e1 = e2;
  u = u + Kp*e2 + Ki*e_sum*T;
  if (u>24){
  u=24;
  e_sum -=e2;
  }
  if (u<0){
  u = 0;
  e_sum -=e2;
  }
  duty = u*1023/24;
}
void ht(long a) {
    int nghin,tram,chuc,dvi;
    nghin=a/1000;
    tram=(a%1000)/100;
    chuc=(a%100)/10;
    dvi=(a%10);
    lcd_putchar(nghin+48);
    lcd_putchar(tram+48);
    lcd_putchar(chuc+48);
    lcd_putchar(dvi+48);
}
void nhapheso(){
  lcd_putchar("nhap tu PC");
  enable_interrupts(int_rda);
  enable_interrupts(GLOBAL); 
while(!flag) ;

}
void truyen()
{
  enable_interrupts(int_rda);
  enable_interrupts(GLOBAL);     
if(flag){

              //if ((strchr(text,'T')) && (strrchr(text, '@')))
       
                text2[0] = text[0];
                text2[1] = text[1];
                text2[2] = text[2];
                text2[3] = text[3];
                text2[4] = text[4];
                tocdodat = atol(text2);
             
                //----------------------------------------
                  while (text[i] != 'P')
                    i++;
                  while (text[j] != 'I')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  Kp = atof(a1);
               
                  printf("P%f",Kp);
                  delay_ms(100); 
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                  i = j;
                  while (text[j] != 'D')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  Ki = atof(a1);
                  printf("I%f",Ki);
                    delay_ms(100);
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                  i = j;
                  while (text[j] != 'C')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  Kd = atof(a1);
                  printf("D%f",Kd);
                    delay_ms(100);
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                  i = j;
                  while (text[j] != '@')
                    j++;
                  i1 = i;
                  temp = j - i;                 
                  for (i = 0; i < temp; i++)
                    a1[i] = text[i1 + i + 1];
                   
                  C = atol(a1);
                  printf("C%Lu",C);
                  flag=0;
                  i=0; j=0;
                  dem=0;
                  if(C==1) RC1=1;
                  If(C==0) RC1=0;
                  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
                                               
          }
disable_interrupts(int_rda);
disable_interrupts(global);
}
void display(int16 n){
int nghin,tram,chuc,dvi;
nghin = n/1000;
tram = (n%1000)/100;
chuc = (n%100)/10;
dvi = n%10;
PORTB=dvi<<1; RD0=0; delay_ms(1);RD0=1;
PORTB=chuc<<1; RD1=0; delay_ms(1);RD1=1;
PORTB=tram<<1; RC4=0; delay_ms(1);RC4=1;
PORTB=nghin<<1; RC5=0; delay_ms(1);RC5=1;

}


bạn dis rda kiểu gì vậy, chỉ mình với, mình cũng bị lỗi này

Ham học 31-08-2015 10:00 AM

lỗi dòng portb=0; là lỗi j zây mọi người, sữa sao được đây
#INCLUDE<16F877A.H>
#FUSES HS,NOWDT,NOPROTECT,NOLVP
#USE DELAY(CLOCK=40000000)
#use fast_io(b)
#byte port=0x06
int8 sck,slx,bx,bl,gt;
void main()
{
set_tris_b(0);
while(true)
{
sck=8;
bl=0;
portb=(0);
delay_ms(1000);
while(sck>0)
{
bx=1;
slx=sck;
while(slx>0)
{
gt=bl|bx;
portb=gt;
delay_ms(1000);
bx=bx<<1;
slx--;
}
bl=gt;
sck--;
}

}

}


Múi giờ GMT. Hiện tại là 05:01 PM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam