PCF8583, I2C, pic16f877a et MPLAB xc8

Fermé
mouadh2017 Messages postés 3 Date d'inscription mercredi 6 septembre 2017 Statut Membre Dernière intervention 24 octobre 2017 - 24 oct. 2017 à 18:46
Bonjour CC,

Je développe un projet pour affciher la date et l'heure en temps réel.
pour faire celà j'utilise un PCF8583, un afficheur LCD4x16 un PIC16F877A et le compilateur xc8 de l'IDE MPLAB X.

mais j'arrive pas à une bonne résultat!!!
svp y-t-il quelqu'un qui peut me donner un coup de pousse que me permet de contunier???

mon projet qu'en j'ai développé:

PCF8583.h

#ifndef PCF8583_H
#define	PCF8583_H

#ifndef PCF8583_WRITE_ADDRESS 
#define PCF8583_WRITE_ADDRESS 0xA0 
#define PCF8583_READ_ADDRESS  0xA1 
#endif 

// Register addresses 
#define PCF8583_CTRL_STATUS_REG    0x00 
#define PCF8583_100S_REG           0x01 
#define PCF8583_SECONDS_REG        0x02 
#define PCF8583_MINUTES_REG        0x03 
#define PCF8583_HOURS_REG          0x04 
#define PCF8583_DATE_REG           0x05 
#define PCF8583_MONTHS_REG         0x06 
#define PCF8583_TIMER_REG          0x07 

#define PCF8583_ALARM_CONTROL_REG  0x08 
#define PCF8583_ALARM_100S_REG     0x09 
#define PCF8583_ALARM_SECS_REG     0x0A 
#define PCF8583_ALARM_MINS_REG     0x0B 
#define PCF8583_ALARM_HOURS_REG    0x0C 
#define PCF8583_ALARM_DATE_REG     0x0D 
#define PCF8583_ALARM_MONTHS_REG   0x0E 
#define PCF8583_ALARM_TIMER_REG    0x0F 

// Use the first NVRAM address for the year byte. 
#define PCF8583_YEAR_REG           0x10 


// Commands for the Control/Status register. 
#define PCF8583_START_COUNTING     0x00 
#define PCF8583_STOP_COUNTING      0x80 
             
typedef struct 
{ 
    unsigned char seconds;    // 0 to 59 
    unsigned char minutes;    // 0 to 59 
    unsigned char hours;      // 0 to 23  (24-hour time) 
    unsigned char day;        // 1 to 31 
    unsigned char month;      // 1 to 12 
    unsigned char year;       // 00 to 99 
    unsigned char weekday;    // 0 = Sunday, 1 = Monday, etc. 
}date_time_t; 

void PCF8583_write_byte(unsigned char address, unsigned char data);   

unsigned char PCF8583_read_byte(unsigned char address);   

void PCF8583_init(void);

unsigned char bin2bcd(unsigned char value);

char bcd2bin(char bcd_value);

void PCF8583_set_datetime(date_time_t *dt);

void PCF8583_read_datetime(date_time_t *dt);

#endif	/* PCF8583_H */


PCF8583.c
#include <xc.h>
#include <pic16f877a.h>
#include "PCF8583.h"
#include "I2C.h"

//---------------------------------------------- 
void PCF8583_write_byte(unsigned char address, unsigned char data) 
{ 

    INTCONbits.GIE = 0; 
    
    I2C_Start(); 
    I2C_Send(PCF8583_WRITE_ADDRESS); 
    I2C_Send(address); 
    I2C_Send(data); 
    I2C_Stop(); 

    INTCONbits.GIE = 1; 
}    

//---------------------------------------------- 
unsigned char PCF8583_read_byte(unsigned char address) 
{ 
    unsigned char retval; 

    INTCONbits.GIE = 0;  
    I2C_Start(); 
    I2C_Send(PCF8583_WRITE_ADDRESS); 
    I2C_Send(address); 
    I2C_Restart(); 
    I2C_Send(PCF8583_READ_ADDRESS); 
    retval = I2C_Read(); 
    I2C_Stop(); 
    INTCONbits.GIE = 1;  
    return(retval); 
}    


void PCF8583_init(void) 
{ 
    PCF8583_write_byte(PCF8583_CTRL_STATUS_REG, 
                              PCF8583_START_COUNTING); 
}    

//---------------------------------------------- 
// This function converts an 8 bit binary value 
// to an 8 bit BCD value. 
// The input range must be from 0 to 99. 

unsigned char bin2bcd(unsigned char value) 
{ 
    char retval; 

    retval = 0; 

    while(1) 
      { 
       // Get the tens digit by doing multiple subtraction 
       // of 10 from the binary value. 
       if(value >= 10) 
         { 
          value -= 10; 
          retval += 0x10; 
         } 
       else // Get the ones digit by adding the remainder. 
         { 
          retval += value; 
          break; 
         } 
       } 

    return(retval); 
} 

//---------------------------------------------- 
// This function converts an 8 bit BCD value to 
// an 8 bit binary value. 
// The input range must be from 00 to 99. 

char bcd2bin(char bcd_value) 
{ 
    char temp; 

    temp = bcd_value; 

    // Shifting the upper digit right by 1 is 
    // the same as multiplying it by 8. 
    temp >>= 1; 

    // Isolate the bits for the upper digit. 
    temp &= 0x78; 

    // Now return: (Tens * 8) + (Tens * 2) + Ones 
    return(temp + (temp >> 2) + (bcd_value & 0x0f)); 

} 

//---------------------------------------------- 
void PCF8583_set_datetime(date_time_t *dt) 
{ 
    unsigned char bcd_sec; 
    unsigned char bcd_min; 
    unsigned char bcd_hrs; 
    unsigned char bcd_day; 
    unsigned char bcd_mon; 

    // Convert the input date/time into BCD values 
    // that are formatted for the PCF8583 registers.  
    bcd_sec = bin2bcd(dt->seconds); 
    bcd_min = bin2bcd(dt->minutes); 
    bcd_hrs = bin2bcd(dt->hours);    
    bcd_day = bin2bcd(dt->day) | (dt->year << 6); 
    bcd_mon = bin2bcd(dt->month) | (dt->weekday << 5); 

    // Stop the RTC from counting, before we write to 
    // the date and time registers. 
    PCF8583_write_byte(PCF8583_CTRL_STATUS_REG, 
                                  PCF8583_STOP_COUNTING); 

    // Write to the date and time registers.  Disable interrupts 
    // so they can't disrupt the i2c operations. 
    INTCONbits.GIE = 0; 
    I2C_Start(); 
    I2C_Send(PCF8583_WRITE_ADDRESS); 
    I2C_Send(PCF8583_100S_REG);   // Start at 100's reg.    
    I2C_Send(0x00);               // Set 100's reg = 0 
    I2C_Send(bcd_sec);  
    I2C_Send(bcd_min); 
    I2C_Send(bcd_hrs);    
    I2C_Send(bcd_day); 
    I2C_Send(bcd_mon); 
    I2C_Stop(); 
    INTCONbits.GIE = 1; 

    // Write the year byte to the first NVRAM location. 
    // Leave it in binary format. 
    PCF8583_write_byte(PCF8583_YEAR_REG, dt->year); 

    // Now allow the PCF8583 to start counting again. 
    PCF8583_write_byte(PCF8583_CTRL_STATUS_REG, 
                                  PCF8583_START_COUNTING); 
} 

//---------------------------------------------- 
// Read the Date and Time from the hardware registers 
// in the PCF8583.   We don't have to disable counting 
// during read operations, because according to the data 
// sheet, if any of the lower registers (1 to 7) is read, 
// all of them are loaded into "capture" registers. 
// All further reading within that cycle is done from 
// those registers. 

void PCF8583_read_datetime(date_time_t *dt) 
{ 
    unsigned char year_bits; 
    unsigned char year; 

    unsigned char bcd_sec; 
    unsigned char bcd_min; 
    unsigned char bcd_hrs; 
    unsigned char bcd_day; 
    unsigned char bcd_mon; 

    // Disable interrupts so the i2c process is not disrupted. 
    INTCONbits.GIE = 0;  

    // Read the date/time registers inside the PCF8583. 
    I2C_Start(); 
    I2C_Send(PCF8583_WRITE_ADDRESS); 
    I2C_Send(PCF8583_SECONDS_REG);   // Start at seconds reg. 
    I2C_Restart(); 
    I2C_Send(PCF8583_READ_ADDRESS); 

    bcd_sec = I2C_Read();      
    bcd_min = I2C_Read();      
    bcd_hrs = I2C_Read();  
    bcd_day = I2C_Read(); 
    bcd_mon = I2C_Read(); 
    I2C_Stop(); 

    INTCONbits.GIE = 1;  

    // Convert the date/time values from BCD to 
    // unsigned 8-bit integers.  Unpack the bits 
    // in the PCF8583 registers where required. 
    dt->seconds = bcd2bin(bcd_sec);      
    dt->minutes = bcd2bin(bcd_min);      
    dt->hours   = bcd2bin(bcd_hrs & 0x3F);  
    dt->day     = bcd2bin(bcd_day & 0x3F); 
    dt->month   = bcd2bin(bcd_mon & 0x1F); 
    dt->weekday = bcd_mon >> 5; 
    year_bits   = bcd_day >> 6;    

    // Read the year byte from NVRAM. 
    // This is an added feature of this driver. 
    year = PCF8583_read_byte(PCF8583_YEAR_REG); 

    // Check if the two "year bits" were incremented by 
    // the PCF8583.  If so, increment the 8-bit year 
    // byte (read from NVRAM) by the same amount. 
    while(year_bits != (year & 3)) 
          year++; 

    dt->year = year; 

    // Now update the year byte in the NVRAM 
    // inside the PCF8583. 
    PCF8583_write_byte(PCF8583_YEAR_REG, year); 

}



I2C.c
#include "I2C.h"
#include <xc.h>
#include <pic16f877a.h>

/*
Function: I2C_Init
Return:
Arguments:
Description: Initialize I2C in master mode, Sets the required baudrate
*/
void I2C_Init(void)
{
    TRISCbits.TRISC3 = 1;       /* SDA and SCL as input pin */
	TRISCbits.TRISC4 = 1;       /* these pins can be configured either i/p or o/p */
	SSPSTAT |= 0x80;            /* Slew rate disabled */
	SSPCON = 0x28;              /* SSPEN = 1, I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) */
	SSPADD = 0x28;              /* 100Khz @ 4Mhz Fosc */
}

/*
Function: I2C_Start
Return:
Arguments:
Description: Send a start condition on I2C Bus
*/
void I2C_Start(void)
{
    SEN = 1;                    /* Start condition enabled */
	while(SEN == 1);            /* automatically cleared by hardware */
                                /* wait for start condition to finish */      
}

/*
Function: I2C_Restart
Return:
Arguments:
Description: Sends a repeated start condition on I2C Bus
*/
void I2C_Restart(void)
{
    RSEN = 1;                   /* Repeated start enabled */
	while(RSEN == 1);           /* wait for condition to finish */
}

/*
Function: I2C_Stop
Return:
Arguments:
Description: Send a stop condition on I2C Bus
*/
void I2C_Stop(void)
{
    PEN = 1;                    /* Stop condition enabled */
	while(PEN == 1);            /* Wait for stop condition to finish */
                                /* PEN automatically cleared by hardware */
}

/*
Function: I2C_Wait
Return:
Arguments:
Description: wait for transfer to finish
*/
void I2C_Wait(void)
{
    while ((SSPCON2 & 0x1F ) || ( SSPSTAT & 0x04 ) );
}

/*
Function: I2C_Send
Return:
Arguments: dat - 8-bit data to be sent on bus
           data can be either address/data byte
Description: Send 8-bit data on I2C bus
*/
void I2C_Send(unsigned char data)
{
    SSPBUF = data;               /* Move data to SSPBUF */
    while(BF);                   /* wait till complete data is sent from buffer */
	I2C_Wait();                   /* wait for any pending transfer */
}

/*
Function: I2C_Read
Return:    8-bit data read from I2C bus
Arguments:
Description: read 8-bit data from I2C bus
*/
unsigned char I2C_Read(void)
{
    unsigned char temp;
/* Reception works if transfer is initiated in read mode */
	RCEN = 1;        /* Enable data reception */
	while(!BF);      /* wait for buffer full */
	temp = SSPBUF;   /* Read serial buffer and store in temp register */
	I2C_Wait();       /* wait to check any pending transfer */
	return temp;     /* Return the read data from bus */
}

/*
Function: I2CAck
Return:
Arguments:
Description: Generates acknowledge for a transfer
*/
void I2C_Ack()
{
	ACKDT = 0;       /* Acknowledge data bit, 0 = ACK */
	ACKEN = 1;       /* Ack data enabled */
	while(ACKEN == 1);    /* wait for ack data to send on bus */
}
 
/*
Function: I2CNck
Return:
Arguments:
Description: Generates Not-acknowledge for a transfer
*/
void I2C_Nak()
{
	ACKDT = 1;       /* Acknowledge data bit, 1 = NAK */
	ACKEN = 1;       /* Ack data enabled */
	while(ACKEN == 1);    /* wait for ack data to send on bus */
}


I2C.h
#ifndef I2C_H
#define	I2C_H

#define i2c_init        I2C_Init
#define I2C_init        I2C_Init
#define I2c_init        I2C_Init
#define i2c_init        I2C_Init

#define I2c_Start       I2C_Start
#define I2C_start       I2C_Start
#define I2c_start       I2C_Start
#define i2c_start       I2C_Start

#define I2c_Restart     I2C_Restart
#define I2C_restart     I2C_Restart
#define I2c_restart     I2C_Restart
#define i2c_restart     I2C_Restart

#define I2c_Stop        I2C_Stop
#define I2C_stop        I2C_Stop
#define I2c_stop        I2C_Stop
#define i2c_stop        I2C_Stop

#define I2c_Wait        I2C_Wait
#define I2C_wait        I2C_Wait
#define I2c_wait        I2C_Wait
#define i2c_wait        I2C_Wait

#define I2c_Send        I2C_Send
#define I2C_send        I2C_Send
#define I2c_send        I2C_Send
#define i2c_send        I2C_Send

#define I2c_Read        I2C_Read
#define I2C_read        I2C_Read
#define I2c_read        I2C_Read
#define i2c_read        I2C_Read

void I2C_Init(void);
void I2C_Start(void);
void I2C_Restart(void);
void I2C_Stop(void);
void I2C_Wait(void);
void I2C_Send(unsigned char data);
unsigned char I2C_Read(void);


#endif	/* I2C_H */


lcd.c
#include <xc.h>
#include "lcd.h"   

#define RS RD2
#define EN RD3

#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#define _XTAL_FREQ 8000000

void Lcd_Port(unsigned char a)
{
   if(a & 1)
      D4 = 1;
   else
      D4 = 0;

   if(a & 2)
      D5 = 1;
   else
      D5 = 0;

   if(a & 4)
      D6 = 1;
   else
      D6 = 0;

   if(a & 8)
      D7 = 1;
   else
      D7 = 0;
}
void Lcd_Cmd(unsigned char a)
{
    RS = 0;             // => RS = 0
    Lcd_Port(a);
    EN  = 1;             // => E = 1
    __delay_ms(4);
    EN  = 0;             // => E = 0
}

void Lcd_Clear(void)
{
   Lcd_Cmd(0);
   Lcd_Cmd(1);
}

void Lcd_Set_Cursor(unsigned char a, unsigned char b)
{
   char temp,z,y;
   if(a == 1)
   {
     temp = 0x80 + b - 1;
      z = temp>>4;
      y = temp & 0x0F;
      Lcd_Cmd(z);
      Lcd_Cmd(y);
   }
   else if(a == 2)
   {
      temp = 0xC0 + b - 1;
      z = temp>>4;
      y = temp & 0x0F;
      Lcd_Cmd(z);
      Lcd_Cmd(y);
   }
   else if(a == 3)
   {
      temp = 0x90 + b - 1;
      z = temp>>4;
      y = temp & 0x0F;
      Lcd_Cmd(z);
      Lcd_Cmd(y);
   }
   else if(a == 4)
   {
      temp = 0xD0 + b - 1;
      z = temp>>4;
      y = temp & 0x0F;
      Lcd_Cmd(z);
      Lcd_Cmd(y);
   }
}

void Lcd_Init(void)
{
  Lcd_Port(0x00);
   __delay_ms(20);
  Lcd_Cmd(0x03);
   __delay_ms(5);
  Lcd_Cmd(0x03);
   __delay_ms(11);
  Lcd_Cmd(0x03);
  /////////////////////////////////////////////////////
  Lcd_Cmd(0x02);
  Lcd_Cmd(0x02);
  Lcd_Cmd(0x08);
  Lcd_Cmd(0x00);
  Lcd_Cmd(0x0C);
  Lcd_Cmd(0x00);
  Lcd_Cmd(0x06);
}

void Lcd_Write_Char(unsigned char a)
{
   char temp,y;
   temp = a&0x0F;
   y = a&0xF0;
   RS = 1;             // => RS = 1
   Lcd_Port(y>>4);             //Data transfer
   EN = 1;
   __delay_us(40);
   EN = 0;
   Lcd_Port(temp);
   EN = 1;
   __delay_us(40);
   EN = 0;
}

void Lcd_Write_String(unsigned char *a)
{
   int i;
   for(i=0;a[i]!='\0';i++)
      Lcd_Write_Char(a[i]);
}

void Lcd_Shift_Right(void)
{
   Lcd_Cmd(0x01);
   Lcd_Cmd(0x0C);
}

void Lcd_Shift_Left(void)
{
   Lcd_Cmd(0x01);
   Lcd_Cmd(0x08);
}



lcd.h
#ifndef LCD_H
#define	LCD_H

void Lcd_Port(unsigned char a);

void Lcd_Cmd(unsigned char a);

void Lcd_Clear(void);

void Lcd_Set_Cursor(unsigned char a, unsigned char b);

void Lcd_Init(void);

void Lcd_Write_Char(unsigned char a);

void Lcd_Write_String(unsigned char *a);

void Lcd_Shift_Right(void);

void Lcd_Shift_Left(void);

#endif	/* LCD_H */


main.c
#include <ctype.h> 
#include <stdio.h>
#include <string.h>

#include <xc.h>
#include "lcd.h"
#include "I2C.h"
#include "PCF8583.h"
#include "UART.h"

#define	_XTAL_FREQ	20000000


// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS 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 (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

void interrupt InterruptServiceRoutine(void)
{
    if(PIR1bits.RCIF && PIE1bits.RCIE)
    {
        PIR1bits.RCIF = 0;
    }
}
///////////////////functia main///////////////////////////////////////////
void main(void)
 {
    date_time_t dt;
    char buf1[13];
    char buf2[13];
    
    unsigned char msg[] = "PCF8583 RTC";
    unsigned char Time[] = "Time:";
    unsigned char Date[] = "Date:";
    
    TRISCbits.TRISC3 = 1;     // I2C_SDA
    TRISCbits.TRISC4 = 1;     // I2C_SCL
    TRISD = 0x00;  
    ADCON1 = 0x0F;      // digital port configured
      
    I2C_Init();    
    Lcd_Init();
    
    PCF8583_init();
    
    Lcd_Set_Cursor(1,3);
    Lcd_Write_String(msg);
    Lcd_Set_Cursor(2,1);
    Lcd_Write_String(Date);
    Lcd_Set_Cursor(3,1);
    Lcd_Write_String(Time); 
    
    dt.month   = 10;    // October 
    dt.day     = 24;    // 24 
    dt.year    = 17;    // 2017 
    dt.hours   = 12;    // 12 hours (11pm in 24-hour time) 
    dt.minutes = 54;    // 54 minutes  
    dt.seconds = 50;    // 50 seconds 
    dt.weekday = 2;     // 0 = Sunday, 1 = Monday, etc. 

    PCF8583_set_datetime(&dt);     
    
    while(1) 
    {   
        __delay_ms(1000);    

        PCF8583_read_datetime(&dt); 
        
        dt.seconds  =  ((dt.seconds & 0xF0) >> 4)*10 + (dt.seconds & 0x0F);
        dt.minutes  =  ((dt.minutes & 0xF0) >> 4)*10 + (dt.minutes & 0x0F);
        dt.hours  =  ((dt.hours & 0xF0) >> 4)*10 + (dt.hours & 0x0F);
        
        sprintf(buf1,"%02d/%02d/%02d", dt.day, dt.month, dt.year); 
        sprintf(buf2,"%02d:%02d:%02d", dt.hours, dt.minutes, dt.seconds); 
        
        Lcd_Set_Cursor(2,6);
        Lcd_Write_String(buf1);
        Lcd_Set_Cursor(3,6);
        Lcd_Write_String(buf2);
        __delay_ms(500);
    }
}