Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Problema servocomando

Elettronica lineare e digitale: didattica ed applicazioni

Moderatori: Foto UtenteIsidoroKZ, Foto UtenteBrunoValente, Foto Utentecarloc, Foto Utenteg.schgor, Foto UtenteDirtyDeeds

0
voti

[51] Re: Problema servocomando

Messaggioda Foto Utentefantamed » 16 nov 2013, 10:27

c1b8 ha scritto:Abbiamo detto che il nostro timer ha un prescaler pari a 8 ed il PIC lavora a 4MHz, pertanto potremmo generare un interrupt per overflow del timer al massimo dopo 256*8=2048 us, che sommati ai 1000 del Ton minimo ci dicono che il nostro tempo costante tra l'inizio del primo Ton e l'inizio del secondo Ton può essere al massimo 2048+1000=3048 us. Deve essere quindi un valore compreso tra 2100 e 3048.

allora avevo capito bene,solo che il 2500 mi confondeva :ok:

Si ci provo stasera quando tutti dormono :mrgreen: ,ieri sera ho preparato i settaggi dei registri,per l'interrupt,dovrebbe andare questo:
Codice: Seleziona tutto
                OPTION=0b10000010;
   INTCON=0b10100100;
   TRISA=0b00011000;           
   TRISB=0b00000110;

O_/
Avatar utente
Foto Utentefantamed
30 5
Frequentatore
Frequentatore
 
Messaggi: 110
Iscritto il: 8 nov 2013, 13:44

0
voti

[52] Re: Problema servocomando

Messaggioda Foto Utentefantamed » 16 nov 2013, 19:08

Il metodo credo di averlo capito,pero non riesco a mettrlo giu : #-o faccio troppa confusione.
Avatar utente
Foto Utentefantamed
30 5
Frequentatore
Frequentatore
 
Messaggi: 110
Iscritto il: 8 nov 2013, 13:44

0
voti

[53] Re: Problema servocomando

Messaggioda Foto Utentefantamed » 16 nov 2013, 20:57

mi faresti un esempio di come si imposta il timer,cioe io faccio

SER1 =1;
SER2 =0;
imposto il timer a 131 per avere i 1000us di ton1
Avatar utente
Foto Utentefantamed
30 5
Frequentatore
Frequentatore
 
Messaggi: 110
Iscritto il: 8 nov 2013, 13:44

2
voti

[54] Re: Problema servocomando

Messaggioda Foto Utentec1b8 » 17 nov 2013, 0:32

Ciao, questo il codice per gestire i 2 servo nella routine di interrupt

Il file settaggioservo.h
Codice: Seleziona tutto
#define PL1    RB0    // puls1
#define PL2    RB1    // puls2
#define PL3    RB2    // puls3
#define PL4    RB3    // puls4
#define LED    RA0    //led rete

#define SER1   RB4    //segnale servo 1
#define SER2   RB5    //segnale servo 2

#define numServo   2
#define byteIntTime   numServo*2
#define maxIntNumber   byteIntTime*8

#define valueLeft   131
#define valueRight   6
#define   valueCenter   69

volatile unsigned char intNumber;
volatile unsigned char intTime[byteIntTime];


il file main.c
Codice: Seleziona tutto
#include <PIC.h> // contiene i nomi mnemonici di registri e porte

__CONFIG(0x3FF9);

#include "settaggioservo.h" // file che contiene il settaggio delle porte

void interrupt ISR (void) {
   if (T0IF==1) {
      if (intNumber>=byteIntTime) {
         TMR0=100;
      } else {
         SER1=0;
         SER2=0;
         TMR0=intTime[intNumber];
         if (intNumber==0) SER1=1;
         if (intNumber==2) SER2=1;
      }
      intNumber++;
      if (intNumber==maxIntNumber)
         intNumber=0;
      T0IF=0;
   }
}

void settaggio(void)
{   
    OPTION_REG=0b10000010;

   TRISA=0b11111110;           
   TRISB=0b00001111;
   LED=0;
   SER1=0;
   SER2=0;

   TMR0=131;
   intNumber=0;
    INTCON=0b10100000;
}

void setServo(unsigned char servo, unsigned char time) {
   servo--;
   servo=servo<<1;
   intTime[servo]=time;   
   servo++;
   intTime[servo]=200-time;
}

void main(void)
{
   settaggio();
   
   setServo(1, valueLeft);
   setServo(2, valueCenter);
   while(1) {
   }
}


Come puoi vedere il programma posiziona il servo1 tutto da un alto ed il servo2 al centro.
Modificando la main.c, dentro alla while(1){}, si possono gestire i pulsanti che dovranno solo modificare le posizione dei servo chiamando la funzione setServo().

Prova a guardarlo e dimmi se ci sono dubbi.
Prova poi ad aggiungere la gestione dei pulsanti per spostare i servo.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

0
voti

[55] Re: Problema servocomando

Messaggioda Foto Utentefantamed » 17 nov 2013, 1:30

:shock: :shock: :shock: mamma mia fabio mi rendo conto che ce tanto di C che non conosco,prima di provare ad inserire i pulsanti,vorrei cercare di capire le cose che non conosco , potresti mettermi accanto ad ogni riga un dettaglio di quello che avviene.
Scusami se possono essere richieste un po pretenziose ma credo che sia l'unico modo per provare a capire passo passo quello che succede,se non lo capisco cosi,non per essere negativi (anzi vorrei riuscire proprio tanto)allora mi conviene lasciar stare.
grazie O_/ Buonanotte
Avatar utente
Foto Utentefantamed
30 5
Frequentatore
Frequentatore
 
Messaggi: 110
Iscritto il: 8 nov 2013, 13:44

0
voti

[56] Re: Problema servocomando

Messaggioda Foto Utentec1b8 » 17 nov 2013, 1:38

Certo, adesso non riesco, ma domani ti commento tutto il programma.
Buona notte.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

0
voti

[57] Re: Problema servocomando

Messaggioda Foto Utentefantamed » 17 nov 2013, 2:08

iOi iOi :lol:
Avatar utente
Foto Utentefantamed
30 5
Frequentatore
Frequentatore
 
Messaggi: 110
Iscritto il: 8 nov 2013, 13:44

1
voti

[58] Re: Problema servocomando

Messaggioda Foto Utentec1b8 » 17 nov 2013, 17:31

Provo a raccontarti un po' il programma.

Partiamo dall'idea. Abbiamo detto che generiamo i segnale di controllo dei servo mediante routine di interrupt su timer0, abbiamo anche detto che suddividiamo i 20ms di periodo del PWM di controllo servo in 8 segmenti di 2500us ciascuna e che ogni segmento si comporrà di 2 semi-segmenti ciascuno, di durata variabile ma tale da avere durata complessiva 2500us.
Ho bisogno quindi di una variabile che mi conteggi il numero di interrupt che si succedono per sapere in quale di quei 16 semiperiodi mi trovi, questa variabile è la intNumber:
Codice: Seleziona tutto
    volatile unsigned char intNumber;

La variabile assume valori da 0 a 15, verrà incrementata di 1 ad ogni interrupt e quando raggiungerà il valore massimo (16) sarà azzerata in modo da ricominciare, all'interno della routine di interrupt, ed in particolare alla fine della stessa, abbiamo quindi:
Codice: Seleziona tutto
          intNumber++;
          if (intNumber==maxIntNumber)
             intNumber=0;


Dobbiamo controllare 2 servo, quindi significativi al fine di generare segnale in uscita sono solo i primi 4 semi-periodi (dallo 0 al 3), i rimanti semi-periodi servono solo a completare il totale di 20ms.
Se i servo sono 2 sappiamo inoltre che ci servono 4 byte (2 per ogni servo) per indicare i tempi dei semi-periodi dei servo, la durata degli altri semi-periodi è invece costante.
Ho dichiarato delle costanti per tutti questi numeri:
Codice: Seleziona tutto
    #define numServo   2               // NUMERO SERVO
    #define byteIntTime   numServo*2     // NUMERO TOTALE BYTE PER CONTROLLO SERVO
    #define maxIntNumber   byteIntTime*8     // NUMERO MASSIMO SEMI-PERIODI

In questo modo se vi fosse la necessità di cambiare il numero di servo da controllare basterebbe cambiare queste costanti.

Nella routine di interrupt abbiamo quindi una prima if che ci dice se siamo in un semi-periodo di completamento o in un semi-periodo di controllo dei servo:
Codice: Seleziona tutto
          if (intNumber>=byteIntTime) {
             TMR0=100;     // QUI SIAMO IN UN SEMIPERIODO DI COMPLETAMENTO
                           //  ED IL TEMPO è COSTANTE
          } else {
              .....      // QUI SIAMO IN UNO DEI PRIMI 4 SEMI-PERIODI,
                         // DEVO GENERARE SEGNALE DI CONTROLLO
          }

Quando ci troviamo in un semiperiodo di completamento (dal 5 al 16 interrupt) c'è poco da fare: si imposta il timer0 ad un valore costante (1250us) e si termina la routine.
Altrimenti si deve generare il segnale di controllo.
Ho pensato di salvare il tempo Ton di ogni servo in un array di 2 byte per ogni servo, nel nostro caso quindi in un array di 4 byte. Ci servono 2 byte perché ci serve conoscere la durata del Ton (1 byte) ed il tempo necessario a completare i 2500us. Ho pensato che la routine di interrupt non dovesse fare alcun calcolo, per non appesantirla troppo, e che questi numeri fossero già calcolati da chi decide come posizionare i servo: sarà quindi compito della parte di controllo dei pulsanti calcolare questi 2 byte per ogni servo.
Quello che a noi interessa nella routine di interrupt è solo sapere che c'è un array di 2 byte per servo:
Codice: Seleziona tutto
    volatile unsigned char intTime[byteIntTime];

e che questo array contiene le durate dei primi 4 semi-periodi.

Nella fase di generazione dei segnali di controllo si deve per prima cosa azzerare tutti i segnali di controllo:
Codice: Seleziona tutto
             SER1=0;
             SER2=0;

quindi impostare il timer0 al prossimo interrupt così come specificato nell'array intTime:
Codice: Seleziona tutto
TMR0=intTime[intNumber];

ed infine impostare alto il segnale di controllo del servo:
se siamo al semiperiodo 0 (primo semiperiodo) imposto alto il servo1, se siamo nel semiperiodo 2 (terzo semiperiodo) imposto alto servo2:
Codice: Seleziona tutto
             if (intNumber==0) SER1=1;
             if (intNumber==2) SER2=1;


La ruotine di interrupt è tutta qui, più difficile a spiegarsi che a scriversi.
La routine è "semplice" ma implica che l'array intTime venga correttamente valorizzato.
Abbiamo detto che questo array deve avere valori così impostati:
intTime[0]=tempo di on del servo 1
intTime[1]=tempo necessario a completare i 2500us del servo1
intTime[2]=tempo di on del servo 2
intTime[3]=tempo necessario a completare i 2500us del servo2
Per facilitare la valorizzazione di questo array ho scritto una routine che riceva il numero di servo ed il tempo di Ton desiderato, la routine imposta i 2 byte del servo richiesto. Questa routine è la void setServo(unsigned char servo, unsigned char time):
Codice: Seleziona tutto
    void setServo(unsigned char servo, unsigned char time) {
       servo--;
       servo=servo<<1;
       intTime[servo]=time;   
       servo++;
       intTime[servo]=200-time;
    }

La routine riceve servo che rappresenta il numero del servo da impostare (contiene 1 o 2).
Quando riceve 1 deve valorizzare i byte 0 e 1, quando riceve 2 deve valorizzare i byte 2 e 3.
Per determinare i byte da valorizzare si eseguono la seguenti:
primoByte=(servo-1)*2
secondoByte=primoByte+1
La prima si scrive:
Codice: Seleziona tutto
       servo--;     // -1
       servo=servo<<1;    // *2

La seconda:
Codice: Seleziona tutto
       servo++;     // +1

il primo byte viene valorizzato con il tempo richiesto, il secondo con il tempo necessario a completare i 2500us e viene calcolato come differenza.

In questo modo per impostare il servo uno in una qualsiasi posizione basta scrivere:
Codice: Seleziona tutto
setServo(1, posizione);

per il servo due:
Codice: Seleziona tutto
setServo(2, posizione);


Ho preferito commentare in questo modo il codice e non con un commento su ogni riga, spero di essete stato abbastanza chiaro, se così non fosse chiedi pure.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

0
voti

[59] Re: Problema servocomando

Messaggioda Foto Utentefantamed » 17 nov 2013, 20:18

si fabio e tutto molto chiaro e dettagliato,ho dato una lettura veloce e intuitivamente mi sembra di capire .

Dovro pero studiarlo per bene bene,tipo:

Non conoscevo Volatile ....... e gia qui una domandina " va da 0 a 15 (0 sarebbe sarebbe (intNumber)e15 (maxIntNumber) ma come mai 15 e standard ?

Non conosco cos'e un'array quindi devo studiarmelo in rete (se conosci un sito dove spiega bene? )

Questo (<<)e uno shift a sinistra, quindi sposti il bYte?

E poi questo:
c1b8 ha scritto:void setServo(unsigned char servo, unsigned char time) {
servo--;
servo=servo<<1;
intTime[servo]=time;
servo++;
intTime[servo]=200-time;
}

che non ho capito molto

Adesso appena riesco ad isolarmi dal quotidiano ;-) , mi metto sotto con lo studio
A presto,buona serata e buona Domenica
Ti ringrazio sei un grande :ok:




grazie a presto
Avatar utente
Foto Utentefantamed
30 5
Frequentatore
Frequentatore
 
Messaggi: 110
Iscritto il: 8 nov 2013, 13:44

0
voti

[60] Re: Problema servocomando

Messaggioda Foto Utentec1b8 » 17 nov 2013, 20:42

fantamed ha scritto:Non conoscevo Volatile ....... e gia qui una domandina " va da 0 a 15 (0 sarebbe sarebbe (intNumber)e15 (maxIntNumber) ma come mai 15 e standard ?

volatile è un qualificatore che si utilizza, o dovrebbe a mio avviso essere utilizzato, nelle variabili che vengono utilizzate nelle routine di interrupt e modificate nel programma principale (o viceversa).
Non ho capito il resto del tuo dubbio. Comunque, dobbiamo contare 16 interrupt, per contare questi interrupt si usa la variabile intNumber. Il primo valore di questa variabile non è 1 ma 0, quindi dopo 16 interrupt assume il valore 15. Ecco perché ho detto che assume valori da 0 a 15.
Non so se fosse questo il tuo dubbio....

fantamed ha scritto:Non conosco cos'e un'array quindi devo studiarmelo in rete (se conosci un sito dove spiega bene? )

No, ma un qualunque corso di C, e non solo di C, ne parla.

fantamed ha scritto:Questo (<<)e uno shift a sinistra, quindi sposti il bYte?

<< shifta a sinistra, >> shifta a destra. Entrambi sono seguiti da un numero, il numero di shift da effettuare. Quindi scrivere << 1 significa shiftare a sinistra di 1, << 3 significa shiftare a sinistra di 3. Stesso discorso per lo shift a destra. Cosa viene shiftato? vengono shiftati i bit. Scrivere A = B << 1 significa shiftare a sinistra di 1 i bit di B e assegnare il risultato ad A.
Shiftare a sinistra o a destra ha molti utilizzi, uno di questi è moltiplicare o dividere per 2.
Shift a sinistra = moltiplicare per 2 ad ogni shift. Shift di 1 = moltiplicare per 2. shift di 2 = moltiplicare per 4 (2*2)
Shift a destra = dividere per 2 ad ogni shift.

Aspetto eventuali altre tue domande dopo lo studio del codice.
Fabio
Avatar utente
Foto Utentec1b8
3.595 3 8 13
G.Master EY
G.Master EY
 
Messaggi: 1770
Iscritto il: 15 gen 2009, 15:23

PrecedenteProssimo

Torna a Elettronica generale

Chi c’è in linea

Visitano il forum: Google [Bot], MSN [Bot] e 227 ospiti