Vai al contenuto
PLC Forum


PIC16F877A eprom esterna 24C02


kiki kaikai

Messaggi consigliati

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.

 

schema pic 16f877a.png

Link al commento
Condividi su altri siti


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.

Link al commento
Condividi su altri siti

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.

Link al commento
Condividi su altri siti

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

 

 

Link al commento
Condividi su altri siti

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.

Link al commento
Condividi su altri siti

 

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

 

Link al commento
Condividi su altri siti

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.

Link al commento
Condividi su altri siti

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

01.JPG

02.JPG

Link al commento
Condividi su altri siti

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;

 

 

 

 

Link al commento
Condividi su altri siti

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

Link al commento
Condividi su altri siti

del_user_97632

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: da _angelo_
Link al commento
Condividi su altri siti

Quando compaiono queste cose rosse

image.png.0d22fec12f6303fe50fff3ab7e85035b.png

 

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

Link al commento
Condividi su altri siti

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 ^_^ 

000.JPG

Link al commento
Condividi su altri siti

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

44.JPG

Link al commento
Condividi su altri siti

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: da dott.cicala
Link al commento
Condividi su altri siti

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

Link al commento
Condividi su altri siti

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.

Link al commento
Condividi su altri siti

del_user_97632
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: da _angelo_
Link al commento
Condividi su altri siti

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 

Link al commento
Condividi su altri siti

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 

 

 

funziona.JPG

Link al commento
Condividi su altri siti

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;

 

Link al commento
Condividi su altri siti

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.

Link al commento
Condividi su altri siti

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 :wallbash:

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

 

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