View Full Version : [Assembler] PIC16F84A
montegentile
07-04-2009, 15:43
Salve,
ho fatto un programma per questo pic, in pratica c'ho attaccato un modulo radio che riceve segnali da un telecomando, sempre radio a 434 MHz
Quando premo un pulsante abilito il salvataggio del codice ricevuto.
Quando esco dalla programmazione (premendo nuovamente il tasto), i bit ricevuti vengono confrontati con quelli salvati in EEPROM prima.
Se combaciano deve attivare o disattivare un relè.
Il problema è che riceve (e lo so perché quando riceve faccio accendere un led), salva (e lo so perché quando salva fa una sequenza di lampeggii), ma non rilascia mai il relè.... perché il confronto è sempre sbagliato....
La mia domanda è:
come posso vedere quello che è stato salvato in EEPROM ???
Inoltre, c'è un simulatore HARDWARE compatimible con MPLAB di MicroChip ?
Grazie
Fabio7586
07-04-2009, 16:27
Salve,
ho fatto un programma per questo pic, in pratica c'ho attaccato un modulo radio che riceve segnali da un telecomando, sempre radio a 434 MHz
Quando premo un pulsante abilito il salvataggio del codice ricevuto.
Quando esco dalla programmazione (premendo nuovamente il tasto), i bit ricevuti vengono confrontati con quelli salvati in EEPROM prima.
Se combaciano deve attivare o disattivare un relè.
Il problema è che riceve (e lo so perché quando riceve faccio accendere un led), salva (e lo so perché quando salva fa una sequenza di lampeggii), ma non rilascia mai il relè.... perché il confronto è sempre sbagliato....
La mia domanda è:
come posso vedere quello che è stato salvato in EEPROM ???
Inoltre, c'è un simulatore HARDWARE compatimible con MPLAB di MicroChip ?
Grazie
Scusa ma non lo puoi scrivere in c il programma? potrebbe risultare più facile, e ci sarebbero molte più persone preparate sull'argomento! :)
montegentile
08-04-2009, 07:04
Potrei, ma il C per MPLab mi pare che non sia gratuito se non per la versione leggera.
Fabio7586
08-04-2009, 08:03
Potrei, ma il C per MPLab mi pare che non sia gratuito se non per la versione leggera.
Guarda che tu puoi scriverlo dovunque il codice c, mica è protetto da copyright!
Apri un foglio di blocco note, scrivi il codice e salvalo .c, ed hai fatto, dopodichè lo compili in assembler con un compilatore gratuito;
Puoi usare meprog, Htlpic, etc.. vedi tu, non esistono solo prgrammi a pagamento! :)
Poi non so se già lo conosci, ma dai un'occhiata qui, la persona che lo gestisce è molto cortese e molto preparata http://www.fisertek.it/ e magari potrà darti una mano un po più specificamente!
montegentile
08-04-2009, 10:18
Ho controllato nell'istallazione di MPLAB ed il compilatore C di HI-TECH è già incluso, così ho creato un nuovo progetto e scritto esclusivamente questa riga:
#INCLUDE<pic1684.h>
Poi ho compilato ma mi restituisce questo errore:
HI-TECH PICC-Lite COMPILER (Microchip PICmicro) V9.60PL2
Copyright (C) 1984-2008 HI-TECH SOFTWARE
Error [939] ; . no file arguments
Che devo fare ???
montegentile
08-04-2009, 10:36
Ok, risolto.
Provvedo a riscrivere il codice in C e poi lo posto.... a tra un po'
montegentile
08-04-2009, 11:21
Mha...
Se uso
#include<pic1684.h> come setto i fuses ?
Li riesco a settare solo includendo pic.h ma non funzionano tutte le uscite
Fabio7586
08-04-2009, 13:15
Mha...
Se uso
#include<pic1684.h> come setto i fuses ?
Li riesco a settare solo includendo pic.h ma non funzionano tutte le uscite
mmm... hai provato ad inserire la direttiva _CONFIG nel sorgente, perchè così facendo dovresti avere un .hex con all'interno informazioni per i fuses;
altrimenti potresti usare Icprog per leggere i fuses e vedere come sono impostati, cambiare il watch dog e riprogrammare il pic!
se invece intendi in quale modo vanno settati, ti posso dire sommariamente che generalmente vanno
# CodeProtect: No
# PowerUpTimer: Yes
# WatchDogDimer: No
# Oscillator: RS
ESEMPIO:
__CONFIG(HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTDIS & DEBUGDIS & UNPROTECT );
I POSSIBILI VALORI PER IL PIC16F877 SONO (Ovviamente tu dovrai fare riferimento al tuo pic, controlla datasheet qui http://ww1.microchip.com/downloads/en/DeviceDoc/35007b.pdf):
*osc configurations*/
RC 0x3FFF // resistor/capacitor
HS 0x3FFE // high speed crystal/resonator
XT 0x3FFD // crystal/resonator
LP 0x3FFC // low power crystal/resonator
/*watchdog*/
WDTEN // enable watchdog timer
WDTDIS // disable watchdog timer
/*power up timer*/
PWRTEN // enable power up timer
PWRTDIS // disable power up timer
/*brown out reset*/
BOREN // enable brown out reset
BORDIS // disable brown out reset
/*Low Voltage Programmable*/
LVPEN // low voltage programming enabled
LVPDIS // low voltage programming disabled
/*data code protected*/
DP // protect data code
// alternately
DPROT // use DP
DUNPROT // use UNPROTECT
/* Flash memory write enable/protect */
WRTEN /* flash memory write enabled */
WRTDIS /* flash memory write protected/disabled */
/*debug option*/
DEBUGEN // debugger enabled
DEBUGDIS // debugger disabled
/*code protection*/
PROTECT /* protect program code */
UNPROTECT /* do not protect the code */
Non sono molto esperto, ma qualcosina la so! Fammi sapere! :)
P.S. Scusa se scrivo in c, ma l'assembler non l'ho mai potuto digerire! :)
montegentile
08-04-2009, 14:19
Col mio programmatore non posso settare direttamente i fuses.
Così, in Assembler, lo facevo attraverso una direttiva __CONFIG
Ma non funziona in C
Così come non funzionano quelli che mi hai appena suggerito...
montegentile
08-04-2009, 14:36
Ho risolto per i fuses...
ho scritto questo codice qui:
#include<pic1684.h>
unsigned short i;
main()
{
TRISA=00011111;
TRISB=00000011;
PORTA=0;
PORTB=0;
RB2=1;
RB3=1;
while(1)
{ //Inizio While
RB7=0;
Delay();
RB7=1;
} //Fine while
}
Delay()
{
for (i=0;i<10000;i++)
{
//Attesa
}
}
Mi aspetterei RB2 e 3 (che sono 2 led collegati) accesi... e se ne accende uno solo.
Poi mi aspetterei un RB7 lampeggiante... e invece niente... che diavolo sbaglio ?
Fabio7586
08-04-2009, 14:59
Ho risolto per i fuses...
ho scritto questo codice qui:
#include<pic1684.h>
unsigned short i;
main()
{
TRISA=00011111;
TRISB=00000011;
PORTA=0;
PORTB=0;
RB2=1;
RB3=1;
while(1)
{ //Inizio While
RB7=0;
Delay();
RB7=1;
} //Fine while
}
Delay()
{
for (i=0;i<10000;i++)
{
//Attesa
}
}
Mi aspetterei RB2 e 3 (che sono 2 led collegati) accesi... e se ne accende uno solo.
Poi mi aspetterei un RB7 lampeggiante... e invece niente... che diavolo sbaglio ?
Così il codice:
#include<pic1684.h>
unsigned short i;
main()
{
TRISA=0;
TRISB=0;
PORTB = 0b00001100;
while(1)
{ //Inizio While
PORTB = 0b00001100;
Delay(1000);
PORTB = 0b10001100;
} //Fine while
}
Delay(1000)
{
for (i=0;i<10000;i++)
{
//Attesa
}
}
montegentile
08-04-2009, 15:40
Non si accende il led collegato a PORTB,3.
Sono sicuro che funziona perché se carico il programma scritto in assembler si accende come da programma.
Ho fatto quest'altro spezzone di codice:
main()
{
while(1)
{ //Inizio While
Tasto0();
Radio();
} //Fine while
}
Radio()
{
//Vede se riceve segnali da radio su PORTA0
if (RA0==1)
{ //Si riceve qualcosa dalla radio
RB2=1;
Delay();
RB2=0;
}
} //Fine Radio
Non ricevo niente, quando invece dovrei vedere un led accendersi di tanto in tanto o quando trasmetto io.
Anche qui: sono sicuro che funziona perché nel programma .asm si accende e riceve segnali.
Fabio7586
08-04-2009, 16:06
Non si accende il led collegato a PORTB,3.
Sono sicuro che funziona perché se carico il programma scritto in assembler si accende come da programma.
Ho fatto quest'altro spezzone di codice:
main()
{
while(1)
{ //Inizio While
Tasto0();
Radio();
} //Fine while
}
Radio()
{
//Vede se riceve segnali da radio su PORTA0
if (RA0==1)
{ //Si riceve qualcosa dalla radio
RB2=1;
Delay();
RB2=0;
}
} //Fine Radio
Non ricevo niente, quando invece dovrei vedere un led accendersi di tanto in tanto o quando trasmetto io.
Anche qui: sono sicuro che funziona perché nel programma .asm si accende e riceve segnali.
Scusa eh, ma hai seguito il codice che ti ho postato più su?
non usare RB, ma PORTB con codice binario, che va scritto anteponendo 0b che sta ad indicare che successivamente c'è un codice binario; deve funzionare obbligatoriamente quello che ti ho scritto!
Rispondi e non mi dici nemmeno se hai provato, ma come te lo do un aiuto sennò?
Nel programma puoi scrivere quello che ti pare, ma le istruzioni da dare al pic sono ben precise! Io non conosco l'assembler, ma col c me la cavo, se nell'assembler usavi RB come porta, qui non va bene, perchè nella conversione in hex, non fai riferimento a nulla!
montegentile
08-04-2009, 23:13
Non ho provato ma proverò al più presto.
Comunque ho letto il file PIC1684.h e dentro ci sono le definizioni per PORTA, PORTB e pure RAx, RBx e puntano agli indirizzo giusti... quindi, secondo me, è la stessa cosa....
montegentile
09-04-2009, 07:52
Ho fatto la prova che chiedevi:
#include<pic1684.h>
unsigned short i;
bit Flag1;
main()
{
//Procedura di inizio
TRISA=00011111;
TRISB=00000011;
PORTB=0;
Flag1=0;
PORTB=0b00001100;
Switch_Status();
while(1)
{ //Inizio While
Tasto0();
Radio();
} //Fine while
}
Tasto0() verifica la pressione di un tasto (e funziona correttamente accendendo un led su PORTB.7)
Radio() dovrebbe ricevere uno stato logico alto quando la ricevente 434 riceve un segnale da un telecomando che ho.... ma non riceve assolutamente niente.
E comunque l'uscita 3 di PORTB alla quale è collegato un LED giallo non si accende mai.
Non so dove sbaglio ma non mi pare ci sia molto da sbagliare...
Volutomitra
09-04-2009, 08:17
Ho fatto la prova che chiedevi:
TRISB=00000011;
E comunque l'uscita 3 di PORTB alla quale è collegato un LED giallo non si accende mai.
Attenzione: quando tu fai TRISB=00000011; setti TRISB a 11 in decimale, cioè 1011 in binario. PORTB3 in questo modo è settato come input.
Dovresti sostituire con:
TRISB=0b00000011;
Fabio7586
09-04-2009, 08:47
Attenzione: quando tu fai TRISB=00000011; setti TRISB a 11 in decimale, cioè 1011 in binario. PORTB3 in questo modo è settato come input.
Dovresti sostituire con:
TRISB=0b00000011;
L'ho precisato anche più su, scrivendoglielo anche, devi anteporre 0b davanti agli indirizzi sennò non te li riconosce come binari!
esattamente gli avevo scritto così:
#include<pic1684.h>
unsigned short i;
main()
{
TRISA=0;
TRISB=0;
PORTB = 0b00001100;
while(1)
{ //Inizio While
PORTB = 0b00001100;
Delay(1000);
PORTB = 0b10001100;
} //Fine while
}
Delay(1000)
{
for (i=0;i<10000;i++)
{
//Attesa
}
}
Ma evidentemente non riesce a capirmi...boh?!
montegentile
09-04-2009, 09:15
Si, OK
Il problema era 0b anteposto a TRISA e TRISB
Faccio un po' di prove...
montegentile
09-04-2009, 09:37
Allora...
Funziona senza problemi anche la dicitura
RBx=1;
dove x è chiaramente l'uscita che si vuole comandare.
Mi chiedo:
Un ciclo fatto così:
Delay()
{
for (i=0;i<1000;i++)
}
Quanto dura utilizzando un quarzo da 4MHz ?
Io credo che dovrebbe durare 1ms... è corretto o no ?
Ho bisogno di implementarmi alcune pause stabilite che vanno da 0.1 ms fino a 1 ms ma debbo poterne cambiare il valore se mi accorgo che la trasmissione arriva sporca.
Fabio7586
09-04-2009, 10:26
Allora...
Funziona senza problemi anche la dicitura
RBx=1;
dove x è chiaramente l'uscita che si vuole comandare.
Mi chiedo:
Un ciclo fatto così:
Delay()
{
for (i=0;i<1000;i++)
}
Quanto dura utilizzando un quarzo da 4MHz ?
Io credo che dovrebbe durare 1ms... è corretto o no ?
Ho bisogno di implementarmi alcune pause stabilite che vanno da 0.1 ms fino a 1 ms ma debbo poterne cambiare il valore se mi accorgo che la trasmissione arriva sporca.
Allora, per sfruttare il quarzo devi includere la routine delay.h
Questa è una routine per 500ms, poi sistemala tu, è per un quarzo a 4Mhz
;************************************************* ****************
;Routine di ritardo per mezzo secondo
;************************************************* ****************
DELAY1S bcf STATUS, RP0 ;Vado al banco 1
movlw .50 ;Carico il valore esadecimale in W 50
movwf TEMPO1 ;Lo metto nel registro di sistema
call DEL_10 ;Richiamo la routine DEL10
return ;Torno al programma chiamante
DEL_10 bcf INTCON, 2 ;Azzero il flag di overflow
movlw 0xd8 ;Carico il valore esadecimale in W
movwf OPTION_REG ;Lo metto nel timer
DEL10 btfss INTCON, 2 ;Controllo se è andato in overflow
goto DEL10 ;No. Torna al DEL10_1
decfsz TEMPO1, 1 ;Decremento il registro TEMPO1 e lascio il risultato
;nel registro TEMP
goto DEL_10 ;SI. Vado a DEL10
return ;Torno all programma chiamante
----Devi dichiarare TEMPO1
Questa è in assembler, controllati l'header per vedere quali sono le funzioni per c
Se invece, non riesci a sfruttare il quarzo, puoi sempre mettere un valore di 100 in delay --------> Delay(100), per ottenere una pausa di 100ms, che è una procedura gestita già da c.
alternativamente in c puoi vedere se funzione questo:
#include <pic.h>
#define POLLING_PERIOD 200 //with 4Mhz processor, 200us
#define TMR0_PRESCALER 1 //gives 1:4 prescaler
//the -3 factor is to make up for overhead
//the 0xff- factor is because the timer counts *up* to 0xff
//do not change this
#define TMR0_SETTING (0xff - (POLLING_PERIOD-3))
main()
{
OPTION&=0B11000000; //turn off bottom 6 bits to configure tmr0
OPTION|=TMR0_PRESCALER; //set prescaler to 1:4
while(1)
{
TMR0=TMR0_SETTING;
T0IF=0;
while(T0IF==0); //wait 800us for flag to go high
//OK, tmr0 has overflowed, flag T0IF has gone high
//this code right here is executed every 800us
}
}
o questo
#include <pic.h>
#define POLLING_PERIOD 200 //with 4Mhz processor, 200us
#define TMR0_PRESCALER 1 //gives 1:4, 800us
//the -5 factor is to make up for overhead
//the 0xff- factor is because the timer counts up to 0xff
#define TMR0_SETTING (0xff - (POLLING_PERIOD-5))
main()
{
OPTION&=0B11000000; //turn off bottom 6 bits to configure tmr0
OPTION|=TMR0_PRESCALER; //set prescaler to 1:4
//work out which interrupt enable bits to set by referring to diagram
T0IE=1;
GIE=1;
while(1)
{
//idle, using interrupt to execute code
}
}
void interrupt isr(void)
{
if (T0IF)
{
TMR0=TMR0_SETTING;
T0IF=0;
//code right here is executed every 800us
}
}
Fammi sapere!
io ti consiglio di provare le routine di delay con un oscilloscopio se ne hai la possibilità.
montegentile
10-04-2009, 11:26
Allora,
sono riuscito a riceve il codice radio, ora vorrei sapere se qualcuno sa come scrivo in EEPROM e leggo da EEPROM in C... grazie
montegentile
10-04-2009, 19:32
Dunque, vorrei brevemente descrivere il progetto:
Ho della sensoristica che produce un codice radio a 36 Bit
Viene trasmesso un 1 attraverso uno stato logico alto che dura X ms.
Dopo un uno viene trasmessa una pausa P1
Viene trasmesso uno 0 attraverso uno stato logico alto che dura Y
Dopo uno zero viene trasmessa una pausa P2
Il totale di ogni periodo è sempre 2 ms.
Io ricevo un codice ma, per problemi di sincronismo perdo il 1° bit che uso per la sincronizzazione.
Io ho usato, per la ricezione del codice radio questa routine:
Radio() //Ricezione Codice radio
{
//Vede se riceve segnali da radio su PORTA0
if (RA0==0)
{
return;
}
//Si riceve qualcosa dalla radio
DelayMs(1);
if (RA0==1)
{
//Ricevo un codice radio
Attesa_Basso(); //Attendo fronte basso
Attesa_Alto(); //Attendo fronte alto
Delay_Breve();
//Decodifica codice
for (j=0; j<36; j++)
{
DelayMs(1);
un_bit=0;
if (RA0==1) un_bit=1;
switch (j)
{
case 1:
B1=un_bit;
...Continua...
Quindi, utilizzo una routine che attende il fronte basso (Attesa_Basso), poi attendo il fronte alto (Attesa_Alto) e a questo punto sono certo di essere all'inizio di un bit, faccio un controllo ogni 2 ms ovvero al centro del periodo, attendo un ms (DelayMs(1)) e quindi mi pongo al centro e poi, non si vede ma c'è, dopo aver ricevuto il codice.
Ho provato a fare una cosa del genere:
Radio()
{
if (RA0==0) return; //Se non c'è ricezione ritorna
Conta_Tempo=0; //Azzero un contatore
while(1);
{
if (RA0==0) break;
Conta_Tempo++
}
if (Conta_Tempo < uncertovalore) un_bit=0;
if (Conta_Tempo > unaltrovalore) un_bit=1;
....Continua....
}
Poi, per debug, ho fatto accende un led per Conta_Tempo volte.
Il led si accende ma solo una volta.... credo che questa non sia la via giusta.
Volevo chiedervi, allora, come si usa il timer interno ?
Vorrei fare una cosa del genere:
Radio()
{
if (RA0==0) return;
Timer=0;
while (1)
{
if (RA0==0) break;
}
Tempo = Timer
...continua...
}
Potrebbe funzionare ?
montegentile
14-04-2009, 15:14
Sono riuscito a fare quasi tutto... il problema è che ho finito il k di memoria...
Passando al 16f628 ci sono variazioni sostanziali o rimane tutto uguale ?
Inoltre, come posso controllare il singolo bit di un byte ?
Cioè, io ho un int Byte1 che parte da 0
Per mettere a 1, il terzo bit da sx come faccio ?
Grazie
Fabio7586
17-04-2009, 09:04
Sono riuscito a fare quasi tutto... il problema è che ho finito il k di memoria...
Passando al 16f628 ci sono variazioni sostanziali o rimane tutto uguale ?
Inoltre, come posso controllare il singolo bit di un byte ?
Cioè, io ho un int Byte1 che parte da 0
Per mettere a 1, il terzo bit da sx come faccio ?
Grazie
Ciao, non ho ben capito sto fatto della memoria, sono un programmatore, quindi so cos'è in linea di massima, ma non ho mai avuto di questi problemi, forse anche perchè non ho mai fatto progetti molto grandi, comunque puoi provare ad usare qualche pic con molta più memoria!
Per il fatto del bit, non ho capito cosa vorresti cercare di leggere, forse intendi così:
10001010 e vorresti mettere lo zero che ho segnato in rosso a 1?
montegentile
17-04-2009, 09:45
Si, esatto.
Siccome ho un codice radio trasmesso a bit, adesso uso una cosa del genere:
for (i=1; i<32; i++)
{
un_bit=0;
if (RB0==1) un_bit=1;
switch (i)
{
case 1:
Byte1=un_bit*128;
break;
case 2:
Byte1=Byte1+un_bit*64;
case 3:
Byte1=Byte1+un_bit*32;
.... e proseguo per 4 Byte
}
}
E' chiaro se se avessi modo di scrivere esattamente il bit che mi interessa potrei scrivere il codice in maniera più opportuna. Seppure in questo modo funziona a dovere.
Per quanto riguarda il fatto della memoria: semplicemente avevo superato le 1024 words scrivibili nel PIC, e quindi, con poche modifiche, ho adattato il tutto ad un PIC più capiente.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.