Tag: C

Pravih za rodjaka neki dan neki primer pa reko mozda bi bilo zgodno podeliti ga.

Shema - klikni za celu semu

Shema - klikni za celu semu

Shema sadrzi

  • mikrokontroler PIC16F887 koji radi na internom oscilatoru na 8MHz
  • reset kolo na MCLR pinu
  • primer kako kontrolisati 2 ledare preko samo jednog pina
  • karakter LCD u 4-bitnom modu (zakacena su paralelno dva, jedan sa jednom linijom i jedan sa dve)
  • unipolarni stepper motor vezan preko ULN2003 (koji je u stvari 7 darlingtona u jednoj kutiji)
  • bipolarni stepper motor sa L297+L298 drajver kombinacijom
  • servo motor

Sors je “samoobjasnjihv” tako da, evo ga:


// LCD pinovi
sbit LCD_EN at RD1_bit;
sbit LCD_RS at RD2_bit;
//sbit LCD_RW at RD3_bit; // MikroC ne koristi RW pin
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;

sbit LCD_EN_Direction at TRISD1_bit;
sbit LCD_RS_Direction at TRISD2_bit;
//sbit LCD_RW_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;

char txt1[] = "TEST TEKST";
char txt2[] = "neki tekst";
char txt3[] = "primer";
char txt4[] = "za lcd";
char txt5[] = "Vozi unapred";
char txt6[] = "UNIPOLARNI STEPP";
char txt7[] = "Vozi unazad";
char txt8[] = "STOP";
char txt9[] = "KRAJ";

// koraci stepper motora
char unipolar_step[] = {0b1100, 0b0110, 0b0011, 0b1001};

#define  Move_Delay() Delay_ms(200)

unsigned char i;

void main(){
  //////////////////////////////////////
  //   INICIJALIZACIJA                //
  //////////////////////////////////////

  // Ugasi ADC (konfigurisi AN pinove kao digital IO)
  ANSEL  = 0;
  ANSELH = 0;

  // Ugasi komparatore
  C1ON_bit = 0;
  C2ON_bit = 0;

  //////////////////////////////////////
  //   PALI, GASI LEDARU              //
  //////////////////////////////////////

  // Na D0 su nam charlieplexed ledare
  TRISD0_bit=1; //postavi D0 na imput - gasi obe ledare
  for (i = 0; i < 10; i++){ //20 puta se izvrti
     //upali prvu ledaru
     RD0_bit=0; //D0 je GND
     TRISD0_bit=0; //D0 je "izlaz"
     Delay_ms(100); //sacekaj 500ms

     //Ugasi ledare
     TRISD0_bit=1;
     Delay_ms(100); //sacekaj 500ms

     //upali drugu ledaru
     RD0_bit=1; //D0 je 5V
     TRISD0_bit=0; //D0 je "izlaz"
     Delay_ms(100); //sacekaj 500ms

     //Ugasi ledare
     TRISD0_bit=1;
     Delay_ms(100); //sacekaj 500ms
  }

  //////////////////////////////////////
  //   LCD  tekstualni                //
  //////////////////////////////////////

  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Cmd(_LCD_CURSOR_OFF);

  Lcd_Out(1,6,txt3);

  Lcd_Out(2,6,txt4);
  Delay_ms(2000);
  Lcd_Cmd(_LCD_CLEAR);

  Lcd_Out(1,1,txt1);
  Lcd_Out(2,5,txt2);

  //iskuliraj 2 sekunde
  Delay_ms(2000);

  //Mrducaj malo tekst na lcd-u
  for(i=0; i<4; i++) {
    Lcd_Cmd(_LCD_SHIFT_RIGHT);
    Move_Delay();
  }

  for(i=0; i<8; i++) {
    Lcd_Cmd(_LCD_SHIFT_LEFT);
    Move_Delay();
  }

  for(i=0; i<8; i++) {
    Lcd_Cmd(_LCD_SHIFT_RIGHT);
    Move_Delay();
  }

  //////////////////////////////////////
  //   UNIPOLARNI STEPPER MOTOR       //
  //////////////////////////////////////

  //mrducaj malo stepper

  //SPREMI RC4 - RC7 da budu izlaz
  TRISC4_bit=0;
  TRISC5_bit=0;
  TRISC6_bit=0;
  TRISC7_bit=0;

  //sacekaj sekund
  Delay_ms(1000);

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,txt5);
  Lcd_Out(2,1,txt6);

  //UNAPRED
  for(i=0;i<100;i++){ // 100 koraka
     RC4_bit =  unipolar_step[i%4] >> 3;
     RC5_bit = (unipolar_step[i%4] >> 2) & 1;
     RC6_bit = (unipolar_step[i%4] >> 1) & 1;
     RC7_bit =  unipolar_step[i%4]       & 1;
     Delay_ms(80); //pauza izmedju koraka, sto manja pauza, brze se vrti stepper
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,txt8);

  //sacekaj sekund
  Delay_ms(1000);

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,txt7);
  Lcd_Out(2,1,txt6);

  //UNAZAD
  for(i=100;i>0;i--){ // 100 koraka
     RC4_bit =  unipolar_step[i%4] >> 3;
     RC5_bit = (unipolar_step[i%4] >> 2) & 1;
     RC6_bit = (unipolar_step[i%4] >> 1) & 1;
     RC7_bit =  unipolar_step[i%4]       & 1;
     Delay_ms(80); //pauza izmedju koraka, sto manja pauza, brze se vrti stepper
  }
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,txt8);
  //sacekaj sekund
  Delay_ms(1000);

  //////////////////////////////////////
  //   BIPOLARNI STEPPER MOTOR        //
  //////////////////////////////////////

  //SPREMI RC0, RC1 da budu izlaz
  RC0_bit = 0;
  RC1_bit = 0;
  TRISC0_bit=0;
  TRISC1_bit=0;
  RC0_bit = 0;

  //vozi unapred
  Delay_ms(1000);
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"Vozi unapred");
  Lcd_Out(2,1,"BIPOLARNI STEPP");

  RC1_bit = 1; // u smeru kazaljke na satu
  for (i=0;i<200;i++){//200 koraka
    RC0_bit = 1;
    Delay_ms(20);
    RC0_bit = 0;
    Delay_ms(20);
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,txt8);
  //sacekaj sekund
  Delay_ms(1000);

  //vozi unazad
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"Vozi unazad");
  Lcd_Out(2,1,"BIPOLARNI STEPP");

  RC1_bit = 0; // suprotno smeru kazaljke na satu
  for (i=0;i<200;i++){//200 koraka
    RC0_bit = 1;
    Delay_ms(20);
    RC0_bit = 0;
    Delay_ms(20);
  }

  //////////////////////////////////////
  //  SERVO MOTOR - DIREKTNA KONTROLA //
  //////////////////////////////////////

  TRISC2_bit = 0; //izlaz
  RC2_bit = 0;

  //DUZINA PULSA ODREDJUJE POZICIJU SERVO MOTORA
  //STANDARD JE 1500us je "centar" 900us je "skroz levo", 2100us je "skroz desno"
  //MADA TO ZAVISI OD MOTORA DO MOTORA, OBICNO PISE U DOKUMENTACIJI MOTORA ALI
  //SE UVEK MOZE EXPERIMENTALNO UTVRDITI

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - CENTAR");
  Lcd_Out(2,2,"DIREKTNO");

  for (i=0;i<50;i++){
     //posalji puls
     RC2_bit = 1;
     Delay_us(1500);
     RC2_bit = 0;
     //cekaj do sledeceg pulsa
     Delay_ms(25);
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - -90");
  Lcd_Out(2,2,"DIREKTNO");

    for (i=0;i<50;i++){
     //posalji puls
     RC2_bit = 1;
     Delay_us(900);
     RC2_bit = 0;
     //cekaj do sledeceg pulsa
     Delay_ms(25);
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - +90");
  Lcd_Out(2,2,"DIREKTNO");

    for (i=0;i<50;i++){
     //posalji puls
     RC2_bit = 1;
     Delay_us(2000);
     RC2_bit = 0;
     //cekaj do sledeceg pulsa
     Delay_ms(25);
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - -45");      //53 1200
  Lcd_Out(2,2,"DIREKTNO");

    for (i=0;i<50;i++){
     //posalji puls
     RC2_bit = 1;
     Delay_us(1250);
     RC2_bit = 0;
     //cekaj do sledeceg pulsa
     Delay_ms(25);
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - +45");               //36 1700
  Lcd_Out(2,2,"DIREKTNO");

    for (i=0;i<50;i++){
     //posalji puls
     RC2_bit = 1;
     Delay_us(1750);
     RC2_bit = 0;
     //cekaj do sledeceg pulsa
     Delay_ms(25);
  }

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - CENTAR");
  Lcd_Out(2,2,"DIREKTNO");

  for (i=0;i<50;i++){
     //posalji puls
     RC2_bit = 1;
     Delay_us(1500);
     RC2_bit = 0;
     //cekaj do sledeceg pulsa
     Delay_ms(25);
  }

  //////////////////////////////////////
  //  SERVO MOTOR - PWM               //
  //  Ovaj uC je suvise brz tako da   //
  //  ne moze da nam da dovoljno spor //
  //  PWM da bi imali full range od   //
  //  min do max. minimalni PWM na    //
  //  8MHZ je 489Hz sto je prebrzo    //
  //  idealan pwm bi bio negde ~100Hz //
  //////////////////////////////////////

  TRISC2_bit = 0; //izlaz
  RC2_bit = 0;
  PWM1_Init(489); //Hz
  PWM1_Set_Duty(0);
  PWM1_Start();

  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"SERVO - SETAJ");
  Lcd_Out(2,2,"PWM");
  for (i=0;i<200;i+=2){
    PWM1_Set_Duty(i);
    Delay_ms(100);
  }
  PWM1_Stop();

  //KRAJ
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,txt9);
  Lcd_Out(2,4,txt9);
  while(1){
    for(i=0; i<4; i++) {
      Lcd_Cmd(_LCD_SHIFT_RIGHT);
      Move_Delay();
    }
    for(i=0; i<4; i++) {
      Lcd_Cmd(_LCD_SHIFT_LEFT);
      Move_Delay();
    }
  }
}

Tags: , , , , ,

Nigel pocinje svoju seriju tutorijala sa tipicnim “hello world” programom za mikrokontrolere – tj “blinkanjem ledara”.

Za prvi deo ovog tutorijala bice nam potrebna GLAVNA1 plocica sa ledarom. sa J1 postavljenim, ili mozemo koristiti LED plocicu na portu B.

Primer 1.1

Jednostavan program koji sve io portove setuje na na 1 a onda na 0 (pisan u MikroC-u):

void main(){
   CMCON = 0x07;    // TURN COMPARATORS OFF (make it like a 16F84)
   TRISA = 0;       // Set port A all output
   TRISB = 0;       // Set port B all output
   
Loop:
     PORTA = 0xFF;  // Set all port A bits high
     PORTB = 0xFF;  // Set all port B bits high
     asm nop        // The nop's make up the time taken by the goto
     asm nop        // giving square wave output
     PORTA = 0;     // Set all port A bits low
     PORTB = 0;     // Set all port B bits low
     goto Loop;     // go back and do it again
}

Prva linija definise pocetak “glavne” funkcije, druga iskljucuje komparatore, naredne dve setuju “pravac” portova A i B. Na PIC mikrokontrolerima, digitalni IO port moze biti “ulaz” ili “izlaz”, da li je port ulazni ili izlazni podesava se registrom TRISx gde za je svaki bit tog registra vezan za bit porta i 0 predstavlja “output” a 1 “input”.

U petlji dizemo sve bitove oba porta na 1, pravimo pauzu od 2 takta (sa nop sto znaci no operation) spustamo vrednost na 0 i skacemo na pocetak petlje (ovaj skok takodje traje 2 takta tako da nam je izlaz simetrican).

Primer 1.2
Ako ste probali primer 1.1 primetili ste da ne primecujete kako LED trepce. Ne mozete primetiti treptanje posto ledare trepcu velikom brzinom (upaljene su 2-3 mikro sekunde i onda su ugasene 2-3 mikro sekunde ako uzmemo u obzir da mikrokontroler radi na 4MHz) sto je prebrzo da bi bilo detektovane golim okom. Kako bi mogli da “vidimo” promene, ubacicemo pauzu izmedju paljenja i gasenje le dioda.

void main(){
   CMCON = 0x07;    // TURN COMPARATORS OFF (make it like a 16F84)
   TRISA = 0;       // Set port A all output
   TRISB = 0;       // Set port B all output
   
Loop:
     PORTA = 0xFF;  // Set all port A bits high
     PORTB = 0xFF;  // Set all port B bits high
     asm nop        // The nop's make up the time taken by the goto
     asm nop        // giving square wave output
     Delay_ms(500); // Half a second pause
     PORTA = 0;     // Set all port A bits low
     PORTB = 0;     // Set all port B bits low
     Delay_ms(500); // Half a second pause
     goto Loop;     // go back and do it again
}

MikroC compiler koristen u ovom primeru koristi funkciju Delay_ms(x) koja sluzi da pauzira program na X milisekundi. Mi smo dodali Delay_ms(500) sto pravi pauzu od 500ms iliti pola sekunde. MikroC takodje ima funkcije Delay_us() (pauza u mikro sekundama), VDelay_ms() (pauza u mili sekundama koja nije “apsolutno tacna” ali zauzima manje prostora od Delay_us()) kao i Delay_Cyc(x) funkciju koja pravi pauzu u “taktovima”. 1 takt na PIC mikro kontroleru je na svake 4 oscilacije glavnog instrukcijskog oscilatora tako da ako nam je oscilator na 4MHz 1 takt je na svake 4 oscilacije, dakle na 1 mikro sekundu. Neki C kompajleri nude delay funkciju samo na nivou “taktova” tako da sami morate u odnosu na to kolika je brzina procesora da racunate koliko taktova vam je potrebno za vremesku pauzu od X milisekundi.

Primer 1.3
Prethodni primeri menjaju vrednost “svih” pinova jednog porta. Cesto zelimo da menjamo vrednost samo jednog pina. Razliciti C kompajleri nam dozvoljavaju da pristupimo pinovima porta na razlicite nacine. MikroC sintaksa ja PORTx.Fn gde je x – ime porta a n bit dakle, PORTA.F0 je najnizi bit porta A, PORTC.F7 je najvisi bit porta C; neke ceste sintakse su: PORTAbits.RA0, PORTA.A0, PORTA.0 i slicno. Neki kompajleri van daju mogucnost da sami kreirate strukturu i imenujete svaki pin, neki daju mogucnost da setujete pojedinacne pinove kroz funkciju (na primer – output_high(porta, 0); ) i slicno.

Ovaj primer pali i gasi RB7 (PORTB MSB – tj. najvisi bit porta B):

void main(){
   CMCON = 0x07;    // TURN COMPARATORS OFF (make it like a 16F84)
   TRISA = 0;       // Set port A all output
   TRISB = 0;       // Set port B all output
   PORTA = 0;       // Set port A all bits low
   PORTB = 0;       // Set port B all bits low

   
Loop:
     PORTB.F7 = 1;  // Set RB7 high
     asm nop        // The nop's make up the time taken by the goto
     asm nop        // giving square wave output
     Delay_ms(500); // Half a second pause
     PORTB.F7 = 0;  // Set RB7 low
     Delay_ms(500); // Half a second pause
     goto Loop;     // go back and do it again
}

Primer 1.4
Ako zelimo da umesto RB7 iz prethodnog posta palimo i gasimo LED na RB4 moramo da nadjemo svuda gde se spominje PORTB.F7 i promenimo u PORTB.F4 .. C jezik nam daje mogucnost definisanja makro-a tako da na pocetku programa mozemo da definisemo makro LED koji ce kompajler sam zameniti sa PORTB.F7 a mi ako zelimo da promenimo port/pin to cinimo samo na jednom mestu te nam je kasnije mnogo lakse da razumemo i administriramo program:

#define LED PORTB.F7
void main(){
   CMCON = 0x07;    // TURN COMPARATORS OFF (make it like a 16F84)
   TRISA = 0;       // Set port A all output
   TRISB = 0;       // Set port B all output
   PORTA = 0;       // Set port A all bits low
   PORTB = 0;       // Set port B all bits low

   
Loop:
     LED      = 1;  // Set RB7 high
     asm nop        // The nop's make up the time taken by the goto
     asm nop        // giving square wave output
     Delay_ms(500); // Half a second pause
     LED      = 0;  // Set RB7 low
     Delay_ms(500); // Half a second pause
     goto Loop;     // go back and do it again
}

Dakle ako sada u prvoj liniji umesto #define LED PORTB.F7 stavimo #define LED PORTB.F4 LED na RB4 ce se paliti i gasiti.

Primer 1.5
Sada cemo “prosetati” svetlo po redu od 8 ledara na portu B

#define LEDPORT PORTB
#define LEDTRIS TRISB

void main(){
   CMCON = 0x07;    // TURN COMPARATORS OFF (make it like a 16F84)
   LEDTRIS = 0;     // Macro points to right TRIS register, set them to output
   LEDPORT = 0;     // Macro points to right PORT, set it all low
Loop:
     LEDPORT = 0x80;// 10000000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x40;// 01000000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x20;// 00100000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x10;// 00010000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x08;// 00001000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x04;// 00000100
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x02;// 00000010
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x01;// 00000001
     Delay_ms(500); // Half a second pause
     goto Loop;     // go back and do it again
}

Primer 1.6
Vrlo lako mozemo da napravimo da se svetlo “odbija” od krajeve:

#define LEDPORT PORTB
#define LEDTRIS TRISB

void main(){
   CMCON = 0x07;    // TURN COMPARATORS OFF (make it like a 16F84)
   LEDTRIS = 0;     // Macro points to right TRIS register, set them to output
   LEDPORT = 0;     // Macro points to right PORT, set it all low
Loop:
     LEDPORT = 0x80;// 10000000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x40;// 01000000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x20;// 00100000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x10;// 00010000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x08;// 00001000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x04;// 00000100
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x02;// 00000010
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x01;// 00000001
     Delay_ms(500); // Half a second pause


     LEDPORT = 0x02;// 00000010
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x04;// 00000100
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x08;// 00001000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x10;// 00010000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x20;// 00100000
     Delay_ms(500); // Half a second pause
     LEDPORT = 0x40;// 01000000
     Delay_ms(500); // Half a second pause

     goto Loop;     // go back and do it again
}

Tags: , , ,
Back to top