kiki kaikai Inserito: 23 agosto 2019 Segnala Inserito: 23 agosto 2019 Buon Giorno amici, in questi giorni sto facendo un semplice esperimento, vorrei utilizzare il PIC16F877A per scrivere in una eprom esterna ( tipo 0x55 ) utilizzo MPLAB X IDE v5.20 e come compilatore uso XC8, Per prima cosa ho scaricato tutto il materiale possibile per studiarci sopra, il concetto i2c è molto chiaro ma la difficoltà è nello scrivere il programma facendo attenzione alle virgolette, in più bisogna anche saper bene cosa scrivere in base al compilatore utilizzato giusto? La seconda cosa che ho fatto è accendere un semplice led così ho testato il PICkit4 , i vari collegamenti per la programmazione e in fine anche il PIC. Come avrete capito sono veramente alle prime armi, quindi vorrei farvi delle domande per risolvere gli errori del programma, ho ripreso il programma che fa accendere un led e da qui sono partito con l'inserimento del codice trovato su vari siti a blocchi,dove spiegano i passaggi per la comunicazione i2c, quindi ho fatto un riassunto e ho preparato il codice ma come immaginavo non funziona. Vorrei postare all'interno di una tendina il codice, ma non so come si fa??adesso cerco come si fa oppure se c'è qualcuno che mi spiega faccio prima, qui sotto allego lo schema.
kiki kaikai Inserita: 23 agosto 2019 Autore Segnala Inserita: 23 agosto 2019 Quote /*********************************************** * Codice scheda: ???????????? * * Firmware version:1.0 * * MCU: PIC16F877A -PIC16F876A * * Piattaforma hardware: ???????????????????? * * Piattaforma software: MPLAB X 5.20 * * Clock 4 Mhz * * Collegamento PIN: * * 1, 11, 32: VCC pin 1 10k +5 * * 12, 31: VSS * * 37: RB4 -> pulsante attivo alto * * 18: SCL * * 23: SDA * * 33: RB1 -> led VERDE * * 34: RB2 -> led GIALLO * ************************************************/ /*Definizione delle funzioni*/ #include <htc.h> #include "delay.h" #include <pic.h> #include "delay.C" /*Funzione di inizializzazione del protocollo i2c*/ void i2c_init(void) { TRISC3 = 1; // Impostazione linea SCL come input TRISC4 = 1; // Impostazione linea SDA come input SSPCON = 0x38; //0b00101000; abilita Modalita' Master, Clock=Fosc/(4*(SSPADD+1)) SSPCON2 = 0; //0x00 ; SSPADD = 0x0B; // Clock a 400 Khz con Fosc a 20 Mhz SSPSTAT = 0b11000000 ; // STAT_CKE = 1;Slew rate disabilitato Sample mode conforme a standard I2C SMP = 0; // Slew rate control (SMP) on (per 100Khz devono stare off) SSPIF = 0; // Reset flag serial port BCLIF = 0; // Reset flag del bus collision } /******************************************************************************/ /*Funzione che attende che sia conclusa l'operazione in corso */ void I2cWait() { while (!SSPIF) { // Attende l'impostazione del flag di interrupt continue; } SSPIF=0; } /******************************************************************************/ /*Funzione di attesa prima di coninciare a scrivere*/ void i2c_waitForIdle() { while(R_nW || (SSPCON2 & 0x1F)); //while ((SSPCON2 & 0x1F) | STAT_RW) vecchio { continue; // Attende per l'idle e trasmissione non in corso } } /******************************************************************************/ /*Funzione di start del protocollo i2c*/ void i2c_start() { i2c_waitForIdle(); SSPIF = 0; SEN = 1; // Avvia lo start I2cWait(); // Attende che sia conclusa l'operazione } /******************************************************************************/ /*Funzione di stop del protocollo i2c*/ void i2c_stop() { i2c_waitForIdle(); SSPIF = 0; PEN = 1; // Avvia lo stop ACKEN = 1; I2cWait(); } /******************************************************************************/ /*Funzione di scrittura seriale sulla eeprom*/ unsigned char i2c_write( unsigned char i2cWriteData ) { i2c_waitForIdle(); SSPBUF = i2cWriteData; // Carica il buffer con il dato I2cWait(); // Attende la fine della trasmissione return !ACKSTAT; // Restituisce 1 se lo slave ha inviato l'ACK } /******************************************************************************/ /*Funzione di scrittura sulla eeprom*/ unsigned char addrh; unsigned char addrl; //addrl=LOW_BYTE(address); void write_ext_eeprom(unsigned char address, unsigned char data,unsigned char addrh,unsigned char addrl) { unsigned char addrh; unsigned char addrl; //addrl=LOW_BYTE(address); //addrh=HIGH_BYTE(address);(address); i2c_start(); i2c_write(0xa0); // send chip addr and set data to write mode i2c_write(addrh); // high addr bits i2c_write(addrl); // low addr bits RB2=i2c_write(data); //se la scrittura è andata a buon fine RB2 = 1 -> led rosso acceso i2c_stop(); DelayUs(10); RB2=0; //spengo il led rosso } /******************************************************************************/ void main(void) { TRISB1=0; //imposta la porta RB1 come output TRISB2=0; //imposta la porta RB2 come output TRISB4=1; //imposta la porta RB4 come input RB1=1; //led verde di accensione i2c_init(); //inizializzazione del protocolle I2C while(1) //rimane in un ciclo infinito { if(RB4==1) //se RB4 è 1 vuol dire che è sato premuto il tasto { write_ext_eeprom(0x0B, 0x00); //scrivo il dato 00 nella posizione 000B write_ext_eeprom(0x1B, 0x05); //scrivo il dato 05 nella posizione 001B }//if }//while }//main il codice è questo cosa ne pensate? Nella prima parte il codice era STAT_CKE = 1; ma mi dava errore, forse perchè era scritto con il compilatore HI TECH C? è l'ho modificato cosi SSPSTAT = 0b11000000 ; ora non mi da più errore ma vi chiedo un vostro parere se ho fatto giusto.
Ctec Inserita: 24 agosto 2019 Segnala Inserita: 24 agosto 2019 Non sono assolutamente pratico dei PIC, ma non capisco perché includi un sorgente #include "delay.C" oltre la corretta inclusione del suo header delay.h Per il resto, non conosco tali processori, ti posso dire che un led che rimane acceso per poco più di 10us non lo vedrai mai, a meno che non lo piloti con diversi ampere. L'unica cosa che noto, da ignoranza del micro, è che dopo aver caricato SSPBUF (che immagino sia il registro di trasmissione I2C), non viene attivato alcun bit di partenza invio, a meno che non lo faccia appena sente un valore caricato (ma se sono due valori uguali?). Poi, vedo che la I2cWait attende un bit di interrupt, ma non vedo descrizione di avvio delle routine di interrupt. Lascio la palla a chi conosce il micro.
kiki kaikai Inserita: 24 agosto 2019 Autore Segnala Inserita: 24 agosto 2019 Ciao Ctec, grazie per aver risposto, ora mi spiego meglio, ho trovato in questo forum una discussione simile e da li ho trovato dei collegamenti a un sito dove spiega in inglese la comunicazione tra PIC e la eprom attraverso la connessione i2C, fin qui tutto bene ho scaricato il pacchetto e ho provato a inserirlo nel mio programma MPLAB, A questo punto ho dovuto ripassare ed aggiornarmi visto che non programmo più un pic da almeno 15 anni. il pacchetto scaricato mi dava un sacco di errori quando lo andavo a compilare, a questo punto ho deciso di partire da zero, quindi ho fatto un programmino che accende un led (blink) per verificare tutto il funzionamento compilatore ecc, e da qui ho iniziato a scrivere il programma mantenendo i file di quel programmino , e uno di questi è proprio #include "delay.C" poi ho inserito i vari pacchetti studiando che attivare i2c occorre accedere a 3 registri, che sono SSPSTAT= MSSP Status REGISTER SSPCON1= MSSP1 registro di controllo SSPCON2= MSSP2 registro di controllo e qui subito un errore SSPCON1 mi da errore, togliendo 1 l'errore scopare ma non so se è giusto perché sul datasheet è chiamato SSPCON1, poi sempre leggendo gli esempi nella prima parte ho capito come settare le porte per la comunicazione, e qui altro errore STAT_CKE = 1; il compilatore mi da errore SSPSTAT = 0b11000000 ; modificato da me sempre usando il datasheet CKE va attivato a 1 per abilitare la SMBus come input, tutto come da manuale, ma anche qui non so se scrivere solo CKE=1; oppure STAT_CHE =1 insomma una vera tragedia con la scrittura del codice, poi gli esempi sono pieni di errori e mi sorgono un mare di dubbi, è il compilatore? In effetti ci sono tanti errori, vi chiedo una mano per capire cosa posso fare per sistemarlo, anche dei link sui registri del 16F877A
Livio Orsini Inserita: 25 agosto 2019 Segnala Inserita: 25 agosto 2019 Son circa dieci anni che non faccio un lavoro con un PIC; Ho archiviato un lavoro fatto che fa proprio qualche cosa di simile. Solo che io ho sempre usato solo il compilatore CCP. Nei prossimi giorni, se trovo il tempo e mi ricordo, provo a dare un'occhiata a quel lavoro e, magari, trovo qualche cosa per aiutarti.
kiki kaikai Inserita: 25 agosto 2019 Autore Segnala Inserita: 25 agosto 2019 Grazie mille Livio sei una speranza per me, posso chiederti come lavora il compilatore CCP? cioè va associato a qualche programma? Io ricordo che il linguaggio C è usato per molte applicazioni in elettronica ma anche per fare programmi ecc, poi usando il compilatore associato al programma tipo XC8 oppure HI-TECHc crea nella cartella del progetto dei file che riconoscono il tipo di PIC per la comunicazione tra linguaggio C e PIC, in fatti si usa scrivere all'inizio del progetto #include <pic.h> ma il compilatore CCP non l'ho mai sentito immagino che sia a pagamento? CIAO LIVIO
Ctec Inserita: 25 agosto 2019 Segnala Inserita: 25 agosto 2019 I file "nomemicro.h" normalmente contengono le definizioni (#define) relative al micro che al compilatore servono per indirizzare i pin, i registri interni, ecc. Per esempio, quando scrivi nel programma SSPSTAT, il compilatore ci assocerà l'indirizzo del registro indicato nel file header .h Per quello probabilmente te hai errore con STAT_CKE, probabilmente non è definito nell'header che hai, perché era per un compilatore diverso. Gli header forniti col compilatore li trovi normalmente indicati inseriti tra < e >, mentre quelli delle parti di programma "tuo" sono tra le virgolette ". Capisco da quanto sopra che non hai molta esperienza del C, forse dovresti studiarlo un pochetto per poterci mettere le mani. Livio ti aiuterà con lo specifico dei PIC.
kiki kaikai Inserita: 25 agosto 2019 Autore Segnala Inserita: 25 agosto 2019 Ciao Ctec Ieri sera ho rifatto tutta la cartella perché era un casino, ma il problema è peggiorato, ho usato il compilatore HI-TECH C , ho inserito il file apposta studiato per PIC16F877A con le funzioni i2c da includere nel programma come #include "877_i2c.h" ma guarda le immagini è tutto un errore. Dunque voglio ripartire per bene un'altra volta, dimmi cosa ne pensi 1)creo le cartelle con il compilatore HI-TECH C 2)parto con un FILE main nuovo 3) scrivo il codice come da datasheet cosi vedo se mi da errore ancora il programma MPLAB, vediamo cosa succede???
kiki kaikai Inserita: 25 agosto 2019 Autore Segnala Inserita: 25 agosto 2019 Eccomi ho rifatto tutto, ho capito perché mi da tutto errore, è perché non ho messo #include <pic.h> allora inserendolo per benino in un nuovo progetto mi da errore ancora alla voce STAT_CKE quindi ho mangiato la foglia e sono entrato nel file generato dal compilatore all'interno del progetto dal programma MPLAB sono andato su CLASSES/HITEC/ poi ho aperto il file ACKSTAT e qui sotto riporto un pezzo di programma, secondo me non è inserita la voce STAT_CKE nel registro SSPSTAT ma si scrive solo CKE come è riportato dal datasheet, quindi se i miei calcoli sono giusti sto impazzendo con un codice non compatibile con il mio PIC16F877A e il compilatore ha ragione a segnarlo in rosso? // Register: SSPCON2 volatile unsigned char SSPCON2 @ 0x091; // bit and bitfield definitions volatile bit SEN @ ((unsigned)&SSPCON2*8)+0; volatile bit RSEN @ ((unsigned)&SSPCON2*8)+1; volatile bit PEN @ ((unsigned)&SSPCON2*8)+2; volatile bit RCEN @ ((unsigned)&SSPCON2*8)+3; volatile bit ACKEN @ ((unsigned)&SSPCON2*8)+4; volatile bit ACKDT @ ((unsigned)&SSPCON2*8)+5; volatile bit ACKSTAT @ ((unsigned)&SSPCON2*8)+6; volatile bit GCEN @ ((unsigned)&SSPCON2*8)+7; #ifndef _LIB_BUILD volatile union { struct { unsigned SEN : 1; unsigned RSEN : 1; unsigned PEN : 1; unsigned RCEN : 1; unsigned ACKEN : 1; unsigned ACKDT : 1; unsigned ACKSTAT : 1; unsigned GCEN : 1; }; } SSPCON2bits @ 0x091; #endif // Register: PR2 volatile unsigned char PR2 @ 0x092; // bit and bitfield definitions // Register: SSPADD volatile unsigned char SSPADD @ 0x093; // bit and bitfield definitions // Register: SSPSTAT volatile unsigned char SSPSTAT @ 0x094; // bit and bitfield definitions volatile bit BF @ ((unsigned)&SSPSTAT*8)+0; volatile bit UA @ ((unsigned)&SSPSTAT*8)+1; volatile bit R_nW @ ((unsigned)&SSPSTAT*8)+2; volatile bit S @ ((unsigned)&SSPSTAT*8)+3; volatile bit P @ ((unsigned)&SSPSTAT*8)+4; volatile bit D_nA @ ((unsigned)&SSPSTAT*8)+5; volatile bit CKE @ ((unsigned)&SSPSTAT*8)+6; volatile bit SMP @ ((unsigned)&SSPSTAT*8)+7; volatile bit R @ ((unsigned)&SSPSTAT*8)+2; volatile bit D @ ((unsigned)&SSPSTAT*8)+5; volatile bit I2C_READ @ ((unsigned)&SSPSTAT*8)+2; volatile bit I2C_START @ ((unsigned)&SSPSTAT*8)+3; volatile bit I2C_STOP @ ((unsigned)&SSPSTAT*8)+4; volatile bit I2C_DATA @ ((unsigned)&SSPSTAT*8)+5; volatile bit nW @ ((unsigned)&SSPSTAT*8)+2; volatile bit nA @ ((unsigned)&SSPSTAT*8)+5; volatile bit nWRITE @ ((unsigned)&SSPSTAT*8)+2; volatile bit nADDRESS @ ((unsigned)&SSPSTAT*8)+5; volatile bit R_W @ ((unsigned)&SSPSTAT*8)+2; volatile bit D_A @ ((unsigned)&SSPSTAT*8)+5; volatile bit READ_WRITE @ ((unsigned)&SSPSTAT*8)+2; volatile bit DATA_ADDRESS @ ((unsigned)&SSPSTAT*8)+5;
Ctec Inserita: 25 agosto 2019 Segnala Inserita: 25 agosto 2019 No, è compatibilissimo con il processore. Il problema è che è stato scritto per un compilatore diverso. Quella non corrispondenza tra STAT_CKE e CKE ne è un esempio. Non conosco i compilatori dei PIC, per cui, davvero, non so come aiutarti. Mi spiace
del_user_97632 Inserita: 25 agosto 2019 Segnala Inserita: 25 agosto 2019 (modificato) Ciao kiki kaikai, perche' usare altri compilatori quando microchip xc8 e' free per qualche mese con massime ottimizzazioni in size abilitate (e mplab-x) ? Anche scaduto il periodo di prova, senza ottimizzazioni in size, non riempi la memoria per un programma semplice. Per altro si trova molto codice d'esempio per xc8 (appunto con i compilatori cambiano gli include dei vari modelli di PIC e spesso cambiano nome i registri, o direttive per programmare le conf word, etc). Hai un oscilloscopio ? Per scriverti un driver i2c seguendo il datasheet direi che e' di fondamentale aiuto. Comincia a fare un loop e sparare dati in continuo e verificare forme bit, mhz, correttezza dei dati). Spesso, piu che scriversi il driver da 0 da datasheet, conviene cercare un codice esistente, di driver i2c per 16f877 ne esistono molti, ma ovviamente se lavori per passione e imparare, scriverlo da zero va benone, ottima palestra. PS: magari non ne hai bisogno, ma puoi anche lavorare sui 18877, costa 1/5, ha delle istruzioni in piu e 64 banchi di memoria, (anche se usando C non ti riguarda), ed e' la scelta che in genere si fa per nuovi prodotti. I 16f877 continuano a essere disponibili senza problemi ma li fan pagare. Buona fortuna Modificato: 25 agosto 2019 da _angelo_
dott.cicala Inserita: 25 agosto 2019 Segnala Inserita: 25 agosto 2019 Quando compaiono queste cose rosse ...significa che il compilatore non riconosce il nome dei registri per il micro selezionato. Stai usando un 877 o un 877A? i nomi dei registri cambiano da un micro all'altro, ma non ricordo le differenze tra i due. Sono belli vecchiotti...
kiki kaikai Inserita: 26 agosto 2019 Autore Segnala Inserita: 26 agosto 2019 Grazie mille per le risposte, il mio è un pic16F877A a 40 pin, si è vecchio ma è quello che avevo qui a casa. 18877 non lo conosco, grazie per le info dopo lo cerco e ci faccio un pensierino. Si ho uno oscilloscopio , mi hai dato una bella dritta gli sparo un codice per capire come lavora SDA SCL praticamente la linea i2c, Quindi faccio un programma in questo modo 1)abilito le porte e attivo la funzione master dei registri SSPSTAT 2) parto con il protocollo dallo start fino allo stop.(una cosa del genere) Comunque stasera ho rifatto tutto, ho usato il compilatore HI-TECK , appena creata la cartella del progetto ho fatto un nuovo file usando il MAIN.C, ho inserito il solito programma modificando i registri con il nome giusto e il compilatore ha fatto anche il file HEX,🤩 ovviamente mi ha dato anche questo errore che posto sotto perché ho dei pezzi di codice da sistemare. guardate l'errore sotto. Comunque grazie per la disponibilità HI-TECH C Compiler for PIC10/12/16 MCUs (Lite Mode) V9.82 Copyright (C) 2011 Microchip Technology Inc. (1273) Omniscient Code Generation not available in Lite mode (warning) mainc.c:91: warning: (1257) local variable "_addrh" is used but never given a value (errore) mainc.c:92: warning: (1257) local variable "_addrl" is used but never given a value (errore) Memory Summary: Program space used CDh ( 205) of 2000h words ( 2.5%) Data space used 8h ( 8) of 170h bytes ( 2.2%) EEPROM space used 0h ( 0) of 100h bytes ( 0.0%) Configuration bits used 0h ( 0) of 1h word ( 0.0%) ID Location space used 0h ( 0) of 4h bytes ( 0.0%) Running this compiler in PRO mode, with Omniscient Code Generation enabled, produces code which is typically 40% smaller than in Lite mode. See http://microchip.htsoft.com/portal/pic_pro for more information. make[2]: Leaving directory 'C:/MPLAB progretti/DEMO1.X' make[1]: Leaving directory 'C:/MPLAB progretti/DEMO1.X' BUILD SUCCESSFUL (total time: 1s) (ok funziona ^_^) Loading code from C:/MPLAB progretti/DEMO1.X/dist/default/production/DEMO1.X.production.hex... Loading completed penso che devo sistemare il codice
dott.cicala Inserita: 26 agosto 2019 Segnala Inserita: 26 agosto 2019 Elimina LOW_BYTE / HIGH_BYTE non servono, lascia il resto. Char è già un byte
kiki kaikai Inserita: 26 agosto 2019 Autore Segnala Inserita: 26 agosto 2019 ho eliminato adesso mi da errore alla DelayMs la parte che riguarda il led, in pratica volevo dirgli quando programmi accendi il led, quando hai finito lo spegni
dott.cicala Inserita: 26 agosto 2019 Segnala Inserita: 26 agosto 2019 (modificato) Come già detto, il compiler non riconosce il delay richiamato così. Dovrebbe essere delay_ms() se non ricordo male...guarda l'h elp delay blocca l'esecuzione fino a che il tempo non è trascorso... Modificato: 26 agosto 2019 da dott.cicala
kiki kaikai Inserita: 27 agosto 2019 Autore Segnala Inserita: 27 agosto 2019 dott.cicala grazie per la risposta mi hai fatto ragionare e ho trovato la soluzione. Ho lavorato tutto il pomeriggio 😥 ho capito che cancellando i progetti e rifacendoli a più non posso !! ho combinato qualcosa che il compilatore mi ha fatto una doppia cartella in C/ progetti MPLAB / nome progetto che alla fine è successo un casino, poi ho notato che ho installato due CX8, a questo punto ho disinstallato MPLAB e anche i compilatori, poi ho scaricato la versione più aggiornata e installato MPLAB e compilatore CX8,poi ho seguito il consiglio di _angelo_ ho fatto un loop di programma i2c senza fine in continuazione, ma senza scrivere su eprom esterne ecc solo una cosa da protocollo interna salvato il progetto tutto funziona a meraviglia, domani lo provo con l'oscilloscopio e poi lo modifico inserendo l'indirizzo eprom e provo a scrive qualcosa poi vediamo... buona notte a tutti sono stanco ma contento.😄 CIAO
Livio Orsini Inserita: 27 agosto 2019 Segnala Inserita: 27 agosto 2019 Ho trovato il programma ///////////////////////////////////////////////////////////////////////// //// //// //// Livio S. Orsini - LSOEngineering //// //// 13- 06 - 2007 V0.2 //// //// //// //// Questo programma seleziona il canale 0 degli AD_C con clock //// //// pari ad 1/32 del quarzo (20MHz). //// //// Seleziona la porta A0 come analogica, Vdd e Vss come riferi- //// //// di tensione, legge il canale 0. //// //// Legge un sensore di temperatura DS18B20, 1Wire, dalla porta //// //// RA1 collegata con una resistenza di pull-up da 4k7. //// //// Vcc = RA2(pin 1) //// //// ^ //// /// | //// /// \ //// /// / //// /// \ Rpup = 4k7 //// /// / //// /// 16F88 | DS16B20S //// /// RA1(pin 18)--------------------DQ(pin2) //// /// //// /// //// /// NOTA! La prima misura dopo un reset del micro o di un power-on //// /// è errata! Rende sempre 0x0550. Per evitare questo dopo un wake //// /// up si eseguono 3 - 4 letture! //// /// //// /// Usa i pins B5 come Tx e B2 ome Rx per una seriale RS232. //// /// Ricevendo da linea seriale un comando "10", in ASCII (0x31, //// /// 0x30) seguito da un CR (0x0D, 0x0A) i dati memorizzati nella //// /// memoria EEPROM esterna ed interna sono letti e sono trasmessi //// /// sulla linea seriale. //// /// Ricevendo da linea seriale un comando "11" seguito da un CR //// /// sarà cancellata la memoria, interna ed esterna. //// /// La cancellazione avviene scrivendo 0xFF nei rispettivi puntatori //// /// I dati sono ancora disponibili per una lettura. //// /// L'elenco completo dei comandi è disponibile del file command.txt //// /// Il pin B3 alimenta la memoria EEPROM; i pins B1 e B4 sono, ri - //// /// spettivamente dato e clock per la memoria esterna. //// ///////////////////////////////////////////////////////////////////////// #include "16F88.h" #include "flash.h" // #fuses HS,NOWDT,NOPROTECT,NOLVP // #use delay(clock=8000000) #use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2) #use I2C(master, sda=PIN_B1, scl=PIN_B4, SLOW) . . . . void memo_ee_ext()//ATTENZIONE ora limite 255 bytes { int add, dat, ptr; SET_TRIS_B(0b11110111); //B3 = output bit_set(port_b,3); //B3 ==> alto ==> memoria alimentata add = 0; dat = read_ext_eeprom(add); //leggeindirizzo ultimo dato add = dat; if (add == 0xFF) { add = 1; } if (add <= (ext_ee_size-2)) { dat = itemp_buffer[1]; write_ext_eeprom(add, dat); //scrive dato add++; dat = itemp_buffer[0]; write_ext_eeprom(add, dat); //scrive dato add++; dat = add; add = 0; write_ext_eeprom(add, dat); //scrive dato } else { flg_ee_full=1; } } void rd_dat()//legge dati da memeoria { int1 flg_mem_ext = 0; int i, idat; i = 0; idat = eeprom_read(i); if (idat < 0xFF) { if (idat = 0xFE) flg_mem_ext = 1; printf("\r\n Memoria interna \r\n"); printf("\r\n Numero di valori memorizzati: %3d\r\n",((idat-1)/2)); for (i = 1; i<= idat; i++) { ibuff_Tx[0] = eeprom_read(i); i++; ibuff_Tx[1] = eeprom_read(i); printf("%2d %2X%2X\r\n",(i/2),ibuff_Tx[0],ibuff_Tx[1]); } if (flg_mem_ext = 1) { i = 0; idat = read_ext_eeprom(i); printf("\r\n Memoria esterna \r\n"); printf("\r\n Numero di valori memorizzati: %3d\r\n",((idat-1)/2)); for (i = 1; i<= idat; i++) { ibuff_Tx[0]=read_ext_eeprom(i); i++; ibuff_Tx[1]= read_ext_eeprom(i); printf("%2d %2X%2X\r\n",(i/2),ibuff_Tx[0],ibuff_Tx[1]); } } } else printf ("\r\n Nessun dato memorizzato \r\n"); } /******************************************************************************/ void rd_mem() //legge tuuta la memoria { int i, idat; long li; printf("\r\n Memoria interna \r\n"); for (li = 1; li < 0xFF; li++) { ibuff_Tx[0] = eeprom_read(li); li++; ibuff_Tx[1] = eeprom_read(li); printf("%3Lu %2X%2X\r\n",(li/2),ibuff_Tx[0],ibuff_Tx[1]); } printf("\r\n Memoria esterna \r\n"); for (i = 1; i < ext_ee_size; i++) { ibuff_Tx[0] = read_ext_eeprom(i); i++; ibuff_Tx[1] = read_ext_eeprom(i); printf("%2d %2X%2X\r\n",(i/2),ibuff_Tx[0],ibuff_Tx[1]); } } /******************************************************************************/ void inizia()//inizializzazione { int i, idat; // inizializzazione registro porta A e timer1 SET_TRIS_A (0b11111001); //tutti input tranne A1 e A2 setup_counters(RTCC_INTERNAL,RTCC_DIV_4); setup_timer_1(T1_INTERNAL); set_timer1(0xB1DF); //Caricato 65.535 - 20.000 = 45.535(0xB1DF) //==> 20.000 * 4 * 125nsec = 10msec // inizializzazione interrupts disable_interrupts(GLOBAL); enable_interrupts(GLOBAL); enable_interrupts(int_timer1); enable_interrupts(INT_EXT); enable_interrupts (INT_RDA); //inizializzazione A/D converter e periferia setup_port_a(sAN0); //A0 come analogica, Vref = Vdd e Gnd setup_adc( ADC_CLOCK_DIV_32); bit_set(ADCON1,7); set_adc_channel( 0 ); SET_TRIS_A(0b111111011); //A2 ==> output, tutti gli altri input bit_clear(port_a,1); //A1 ==> basso time_data = 5; //set up timer interno 50ms SET_TRIS_B(0b11110111); //B3 = output bit_set(port_b,3); //B3 ==> alto ==> memoria alimentata bit_set(port_a,2); //A2=> alto ipunt = &itemp_buffer[0]; } // /******************************************************************************/ // void main() { int i, idat; // inizia(); //Inizializzazione while (TRUE) { idat = sel_com(); switch (idat) { case 1:rd_dat(); break; case 2:eras_mem(); break; case 3:wr_ID(); break; case 4:rd_mem(); break; case 5:rd_temp(); break; } } } #int_timer1 void Timer10ms() { set_timer1(0xB1DF); // Caricato 15535 ==> // 20.000 * 4 * 125nsec = 10msec // 65535 - 20000 = 45535(0xB1DF) if (ltime_out >0) { ltime_out--; } } #int_ext //Interrupt sul fronte di RB0 void rb0_int() { #asm btfss port_b,0 goto end_int #endasm SET_TRIS_A(0b111111011); //A1&A2> output, tutti gli altri input bit_set(port_a,1); //A1 ==> alto in = 0; tem_conv(ipunt); tem_conv(ipunt); tem_conv(ipunt); SET_TRIS_A(0b111111011); //A1&A2 output, tutti gli altri input bit_clear(port_a,1); //A1==> basso memo_temp(); #asm end_int: nop #endasm } void memo_temp() { int add, dat, ptr; add = 0; dat = eeprom_read(add); if (dat == 0xFE) { memo_ee_ext(); } else { if (dat <= 0xFD) { add = dat; } if (dat == 0xFF) { add = 1; } dat = itemp_buffer[1]; eeprom_write(add, dat); add++; dat = itemp_buffer[0]; eeprom_write(add, dat); add++; if (add <=0xFD) { dat = add; add = 0; eeprom_write(add, dat); } else { dat = 0xFE; add = 0; eeprom_write(add, dat); } } } /******************************************************************************* * Cancella memoria EEPROM e EEPROM esterna * *******************************************************************************/ void eras_mem() { int add, dat; add = 0; dat = 0xff; eeprom_write(add, dat); write_ext_eeprom(add, dat); //scrive dato } /******************************************************************************* * Scrive Identificativo * *******************************************************************************/ void wr_ID()//Scrive Identificativo { int add, dat, ptr; printf("Invia gg-mm-aa hh:mm ID \r\n"); iRxpnt = 0; ltime_out = 3000; //equivale a 30" di attesa while (flg_ID_req == 0) { if ((ibuff_Rx[10]== 0x49) && (ibuff_Rx[11]== 0x44)) { flg_ID_req = 1; } if (ltime_out == 0) //trascorso il tempo di time out senza ricevere //risposta si annulla il comando { flg_tmut = 1; break; } } if (flg_tmut == 0) { eras_mem(); add = 1; for (iptr = 0; iptr < 10; iptr++) { dat = ibuff_Rx[iptr] - 0x30; dat = dat * 10; iptr++; dat = dat + (ibuff_Rx[iptr] - 0x30); eeprom_write(add, dat); add++; } dat = add; add = 0; eeprom_write(add, dat); for (iptr = 0; iptr < 15; iptr++) { ibuff_Rx[ptr]= 0; } flg_ID_req = 0; } else { printf("\r\nTime out; ID non valido\r\n"); flg_tmut = 0; } } /******************************************************************************/ void trans_mem_temp()//conversione hex_ASCII { int dato, add; for (add = 0; add<16; add++) { dato = eeprom_read(add); if ( dato <=0x9) { dato = dato + 0x30; } else { dato = dato + 0x37; } ibuff_Tx[add] = dato; } } /******************************************************************************/ void rd_temp() //lettura temperatura { SET_TRIS_A(0b111111011); //A1&A2> output, tutti gli altri input bit_set(port_a,1); //A1 ==> alto tem_conv(ipunt); tem_conv(ipunt); tem_conv(ipunt); printf("Temperatura (hex) = %2X%2X\r\n",itemp_buffer[1],itemp_buffer[0]); } /******************************************************************************/ void rd_ad () //lettura A/D_C { var1 = read_adc(); set_adc_channel(0); } /******************************************************************************/ void Tx_232()//trasmissione { for (iTxpnt=0; iTxpnt<16; iTxpnt++) { putc(ibuff_Tx[iTxpnt]); } } /******************************************************************************/ void rd_dat()//legge dati da memeoria { int1 flg_mem_ext = 0; int i, idat; i = 0; idat = eeprom_read(i); if (idat < 0xFF) { if (idat = 0xFE) flg_mem_ext = 1; printf("\r\n Memoria interna \r\n"); printf("\r\n Numero di valori memorizzati: %3d\r\n",((idat-1)/2)); for (i = 1; i<= idat; i++) { ibuff_Tx[0] = eeprom_read(i); i++; ibuff_Tx[1] = eeprom_read(i); printf("%2d %2X%2X\r\n",(i/2),ibuff_Tx[0],ibuff_Tx[1]); } if (flg_mem_ext = 1) { i = 0; idat = read_ext_eeprom(i); printf("\r\n Memoria esterna \r\n"); printf("\r\n Numero di valori memorizzati: %3d\r\n",((idat-1)/2)); for (i = 1; i<= idat; i++) { ibuff_Tx[0]=read_ext_eeprom(i); i++; ibuff_Tx[1]= read_ext_eeprom(i); printf("%2d %2X%2X\r\n",(i/2),ibuff_Tx[0],ibuff_Tx[1]); } } } else printf ("\r\n Nessun dato memorizzato \r\n"); } /*----------------------------25/05/07 19.10-----------------------------------* * Funzioni per lettura e scrittura di eeprom esterna * * ---------------------------------------------------------------------------*/ #define EEPROM_ADD Byte #define EEPROM_SIZe 128 /******************************************************************************/ BOOLEAN ext_eeprom_ready() //test memoria pronta { int1 ack; i2c_start(); // Se il comando di scrittura è rico- ack = i2c_write(0xa0); // nosciuto il dispositivo è pronto i2c_stop(); return !ack; } /******************************************************************************/ void write_ext_eeprom(BYTE address, BYTE data) //Scrive dato { while(!ext_eeprom_ready()); i2c_start(); i2c_write(0xa0); i2c_write(address); i2c_write(data); i2c_stop(); } /******************************************************************************/ BYTE read_ext_eeprom(BYTE address) //legge dato { BYTE data; while(!ext_eeprom_ready()); i2c_start(); i2c_write(0xa0); i2c_write(address); i2c_start(); i2c_write(0xa1); data=i2c_read(0); i2c_stop(); return(data); } /******************************************************************************/ Il micro è un 16f88, molto più piccolo del 16f877, però il tutto è simile Le ultime 2 routine sono proprio quelle per leggere e scrivere la EEprom esterna. Ho tolto dal programma tutta la lettura della temperatura e lagestione della seriale per non appesantire troppo il tutto. Come vedi dalla data è un lavoro di 12 anni fa, quindi dovrei ristudiaarmelo un poco per ricordarmi anche i dettagli. Il compilatore è quello della PICC, che si integra in MPLAB, purtroppo non è mai stato gratuito, io la mia copia ho smesso di aggiornarla per non pagare l'abbonamento, visto che non svolgo più attività professinale sui PIC da lungo tempo.
del_user_97632 Inserita: 27 agosto 2019 Segnala Inserita: 27 agosto 2019 (modificato) 1 ora fa, Livio Orsini scrisse: Il compilatore è quello della PICC, che si integra in MPLAB, purtroppo non è mai stato gratuito, io la mia copia ho smesso di aggiornarla per non pagare l'abbonamento, visto che non svolgo più attività professinale sui PIC da lungo tempo. Purtroppo Microchip insiste con questa storia delle licenze a pagamento, mpasm e' almeno quello gratuito (ovviamente c'e' anche gpasm), ma l'assembly, che a molti piace, non ti aiuta in produttivita' quando devi consegnare lavori. xc8 e' gratuito senza ottimizzazioni in size, o gratuito per 2 mesi con le ottimizzazioni. Cioe in un mondo dove ormai i compilatori per lavorare sui micro sono buoni e open (vedi AVR gcc, STM ed altri, tutto cioe che e' cortex-M ma anche i piu recenti risc-v) loro insistono con delle licenze a tempo ... di fatto la cosa ha poco senso. Per questo motivo a chi impara suggerisco sempre di andare su AVR. Modificato: 27 agosto 2019 da _angelo_
kiki kaikai Inserita: 27 agosto 2019 Autore Segnala Inserita: 27 agosto 2019 Grazie Livio è proprio quello che cercavo per completare questo programma, ieri ho compilato un programmino prendendo spunto dai vari tutorial in rete, ho fatto un confronto con il mio vecchio e alla fine ho appreso ancora altre informazioni. #include <xc.h> #include "I2C.h" // Function Purpose: Configure I2C module void InitI2C(void) { SDA_DIR = 1; // Impostazione linea SCL come input SCK_DIR = 1; // Impostazione linea SDA come input SSPADD = ((_XTAL_FREQ/4000)/I2C_SPEED) - 1; SSPSTAT = 0x80; // 0b11000000 Slew rate disabilitato SSPCON = 0x28; // 0b00101000; abilita Modalita' Master } // Funzione di start del protocollo i2c*/ void I2C_Start(void) { SEN = 1; // Avvia lo start while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit } // rinvia lo start void I2C_ReStart(void) { RSEN = 1; // invia il Restart bit while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit } //Funzione di stop del protocollo i2c*/ void I2C_Stop(void) { PEN = 1; // Avvia lo stop del bit while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit } //Function : I2C_Send_ACK sends ACK bit sequence void I2C_Send_ACK(void) { ACKDT = 0; // 0 means ACK ACKEN = 1; // Send ACKDT value while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit } //Function : I2C_Send_NACK sends NACK bit sequence void I2C_Send_NACK(void) { ACKDT = 1; // 1 means NACK ACKEN = 1; // Send ACKDT value while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit } // Function Purpose: I2C_Write_Byte transfers one byte bit I2C_Write_Byte(unsigned char Byte) { SSPBUF = Byte; // invia il valore del Byte while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit return ACKSTAT; // Return ACK/NACK from slave } // Function Purpose: I2C_Read_Byte reads one byte unsigned char I2C_Read_Byte(void) { RCEN = 1; // Abilita la ricezione di 8 bit while(!SSPIF); // aspetta che si completa SSPIF = 0; // pulisci il bit return SSPBUF; // Restituisci i byte ricevuti } file i2c.h #define _XTAL_FREQ 20000000 #ifndef I2C_H #define I2C_H #ifdef __cplusplus extern "C" { #endif // Define i2c pins #define SDA RC4 // Data pin for i2c #define SCK RC3 // Clock pin for i2c #define SDA_DIR TRISC4 // Data pin direction #define SCK_DIR TRISC3 // Clock pin direction // Define i2c speed #define I2C_SPEED 100 // kbps //Function Declarations void InitI2C(void); void I2C_Start(void); void I2C_ReStart(void); void I2C_Stop(void); void I2C_Send_ACK(void); void I2C_Send_NACK(void); bit I2C_Write_Byte(unsigned char); unsigned char I2C_Read_Byte(void); #ifdef __cplusplus } #endif #endif /* I2C_H */ Quindi , 1) setta le porte attiva il master 2)invia lo start, 3)poi lo invia ancora (non so perché??) 4) si ferma stop 5)aspetta un segnale di ACK così( se arriva) il master capisce che il segnale è arrivato 6) la NACK la devo ancora studiare 7)scrive il byte 8)legge il byte Da quanto ho capito il giro è questo, ora lo devo modificare inserendo l'indirizzo della eprom (seguendo il file di Livio) ma devo anche mettere un qualcosa che fa fermare il loop quando ha completato.Piano piano ci stiamo arrivando tutto grazie a voi, vi aggiorno con il prossimo codice, se avete suggerimenti scrivete pure nel frattempo io ci studio sopra. A dopo
kiki kaikai Inserita: 28 agosto 2019 Autore Segnala Inserita: 28 agosto 2019 GRAZIE MILLE A TUTTI FUNZIONA VI AMO !!!!!! vi giuro che mi sta scoppiando la testa è dalle 9 di questa mattina che cerco di inserire led e pulsanti ma non riesco a farlo andare, sembra banale ma con le funzioni i2c non riesco a capire dove e quando inserirli, a questo punto non ho inserito led e pulsanti, ho usato il quarzo interno, ma almeno funziona vi mando la prima scrittura
kiki kaikai Inserita: 29 agosto 2019 Autore Segnala Inserita: 29 agosto 2019 Buon Giorno vi porgo l'ultimo aiuto per completare la programmazione con 1 led e un pulsante, premo il pulsante e si accende il led verde START,( inizia a programmare), poi quando finisce il led verde lampeggia per 2 secondi e poi si spegne per indicare la scrittura terminata. Consigliatemi se sto facendo giusto, prima definisco il led e il pulsante, poi abilito le porte dedicate, il codice lo scrivo nella parte dell codice dove I2c parte con la scrittura? per il pulsante devo inserire l'anti rimbalzo? #define PULSANTE_1 RB4 // pulsante start #define LED_V RB1 // led verde on_start #define ATTESA 2 // attesa per il lampeggio // configuro le porte void I2C_init (uint32_t clock) { SSPADD = (_XTAL_FREQ/(4*clock))-1; // here clock is the BR/clock speed SSPCON = 0b00101000; //first 4 bits I2c master mode , 6th bit is SSPEN enables the scl and sda line SSPSTAT = 0; //cancellare tutti i bit nel registro SSPSTAT TRISC3 = 1; TRISC4 = 1; TRISB = 0b00001000; //abilito RB4 come input,RB1 come output // inizia la crittura I2c nella eprom (qui dentro scrivo il pulsante) void main(void) { I2C_init (100000); // initialise i2c @ 100 KHz uint8_t data; while (1) { // write data I2C_start (); // start I2C I2C_write (0xA0); // using 24aa00 slave address I2C_write (0x01); // scrivi al registro I2C_write ('f'); // scrivi f I2C_stop (); // stop I2C __delay_ms (1000); // 1 sec delay between write and read // leggo la eprom I2C_start (); // start I2C I2C_write (0xA0); // using 24aa00 slave address I2C_write (0x01); // writing into register 0x01 I2C_repeated_start(); // repeated start I2C_write (0xA0|0x01); // using 24aa00 slave address + read data = I2C_read (1); // read data and send NACK I2C_stop (); __delay_ms (2000); // 2sec delay } return;
Livio Orsini Inserita: 29 agosto 2019 Segnala Inserita: 29 agosto 2019 2 ore fa, kiki kaikai scrisse: per il pulsante devo inserire l'anti rimbalzo? Certo! Ti consiglio di farti un timer con il timer1 del PIC, lo programmi per 10ms, così hai il tuo tic di sistema che ti permette anche di eliminare tutti i ritardi bloccanti (delay_ms). Ad ogni interrupt di timer leggi gli ingressi e li confronti con lo stato precedente, se sono eguali alzi il flag di stato stabile, poi sostituisci il valore precedente con l'attuale. In questo modo realizzi un debouncing con ritardo di 10ms che è sufficiente per tutti i contatti normali. Invece dei delay_ms metti dei contatori che saranno decrementati nella routine di servizio dell'interrutp, in questo medo eviti il ritardo boccante di secondi.
kiki kaikai Inserita: 29 agosto 2019 Autore Segnala Inserita: 29 agosto 2019 Ciao Livio , il tuo consiglio è sicuramente il migliore confronto i ritardi delle (delay_ms) ma devo studiarmelo perché non so neanche da che parte iniziare inizio a guardare il datasheet Perchè in effetti ho fatto un giochino con le delay_ms ma non sono precise anzi sono in ritardo di brutto. Il timer va bene anche per il discorso dei pulsante? // lampeggio del led programmazione finale LED_G=1; //se la scrittura è andata a buon fine led giallo acceso __delay_ms(200); LED_G=0; //spengo il led giallo __delay_ms(200);// tempo 2 secondi LED_G=1; //se la scrittura è andata a buon fine led giallo acceso __delay_ms(200);// tempo 2 secondi LED_G=0; //spengo il led giallo __delay_ms(200);// tempo 2 secondi LED_G=1; //se la scrittura è andata a buon fine led giallo acceso __delay_ms(200);// tempo 2 secondi LED_G=0; //spengo il led giallo __delay_ms(200);// tempo 2 secondi LED_G=1; //se la scrittura è andata a buon fine led giallo acceso __delay_ms(3000);// tempo 3 secondi LED_G=0; //spengo il led giallo __delay_ms(3000);// tempo 3 secondi I2C_stop (); __delay_ms (2000); // 2sec delay
Messaggi consigliati
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 accountAccedi
Hai già un account? Accedi qui.
Accedi ora