Thông báo

Collapse
No announcement yet.

Nguyên lí chạy tốt,mạch thật chạy sai,ai giúp mình cái điều khiển động cơ này với

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Nguyên lí chạy tốt,mạch thật chạy sai,ai giúp mình cái điều khiển động cơ này với

    Mình làm đồ án về điều khiển động cơ DC có encoder hồi tiếp về.Mục đích của đồ án này là cấp cho vđk 1 số lượng xung nào đó, thì vdk sẽ điều khiển cho động cơ chạy đúng theo số lượng xung như thế, nếu chạy quá nhanh , vđk sẽ tự hãm lại, ngược lại sẽ cho động cơ quay nhanh hơn.Code và nguyên lí mình đã hoàn thành xong, nhưng khi ra mạch thật thì chạy sai bét.LCD thì chẳng chịu hiển thị, input vào đo bằng timer 0 cũng chẳng chịu đo, phát xung ra bậy bạ, riêng chỉ có mạch cầu H thiết kế hoạt động tốt.Mình đang bế tắc không biết nguyên nhân vì sao cả, khi code không có warning nào cả, cũng như nguyên lí cũng không thấy có báo warning nào cả.Động cơ mình dùng nguồn 12V, 2A, encoder 100xung/vòng, input mình cũng dự định dùng encoder riêng ở ngoài 100xung/vòng, sử dụng mạch nạp Burn-E để nạp code.Xin mọi người giúp dùm mình với.
    Sau đây là code và mạch của mình
    Code:
    #include <16f877a.h>
    #include <DEFS_16f877A.h>
    #fuses NOWDT,HS,PUT,NOPROTECT,NOLVP
    #device *=16 ADC=8
    #use delay(clock=8000000)
    #include "LCD420.c"
    #include <math.h>
    
    signed int16 Pulse_IN,Pulse_ENC,Pulse_ENCn;
    signed int16 sub_ENC=0,sub_IN=0,sub_IN2=0,sub_ENC2=0;
    int1 flag=0;
    
    void display(unsigned int16 data)
    { 
       lcd_putc(data/100+0x30);
       lcd_putc((data%100)/10+0x30);
       lcd_putc(data%10+0x30); 
    }
    
    void LCD()
    {
          lcd_gotoxy(1,1);
          lcd_putc("IN: ");
          display(Pulse_IN);
          if(RA3==0)
          {
          lcd_gotoxy(9,1);
          if(Pulse_ENC>=0)
          {
          lcd_putc("ENC :");
          display(Pulse_ENC);      
          }
          else
          {
          lcd_putc("ENC:");
          lcd_putc("-");
          display(-Pulse_ENC);
          }
          lcd_gotoxy(1,2);
          lcd_putc("IN>:");
          display(sub_IN);      
          lcd_gotoxy(9,2);
          lcd_putc("ENC>:");
          display(sub_ENC);
          }
          else
          {
          lcd_gotoxy(9,1);
          if(Pulse_ENCn>=0)
          {
          lcd_putc("ENC :");
          display(Pulse_ENCn);      
          }
          else
          {
          lcd_putc("ENC:");
          lcd_putc("-");
          display(-Pulse_ENCn);
          }
          lcd_gotoxy(1,2);
          lcd_putc("IN>:");
          display(sub_IN2);      
          lcd_gotoxy(9,2);
          lcd_putc("ENC>:");
          display(sub_ENC2);
          }
    }
    
    void PWM1(unsigned long speed)
    {
       RE0=1;
       delay_us(speed);
       RE0=0;
    }
    
    void PWM2(unsigned long speed)
    {
       RE1=1;
       delay_us(speed);
       RE1=0;
    }
    
    #int_ext
    void demxung()
    {
       if(RB1==0) 
       {
       Pulse_ENC--;
       Pulse_ENCn++;
       }
       else 
       {
       Pulse_ENC++;
       Pulse_ENCn--;
       }
    }
    void main()
    {
       lcd_init();
       set_tris_a(0xff); //Port a input
       set_tris_b(0xff);//RB0-RB1-input
       set_tris_e(0x00); //Port e output
       PORTA=0x00;
       PORTE=0x00;
       PORTB=0x00;
       enable_interrupts(int_ext);
       ext_int_edge(H_TO_L);;
       setup_timer_0(RTCC_DIV_1|RTCC_EXT_H_TO_L);
       set_timer0(0);
       enable_interrupts(global);
       while(1)
       {
       Pulse_IN=get_timer0();
       if(RA3==0)
       {
       if(Pulse_IN==Pulse_ENC)
       {
       sub_ENC=0;
       sub_IN=0;   
       }
       else if(Pulse_IN>Pulse_ENC)
       {
       sub_IN=Pulse_IN-Pulse_ENC;
       }
       else 
       {
       sub_ENC=Pulse_ENC-Pulse_IN;
       }
       LCD();
       if(Pulse_IN>0&&sub_ENC==0)
       {
       PWM1(20000);
       //delay_us(40000);
       flag=1;
       }   
       if(sub_ENC>0)
       {
       if(sub_ENC>10)
       {
       PWM2(20000);
       sub_ENC--;
       }
       else if(sub_ENC>8)
       {
       PWM2(1200);
       sub_ENC--;
       }
       else if(sub_ENC>5)   
       {
       PWM2(1000);
       sub_ENC--;
       }
       else if(sub_ENC>4)
       {
       PWM2(800);
       sub_ENC--;
       }
         else if(sub_ENC>3)
       {
       PWM2(500);
       sub_ENC--;
       }
        else if(sub_ENC>2)
       {
       PWM2(300);
       sub_ENC--;
       }
       else
       {
       PWM2(100);
       sub_ENC--;
       }
       }
       if(sub_IN>0)
       {
       if(sub_IN>10)
       {
       PWM1(20000);
       sub_IN--;
       }
       else if(sub_IN>8)
       {
       PWM1(1200);
       sub_IN--;
       }
       else if(sub_IN>5)
       {
       PWM1(1000);
       sub_IN--;
       }
       else if(sub_IN>4)
       {
       PWM1(800);
       sub_IN--;
       }
       else if(sub_IN>3)
       {
       PWM1(500);
       sub_IN--;
       }
       else if(sub_IN>2)
       {
       PWM1(300);
       sub_IN--;
       }
       else
       {
       PWM1(100);
       sub_IN--;
       }
       }
       if(sub_IN==0&&sub_ENC==0&&flag==1)
       {   
       set_timer0(0);
       Pulse_ENC=0;
       Pulse_ENCn=0;
       flag=0;
       delay_ms(4);
       }
       }
       else                                            /////////////Quay nghich/////////
       {
       if(Pulse_IN==Pulse_ENCn)
       {
       sub_ENC2=0;
       sub_IN2=0;   
       }
       else if(Pulse_IN>Pulse_ENCn)
       {
       sub_IN2=Pulse_IN-Pulse_ENCn;
       }
       else 
       {
       sub_ENC2=Pulse_ENCn-Pulse_IN;
       }
       LCD();
       if(Pulse_IN>0&&sub_ENC2==0)
       {
       PWM2(20000);
       flag=1;
       }   
       if(sub_ENC2>0)
       {
       if(sub_ENC2>10)
       {
       PWM1(20000);
       sub_ENC2--;
       }
       else if(sub_ENC2>8)
       {
       PWM1(1200);
       sub_ENC2--;
       }
       else if(sub_ENC2>5)   
       {
       PWM1(1000);
       sub_ENC2--;
       }
       else if(sub_ENC2>4)
       {
       PWM1(800);
       sub_ENC2--;
       }
       else if(sub_ENC2>3)
       {
       PWM1(500);
       sub_ENC2--;
       }
       else if(sub_ENC2>2)
       {
       PWM1(300);
       sub_ENC2--;
       }
       else
       {
       PWM1(100);
       sub_ENC2--;
       }
       }
       if(sub_IN2>0)
       {
       if(sub_IN2>10)
       {
       PWM2(20000);
       sub_IN2--;
       }
       else if(sub_IN2>8)
       {
       PWM2(1200);
       sub_IN2--;
       }
       else if(sub_IN2>5)
       {
       PWM2(1000);
       sub_IN2--;
       }
       else if(sub_IN2>4)
       {
       PWM2(800);
       sub_IN2--;
       }
       else if(sub_IN2>3)
       {
       PWM2(500);
       sub_IN2--;
       }
       else if(sub_IN2>2)
       {
       PWM2(300);
       sub_IN2--;
       }
       else
       {
       PWM2(100);
       sub_IN2--;
       }
       }
       if(sub_IN2==0&&sub_ENC2==0&&flag==1)
       {   
       set_timer0(0);
       Pulse_ENC=0;
       Pulse_ENCn=0;
       flag=0;
       delay_ms(4);
       }
       }
    }           
    }
    Click image for larger version

Name:	mach.jpg
Views:	1
Size:	137.8 KB
ID:	1414809
    Click image for larger version

Name:	khoi dieu khien.JPG
Views:	1
Size:	58.1 KB
ID:	1414810
    Click image for larger version

Name:	cau h.JPG
Views:	1
Size:	54.1 KB
ID:	1414811

  • #2
    Có thể trình bày vắn tắt xem code cậu viết gì không.

    Comment


    • #3
      Nguyên văn bởi zerotohero Xem bài viết
      Có thể trình bày vắn tắt xem code cậu viết gì không.
      Code mình sẽ đếm số xung từ đầu vào bằng timer0, vì dự định dùng encoder tạo xung tay tốc độ 100xung/vòng nên 8bit đếm của timer0 là đủ.Nhận được xung lớn hơn giá trị 0 thì sẽ cho động cơ chạy.Encoder thứ 2 gắn trên động cơ sẽ hồi tiếp giá trị về, giá trị này là Pulse_ENC.Sau đó VDK sẽ so sánh 2 giá trị Pulse_IN và Pulse_ENC này để tìm ra sai số sub_IN(nếu IN > ENC) và sub_ENC(nếu ENC>IN), từ đó cho động cơ chạy thêm hoặc hãm lại để điều chỉnh cho 2 cái sub này tiến về 0 hay nói cách khác là để Pulse_ENC = Pulse_IN.Để quay mượt mình chia nhiều cấp độ, nếu sai số lớn thì sẽ cho hãm mạnh, chạy thêm mạnh, sai số nhỏ sẽ hãm yếu hơn, như thế động cơ sẽ không bị giật qua giật lại.

      Comment


      • #4
        Mình thì không rõ tại sao cậu lại chọn cách điều khiển như thế này.
        Vấn đề LCD không hiển thị thì là do thư viện lcd không chuẩn là chủ yếu. Không biết là có ai gặp chưa nhưng mình dùng con LCD hàng tàu. Thư viện LCD tự viết thì mô phỏng không tài nào chạy nhưng chạy thực lại ok và ngược lại( cái này dùng lệnh kiểm tra cờ bận và chế độ 4bit 2 dòng).
        Tiếp theo là phần PWM của cậu.chắc chắn là không đảm bào.-> sao không dùng timer2 chế độ PWM cho tiện. Động cơ thực tế thì tần số băm xung bét thì cũng phải >1KHz.Cả một vòng lặp chỉ tạo một xung PWM.Tuy nhiên cậu còn làm nhiều việc khác tốn thời gian như hiển thị LCD(trong lúc này PWM đang ở giai đoạn Toff)...--> độ rộng xung không còn đúng nữa

        Còn thuật toán điều khiển thì nếu có thể thì thay bằng thuật toán khác như PI hoặc fuzzy chẳng hạn.Làm như cậu thì mình không nghĩ là tốc độ động cơ của cậu nếu chạy thì nó theo ý muốn của cậu.

        Còn encoder thực thì phải xem cấu tạo cảu nó. có thể nó để dạng open connector (như port0 của 8051) cho nên cần phải có trở treo nếu muốn đo xung( mình có con động cơ có encoder như thế)

        còn sô xung đặt thì dùng con NE555 ấy chứ ai lại thêm con encoder nữa. Không thì thêm 2 nút ấn tăng giảm số xung đặt là ok rồi

        Comment


        • #5
          Nguyên văn bởi zerotohero Xem bài viết
          Mình thì không rõ tại sao cậu lại chọn cách điều khiển như thế này.
          Vấn đề LCD không hiển thị thì là do thư viện lcd không chuẩn là chủ yếu. Không biết là có ai gặp chưa nhưng mình dùng con LCD hàng tàu. Thư viện LCD tự viết thì mô phỏng không tài nào chạy nhưng chạy thực lại ok và ngược lại( cái này dùng lệnh kiểm tra cờ bận và chế độ 4bit 2 dòng).
          Tiếp theo là phần PWM của cậu.chắc chắn là không đảm bào.-> sao không dùng timer2 chế độ PWM cho tiện. Động cơ thực tế thì tần số băm xung bét thì cũng phải >1KHz.Cả một vòng lặp chỉ tạo một xung PWM.Tuy nhiên cậu còn làm nhiều việc khác tốn thời gian như hiển thị LCD(trong lúc này PWM đang ở giai đoạn Toff)...--> độ rộng xung không còn đúng nữa

          Còn thuật toán điều khiển thì nếu có thể thì thay bằng thuật toán khác như PI hoặc fuzzy chẳng hạn.Làm như cậu thì mình không nghĩ là tốc độ động cơ của cậu nếu chạy thì nó theo ý muốn của cậu.

          Còn encoder thực thì phải xem cấu tạo cảu nó. có thể nó để dạng open connector (như port0 của 8051) cho nên cần phải có trở treo nếu muốn đo xung( mình có con động cơ có encoder như thế)

          còn sô xung đặt thì dùng con NE555 ấy chứ ai lại thêm con encoder nữa. Không thì thêm 2 nút ấn tăng giảm số xung đặt là ok rồi
          Uhm, vì số xung đặt bằng encoder do thầy cung cấp nên mình làm theo hướng đó thôi, nói chung là có 1 nguồn tạo xung đầu vào để so sánh thôi.
          Còn về phần sao ko dùng PWM của timer2 thì là vì do mình muốn cấp xung 1 chút rồi ngưng ko cấp nữa trong 1 vòng lặp while(1) thôi, nếu dùng timer2 pwm thì cũng làm theo hướng phải delay 1tg rồi lại set_pwm_duty(0) lại.Nói chung thì mục đích tạo xung của mình chỉ là cho động cơ chạy thôi chứ không theo tính toán gì cả.Còn về mấy thuật toán kia thì mình bị bó tay trong lĩnh vực này, nên tìm cách khác mà không dùng tới pid.Cảm ơn bạn vì lời góp ý.

          Comment

          Về tác giả

          Collapse

          boy_legend Tìm hiểu thêm về boy_legend

          Bài viết mới nhất

          Collapse

          Đang tải...
          X