Vai al contenuto
PLC Forum


Interrupt O Polling?


aduri

Messaggi consigliati

Salve a tutti,

Vorrei un consiglio di programmazione.

Nel momento in cui ricevo un impulso di comando devo compiere conversioni A/D per circa 5msec.

Questa successione è periodica e si ripete 7 volte.

Io, inizialmente, pensavo di usare gli interrupt su RB0 e impostare il timer1 per contare fino a 5msec.

Leggendo, però, alcune discussioni sembra che quando i segnali sono periodici e quindi non eventi casuali (ad esempio una tastiera) è preferibile la tecnica del polling.

Sul primo INT su Rb0 penso basti controllare lo stato del pin RB0 e se si verifica l’evento si va al sotto programma dell’ADC.

Riguardo il timer avete dei consigli su cosa fare.

Il timer inteso come delay non credo mi possa essere utile.

Ciao

Antonio

Link al commento
Condividi su altri siti


Per prima cosa vediamo se ho capito correttamente il problema.

Dalle sigle che usi si arguisce che il micro sia un PIC e che usi il convertitore A/D integrato nel micro stesso.

Hai un segnale con funzioni di comando; al riconoscimento del comado devi eseguire una serie di conversioni A/D per circa 5 ms.

Il polling lo si esegue per segnali lenti e che abbiano una durata consistente. Per esempio se devo riconosce la pressione di un tasto azionato da una persona, posso usare la tecnica del polling.

Il miglior modo di eseguire il polling è quello di leggere gli ingressi a cadenza fissa, ad esempio ogni 10ms o 20ms. In questo modo è anche facile eseguire un debouncing (antirimbalzo) software

Se invece devi riconoscere un evento veloce, specialmente se di breve durata come una camma, per esempio, la tecnica migliore è collegare un ingresso ad interrupt al generatore di evento.

Nel tuo caso, dalle generiche informazioni che dai, sembra sia utile usare interrupt come da te ipotizzato con l'uso di RB0.

Riconosciuto il comando io effettuerei una serie di conversioni non per un tempo, ma per un numero fisso. In funzione del tipo di micro e del clock che usi sai il tempo di conversione del tuo A/D. Ipotizzando, ad esempo, 250us per conversione eseguirai 20 conversioni con un semplice loop di for o while.

Se in vece necessiti proprio di un tempo fisso nel quale eseguire le conversioni, programma il timer 1 con interrupt alla scadenza.

Modificato: da Livio Orsini
Link al commento
Condividi su altri siti

Grazie della risposta.

In effetti io pensavo di usare l'interrupt su Rb0 sul fronte di salita in quanto si tratta di analizzare la parte positiva di 2 sinusoidi fino al picco con creazione array di dati ed invio in seriale nei successivi 5ms prima della nuova serie di campionamenti.

Lo zero crossing generato da un ne55 è il segnale di trigger su rb0.

Io utilizzando un pic18f4550, avevo calcolato, datasheet alla mano un tempo di 24uSec a campionamento che arrotondato a 30 portava a 5000/30=166 campionamneti in 5msec

(più che sufficenti anche facendo la media aritmetica tra i campionamenti in questa successione adc1 adc2 adc2 adc1 per avere il valore medio il più possibile sincrono tra i due canali che purtroppo sono in multiplex).

Da dove viene il tempo di sampling così alto???? non è che ti riferivi alla serie 16F.

Comunque io per l'adc uso una libreria personale che lavora direttamente sui registri.

Ho optato per la serie 18F in quanto rispetto al pic16f877a il condensatore di hold e di 25 anzichè 120pF.

Chiaramente gli ingressi vengono condizionati e passano per un operazionale configurato come inseguitore per ottenere una impedenza in uscita quasi nulla gradita ai PIC.

Ciao

Antonio

Link al commento
Condividi su altri siti

Oltre a quanto già detto, direi che è fondamentale per la scelta il fatto di dover fare o meno altre operazioni durante l'attesa di RB0.

Se fai un polling e vuoi essere sicuro di beccare il trigger, difficilmente puoi permetterti di fare altre cose. L'interrupt ti permette di fare altre operazioni senza preoccuparti di niente.

Stessa cosa negli intervalli tra una lettura e l'altra, un conto è fare un polling sul flag del timer, altra cosa è sfruttare l'interrupt anche per questo (come suggerito da Livio).

L'uso degli interrupt è sicuramente più efficace ed anche più elegante. L'unico motivo per evitarlo è la difficolta a comprenderne il funzionamento (tipico degli hobbisti) ma se parli di tesi non dovrebbe essere il tuo caso. laugh.gif

Link al commento
Condividi su altri siti

Per ora comincio a provare col polling poi magari passo all'interrupt.

Ho provato questo codice senza la funzione fast adc ma con libreria std MKB, che è dedicata al pic18f4550, e funzionava ma lentamente.

Col 4550 manda invece sulla seriale in yperterminal tutti zero.

Dal datasheet non sono riuscito a capire ma non è che la usart del 4550 lavora diversamente dal 877a? E' legato all'USB?

grazie ancora

Antonio

program prova_da_adc_232_4550

'in prova_da_adc_232 

dim t as word
    Text as char[20]
    tword as string[5]
    i as byte

    dim Va as word[4][4] 'bidim. array for anodic voltage
    dim Vk as word[4][4] 'bidim. array for anodic voltage
    dim Ca,g,ch as byte      'Ca ---> sampling, g----> grid voltage

 'function speed adc 
   
  sub function ReadADC(dim Ch as Byte) as word
    ADCON2 = %10001010 '  FOSC/32  ,  2 TAD  ,Right Justified
    ADCON0 =  Ch * 4
    SetBit(ADCON0,ADON)
    SetBit(ADCON0,GO)
    while TestBit(ADCON0,GO) wend   'Wait for Conversion
    Result = ADRESH  * 256 + ADRESL  '10 Bit  Right Justified
    ClearBit(ADCON0,ADON)
  end sub

sub procedure Usart_out

  Usart_Init(9600)

for g=0 to 6
          for Ca=0 to 69

              t=Va[g][Ca] 'load array V anodic and k index Vgrid
                     wordtostr(t,tword)
                     Usart_Write_text(tword)
                     Usart_Write(",")

              t=VK[g][Ca] 'load array V catodic and k index Vgrid
                     wordtostr(t,tword)
                     Usart_Write_text(tword)
                     Usart_Write(";")
          next Ca
next g

end sub

sub procedure setup

    lcd_cmd(LCD_CLEAR)
    lcd_out(1,1,"wait")
    lcd_chr(2,9,"S")
    lcd_chr(2,10,"T")
    lcd_Out(2,11,"ART")
    delay_ms(1000)

end sub

main:

  TRISC=0x00
  PORTB  =0
  TRISB  =0
  intcon =0
  Lcd_init(PORTD)
  lcd_cmd(LCD_CURSOR_OFF)
  lcd_cmd(LCD_CLEAR)
  'Text ="Tube tracer"
  lcd_out(1,1,"Tube tracer")
  Text ="A. Durighello"
  lcd_out(2,1, Text)
  'Setbit(PORTB,1)     'for usb project
  OPTION_REG = $80
  ADCON1     = $82
  TRISA      = $FF
  Delay_ms(1000)
  lcd_cmd(LCD_CLEAR)
  Text  = "Ciclo letture:"
  Delay_ms(2000)
  lcd_out(2,1,Text)

  setup

while true
if (portb. 0 = 1) then

for g=0 to 6  'nr. 7 measure x each Vgrid

  for Ca=0 to 69   '70 campioni per ogni tensione
             'Va[g][Ca]=Adc_Read(0)  'load array V anodic and k index Vgrid
             'Vk[g][Ca]=Adc_Read(1)  'load array V catodic and k index Vgrid
             
             'adc con registri x 18f4550
             Va[g][Ca]=ReadADC(0)
             Vk[g][Ca]=ReadADC(1)
             

             delay_us(3)            'to modify to target a delay about 10msec

  next Ca
  'g=g+1   ' shynchron.

next g
    if (g = 6)  then
       usart_out
    end if

end if
wend

end.

Link al commento
Condividi su altri siti

Un USART è un USART e lavoran tutti nel medesimo modo; sicuramente saran diversi i registri e l'interfaccia con il micro.

Modificato: da Livio Orsini
Link al commento
Condividi su altri siti

Sono in velocità e quindi non riesco a dare una occhiata attenta al codice che hai postato. Però la USART è sempre la stessa. Hai settato correttamente i registri?

Per i PIC in genere i principali sono l'SBRGH per il baud rate ed ovviamente il TXREG e RCREG per la trasmissione e la ricezione.

Sicuramente mi sbaglio perchè ho letto in fretta il codice, però, se non ricordo male, nel 16F877 varia "qualcosa" nel settaggio dell'ADC, ovvero devi settare anche il registro ANSEL per la configurazione del modulo AC:

ANSEL.ADCS = 010 in tal modo setti Fosc/32.

Attento anche al registro CMCON che è il comparatore e può a volte creare conflitti (se dovesse dare "rogne" meglio disabilitarlo --> 0x07h).

Ciao

Edge

Link al commento
Condividi su altri siti

Grazie delle risposte, intanto mi sono accorto di un errore grossolano il dimensionamento degli array:

dim Va as word[4][4] 'bidim. array for anodic voltage

dim Vk as word[4][4] 'bidim. array for anodic voltage

deve essere

[7][70]

Poi, poichè il codice deriva da uno funzionante col 877a ho fatto un pò di caos coi registri.

La funzione ReadADC(dim Ch as Byte) dovrebbe contenere i settaggi giusti ma

nel main ho messo questi settaggi di registri che vanno in conflitto.

OPTION_REG = $80

ADCON1 = $82

proverò a correggerli.

Grazie

Ciao

Antonio

Link al commento
Condividi su altri siti

non conviene dichiarare nel codice le costanti con i valori dei registri, ci sono gli "include" che comprendono queste informazioni specifiche per ogni micro.

Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...