|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Junior Member
Iscritto dal: Dec 2013
Messaggi: 2
|
Programma Assembly
Salve, a tutti sono nuovo del forum è la prima volta che posto qualcosa in quanto avrei bisogno di un grosso aiuto da parte vostra.
Dovrei scrivere un programma in assembler per il pic 16f887 ma non so dove mettere le mani. Il programma da scrivere è il seguente : Si realizzi un programma che conti quante volte l utente preme un pulsante,terminando il conteggio quanto un time-out di 1 s trascorre senza che sia premuto il tasto,quindi emetta brevi suoni con il buzzer, con n pari al numero di pressioni di contatto. Il mio problema è che non so come far leggere il numero di volte che è stato premuto il pulsante, per quanto riguarda il time out l ho gia settato. Vi ringrazio anticipatamente per il vostro aiuto ![]() |
![]() |
![]() |
![]() |
#2 |
Junior Member
Iscritto dal: Dec 2013
Messaggi: 2
|
Ho risolto il problema però , se ne è posto un altro... il buzzer suona di continuo come premo il reset e inizio a premere il pulsante suona tante volte quante volte ho premuto il tasto però se non lo premo più suona di continuo...come faccioa risolverlo?
Metto in allegato il codice in assembly list p=16f887 ; direttiva che definisce il tipo di processore #include <P16F887.INC> ; file che contiene le definizioni dei simboli ;****************************************** ; ******CONFIGURATION BIT******** __CONFIG _CONFIG1, _INTRC_OSC_NOCLKOUT & _CP_OFF & _WDT_OFF & _BOR_OFF & _PWRTE_OFF & _LVP_OFF & _DEBUG_OFF & _CPD_OFF ;****************************************** ; ******** DEFINIZIONE COSTANTI********* ; Costanti con cui settare il contatore del timer per contare un determinato intervallo di tempo. tmr_50ms EQU (.259 - .195) ;********************************************************************** ; *** Definizione variabili *** ; La direttiva UDATA_SHR (uninitialized data shared) dichiara una sezione di dati ; da allocare in RAM, e precisamente nella sezione di RAM comune a tutti ; i banchi, in modo da poter accedere ai dati indipendentemente dal banco ; impostato. udata_shr counter RES 1 ; riserva un byte di memoria associato alla label counter (= contatore) oscil RES 1 ; BYTE PER FAR OSCILLARE IL BUZZER ;********************************************************************** ; *** Vettore di reset *** ; Il vettore di reset è l'istruzione che viene eseguita per prima ; dopo un reset del microcontrollore. ; La direttiva CODE dichiara una sezione di codice da allocare in ROM. ; Viene specificato esplicitamente l'indirizzo 0000, in quanto il ; vettore di reset deve trovarsi in questa posizione (codice non rilocabile). ; La label non è necessaria, ma è utilizzata per chiarezza del codice. RST_VECTOR CODE 0x0000 pagesel start ; imposta la pagina della memoria di programma in cui si trova ;l'indirizzo della label start goto start ; salta all'indirizzo indicato dalla label start ;********************************************************************** ; *** Programma principale *** ; La direttiva CODE dichiara una sezione di codice da allocare in ROM. ; Non viene specificato un indirizzo esplicito, il linker successivamente ; assegnerà un indirizzo assoluto di inizio per la sezione (codice rilocabile) MAIN CODE start ; N.B: l'assembler non accetta una label sulla ;stessa riga di una direttiva ; inizializzazione hardware pagesel INIT_HW ; direttiva che imposta la pagina della memoria ;di programma in cui risiede la subroutine INIT_HW call INIT_HW ; chiamata alla subroutine indicata dalla label INIT_HW banksel PORTD clrf PORTD clrf counter ; loop principale main_loop ; N.B: l'assembler non accetta una label su una direttiva movlw 0x80 banksel TMR1H movwf TMR1H banksel PIR1 bcf PIR1,TMR1IF ; loop di attesa pressione pulsante banksel PORTB ; banco di PORTB wait_press clrwdt ; azzera timer watchdog per evitare reset btfss PORTB,0 ; se il bit 0 della porta B è = 0 (pulsante premuto) salta l'istruzione seguente goto premuto ; ripete il loop ; pulsante premuto: debounce e inizio conteggio di 1 s per determinare pressione successiva banksel PIR1 btfsc PIR1,TMR1IF goto buzzer goto wait_press ; periodo timer scaduto (1s) premuto pagesel DELAY movlw tmr_50ms call DELAY ; *** provare a commentare la chiamata a subroutine DELAY per evitare il debouncing *** ; loop di attesa rilascio pulsante banksel PORTB ; banco di PORTB asp_press clrwdt ; azzera timer watchdog per evitare reset btfss PORTB,0 ; se il bit 0 della porta B è = 1 (pulsante rilasciato) salta l'istruzione seguente goto asp_press ; ripete il loop ; pulsante rilasciato: attesa debouncing e ripetizione loop principale pagesel DELAY ; imposta la pagina della memoria di programma in cui risiede la subroutine DELAY ; carica in W la costante (precedentemente definita) per la misura di 10 ms movlw tmr_50ms call DELAY ; *** provare a commentare la chiamata a subroutine DELAY per evitare il debouncing *** incfsz counter,f ; incrementa counter goto main_loop buzzer banksel PORTD bsf PORTD,0 loop_buzzer call beep movlw tmr_50ms call DELAY decfsz counter goto loop_buzzer goto main_loop beep movlw .200 movwf oscil beep1 movlw B'00000100' ; carico il valore binario in W banksel PORTC xorwf PORTC,f ; inversione del bit movlw .253 call DELAY decfsz oscil,f goto beep1 return ; *** Subroutine DELAY: attesa di un tempo selezionabile *** ; nel registro W viene passato il valore da impostare come contatore iniziale del timer. DELAY ; Utilizzo del timer in polling: settare il contatore al valore iniziale voluto, ; azzerare il flag e attendere tramite un loop che il flag venga settato di nuovo. banksel TMR0 movwf TMR0 ; copia W in TMR0 (contatore del timer) bcf INTCON,T0IF ; azzera il flag di overflow di TMR0 wait_delay clrwdt ; azzera timer watchdog per evitare reset btfss INTCON,T0IF ; se il flag di overflow del timer è = 1, salta l'istruzione seguente goto wait_delay ; ripeti il loop di attesa return ; uscita da subroutine e ritorno al punto del codice in cui era stata chiamata INIT_HW ; registro OPTION_REG: ; - pull-up porta B abilitati. ; - TMR0 incrementato da clock interno (1 MHz) ; - prescaler assegnato a TMR0 ; - valore prescaler 1:256 (clock TMR0 = 3.90625 kHz) ; Le impostazioni precedenti determinano per TMR0 i seguenti valori: ; - periodo di un singolo incremento (tick) = 256 us ; - periodo totale (da 00 a FF) = 65.536 ms banksel OPTION_REG ; banco di OPTION_REG movlw B'00000111' ; carica costante binaria 00000110 in W movwf OPTION_REG ; copia W (11000110b) in OPTION_REG ; registro INTCON: ; - tutti gli interrupt disabilitati clrf INTCON ; INTCON = 0 ; Porte I/O: ; - porte A,C,B,E settate come input digitali per tutti i pin, ; tranne RA0 settato come input analogico ; - porta D: pin 0..3 settati come output (LED), pin 4..7 come input banksel TRISA ; banco di TRISA, stesso banco anche per gli altri registri TRISx movlw 0xFF ; carica costante FF in W movwf TRISA ; copia W (FF) in TRISA movwf TRISB ; copia W (FF) in TRISB movwf TRISE ; copia W (FF) in TRISE movlw 0xF0 ; carica costante F0 in W movwf TRISD ; copia W (F0) in TRISD movlw B'11111011' ; movwf TRISC ; ; Di default, tutti i pin connessi all'ADC sono settati come input analogici, ; impedendone l'uso come I/O digitali. L'impostazione seguente rende I/O digitali ; i pin RB0..RB3 banksel ANSELH ; banco di ANSELH clrf ANSELH ; AN8..AN13 disattivati movlw B'00001011' banksel T1CON movwf T1CON return end Spero in un vostro aiuto Grazie |
![]() |
![]() |
![]() |
#3 | |
Senior Member
Iscritto dal: Jan 2001
Città: Livorno
Messaggi: 1361
|
Suona di continuo perchè tu gli stai dicendo:
conta fino x se premo il pulsante riparti a contare da 0 se non lo premo continua a contare se raggiungi x suona Infatti se il pulsante non viene mai premuto il ciclo è questo: Codice:
wait_press clrwdt ; azzera timer watchdog per evitare reset btfss PORTB,0 ; se il bit 0 della porta B è = 0 (pulsante premuto) salta l'istruzione seguente goto premuto ; ripete il loop ; pulsante premuto: debounce e inizio conteggio di 1 s per determinare pressione successiva banksel PIR1 btfsc PIR1,TMR1IF goto buzzer goto wait_press Ovvio che se non premi il tasto prima o poi raggiunge x e quindi suona. Il programma comunque è concepito male, devi usare gli interrupt impostando quello sul cambiamento di stato degli ingressi tipo RB0. Poi ci vuole quello su tmrf1 che deve generarsi quando va in timeout. Non conosco il 16f887 ma probabilmente ha la funzione capture, se ce l'ha usa quella e parti da 0 a contare anzichè da 0x80, è una soluzione più pulita. A quel punto il main loop diventa: Quote:
|
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 07:08.