Vai al contenuto
PLC Forum


Accendere suonare un Cicalino per 1 Secondo ... - tramite un impulso di 5ms


stefano_

Messaggi consigliati

salve a tutti,

il problema questa volta è che devo far suonareun cicalino per un secondo avendo com start un impulso che dura 5ms proveniente dal pic.

Ho fatto la seguente prova:

dall'uscita del pic vado alla base di un transistor npn (bc337) tramite una r da 10K, collego il collettore a +5v e l'emettitore a massa, fatto ciò ho messo in parallelo al cicalino un condensatore da 4,7 uF.

Il problema è che in questa maniera il cicalino suona per circa 4 / 5 secondi, vorrei solamente diminuire la durata sino ad arrivare a 0.5 / 1 secondo al massimo come posso fare ?? Ho sbagliato tutto oppure c'è qualcosa di buono ??

Grazie 1000 a tutti

Link al commento
Condividi su altri siti


perche il pic lo utilizzo per visualizzare delle cifre su 4 display multiplexati, quindi il loop principale del programma del pic lo utilizzo per variare lo stato delle uscite ogni 5ms quindi il ritardo di cui sopra lo dovrei fare tramite l'interrupt ( magari di overflow del tmr0 ) ma non so proprio da dove cominciare.

Il pic lo programmo in basic tramite pic basic ma non ho capito ancora come gestire l'interrupt, per questo ho voluto fare un circuitino esterno che con l'impulso mi fa rimanere attivo il cicalino per 1s circa.

Se sapete qualcosa sull'interrupt in pic basic AIUTATEMI !!!

comunque grazie 1000 per le vostre risposte male che va utilizzerò il cond + piccolo

ciao e grazie ancora

Link al commento
Condividi su altri siti

Non finirò mai di ripeterlo: prima di utilizzare linguaggi di programmazione di "alto" livello con i PIC, bisogna comprendere bene l'Assembler. E comuque c'è sempre la possibilità di realizzare le routine potenti e complesse in Basic o in C e le routine che necessariamente devono essere affidabili e snelle in Assembler.

Ti riporto il codice per la gestione in Assembler di tmr0 ad interrupt. Si tratta di un lavoro che avevo fatto anni fa su PIC16F876 e funziona benissimo. Non limitarti ad un copia e incolla... il codice è molto commentato e faresti bene a capirlo prima di implementarlo nella tua applicazione. Se il tuo compilatore basic decompila, potresti provare a dargli in pasto il file ASM e verificare se lo interpreta correttamente. Trovi applicazioni simili sui tutorial Microchip.

Tieni presente che io uso molto le macro e le subroutine e tendo a definire i MIEI mnemonici, il tutto è molto semplificabile. Ti ho lasciato le macro per i vari valori di prescaler per darti la possibilità di cambiare la base dei tempi del timer.

; *****************************************************************************
; LIST STATEMENT 
; *****************************************************************************
    list  p=16F876
; *****************************************************************************
; REGISTER FILES ASSIGNMENT 
; *****************************************************************************
    tmr0            equ     H'01'; timer 0
    status          equ     H'03'; stato ALU
    option_reg    equ    H'81'; controllo opzioni diverse
    intcon  equ    H'0B'; controllo interrupt
; *****************************************************************************
; REGISTER BITS ASSIGNMENT 
; *****************************************************************************
    c         equ     H'00'; riporto
    z  equ    H'02'; risultato logico/aritmetico
    t0if  equ    H'02'; interrupt timer 0
    t0ie  equ    H'05'; abilitazione interrupt timer 0
    gie  equ    H'07'; abilitazione interrupt globali    
    rp0  equ    H'05'; bit 0 selezione banco memoria
    rp1  equ    H'06'; bit 1 selezione banco memoria
    ps0  equ    H'00'; bit 0 valore prescaler
    ps1  equ    H'01'; bit 1 valore prescaler
    ps2  equ    H'02'; bit 2 valore prescaler    
    psa  equ    H'03'; bit assegnazione prescaler
    t0cs  equ    H'05'; selezione sorgente clock timer 0
; *****************************************************************************
; INTERNAL BIT DEFINITIONS 
; *****************************************************************************
    #define  zero  status,z; bit di zero
    #define  carry  status,c; bit di carry
    #define  tmr0_int    intcon,t0if; interrupt timer 0
    #define  tmr0_int_en    intcon,t0ie; abilit. int. timer 0
    #define  glb_int_en    intcon,gie; abilit. int. globali
    #define  clk10ms  tmr1s,0    ; clock 10 ms
; *****************************************************************************
; CONSTANTS DEFINITION
; *****************************************************************************
    #define  tmr0_rst_val    H'00'; valore reset timer 0
    #define  tmr0_pst_val    D'99'; valore preset timer 0    
; *****************************************************************************
; VARIABLES ASSIGNMENT
; *****************************************************************************
    tmr1s  equ    H'20'; timer 1 secondo
; *****************************************************************************
; RESET VECTOR
; *****************************************************************************
      org    H'00'    ; vettore reset
        goto    Init    ; inizializzazione programma  
; *****************************************************************************
; INTERRUPT VECTOR
; *****************************************************************************
      org    H'04'    ; vettore di interrupt
      goto    IntT0    ; gestione interrupt
; *****************************************************************************
; MACROS
; *****************************************************************************
;
; Bank
; 
    bank0  macro  ; inizio macro
      bcf    status,rp0; seleziona banco memoria 0
      bcf    status,rp1; //    
      endm  ; fine macro
    bank1    macro  ; inizio macro
      bsf    status,rp0; seleziona banco memoria 1
      bcf    status,rp1; //    
      endm  ; fine macro
    bank2    macro  ; inizio macro
      bcf    status,rp0; seleziona banco memoria 2
      bsf    status,rp1; //    
      endm  ; fine macro
    bank3    macro  ; inizio macro
      bsf    status,rp0; seleziona banco memoria 3
      bsf    status,rp1; //    
      endm  ; fine macro
;
; Timer 0
;
    tmr0_clk_int    macro  ; inizio macro    
      bank1  ; seleziona banco memoria 1
      bcf    option_reg,t0cs; abilita clock interno
      bank0  ; seleziona banco memoria 0    
      endm  ; fine macro
    tmr0_int_enf    macro  ; inizio macro    
      movlw    0x00    ; azzeramento bit registro 
      movwf    intcon    ; //
      bsf    glb_int_en; abilitazione interrupt glob. 
      bsf    tmr0_int_en; abilitazione interrupt tmr0
      endm  ; fine macro      
    tmr0_rst    macro  ; inizio macro    
      movlw    tmr0_rst_val; azzeramento timer 0
      movwf    tmr0    ; //
      endm  ; fine macro
    tmr0_pst    macro  ; inizio macro
      movlw    tmr0_pst_val; impostazione timer 0
      movwf    tmr0    ; //    
      endm  ; fine macro
;    
; Prescaler
;
    prsclr_tmr0    macro  ; inizio macro
      bcf    option_reg,psa; abilita prescaler (tmr0)
      endm  ; fine macro
    prsclr_2    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bcf    option_reg,ps0; rapporto prescaler 1:2
      bcf    option_reg,ps1; //
      bcf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0
      endm  ; fine macro
    prsclr_4    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bsf    option_reg,ps0; rapporto prescaler 1:4
      bcf    option_reg,ps1; //
      bcf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0    
      endm  ; fine macro
    prsclr_8    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bcf    option_reg,ps0; rapporto prescaler 1:8
      bsf    option_reg,ps1; //
      bcf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0
      endm  ; fine macro
    prsclr_16    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bsf    option_reg,ps0; rapporto prescaler 1:16
      bsf    option_reg,ps1; //
      bcf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0
      endm  ; fine macro
    prsclr_32    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bcf    option_reg,ps0; rapporto prescaler 1:32
      bcf    option_reg,ps1; //
      bsf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0
      endm  ; fine macro
    prsclr_64    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bsf    option_reg,ps0; rapporto prescaler 1:64
      bcf    option_reg,ps1; //
      bsf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0    
      endm  ; fine macro
    prsclr_128    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bcf    option_reg,ps0; rapporto prescaler 1:128
      bsf    option_reg,ps1; //
      bsf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0
      endm  ; fine macro
    prsclr_256    macro  ; inizio macro
      bank1  ; seleziona banco memoria 1
      bsf    option_reg,ps0; rapporto prescaler 1:256
      bsf    option_reg,ps1; //
      bsf    option_reg,ps2; //
      bank0  ; seleziona banco memoria 0
      endm  ; fine macro
; *****************************************************************************
; INIT 
; *****************************************************************************
    Init    call    IniT1s    ; Inizializzazione timer 1 secondo
  call    IniT0    ; inizializzazione timer 0
  goto    Main    ; salto a programma principale
; *****************************************************************************
; SUBROUTINES
; *****************************************************************************
;
; IniT1s azzera il timer 1 secondo.
;
    IniT1s    clrf    tmr1s    ; azzera il timer 1 secondo
  return  ; fine subroutine  
;
; IniT0 inizializza il timer 0.  Le impostazioni sono le seguenti: sorgente di
; clock interna, prescaler abilitato con rapporto 1:64, interrupt timer 0
; abilitato, interrupt globali abilitati, impostazione registro al valore 99.
;
    IniT0    tmr0_clk_int    ; abilitazione clock interno
  prsclr_tmr0    ; abilitazione prescaler 
  prsclr_64    ; rapporto prescaler 1:64      
  tmr0_int_enf    ; abilitazione interrupt
  tmr0_pst    ; impostazione registro timer
  return  ; chiusura subroutine
; 
; IntT0    verifica lo stato del bit di interrupt del timer 0. Se il timer 0 ha
; raggiunto la condizione di overflow, viene azzerato l'interrupt e
; aggiornato il contatore. Le funzioni nop sono necessarie per ottenere un
; timing pari esattamente a 10 ms (9.984 + 16 us) e tenendo presente che è
; richiamata una macro.  
;
    IntT0    btfss    tmr0_int; verifica interrupt timer 0      
  retfie  ; fine subroutine
  bcf    tmr0_int; azzeramento interrupt timer 0
  nop  ; nessuna operazione
  nop  ; //    
  nop  ; //
  nop  ; //
  nop  ; //
  nop  ; //
  nop  ; //
  nop  ; //
  nop  ; //
  tmr0_pst    ; impostazione registro timer 0
  call    TmrSvc    ; aggiornamento timer 1 secondo    
  retfie  ; fine subroutine
;
; TmrSvc gestisce tmr1s    che è un contatore incrementale da 0 a 100. La base dei
; tempi è pari a 10 ms. L'overflow del contatore viene pertanto raggiunto ogni
; secondo.
; 
    TmrSvc    incf    tmr1s,w    ; incrementa il timer e salva in w
      xorlw    D'100'    ; verifica se il valore è 100
  btfsc    zero    ; //
  clrf    tmr1s    ; se valore = 100 azzera il timer
  incf    tmr1s,f    ; se valore != 100 incrementa il timer
  return  ; fine subroutine
; *****************************************************************************
; MAIN
; *****************************************************************************
    Main      ; INSERISCI QUI IL PROGRAMMA PRINCIPALE
  goto    Main    ; chiude il loop
; *****************************************************************************
; END
; *****************************************************************************      
    End      ; fine del programma    

Ricorda che usare una rete RC per generare un ritardo avendo a disposizione un microprocessore che fa anche il caffè è tremendamente squalificante! :lol:

Ciao.

Link al commento
Condividi su altri siti

Ho notato che la formattazione del codice fa un po' schifo... forse nel file che ho copiato c'era qualche TAB che è stato sostituito da spazi dalla funzione CODE del forum. Se decidi di usarlo è meglio metterlo a posto in modo che sia bel leggibile. Lo farei io ma non ho tempo! ;)

Ciao.

Link al commento
Condividi su altri siti

grazie 1000 FranSys la penso come te ma non è semplice affatto imparare l'assembler senza nessuno a fianco che ti dia qualche dritta,

voi del forum siete gentilissimi e sempre pronti a tutto ma vi assillerei troppo se ad ogni problema spedissi un post comunque

voglio provare ...... speriamo bene...

Link al commento
Condividi su altri siti

Non ho ben capito se il pin che utilizzi per il cicalino è utilizzato anche per pilotare un altra cosa oppure no.

Nel secondo caso non potresti risolvere con queste due seguenti righe?

High X' (x=pin da controllare)

pause 1000 '(attesa 1 secondo)

Low X ' (x=pin da controllare)

Andare a cercare un interrupt per la temporizzazione di durata di un cicalino mi sembra una discreta complicazione inutile.

Ciao a tutti

Link al commento
Condividi su altri siti

si, il pin è libero il problema è che io utilizzo altre 4 uscite per pilotare 4 display a 7 segmenti multiplexandole ogni 5ms

se utilizzo pause il multiplexing si blocca per 1 secondo !!!

grazie 1000 a tutti

Link al commento
Condividi su altri siti

Puoi fare in questo modo:

Quando la condizione per far suonare il cicalino si verifica setti l'uscita, se l'uscita è settata inizi a incrementare la variabile contatore, quando questo ha raggiunto tot conteggi (io ho messo 800) resetti l'uscita e azzeri la variabile.

Considera che la durata del suono è legata al tempo ciclo del tuo programma, in questo caso dura 800 scansioni.

Ovviamente il tempo non sarà costante dal momento che dipende dalle scansioni, ma eviti di usare interrupt o altre cose complicate, se il suono dura 1 secondo o 1,1 secondi poco cambia

contatore var word

contatore=0

cicalino=0

******* TUO CODICE *******

If condizionesuono=1 then high cicalino

if cicalino=1 then contatore=contatore+1

if contatore>=800 then low cicalino:contatore=0

Io molte volte faccio così.

Ciao

Marco

Modificato: da k6233
Link al commento
Condividi su altri siti

Anch'io a volte ho usato il metodo di k6233, quando non serviva precisione. Però è una soluzione poco elegante che ho adottato solo per comodità.

Credo che la gestione degli interrupt, per chi usa i microcontrollori, sia un "must have", spesso irrinunciabile.

Tenete presente che sfrondando il codice che ho riportato, il tutto si riduce ad una ventina d'istruzioni. Attenzione alla frequenza del quarzo dell'oscillatore. Io usavo un quarzo da 4 MHz per avere 1 us per ogni step di programma.

Ciao.

Link al commento
Condividi su altri siti

per K6233

facendo come dici tu sorge il seguente problema:

dopo il codice che accende il cicalino collegato per esempio alla portb 5 trovo il seguente codice che serve per accendere i display

portb = % 1001

come puoi notare cambio lo stato dei soli primi quattro bit ma nonostante ciò il bit 5 va a zero

considerando che cambio lo stato delle uscite all'interno di un ciclo select e che ripeto l'operazione per 30 volte

come posso fare ???

grazie 1000 a tutti

Link al commento
Condividi su altri siti

Il bit 5 va a 0 perchè fai una assegnazione diretta al valore della portab.

Per evitare questo dovresti cambiare lo stato dei primi quatto bit singolarmente:

high portb.0

low portb.1

low portb.2

high portb.3

Credo ci siano altri modi (meno macchinosi) ma adesso sono un pò arrugginito, è un pò di tempo che non scrivo codice!!!

Saluti

Marco

Link al commento
Condividi su altri siti

ciao K6233

funziona !!!! tutto ok o quasi.....

visto che ci sono ne approfitto per romperti ancora un pò e chiederti l'ultimo aiuto.

Devo vedere se una variabile vale 5 o un multiplo di 5 e se è così attivare porta.4 .Il codice che ho utilizzato è il seguente

if variabile = 5 or variabile = 10 or variabile = 15 then set porta.4

come puoi notare non è che sia il massimo anche perche devo arrivare fino a 100 !!!

ho visto che c'è una funzione che si chiama modulus e il simbolo è //

Dall'. in linea mi sembrava di aver capito che questa funzione mi restituisse il resto della divisione quindi se il resto di

variabile // 5 è 0 significa che la variabile vale 5 o un suo multiplo

Purtroppo non è cosi questo ragionamento va bene solo per il numero 2 e quindi riesco a vedere se un numero è pari ( 2 o un suo multiplo )

con 5 non funziona.

Come posso fare ??

grazie 1000 a tutti,

non so proprio come farei senza di voi !!!!

ciao ciao

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...