Jump to content
PLC Forum


Sign in to follow this  
dantares

Semplice Applocazione pic 16f876

Recommended Posts

dantares

Salve, io dovrei creare un semplicissimo circuito con un pic 16f876 e programmazione c. Quello che dovrebbe fare è modificare i dati su una eeprom 24c02 agli indirizzi:

0x0B,0x18,0x1B,0x44,0x45,0x46,0x47,0x4C,0x4D,0x4E,0x4F,0x54,0x55,0x56,0x57,0x5C,0x5D,0x5E,0x5F

L'idea è di interfacciare la eeprom col pic via I2C e, una volta acceso il circuito, premendo un tasto avviene la dei dati sulla eeprom.

Il problema è che io non uso i pic da un tanto tempo, e non so da dove cominciare per scrivere il programma, sopratutto non so come usare il protocollo I2C, sapreste darmi delle linee guida? io mi sono informato su internet e ho trovato tanti esempi di come scrivere su eeprom ma non ho capito come funzionano, dite che questo può essermi di aiuto?

#use I2C(Master,sda=PIN_C4,scl=PIN_C3,FAST)

void i2c_eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data);
unsigned char i2c_eeprom_read(unsigned char addrh,unsigned char addrl);
void i2c_eeprom_write_str(unsigned char addrh,unsigned char addrl,char* data);


/************************** Eeprom Write **************************************/
/**** Writes a single byte to the eeprom supports 2^16 addresses ****/

void i2c_eeprom_write(unsigned char addrh,unsigned char addrl,unsigned char data)
{
        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
        i2c_write(data);                // write data
        i2c_stop();
        delay_ms(5);
}

Sareste così gentili da spiegarmi come funziona questo codice?

Un'altra semplice domanda... dite che la memoria interna del pic riesca a contenere i dati da scrivere sulla eeprom o devo interfacciarmi con un'altra e riversare il contenuto di questa su quella da modificare? Se così fosse devo suicidarmi? :P:D:(

Grazie a tutti per l'aiuto!

Share this post


Link to post
Share on other sites

walterword

scarica e studiati il protocollo del bus seriale sincrono I2C

Share this post


Link to post
Share on other sites
dantares

suvvia questo non è un forum di aiuto? il protocollo I2C me lo sono studiato ma da passare dalla teoria alla pratica è dura per uno che non ha mai fatto queste cose... per questo ho chiesto aiuto a voi! :(

Share this post


Link to post
Share on other sites
Livio Orsini

dantares, non è cattiveria, è che c'è ben poco da spiegare; è sufficiente leggere i commenti alle istruzioni. Tutto quello ch esi può dire è già scritto. Al limite lo si dice in italiano.

Da il comando di start

Invia il codice che indica il modo scrittura che è 1010.0000 in binario

Invia l'indirizzo alto

Invia l'indirizzo basso

Invia il dato

Da il comando di stop

attendi 5ms oppure si può fare polling su un bit che indica la fine delle operazioni, poi sarò possibile scrivere un nuovo dato

Il perchè si debba eseguire il tutto in questo modo lo trovi nel datasheet della memoria e nel manuale del protocollo I2C

Edited by Livio Orsini

Share this post


Link to post
Share on other sites
dantares

ok, grazie livio! ora lavoro un pò sul codice poi ve lo mostro e mi dite cosa ho combinato ;)

Share this post


Link to post
Share on other sites
dantares

ok, penso di aver scritto qualcosa, ho usato delle routines che ho trovato Qui ed è venuto fuori qualcosa... ditemi se ho imboccato la strada giusta e se ho sbagliato qualcosa correggetemi :D

un ultimo quesito... nello schemino logico che mi hai scritto te, prima di inviare il dato, dici di inviare l'indirizzo alto e basso ma a cosa servono questi? non posso inviare direttamente l'indirizzo di memoria da modificare?

Grazie!!!!

il codice che ho scritto è questo:

\****************************************************************/
* Clock 4 Mhz                                                  
* Collegamento PIN:                                                                                   
* 1, 11, 32: VCC                                                 
* 12, 31: VSS                                                     
* 2: RA0 -> pulsante attivo alto                                 
* 18: SCL                                                        
* 23: SDA                                                      
* 33: RB0 -> led verde                                           
* 34: RB1 -> led rosso                                           
\****************************************************************/

#include <htc.h>
#include "delay.h"
#include "delay.C"
/******************************************************************************/
/*Definizione delle funzioni*/
/******************************************************************************/
/*Funzione di inizializzazione del protocollo i2c*/
void i2c_init(void)
{
    TRISC3=1;       // set SCL and SDA pins as inputs
     TRISC4=1;

     SSPCON = 0x38;  // set I2C master mode
     SSPCON2 = 0x00;

     SSPADD = 10;    // 100k at 4Mhz clock

     STAT_CKE=1;     // use I2C levels      worked also with '0'
     STAT_SMP=1;     // disable slew rate control  worked also with '0'

     PSPIF=0;        // clear SSPIF interrupt flag
     BCLIF=0;        // clear bus collision flag
}
/******************************************************************************/
/*Funzione di attesa prima di coninciare a scrivere*/
void i2c_waitForIdle(void)
{
    while (( SSPCON2 & 0x1F ) | STAT_RW ) {};
}
/******************************************************************************/
/*Funzione di start del protocollo i2c*/
void i2c_start(void)
{
    i2c_waitForIdle();
    SEN=1;
}
/******************************************************************************/
/*Funzione di stop del protocollo i2c*/
void i2c_stop(void)
{
    i2c_waitForIdle();
    PEN=1;
}
/******************************************************************************/
/*Funzione di scrittura seriale sulla eeprom*/
unsigned char i2c_write( unsigned char i2cWriteData )
{
    i2c_waitForIdle();
    SSPBUF = i2cWriteData;

    return ( ! ACKSTAT  ); // se 1 la trasmissione è stata completata
}
/******************************************************************************/
/*Funzione di scrittura sulla eeprom*/
void write_ext_eeprom(unsigned char address, unsigned char data)
{
       i2c_start();
       i2c_write(0xa0);
       i2c_write(address);
       RB1=i2c_write(data); //se la scrittura è andata a buon fine RB2 = 1 -> led rosso acceso
       i2c_stop();
       DelayMs(11);
       RB1=0; //spengo il led rosso
}
/******************************************************************************/
void main(void)
{
    TRISB=0;    //imposta le porte B come output
    TRISA=1;    //imposta le porte A come input
    RB0=1;        //led verde di accensione
    
    i2c_init(); //inizializzazione del protocolle I2C
    
    while(1)    //rimane in un ciclo infinito
    {
        if(RA0==1)    //se RA0 è 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

Share this post


Link to post
Share on other sites
Livio Orsini

Da una scorsa veloce sembra OK, però che compilatore usi?

Nella prima funtion che hai postato addrl e addrh sono dichiarati char, cioè byte. se il tuo dispositivo ha più di 255 byte di dati è necessario indirizzarlo con due bytes. le funzioni dell'ultimo post, se ho capito bene, sono relative alla eeprom interna del micro che è <255 bytes

Share this post


Link to post
Share on other sites
dantares

il compilatore che uso è hi-tech c e la eeprom su cui scrivere è una 24c02. Nella seconda function la mia intenzione era di scrivere sulla eeprom esterna non in quella interna :unsure: , cosa ho sbagliato? e poi non ho ancora capito cosa sono questi addrl e addrh...

grazie

Share this post


Link to post
Share on other sites
Livio Orsini

Non conosco quel compilatore. Il software Microchip per i 16Cxx e 1Fxx, in genere, è compatibile con CCS.

Addrl e addrh sono i valori dell'indirizzo. Se vuoi scrivere un dato nel 496.o byte l'indirizzo sarà 1EFh ==> addrh = 01h e addrl = EFh;

Però prima di inizare a smanettare sarebbe cosa buona e giusta studiare almeno i concetti fondamentali della programmazione, dei linguaggi e dei controllori che s'intendono utilizzare.

Share this post


Link to post
Share on other sites
dantares

Ok, ora ho capito cosa si intende per addrl e addrh, io ho delle basi di programmazione ed elettornica in generale è solo che non ho mai scambiato informazioni tra pic e eeprom, chiunque alla prima volta trova enormi difficolta ed è per questo che ti chiedo aiuto. Tornando al mio problema... ho modificato un pò il codice e l'ho provato su pic simulator e sembra funzionare ma se collego l'oscilloscopio alle porte RC3 e RC4 non vedo nessuna modifica del segnale, è normale?

Un'altra curiosità, come mai si impostano le porte RC3 e RC4 come input se devo trasmettere dai alla eeprom?

Grazie

#include <pic1687x.h>
#include <delay.c>

// Byte più significativo di un WORD - unsigned int
#define HIGH_BYTE(x)            (unsigned char)(x>>8)
// Byte meno significativo di un WORD - unsigned int
#define LOW_BYTE(x)                (unsigned char)(x & 0xFF)

/******************************************************************************/
/*Definizione delle funzioni*/
/******************************************************************************/
/*Funzione di inizializzazione del protocollo i2c*/
void i2c_init(void)
{
    TRISC3 = 1;                 // Impostazione linee SCL/SDA come input
    TRISC4 = 1; 
    SSPCON = 0x38;                 // Modalita' Master, Clock=Fosc/(4*(SSPADD+1))
    SSPCON2 = 0;
    SSPADD = 0x0B;                 // Clock a 400 Khz con Fosc a 20 Mhz
    STAT_CKE = 0;                  // Sample mode conforme a standard I2C
    STAT_SMP = 0;                  // Slewrate 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 ((SSPCON2 & 0x1F) | STAT_RW) 
     {
         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*/
void write_ext_eeprom(unsigned char address, unsigned char data)
{
    unsigned char addrh;
    unsigned char addrl;
    addrl=LOW_BYTE(address);
    addrh=HIGH_BYTE(address);
    i2c_start();
       i2c_write(0xa0);
       i2c_write(addrh);
       i2c_write(addrl);
       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

Share this post


Link to post
Share on other sites
Livio Orsini
...ma se collego l'oscilloscopio alle porte RC3 e RC4 non vedo nessuna modifica del segnale, è normale?
Edited by Livio Orsini

Share this post


Link to post
Share on other sites
dantares

non ho prorpio usato un oscilloscopio vero, ho provato il programma su pic simulator e collegando l'oscilloscopio virtuale sulle porte di trasmissione non si vede niente...

Share this post


Link to post
Share on other sites
Livio Orsini

Ehe no! Così non vale! :)

Io di tutti quei simulatori mi fido poco, anzi quasi niente. L'unico discretamente affidabile è quello incorporato in MPLAB. Però non ha l'oscilloscopio in dotazione :(

Share this post


Link to post
Share on other sites
dantares

ok, allora mi procuro i componenti mancanti, faccio qualche prova e ti faccio sapere com'è andata :)

Grazie di tutto!!

Share this post


Link to post
Share on other sites
dantares

azz.. la sfiga mi perseguita, ho completato il programma ma ora non so perchè non riesco a far andare il pic... quando lo alimento non accade niente, ho anche creato un programmino per fargli accendere le porte b alle quali ho collegato dei led ma non mostrano alcun segno di vita. Ho anche alimentato il pic tramite 7805 quindi non dovrebbero esserci problemi di alimentazione. Il quarzo è da 4mhz e gli ho messo 2 condensatori da 22pF, lo schemino del circuito è questo:

16f8768av.gif

premetto che ho misurato le tensioni col multimetro e sono ok, quindi il pic è alimentato correttamente.

Quale può essere il problema?

Grazie

Share this post


Link to post
Share on other sites
Livio Orsini

Dallo schema che pubblichi non c'è niente di evidentemente errato. I due condensatori di filtro, ai capi del regolatore, andrebbero da 220uF con in parallelo 0.1uF ceramici; si ha un miglior filtraggio ed il ripple a 100Hz si riduce a livelli trascurabili sul 5v.

Io preferisco connettere il pin 1, MC, al +5v tramite una resistenza da 10k.

Il problema potrebbe essere come lo programmi. Non vedo le connessioni classiche all'in circuit programmere: Vpp -->pin 1, RB7 e RB6 per dati e clock. Poi i LED bovrebbero essere connessi tramite un R per limitare la corrente.

Share this post


Link to post
Share on other sites
dantares

le connessini per programmarlo non ci sono perchè lo programmo a parte, comunque anche con i tuoi cambiamenti non funziona... come faccio a vedere se per caso è il quarzo ad essere andato? il programmino che gli ho messo per fare una prova sono 4 semplici righe:

void main(){

TRISB=0;

RB1=1;

}

ma non mi si accende nessun led...

Share this post


Link to post
Share on other sites
Livio Orsini

Per vedere se il quarzo oscilla dovresti avere un oscilloscopio, ma uno vero non simulato.

Poi il led come lo hai collegato?

Il problema di quando non si usa un in circuit debugger è che si deve andare a tentoni. :angry:

Share this post


Link to post
Share on other sites
dantares

infatti... per questo stavo pensando di procurarmi un ICD, QUESTO come ti sembra?

La cosa strana è che per 2 o 3 prove ha funzionato, sono riuscito a far lampeggiare 2 led alternativamente ma ora non va ancora... mi sa che dovrò aspettare di avere un programmatore serio, ora ne uso uno seriale di recupero ma sto pensando di costruirmene uno parallelo

Share this post


Link to post
Share on other sites
Livio Orsini

A parer mio sono soldi no dico gettati, ma quasi. Il mio consiglio è: "Acquista un ICD2 direttamente da microchip!"

hai uno strumento professionale, sicuro, affidabile, programmi tutti i PIC e i dsPIC, esegui in circuit debug e sei sempre aggiornato anch eper futuri dispositivi. Spendi solo pochi Euro in più.

C'è una discussione dove uno descrive come lo ha acquistato via internet, quanto ha speso ed in quanto tempo lo ha ricevuto.

Questo è il sito

Edited by Livio Orsini

Share this post


Link to post
Share on other sites
dantares

ok, sono a cavallo, era un problema di icprog, ora con win pic riesco a programmare bene il pic.

sono riuscito a scrivere sulla eeprom quello che voglio e dove voglio ma ho un piccolo dettaglio che non riesco a risolvere... infatti il programma continua all'infinito, per fermarlo ho fatto questo:

int c=1;
if(c==1)
{
      esegui il codice;
      c=0;
}
ma continua comunque ad andare avanti, sai suggerirmi qualche sottigliezza per fermarlo? un'altra cosa, ho provato a collegare un pulsante per dare l'avvio al programma una volta alimentato il pic ma non riesco proprio a farlo andare, quello che ho scritto è questo:
TRISB2=1;

if(RB2==1)
{
      esegui il codice;
}

ma non va, addirittura pare non si accenda nemmeno il pic perchè tutti i led rimangono spenti...

Share this post


Link to post
Share on other sites
Livio Orsini

Se stai usando "C" "esegui il codice" non dovrebbe neanche compilarlo e darti un errore perchè dovrebbe essere "esegui_il_codice();" se "invece esegui il codice" è un'allocuzione al posto delle righe di codice bisoggnerebbe vedere cosa hai scritto.

Share this post


Link to post
Share on other sites
dantares

no, "esegui il codice" è un esempio quello che dovrebbe fare è:

    if(c==1)
    {    
                DelayMs(10);    
        RB1=0;
        RB4=1;
        DelayMs(10);
        RB1=1;
        RB4=0;
        DelayMs(10);
        RB1=0;
        RB4=1;
        DelayMs(10);
        RB1=1;
        RB4=0;
        DelayMs(10);
        RB1=0;
        RB4=1;
        DelayMs(10);
        RB1=1;
        RB4=0;
        DelayMs(10);
        RB1=0;
        RB4=1;
        DelayMs(10);
        RB1=1;
        RB4=0;
        
        c=0;
    }

ho provato a scrivere su eeprom 24lc64 e funziona ma su 24c02 non va, sapresti dirmi il perchè? Grazie

Edited by dantares

Share this post


Link to post
Share on other sites
kiki kaikai

Ciao a tutti

Sto cercando di fare lo stesso progetto come il tuo,ma non ho un PIC16F876 ma sto usando un PIC16F877A, programmazione C. 

Vorrei poter scrivere un dato in una eprom esterna 24c02  semplicemente premendo un pulsante. vi posto lo schema

Ho provato a caricare il tuo progetto in MPLAB X IDE v5.20 ma come già pensavo mi da un sacco di errori perché ho impostato il PIC16F877A , ma facendo delle modifiche ho aggiustato qualcosa ma ancora sono in alto mare. Per capirci meglio posto anche il listato,  

PIC877A.JPG

Share this post


Link to post
Share on other sites
kiki kaikai

 

 

/***********************************************
*               24c02                           *
*   Codice scheda: ????????????                 *
*   Firmware version:1.0                        *
*   autore: ******************                  *
*   Data:03/08/2019                             *
*   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 "delay.C"
//#define _XTAL_FREQ 4000000
#include <pic.h>

/*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;
    addrl=LOW_BYTE(address);
    addrh=HIGH_BYTE(address);(address);
    i2c_start();
       i2c_write(0xa0);
       i2c_write(addrh);
       i2c_write(addrl);
       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

errore.JPG

Edited by kiki kaikai

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

×
×
  • Create New...