Vai al contenuto
PLC Forum


Modem Gsm E Pic 16F628


Saveriopapadia

Messaggi consigliati

Buongiorno,

ho delle difficoltà a far funzionare un modem gsm con modulo siemes t35 ed un pic 16f628 programmato in assembler.

Il mio obbiettivo è far partire una chiamata dal modem inviando in modo seriale il comando AT: ATD>SM1;

Il pic è stato programmato per inviare in modo seriale il comando AT+ il carriage return ma Il modem purtroppo non risponde.

Facendo delle prove traverse, in particolare collegando il modem al pc tramite hyperterminal, il modem effettua egregiamente la chiamata.

Ho collegato anche il pic al pc ed hyperterminal scrive il testo: ATD>SM1; e va a capo con il carriege return.

Non capisco perchè non funziona.

Di seguito il codice assembly:

LIST P=16F628, R=DEC ; Use the PIC16F628 and decimal system
#include "P16F628.INC" ; Include header file
__config _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_ON &
_BODEN_ON & _MCLRE_OFF
CBLOCK 0x20 ; Declare variable addresses starting at 0x20
dataL
Count
counta
ENDC
ORG 0x000 ; Program starts at 0x000
;
; --------------------------------
; SET ANALOG/DIGITAL INPUTS PORT A
; --------------------------------
;
movlw 7
movwf CMCON ; CMCON=7 set comperators off
;
; ----------------
; INITIALIZE PORTS
; ----------------
;
movlw b'00000000' ; set up portA
movwf PORTA
movlw b'00000100' ; RB2(TX)=1 others are 0
movwf PORTB
bsf STATUS,RP0 ; RAM PAGE 1
movlw 0xFF
movwf TRISA ; portA all pins input (per ricordarci 1 ingresso 0 uscita)
movlw b'11110010' ; RB7-RB4 and RB1(RX)=input, others output
movwf TRISB
; ------------------------------------
; SET BAUD RATE TO COMMUNICATE WITH PC
; ------------------------------------
; Boot Baud Rate = 9600, No Parity, 1 Stop Bit
;
movlw 0x19 ; 0x19=9600 bps (0x0C=19200 bps)
movwf SPBRG
movlw b'00100100' ; brgh = high (2)
movwf TXSTA ; enable Async Transmission, set brgh
bcf STATUS,RP0 ; RAM PAGE 0
movlw b'10010000' ; enable Async Reception
movwf RCSTA
;
; ------------------------------------
; PROVIDE A SETTLING TIME FOR START UP
; ------------------------------------
;
clrf dataL
settle decfsz dataL,F
goto settle
movf RCREG,W
movf RCREG,W
movf RCREG,W ; flush receive buffer
;
; ---------
MAINLOOP
btfss PORTA,1
goto MAINLOOP
call Delay
btfss PORTA,1
goto MAINLOOP

; ---------
;
call message ;
;
goto MAINLOOP
;
; -------------------------------------------------------------
; SEND CHARACTER IN W VIA RS232 AND WAIT UNTIL FINISHED SENDING
; -------------------------------------------------------------
;
send movwf TXREG ; send data in W
TransWt bsf STATUS,RP0 ; RAM PAGE 1
WtHere btfss TXSTA,TRMT ; (1) transmission is complete if hi
goto WtHere
bcf STATUS,RP0 ; RAM PAGE 0
return
;
; -------
; MESSAGE
; -------
;
message ;
movlw 'A'
call send
call Delay
call Delay
movlw 'T'
call Delay
call Delay
call send
movlw 'D'
call Delay
call Delay
call send
movlw b'00111110'
call Delay
call Delay
call send
movlw 'S'
call send
call Delay
call Delay
movlw 'M'
call send
call Delay
call Delay
movlw '1'
call send
call Delay
call Delay
movlw ';'
call send
call Delay
call Delay
movlw 0x0D ; CR
call send
return

Delay
clrf Count
clrf counta
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz counta,1
goto DelayLoop
return
END

Link al commento
Condividi su altri siti


Sembra che tu stia utilizzando l'oscillatore RC interno, non so se sia questo il tuo problema, ma quando usi una seriale asincrona il tempo è fondamentale e l'uso dell'oscillatore RC è sbagliato a prescindere.

Usa un quarzo, e scegli la frequenza più adatta in base all'errore che ovviamente dovrebbe essere più basso possibile.

Sul datasheet trovi sia la formula per calcolare l'errore che una tabella riportante gli errori alle varie velocità di seriale con le frequenze di cristalli più diffusi.

Link al commento
Condividi su altri siti

Scusa per il ritardo ma non mi collego da un pò.

Me se è come dici perchè la stringa è letta da Hyperterminal?

Secondo il mio punto di vista se hyperterminal legge la stringa significa che i tempi sono rispettati.

Leggerò il datasheet, grazie

Link al commento
Condividi su altri siti

Me se è come dici perchè la stringa è letta da Hyperterminal?

perchè si basa sull'UART del PC che è molto più tollerante in fatto di tempi.

L'uso di RC come clock del micro è consentito quando non si ha necessità di temporizzazioni precise e costanti. Quando si fa uso dell'oscillatore interno per generare clock asincroni, come in questo caso, la precisione e la costanza sono fondamentali, quindi bisogna usare un quarzo.

Link al commento
Condividi su altri siti

Non scomodatevi troppo!!!

Ho da poco implementato un programma Custom con UART via seriale usando l'oscillatore interno a 4MHz con il 16F628A, questi sono i valori di baudrate possibili utilizzando la suddetta configurazione:

// REAL BAUDRATE (bps) AT 4MHZ
/*    1200 =  1202 bps (error = 0.17 percent)
      2400 =  2404 bps (error = 0.17 percent)
      4800 =  4808 bps (error = 0.17 percent)
      9600 =  9615 bps (error = 0.16 percent)
      19200 = 19231 bps (error = 0.16 percent)
      38400 = 35714 bps (error = 6.99 percent) ???
      57600 = 62500 bps (error = 8.51 percent) ???
*/
Link al commento
Condividi su altri siti

Grazie ad entrambi, una domanda per Girock: con gli errori x baudrate postati mi vuoi dire che può andare bene anche l'oscillatore interno??

Oppure è solo una info sugli errori x baudrate

Link al commento
Condividi su altri siti

Il baudrate a 9600 va benissimo, il vero problema, è che c'erano degli errori nella configurazione, i caratteri trasmessi erano incomprensibili, ora li ho corretti e funziona...

    
    LIST P=16F628, R=DEC ; Use the PIC16F628 and decimal system
    
    #include "P16F628.INC" ; Include header file
    
    __CONFIG _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _MCLRE_OFF
    
    ERRORLEVEL -302
    
    CBLOCK 0x20 ; Declare variable addresses starting at 0x20
        dataL
        Count
        counta
    ENDC
    
    ORG 0x000 ; Program starts at 0x000
;
; --------------------------------
; SET ANALOG/DIGITAL INPUTS PORT A
; --------------------------------
;
    movlw 7
    movwf CMCON ; CMCON=7 set comperators off
;
; ----------------
; INITIALIZE PORTS
; ----------------
;
    movlw b'00000000' ; set up portA
    movwf PORTA
    movlw b'00000010' ; RA1 = input
    movwf PORTB
    bsf   STATUS,RP0 ; RAM PAGE 1
    movlw 0xFF
    movwf TRISA ; portA all pins input  (per ricordarci 1 ingresso 0 uscita)
    movlw b'00000010' ; RB7-RB4 and RB1(RX)=input RB2(TX)=output, others output
    movwf TRISB
; ------------------------------------
; SET BAUD RATE TO COMMUNICATE WITH PC
; ------------------------------------
; Boot Baud Rate = 9600, No Parity, 1 Stop Bit
;
    movlw 0x19 ; 0x19=9600 bps (0x0C=19200 bps)
    movwf SPBRG
    movlw b'00100100' ; brgh = high (2)
    movwf TXSTA ; enable Async Transmission, set brgh
    bcf   STATUS,RP0 ; RAM PAGE 0
    movlw b'10010000' ; enable Async Reception
    movwf RCSTA
;
; ------------------------------------
; PROVIDE A SETTLING TIME FOR START UP
; ------------------------------------
;
    clrf dataL
SETTLE 
    decfsz dataL,F
    goto SETTLE
    movf RCREG,W
    movf RCREG,W
    movf RCREG,W ; flush receive buffer
;
; ---------
MAINLOOP
    btfss PORTA,1
    goto  MAINLOOP
    call  Delay
    btfss PORTA,1
    goto  MAINLOOP

; ---------
;
    call message ;
;
    goto MAINLOOP
;
; -------------------------------------------------------------
; SEND CHARACTER IN W VIA RS232 AND WAIT UNTIL FINISHED SENDING
; -------------------------------------------------------------
;
SEND
    movwf TXREG ; send data in W
TRANSWT 
    bsf   STATUS,RP0 ; RAM PAGE 1
WTHERE
    btfss TXSTA,TRMT ; (1) transmission is complete if hi
    goto  WTHERE
    bcf   STATUS,RP0 ; RAM PAGE 0
    return
;
; -------
; MESSAGE
; -------
;
message ;
    movlw 'A'
    call SEND
    call Delay
    call Delay
    movlw 'T'
    call Delay
    call Delay
    call SEND
    movlw 'D'
    call Delay
    call Delay
    call SEND
    movlw b'00111110'
    call Delay
    call Delay
    call SEND
    movlw 'S'
    call SEND
    call Delay
    call Delay
    movlw 'M'
    call SEND
    call Delay
    call Delay
    movlw '1'
    call SEND
    call Delay
    call Delay
    movlw ';'
    call SEND
    call Delay
    call Delay
    movlw 0x0D ; CR
    call SEND
    return



Delay
    clrf   Count
    clrf   counta
DelayLoop
    decfsz Count,1
    goto   DelayLoop
    decfsz counta,1
    goto   DelayLoop
    return
    
 END

P.S. Non c'è nessuna ragione per trasmettere così lentamente, puoi anche ridurre il Delay...

Link al commento
Condividi su altri siti

via seriale usando l'oscillatore interno a 4MHz con il 16F628A,

Stai attento Gio. Le variazioni per temperatura rischian di portarti fuori tolleranza. Poi se dall'altra parte c'è un qualche cosa che è gia al limite di suo....auguri.

Link al commento
Condividi su altri siti

Ho controllato il codice, hai inserito: ERRORLEVEL -302, cosa vuol indicare nella configurazione?

Perché mi hai portato a 0 i bit dal 4 al 7 del TRISB?

Link al commento
Condividi su altri siti

E' logico Livio, dipende tutto anche da questi fattori termici, ma nel mio caso erano 2 PIC che dialogavano a temperatura ambiente, e quindi NO PROBLEM!!!

Comunque concordo, io non avendo più pin liberi ho optato per questa soluzione, altrimenti il quarzo è sempre preferibile anche se l'oscillatore interno è abbastanza preciso...

Diciamo che per ogni applicazione specifica, andrebbe valutata sempre la soluzione ottimale, in questo esempio praticamente non si utilizza quasi nulla dell'I/O a disposizione, quindi mettiamoci pure un bel quarzetto... :thumb_yello:

FILMATINO

Link al commento
Condividi su altri siti

Perché mi hai portato a 0 i bit dal 4 al 7 del TRISB?

Perchè li programma come out.

Giò io ho un'altra filosofia; considero il quarzo come obbligatorio. Non pretendo che sia condivisa da tutti, però io con questa scelta non ho mai avuto problemi di sorta. E il quarzo sempre alla massima frequenza ammessa dal micro, a meno di dover limitre i consumi.

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

Mi sono accorto ora e con più calma di prima, che le prime righe del codice inerrenti all'inizializzazione delle PORT non servono, prima si impostano le TRIS e poi al limite si assegna il valore alle PORT, in questo caso non devi fare nulla al di fuori di decidere quali sono gli IN e quali gli OUT, al resto pensa tutto il PIC e anche l'UART parte in base alla sua inizializzazione...

Da togliere senza pietà:

    ;movlw b'00000010' ; set up portA
    ;movwf PORTA
    ;movlw b'00000010' ; RA1 = input
    ;movwf PORTB

ERROR LEVEL -302, vuol dire che il compilatore non ti restiruisce quei fastidiosi messaggi sull'impostazione dei BANKs tipo: "Register in operand not in bank 0. Ensure that bank bits are correct."

Stavo anche pensando: non è che devi trasmettere il segnale Invertito???

In questo caso devi avere una pull-up con diodo su TX del PIC o un invertitore fatto con un transistor NPN...

P.S. La Regola impone che se imposti gli ingressi come IN, questi devono avere una pull-up o pull-down anche se non li usi, quindi è meglio mettere tutto su OUT quando sono liberi...


#Livio:

Come ti dicevo prima, dipende cosa devi farci, per utilizzo professionale sono d'accordo con te, ma per uso privato se non servono grandi precisioni, la cosa è comunque fattibile, non dimenticarti che il 16F628 è un piccolo gioiellino della casa Microchip, se pur datato, il suo oscillatore interno è ben calibrato...

Link al commento
Condividi su altri siti

una domanda per Girock: con gli errori x baudrate postati mi vuoi dire che può andare bene anche l'oscillatore interno??

...Forse a Gio è sfuggita la tua domanda, ti rispondo io... No! :smile:

Quelli elencati si riferiscono alla percentuale di errore che ottieni ad un dato baud rate con una data frequenza di clock.

Clock preciso non significa baudrate preciso, a meno che tu non scelga una quarzo con una frequenza avente un periodo che divida perfettamente il tempo di un bit nella trsmissione/ricezione seriale.

Forse un esempio chiarisce meglio il tutto:

Con un quarzo da 4 MHz il periodo è di 0,00000025 secondi (se preferisci 250 nS o 0,25 uS).

A 9600 bps un bit ha una durata di 0,00010416 secondi, o 104,16 uS (il 6 sarebbe periodico)

Per far trascorrere il tempo di un bit la CPU deve contare (104,16 / 0,25) 416 cicli di clock, ma 416 * 0,25 fa 104... non 104,16!

Ecco spiegati gli errori nella tabella postata da Gio.

A pagina 69 del datasheet trovi la formula per calcolare l'errore in base al baudrate e al clock, mentre a pagina 71 trovi le tabelle complete con gli errori già calcolati (quella di Gio è solo una parte) che ti consentono di scegliere il quarzo giusto per ottenere l'errore più basso possibile in base al baudrate desiderato.

Le tabelle ovviamente si riferiscono ad una frequenza ideale, e non fanno riferimento ad un particolare tipo oscillatore usato, anche usando un oscillatore atomico superpreciso avresti sempre un errore, a meno di usare una frequenza che divida perfettamente il baudrate.

Detto questo, mi rendo conto che preferiresti che potesse andare bene anche l'oscillatore interno, ma come già scritto in precedenza l'uso dell'RC interno è sbagliato a prescindere, giustificato solo dalla mancanza di pin per il quarzo, come indicato da Gio, e solo per applicazioni hobbistiche dove l'affidabilità è subordinata alle aspettative dell'hobbista stesso.

In poche parole, usalo pure ma non ti lamentare se non funziona :superlol:

Tanto per rendere l'idea della "precisione" dell'oscillatore interno ti allego un immagine tratta dal datasheet che mostra la frequenza dell'oscillatore interno in funzione della temperatura e della tensione di alimentazione. Come puoi vedere tu stesso la frequenza è tutt'altro che stabile.

L'oscillatore interno, essendo un banalissimo RC va usato SOLO se la precisione dei tempi di esecuzione non è importante, e nel caso di una seriale asincrona la precisione è importantissima.

Spero di aver chiarito la questione :smile:

6wlj.jpg

Link al commento
Condividi su altri siti

Ottima spiegazione e molto dettagliata Nikiki :thumb_yello:, in effetti vedo solo ora la domanda fatidica... :superlol:

Ad ogni modo, quando l'ho testato comparivano dei geroglifici al posto delle lettere, questo è dovuto alla scorretta inizializzazione delle PORT... :blink:

Nel codice, comunque mancano alcune cose fondamentali, io aggiungerei anche questo per completezza:

; --------------------------------
; SET ANALOG/DIGITAL INPUTS PORT A
; --------------------------------
;
    movlw 7
    movwf CMCON ; CMCON=7 set comperators off
   
    ;Disable pull-up
    BANKSEL OPTION_REG
    movlw   b'10000000'
    movwf   OPTION_REG
   
    BANKSEL INTCON
    clrf    INTCON


Per tornare al discorso di Livio sul risparmio energetico, la tecnica migliore da usare e mettere il PIC in sleep ed usare l'interrupt su RB0/INT dove è meglio che il pulsante risieda, in questo modo, ad ogni pressione del tasto si avrà un intervento a prescindere dalla modalità attuale in cui si trova il PIC, dopo l'invio dei dati si ritorna in modalità sleep diminuendo notevolmente l'assorbimento...

E inutile che il PIC cicli in eterno se queste chiamate sono sporadiche, io per esempio, l'ho usato per il campanello con melodia, mica lo faccio girare a manetta in attesa che qualcuno si degni di schiacciare il pulsante, lo accendo, si configura e si mette subito in sleep, se qualcuno poi preme il pulsante su RB0/INT, allora l'interrupt risveglia il sistema che rientra al volo sui 4MHz o alla massima velocità impostata...


MANUALE SIEMENS T35

Link al commento
Condividi su altri siti

Cerco di riepilogare,

Ho notato degli errori, probabilmente perchè ho postato un programma vecchio :whistling: , sotto quello aggiornato in particolare con i vostri consigli.
La porta input comando è la Rb4 è settata ad 1, Ra0 tutte output.

X Giorock:
Stavo anche pensando: non è che devi trasmettere il segnale Invertito???
In questo caso devi avere una pull-up con diodo su TX del PIC o un invertitore fatto con un transistor NPN...

Io ho utilizzato il classico schema con le porte del pic collegate alla max 232. Non sono molto esperto però ritengo che se funziona su hyperterminal credo che il segnale non dovrebbe essere invertito.

il pcb prevede la resistenza di pull down sulla porta rb4 .

Vi aggiorno non appena riprogrammo con il codice corretto. Nel caso in cui non funziona devo procurarmi il quarzo e rifare il pcb.

Ultimo codice:

LIST P=16F628, R=DEC ; Use the PIC16F628 and decimal system

#include "P16F628.INC" ; Include header file

__CONFIG _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _MCLRE_OFF

ERRORLEVEL -302

CBLOCK 0x20 ; Declare variable addresses starting at 0x20
dataL
Count
counta
ENDC

ORG 0x000 ; Program starts at 0x000
;
; --------------------------------
; SET ANALOG/DIGITAL INPUTS PORT A
; --------------------------------
;
movlw 7
movwf CMCON ; CMCON=7 set comperators off
;Disable pull-up
BANKSEL OPTION_REG
movlw b'10000000'
movwf OPTION_REG

BANKSEL INTCON
clrf INTCON
;
; ----------------
; INITIALIZE PORTS
; ----------------
;

bsf STATUS,RP0 ; RAM PAGE 1
movlw b'00000000'
movwf TRISA ; portA all pins input (per ricordarci 1 ingresso 0 uscita)
movlw b'00010010' ; RB4= input and RB1(RX)=input RB2(TX)=output, others output
movwf TRISB
; ------------------------------------
; SET BAUD RATE TO COMMUNICATE WITH PC
; ------------------------------------
; Boot Baud Rate = 9600, No Parity, 1 Stop Bit
;
movlw 0x19 ; 0x19=9600 bps (0x0C=19200 bps)
movwf SPBRG
movlw b'00100100' ; brgh = high (2)
movwf TXSTA ; enable Async Transmission, set brgh
bcf STATUS,RP0 ; RAM PAGE 0
movlw b'10010000' ; enable Async Reception
movwf RCSTA
;
; ------------------------------------
; PROVIDE A SETTLING TIME FOR START UP
; ------------------------------------
;
clrf dataL
SETTLE
decfsz dataL,F
goto SETTLE
movf RCREG,W
movf RCREG,W
movf RCREG,W ; flush receive buffer
;
; ---------
MAINLOOP
btfss PORTB,4
goto MAINLOOP
call Delay
btfss PORTB,4
goto MAINLOOP

; ---------
;
call message ;
;
goto MAINLOOP
;
; -------------------------------------------------------------
; SEND CHARACTER IN W VIA RS232 AND WAIT UNTIL FINISHED SENDING
; -------------------------------------------------------------
;
SEND
movwf TXREG ; send data in W
TRANSWT
bsf STATUS,RP0 ; RAM PAGE 1
WTHERE
btfss TXSTA,TRMT ; (1) transmission is complete if hi
goto WTHERE
bcf STATUS,RP0 ; RAM PAGE 0
return
;
; -------
; MESSAGE
; -------
;
message ;
movlw 'A'
call SEND
call Delay
call Delay
movlw 'T'
call Delay
call Delay
call SEND
movlw 'D'
call Delay
call Delay
call SEND
movlw b'00111110'
call Delay
call Delay
call SEND
movlw 'S'
call SEND
call Delay
call Delay
movlw 'M'
call SEND
call Delay
call Delay
movlw '1'
call SEND
call Delay
call Delay
movlw ';'
call SEND
call Delay
call Delay
movlw 0x0D ; CR
call SEND
return

Delay
clrf Count
clrf counta
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz counta,1
goto DelayLoop
return

END



Questo è il code che utilizzerò:

Link al commento
Condividi su altri siti

Mentre tutti parlano solamente del fattore temperatura che degrada la precisione del baudrate, io sto anche analizzando il codicillo che non mi pare un esempio di assoluta correttezza... :wacko:

Io toglierei tutti quei Delay, tanto la trasmissione è controllata dal flag TRMT, piuttosto ne aggiungerei uno prima della call MESSAGE ed un paio a fine trasmissione per evitare che se il pulsante viene mantenuto premuto troppo a lungo, la routine possa essere richiamata velocemente, comunque andrebbe ottimizzato ancora come ti ho spiegato nel post precedente...

Se vuoi puoi metterci anche questo per resettare le PORT:

    bcf   STATUS,RP0 ; RAM PAGE 0

    ;----------------------------
    ; RESET ALL PORT
    ;----------------------------
    clrf PORTA
    clrf PORTB

Per ora verifica che il problema non sia dovuto alla mancanza del quarzo, ma inviare i dati così lentamente, potrebbe inficiare ulteriormente la ricezione... ;)

Link al commento
Condividi su altri siti

  • 2 weeks later...
Saveriopapadia

Salve, scusate l'enorme ritardo nel fare le prove.

NON FUNZIONA!!!!!!

Ho ridotto e tolto anche i delay ma non funziona, proverò a sviluppare un pcb con quarzo.

Link al commento
Condividi su altri siti

Ho trovato il sito dove hai preso il codice (potevi anche linkarlo prima al posto di farlo passare come tuo), come si evince dalla lettura, il PIC necessita una conversione degli stati logici da TTL a RS232, spero che tu non abbia collegato direttamente quest'ultimo al MODEM...

628uart.gif

Link al commento
Condividi su altri siti

Salve, scusate l'enorme ritardo nel fare le prove.

NON FUNZIONA!!!!!!

Ho ridotto e tolto anche i delay ma non funziona, proverò a sviluppare un pcb con quarzo.

Puoi anche provare a mettercelo volante il quarzo prima di ridisegnare il pcb.
Link al commento
Condividi su altri siti

Sembra facile fare un buon caffè, ma a volte ci si ritrova con delle ciofeche imbevibili. :smile:

Le cose se non si studiano prima si devono imparare più faticosamente dopo. ;)

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