home | area personale         schemi | tutorial | robotica | pic micro | recensioni         forum | chat irc         faq | contatti         store | Ordina PCB
username
password
cerca

 
FORUM: Pic Micro
Tutto quanto riguarda questi microprocessori... progetti, suggerimenti, aiuti, discussioni...ecc


PORTA analogica in PIC16F873A
     
Autore Messaggio opzioni
e.ferriani





postato il:
10.09.2018, alle ore 07:52
picmicro675:
Fai quello che preferisci.
Mi sembra che ho spiegato alcuni metodi. Se hai bisogno di migliorare, potremmo continuare con l' esempio dei LED e mettere una altra funzione.


Certo che voglio migliorare le mie conoscenze ed il programma che sto scrivendo. Continuiamo pure con l'esempio del led.
Infatti, come detto mi sono letto il programma che hai messo, anche se ad un certo punto essendoci delle cose che non conosco mi sono un po' perso, ma non demordo.

Stavo facendo qualcosa a riguardo di qualche post dietro.

picmicro675:

Aggiungiamo una nuova fase all' esercizio.....
Ogni 200 millisecondi il master legge i dati da uno slave. Mettiamo un contatore che ad ogni evento cambia l' indirizzamento di quale slave vuole dialogare...


Ho avuto un pochino di tempo per giocare ieri ed ho aggiunto la mia vecchia funzione di Avvio e quella si Stop, sotto due interrupt diversi di due pulsanti, Avvio e Stop appunto.
Ho fatto un esperimento ma credo che la mia routine sia più lunga di 1mS, che è la durata dell'interrupt del TMR0.
La loro funzione è, una volta accesa la macchina ed inizializzata, premendo Start andare a dire agli N slaves di "sincronizzarsi", avviarsi e dire al master che l'hanno fatto.
Al contrario, il tasto Stop, dice a tutti di fermarsi e di rispondere che l'hanno fatto.

Credo che per comunicare e leggere il singolo slave il master impieghi qualcosa tipo 400ms. Se lo moltiplico per 4 fa 1200mS. Attualmente ho un interrupt di circa 1msec su TMR0.

Capita che premendo Start gli slave si avviano, e premendo Stop si fermano. Ovviamente non andando in errore il gioco si ripete ogni volta che li premo.
Se però vado a vedere il RC6, che è il bit che attivo e disattivo al passaggio per l'overwlow del timer, funziona all'avvio della macchina, ma una volta intervenuti uno dei due pulsanti questo non accade più.
Credo che potrebbe essere che la lunghezza della funzioni Avvio e Stop chiamate dall'interrupt possano essere troppo lunghe.
Metterò al loro posto due variabili avvio_programma ed arresto_programma, poi il richiamo alle funzioni lo farò nel while del main.





Enea Ferriani
picmicro675




una ogni 10 livelli


postato il:
10.09.2018, alle ore 09:08
Facciamo piccoli passi.
Metti il modello di source creato da qualche parte e lo analizziamo. Per I files già esistenti non serve ripetere, li ho messi da parte. Riprendiamo la parte del ciclo principale dei due LED e un invio comando ad UNO slave a 100 mS. Magari mettiamo, in seguito, lettura risposta da UNO slave a 100 mS.

I modelli proposti dall' AN736, sono di natura organizzata che tiene le informazioni in Union e Struct. Questi sono una materia nuova per i principianti, me compreso.



Anno nuovo, forum nuovo.
Mi sa che lascio.
e.ferriani





postato il:
11.09.2018, alle ore 08:07
Questo funziona, piccoli passi.
Tralasciando quello che non serve o non è inerente, di seguito metto la routine di interrupt.

Per l'anti rimbalzo dei pulsanti ho provato come segue. Non so se va bene, ma dato che la variabile "timer1" la uso, per ora, solo qua la azzero e la incremento ogni volta che premo i pulsanti.

Alla fine ci sono routines di AVVIO E ARRESTO che per ora fa solo comparire delle cose sul display.
Scusami ma l'avevo sullo stomaco e non riuscivo a farle girare. Se metto altre cose nelle due routines, come per esempio la comunicazione non funziona più niente, come avevo detto ieri. Non ho fatto in tempo a verificare la durata del ciclo, per vedere se è troppo lunga.

Ora bisogna andare avanti con l' esercizio proposto da Picmicro675.

MAIN



#pragma config FOSC = XT   // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF   // Low-Voltage In-Circuit Serial Programming Enable bit
#pragma config CPD = OFF   // Data EEPROM Memory Code Protection bit 
#pragma config WRT = OFF   // Flash Program Memory Write Enable bits 
#pragma config CP = OFF    // Flash Program Memory Code Protection bit

unsigned int valore_trimmer_velocita;
char riga_valore_trimmer = 1;                         //posizione "y" del dato
char colonna_valore_trimmer = 13;                      //posizione "x" del dato
unsigned char string_velocita[5]="";
char lung_velocita;

char millisec;

void main()
{  
  void I2C_Master_Init(const unsigned long c);
  Settaggi();
  IngressiAnalogici();
  I2C_Master_Init(I2C_SPEED);           
  
  INTCONbits.GIE = 1;
//  ************ DA QUI IN POI GLI INTERRUPT SONO ABILITATI   *********
  
//***** DISPLAY *********
  LCD_INIT();                                 //Inizializza display LCD 
  __delay_ms(1); 
  LCD_CLEAR(); 
  __delay_ms(100); 
//***** DISPLAY FINE  *********
  
  lcd_gotoxy(1,1);
  lcd_puts("PREMI START  ");
  lcd_gotoxy(2,1);
  lcd_puts("****************");
  
  while (1)
  {
    if(periodo_lettura_trimmer_velocita >= 100)
    {
      LetturaTrimmerVelocita();
      ScritturaValoreTrimmer();
      periodo_lettura_trimmer_velocita=0;
    }
    
    if (avvio_premuto==1)
    {
      Avvio_Programma();
      programma_avviato=1;
      avvio_premuto=0;
    }
    if (arresto_premuto==1)
    {
      Arresto_Programma();
      programma_avviato=0;
      arresto_premuto=0;
    }
  }
}




INTERRUPT



void __interrupt( ) ISR (void)
{
  //***************************************************************
  //**********  INTERRUPT DI TMR0  ********************************
  //***************************************************************
    
    
  if (T0IF)       // L'interrupt Ã¨ stato causato da un overflow del timer0 ???
  {
    TMR0 = 195;         // con Prescaler 1:16 => Overflow di TMR0 ogni 996uS
    T0IF=0;             // Resetto il flag interrupt su Timer0
    millisec++;
    periodo_lettura_trimmer_velocita++;
    periodo_scrittura_I2C++;
    periodo_lettura_I2C++;
    timer1++;
  }

  
  if (pulsante_avvio & (programma_avviato==0))
  {
    timer1=0;
    if(timer1==50)
    {
      RC7=0;
      if (pulsante_avvio)
      {
        avvio_premuto=1;
      }
      timer1=0;
    }
  }
  if (pulsante_arresto & (programma_avviato==1))
  {
    timer1=0;
    if(timer1==50)
    {
      if (pulsante_arresto)
      {
        arresto_premuto=1;
      }
      timer1=0;
    }
  }
}



Le routines di AVVIO E ARRESTO



void Avvio_Programma (void)
{
  procedura_di_avvio=1;
  lcd_gotoxy(1,1); 
  lcd_puts((unsigned char *)"AVVIATO     ");
  lcd_gotoxy(2,1);
  lcd_puts((unsigned char *)"A=> B=> C=> D=> ");
  procedura_di_avvio=0;
  programma_avviato=1;
}

void Arresto_Programma (void)
{
  lcd_gotoxy(1,1);
  lcd_puts((unsigned char *)"FERMATO     ");
  lcd_gotoxy(2,1);
  lcd_puts((unsigned char *)"A=X B=X C=X D=X ");
  programma_avviato=0;
}




Enea Ferriani
picmicro675




una ogni 10 livelli


postato il:
11.09.2018, alle ore 10:25
Vedi se questo è meglio
if(timer1>=50)
{
    if (pulsante_arresto)
    {
        arresto_premuto=1;
        timer1=0;
    } else {
        timer1=0;
    }
}

Secondo me nel tuo modo, Timer1 non arriverà mai a 50. Anche se succedesse, devi stare ben attento che lo legge nel periodo che è a 50, altrimenti aspetti che il conteggio faccia il giro. Se hai usato una long, ti ci vuole 49 gg e rotti.



Anno nuovo, forum nuovo.
Mi sa che lascio.
e.ferriani





postato il:
11.09.2018, alle ore 13:25
Ok, proverò. Ma scusami una domanda. Come vedrai nel mio codice ho messo due variabili,"periodo_scrittura_I2C" e "periodo_lettura_I2C", che avevo predisposto per creare il timing di lettura e scrittura appunto.

E' una strada buona o suggerisci di fare in un altro modo? Cioè nel while del programma principale, potrei andare a tastare il valore della variabile di lettura e raggiunti i 100mS vedere se è successo qualcosa, poi azzerarla. Allo stesso modo ogni 100mS, con la variabile di scrittura, mandare un comando a qualcuno ed azzerarla.
Facendo così però rischierei di perdermi delle comunicazioni dagli slave?

Magari ne riparleremo in seguito, ma ti ricordo che nel mio circuito il master non prende molte decisioni, almeno come lo avevo pensato. Non fa altro che ascoltare quello dicono gli slave sul bus e girare il contenuto della comunicazione al destinatario. Si comporta più come un instradatore che come un master, ma potrei riconsiderarne il funzionamento.

A meno che ognuno non tenga bloccata la comunicazione finchè il proprio stato non è stato recepito.
Provo a spiegarmi in altre parole.

1 - evento A sullo slave1
2 - slave 1 scrive sul bus
3 - 100mS master legge
4 - master indirizza l'azione relativa all'evento A allo slave destinatario
5 - slave destinatario esegue l'azione predisposta e comunica il completamento
6 - ...

Supponiamo che in mezzo a quei 100ms del punto 3 accada un evento B sullo slave 3. Chi se lo legge se nel frattempo è già partita la scrittura del master?

Il mio vecchio codice prevedeva la lettura e scrittura continua, ogni completamento del while, non ricordo i millisecondi del periodo.

Credo che bisognerebbe scrivere qualcosa del genere, ma andiamo pure per gradi. Una cosa alla volta, poi le cose verranno da sole.



Enea Ferriani
picmicro675




una ogni 10 livelli


postato il:
11.09.2018, alle ore 20:25
Nota 1, il nome delle variabili sarebbe conveniente tenerle di una lunghezza ragionevole. Il caso sta quando cominci a comporre un calcolo o una chiamata a funzione con diversi parametri che subito ti trovi a una larghezza di pagina esorbitante. Quindi variabili significanti ma il più corte possibili. P.es. valpotvelA è intuitivo tanto come valore_potenziometro_velocita_accelerazione. Magari si scrive il commento per chiarire a cosa viene riferito.
Poi linee vuote non più di una.

Nota 2, il ragionamento l'ho già scritto (pag. 10 art. 6, pag. 12 art. 8, pag 13 art. 5). Ci sono due modi di operare
A) ad ogni operazione dai un periodo di tempo di attenzione.
B) ogni operazione viene eseguita di seguito all' altra nel ciclo principale.

Caso A, si accerta che tutte le operazioni ricevono l' attenzione entro limiti stabiliti. Eventualmente viene postposta al periodo successivo.
Caso B, ogni evento prende l' attenzione fino a completamento della azione. Ci possono essere situazioni che il lavoro non è bilanciato. Per questo bisogna calcolare i tempi per ogni azione che rimane in certi limiti.

Se ti trovi che il caso B non assolve il compito voluto, vediamo il caso B. Altrimenti prepariamo il caso intermedio.

Io sono del parere che sia preferibile il caso A. Come volevasi dimostrare con i 2 LED che lampeggiano a frequenza diversa. Perché se si facesse come il caso B, la frequenza di lampeggio sarebbe di 3,4 secondi. Del quale 1 secondo LED1 acceso, 1 secondo LED1 spento, 0,7 secondi LED2 acceso e 0,7 secondi LED2 spento. Quindi il LED1 sta spento, in realtà 2,4 secondi. Per questo bisognerebbe ricalcolare il minimo comune multiplo (mcm) e usarlo come base tempi.
Nel caso A, si ha il momento che gli eventi accadono con il massimo comune denominatore (mcd). Ma di fatto viene eseguito nella sequenza che sono scritti nel programma. Per tanto il secondo avrà il ritardo della esecuzione del primo.
Il caso A, ha il vantaggio che non serve ricalcolare ad ogni volta che si fanno delle modifiche. C'è un orologio che determina la cadenza degli eventi. L' altro caso invece si deve ricalcolare l' mcm per ricombinare gli eventi.

Nel tuo progetto, si caratterizza che ogni ramo ha funzioni proprie. Le quali sono il controllo velocità, segnali ingressi aperti-chiusi e segnali uscite acceso-spento, (eventuale) scelta di intervenire per un caso particolare. Questi sono le azioni degli slave.
Il master raccoglie le informazioni degli slave e determina i comandi da eseguire con la parte di visualizzazione lato operatore.
Questo determina che il master prende le informazioni dall' operatore, legge lo stato del ramo interessato e determina il comando da eseguire. La routine si ripete per tutti i rami interessati.
Per questo il caso A, può garantire che all' operatore viene garantito un periodo per intervenire a tempo umanamente accettabile (facciamo in meno di un secondo) e quindi caratterizzare le manovre come una vera stazione ferroviaria.

Per questo che dico che bisogna organizzare un pacchetto di dati per ogni slave. Forse 16 bytes sono abbondanti, ma ti permette di mettere le mani avanti per lo sviluppo di aggiornamento. Di questi bytes si può determinare i valori da assegnare ai PWM, letture ADC, ingressi. uscite e codice di controllo di ogni ramo.
Ora abbiamo delle routines già fatte (AN735), le quali bisogna prenderle come oggetti finiti senza troppi ripensamenti, come si fa per le librerie di un display LCD, comunicazione SERIALE e quant' altro. Queste definiscono

un pacchetto che determina la lunghezza dei dati e la locazione di memoria (come se fosse necessario scrivere in un particolare punto=, poi codici di controllo per eventuali errori.
C'è magari una parte del programma che invia dati all' operatore (tramite seriale) che eventualmente possiamo invece cambiare per far lavorare l' LCD.
Il vantaggio è che ci sia più tempo dal fatto che si determina la lunghezza fissa dei dati ed il numero di slaves minori. Quindi tutto dovrebbe funzionare in modo egregio. Eventualmente ci saranno delle varianti per le operazioni che devono fare gli slave secondo i valori ricevuti.
Se vogliamo, si può ridisegnare la prima parte che determina la gestione delle stringhe da trasmettere.

Per provare queste modifiche sarà necessario almeno un master ed uno slave. Per il tipo di micro il debugging è comodo anche in hardware. Se hai il pickit3, puoi istruire MPLABX per fare il debug durante l'esecuzione in reale.



Anno nuovo, forum nuovo.
Mi sa che lascio.
e.ferriani





postato il:
12.09.2018, alle ore 13:06
picmicro675:
....
Per provare queste modifiche sarà necessario almeno un master ed uno slave. Per il tipo di micro il debugging è comodo anche in hardware. Se hai il pickit3, puoi istruire MPLABX per fare il debug durante l'esecuzione in reale.


Oscilloscopio, ICD3 e simulatore con 5 micro presenti.

Dato che il programma gira su più micro credo sia sufficiente il simulatore e l'oscilloscopio.
Non si possono debuggeare con un solo ICD3 due micro contemporaneamente, ci vorrebbero due pc e due programmatori. Effettivamente ho un ICD2 ed un altro pc con Windows XP 32bit, quello che mi fa delle storie. Potrei anche pensarci, ma per ora vado di oscilloscopio e led.



Enea Ferriani
picmicro675




una ogni 10 livelli


postato il:
12.09.2018, alle ore 15:27
Penso si possa usare entrambe in un computer. Solo che ICD 2 gira solo con MPLAB 8.60.
Ho provato ad avviare MPLAX 3.35 e MPLAB 8.60 su win7.
Non posso dire che funzionano i due dispositivi perché non li ho.



Anno nuovo, forum nuovo.
Mi sa che lascio.
e.ferriani





postato il:
13.09.2018, alle ore 22:27
Mi sono incartato, non riesco ad andare avanti. Forse sto sbagliando strada ad utilizzare parti di codice esistenti e funzionanti nel vecchio programma.
Sembra che I"c, in particolare il secondo "I2C_Master_Wait();" della routine di seguito. Provato con l'attivazione di una uscita RC7. Fino a "I2C_Master_Stop();" funziona, dopo il wait successivo non si attiva più.

 
void I2C_Master_Start()
{
  I2C_Master_Wait();
  SSPIF = 0;
  I2C_Master_Stop();
  I2C_Master_Wait();
  SSPCON2bits.SEN = 1;



Il programma non esce da lì se faccio coesistere interrupt e comunicazione.


Se lascio la comunicazione I2C fuori dai giochi il timer TMR0 funziona, o almeno riesco a fargli fare qualcosa. Appena attivo la comunicazione I2C, chiamando l'avvio alla pressione dei due pulsanti nella routine di interrupt, si blocca completamente la routine di interrupt.

Se smaschero il ciclo presente nel while del main
// RC7=1;
// Avvio_Programma();
// RC7=0;
vedo la comunicazione di avvio con l'oscilloscopio e riesco a far sentire la pressione dei pulsanti in interrupt, switchando RC6 e vedendo la comunicazione andare da 0b00110011 a 0b11001100.

Forse devo proprio abbandonare quel codice? ma ci sarà un motivo però per questo comportamento?

INTERRUPT



void __interrupt( ) ISR (void)
{
  
  //***************************************************************
  //**********  INTERRUPT DI TMR0  ********************************
  //***************************************************************

  if (T0IF)       // L'interrupt Ã¨ stato causato da un overflow del timer0 ???
  {
    TMR0 = 195;         // con Prescaler 1:16 => Overflow di TMR0 ogni 996uS

    T0IF=0;             // Resetto il flag interrupt su Timer0
    millisec++;
    periodo_lettura_trimmer_velocita++;
    periodo_scrittura_I2C++;
    periodo_lettura_I2C++;
    timer1++;
  }

  //***************************************************************
  //**********  INTERRUPT DI COMUNICAZIONE  ***********************
  //***************************************************************
  

  
  //***************************************************************
  //**********   INTERRUPT  AGGIUNTIVI   **************************
  //***************************************************************
  
  if (pulsante_avvio)// & (programma_avviato==0))
  {
      avvio_premuto=1;
      RC6=1;
  }

  if (pulsante_arresto)// & (programma_avviato==1))
  {
      arresto_premuto=1;
      RC6=0;
  }
}


MAIN


void main()
{  
  void I2C_Master_Init(const unsigned long c);
  Settaggi();
  IngressiAnalogici();
  __delay_ms(100); 
  I2C_Master_Init(I2C_SPEED);             //I2C_SPEED   100000
  __delay_ms(1000);
  
  INTCONbits.GIE = 1;
//  ************ DA QUI IN POI GLI INTERRUPT SONO ABILITATI
  
//***** DISPLAY 
  LCD_INIT();                                 //Inizializza display LCD 
  __delay_ms(1); 
  LCD_CLEAR(); 
  __delay_ms(100); 
//***** DISPLAY FINE
  
  lcd_gotoxy(1,1);
  lcd_puts("PREMI START  ");
  lcd_gotoxy(2,1);
  lcd_puts("****************");
    
  while (1)
  {   
//    RC7=1;
//    Avvio_Programma();
//    RC7=0;

   
    if(periodo_lettura_trimmer_velocita >= 100)
    {
      LetturaTrimmerVelocita();
      ScritturaValoreTrimmer();
      periodo_lettura_trimmer_velocita=0;
    }
    
    if (avvio_premuto==1)
    {
      Avvio_Programma();
      programma_avviato=1;
      avvio_premuto=0;
    }
    if (arresto_premuto==1)
    {
      Arresto_Programma();
      programma_avviato=0;
      arresto_premuto=0;
    }
    
  }
}
  
//--------------------
// ROUTINES ACCESSORIE
//--------------------


void LetturaTrimmerVelocita (void)
{
  ADCON0 = 0b00000001;
  
  ADCON0bits.GO = 1; 
  while (ADCON0bits.GO_DONE);
  valore_trimmer_velocita =(unsigned int) (ADRESL + (ADRESH<<8));
}

void ScritturaValoreTrimmer (void)
{  
  itoa( (char *)string_velocita , valore_trimmer_velocita, 10);    

  lcd_gotoxy ( riga_valore_trimmer , colonna_valore_trimmer );
  lcd_puts(string_velocita);
  lung_velocita = strlen((char *)string_velocita);
  lung_velocita+=colonna_valore_trimmer;
  lcd_gotoxy(riga_valore_trimmer,lung_velocita);
  lcd_puts((unsigned char *)"    ");
  lung_velocita = 0;
}


Routine semplice per AVVIO programma, tanto per vedere se la comunicazione si attiva



void Avvio_Programma (void)
{
  marcia=1;
  procedura_di_avvio=1;
  lcd_gotoxy(1,1); 
  lcd_puts((unsigned char *)"AVVIATO     ");
  lcd_gotoxy(2,1);
  lcd_puts((unsigned char *)"A=> B=> C=> D=> ");
  
  //****************************************************************
  //  SCRITTURA SLAVE 1-4  AVVIO PROGRAMMA
  //****************************************************************
  
  for (selezione_slave=1;selezione_slave<=1;selezione_slave++)
  {
    RC7=1;
    dato_ricevuto=0;
    I2C_Master_Start();
    I2C_Master_Write(0b00000010);
    I2C_Master_Wait();
    I2C_Master_Write(0b00110011);
    I2C_Master_Stop();
  }
  procedura_di_avvio=0;
  programma_avviato=1;
}
void Arresto_Programma (void)
{
  marcia=0;
  lcd_gotoxy(1,1);
  lcd_puts((unsigned char *)"FERMATO     ");
  lcd_gotoxy(2,1);
  lcd_puts((unsigned char *)"A=X B=X C=X D=X ");
  
  //****************************************************************
  //  SCRITTURA SLAVE 1-4  ARRESTO PROGRAMMA
  //****************************************************************
  
  for (selezione_slave=1;selezione_slave<=1;selezione_slave++)
  {
    RC7=1;
    dato_ricevuto=0;
    I2C_Master_Start();
    I2C_Master_Write(0b00000010);
    I2C_Master_Wait();
    I2C_Master_Write(0b11001100);
    I2C_Master_Stop();
  }

  programma_avviato=0;
}




Settaggi I2C



//-----------------------------------------------------------------------------
//INIZIALIZZAZIONI I2C
//-----------------------------------------------------------------------------

void I2C_Master_Init(const unsigned long c)
{
//REGISTRO  SSPCON    

  SSPCONbits.WCOL = 0;
  SSPCONbits.SSPOV = 0;
  SSPCONbits.SSPEN = 1;
  SSPCONbits.CKP = 0;
  SSPCONbits.SSPM3 = 1;
  SSPCONbits.SSPM2 = 0;
  SSPCONbits.SSPM1 = 0;
  SSPCONbits.SSPM0 = 0;

//REGISTRO SSPCON2

  SSPCON2bits.GCEN = 0;
  SSPCON2bits.ACKSTAT = 0;
  SSPCON2bits.ACKDT = 0;
  SSPCON2bits.ACKEN = 0;
  SSPCON2bits.RCEN = 0;
  SSPCON2bits.PEN = 0;
  SSPCON2bits.RSEN = 0;
  SSPCON2bits.SEN = 0;
  
  SSPADD = (_XTAL_FREQ/(4*I2C_SPEED))-1;
    
  PIR1bits.SSPIF = 0;
  PIR2bits.BCLIF = 0;
  PIE2bits.BCLIE = 1;
  PIE1bits.SSPIE = 1;
  INTCONbits.PEIE = 1;
//  INTCONbits.GIE = 1;     //attivato nel main
  
  SSPSTATbits.SMP = 0;
  SSPSTATbits.CKE = 0;
  SSPSTATbits.D_nA = 0;
  SSPSTATbits.P = 0;
  SSPSTATbits.S = 0;
  SSPSTATbits.R_nW = 0
  SSPSTATbits.UA = 0;
  SSPSTATbits.BF = 0;
  
}

void I2C_Master_Wait()
{
  while ((SSPSTAT & 0b00000100) || (SSPCON2 & 0b00011111)); 
  }
  
void I2C_Master_Start()
{
  I2C_Master_Wait();
  SSPIF = 0;
  I2C_Master_Stop();
  I2C_Master_Wait();
  RC7=0;
  SSPCON2bits.SEN = 1;
}

void I2C_Master_RepeatedStart()
{
  I2C_Master_Wait();
  SSPCON2bits.RSEN = 1;
}

void I2C_Master_Stop()
{
  I2C_Master_Wait();
  SSPCON2bits.PEN = 1;  
}

void I2C_Master_Write(unsigned d)
{
  I2C_Master_Wait();
  SSPBUF = d;
}

unsigned short I2C_Master_Read(unsigned short a)
{
  unsigned short temp;
  I2C_Master_Wait();
  SSPCON2bits.RCEN = 1;
  
  I2C_Master_Wait();
  temp = SSPBUF;
  I2C_Master_Wait(); 
  
  SSPCON2bits.ACKDT = (a)?0:1;  
  SSPCON2bits.ACKEN = 0;
  
  return temp;
}




Enea Ferriani
picmicro675




una ogni 10 livelli


postato il:
14.09.2018, alle ore 08:46
Vedo il tuo messaggio in dettaglio.
Stavo scrivendo un articolo abbastanza lungo e per sbaglio ho toccato il touchpad che mi ha cambiato pagina. Così, ho perso quello che ho scritto per circa un' ora.



Anno nuovo, forum nuovo.
Mi sa che lascio.
segui questo thread con grixFC, per questa funzione devi aver installato il software grixFC

torna su
     

Come utente anonimo puoi leggere il contenuto di questo forum ma per aprire una discussione
o per partecipare ad una discussione esistente devi essere registrato ed accedere al sito




 







 
 
indietro | homepage | torna su copyright © 2004/2024 GRIX.IT - La community dell'elettronica Amatoriale