Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] ds1307 slows with 7 segment display

mayasunny

Member level 3
Joined
Mar 21, 2019
Messages
56
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
481
Hello all,
I am currently working with developing Digital clock. I'm using PIC18F4550, DS1307 RTC, 6 seven segment display for displaying clock in HH.MM.SS format.
While reading the clock, I'm getting approximately 10 sec of delay for each second. I don't know where I'm going wrong. Below are my specifications
1. pic18f4550 micro controller
2. Ds1307 RTC with 32.76KHz, 3v battery
3. 1-digit Common cathode 7-segment displays ( using multiplexing concept)

If I mention about 500ms delay after every read, it shows the proper time but 7-Segment display is flickering continuously.
I testing the code with proteus software.
 
Solution
It seems appropriate to use the RTC for time display. The accuracy of processor clock usually can't keep up with the RTC. And it's much simpler to keep the time over power loss. Even if you prefer a software clock, you'll synchronize it to the RTC from time-to-time.

mayasunny

Member level 3
Joined
Mar 21, 2019
Messages
56
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
481
thanks for your replay Mr.Brain
Code:
#include <xc.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "configbits.h"
#include "i2c.h"                                // This header file includes I2C.c file which is used to interface the I2C
#include "uart.h"                                // This header file includes uart.c file which is used to interface the UART for serial communication
#include "segment.h"
#include "lcd.h"
#define _XTAL_FREQ 20000000
#define I2C_SPEED 100000 // kbps
//Function Declarations

// Define RTC device address
#define DS1307_Add_write 0xD0
#define DS1307_Add_read 0xD1
#define switch1 PORTCbits.RC0
#define switch2 PORTCbits.RC1
#define switch3 PORTCbits.RC2

int sec,min,hour;
int Day,Date,Month,Year;
int i;
char secs[10],mins[10],hours[10];
char Clock_type = 0x06;                                    
char AM_PM = 0x05;
int H_value,M_value,S_value;
int upd_hour,upd_min,upd_sec;
int status,status1,status2;


char BCDtoDecimal (char val)
{
    char res;
    res = (val & 0x0F) + ((val & 0xF0)>>4)*10;
    return res;
}

char Dec2BCD(char val)
{
    char res;
    res = (val/10) << 4;
    res = res | (val % 10);
    return res;
}

void RTC_Clock_Write(char sec1, char min1, char hour1, char AM_PM)                    // function for clock
{
    I2C_Start();
    I2C_Write(0xD0);
    I2C_Write(0x00);
   // I2C_Write(0x80);    //CH = 1 Stop oscillator
    I2C_Write(Dec2BCD(sec1));
    I2C_Write(Dec2BCD(min1));    //Minute
    I2C_Write(Dec2BCD(hour1)); //Hour

    I2C_Stop();        //Stop the I2C Protocol
    __delay_ms(20);

}


void RTC_Read_Clock(char read_clock_address)
{
    I2C_Start();
    I2C_Write(DS1307_Add_write);
    I2C_Write(Dec2BCD(read_clock_address));
    I2C_ReStart();
    I2C_Write(DS1307_Add_read);
    sec = I2C_Read_Byte();                                                             //read data and send ack for continuous reading
    I2C_Send_ACK();
    min = I2C_Read_Byte();                                                             //read data and send ack for continuous reading
    I2C_Send_ACK();
    hour= I2C_Read_Byte();                                                             //read data and send nack for indicating stop reading
    I2C_Send_NACK();
}

void Read_RTCclock(void)
{
    RTC_Read_Clock(0);                                                    //gives second,minute and hour
    I2C_Stop();
    __delay_ms(10);
    if(hour & (1<<Clock_type)){                                                 // check clock is 12hr or 24hr
        hour = hour & (0x1f);
        hour = BCDtoDecimal(hour);
        min = BCDtoDecimal(min);
        sec = BCDtoDecimal(sec);
        Segment_Disp(hour,min,sec);
    }
    else{
        hour = hour & (0x3f);
        hour = BCDtoDecimal(hour);
        min = BCDtoDecimal(min);
        sec = BCDtoDecimal(sec);//__delay_ms(250);
        Segment_Disp(hour,min,sec);
    }
  
}   


void main()
{
    ADCON1 = 0X0F;
    segment_Init();
    int count = 0;
    InitI2C();
    TRISB0 = 1;
    TRISB1= 1;
    TRISC0 = 1;
    TRISC1 = 1;
    TRISC2 = 1;
    PORTC = 0X00;                                                                //set frequency to 8 MHz

    while(1)
    {
        Read_RTCclock();
    }
}
--- Updated ---

Here is the schematic
 

Attachments

  • Final_Clock.zip
    18.8 KB · Views: 2
Last edited by a moderator:

KlausST

Super Moderator
Staff member
Joined
Apr 17, 2014
Messages
20,352
Helped
4,441
Reputation
8,891
Reaction score
4,468
Trophy points
1,393
Activity points
134,557
Hi,
using multiplexing concept
I can´t find any display multiplexing in your code.

Also I can´t open your attachment. Please upload the schematic as PNG or as PDF.

***
Generally the whole code is a waste of processing power.
I´d use a software clock, calibrate the SW clock only every couple of hours.
You may even use the SQW/OUT of the RTC .. so the software clock is sync´d to the HW RTC.

I´d say a software clock needs about 0.001% of processing power. (My guess: 10us per second)
In other words: your code consumes maybe 100,000 times the processing power.

Klaus
 

FvM

Super Moderator
Staff member
Joined
Jan 22, 2008
Messages
48,749
Helped
14,307
Reputation
28,877
Reaction score
13,035
Trophy points
1,393
Location
Bochum, Germany
Activity points
281,548
It seems appropriate to use the RTC for time display. The accuracy of processor clock usually can't keep up with the RTC. And it's much simpler to keep the time over power loss. Even if you prefer a software clock, you'll synchronize it to the RTC from time-to-time.
 
Solution

mayasunny

Member level 3
Joined
Mar 21, 2019
Messages
56
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
481
Mr.KlausST, below is a 7-segment multiplexing code
[ code ]
Code:
#include <xc.h>
#include "configbits.h"
#include "segment.h"
#define _XTAL_FREQ 20000000                                                 //define crystal frequency to 20MHz
#define control1 PORTBbits.RB2
#define control2 PORTBbits.RB3
#define control3 PORTBbits.RB4
#define control4 PORTBbits.RB5
#define control5 PORTBbits.RB6
#define control6 PORTBbits.RB7
char binary_pattern[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};


void segment_Init(void)
{
    TRISD = 0X00;                                                              // initialize PORTD pins to active low
    TRISB2 = 0;
    TRISB3 = 0;
    TRISB4 = 0;
    TRISB5 = 0;
  //    // TRISC = 0X00;
    TRISB6 = 0;
    TRISB7 = 0;
    ADCON1 = 0X0F;                                                              // To Make PORTB pins as Digital I/O
    control1 = 1;                                                               // TurnOff all 6 Segments
    control2 = 1;
    control3 = 1;
    control4 = 1;
    control5 = 1;
    control6 = 1;


}
void Segment_Disp(int value1, int value2, int value3)
{
   // PORTD = 0X80;
    unsigned int a,b,c,d,e,f;
    a = value1 / 10;                                                           
    b = value1%10;                                                         
    c = value2/10;                                                             
    d = value2%10;                                                             
    e = value3 / 10;                                                         
    f = value3 % 10;                                                           
    PORTD=binary_pattern[a];             
    control1=0;                                                     
    __delay_ms(3);
    control1=1;                                                               
    PORTD=binary_pattern[b] | 0x80;                     
    control2=0;                                                               
    __delay_ms(3);
    control2=1;                                                     
    PORTD=binary_pattern[c];
    control3 = 0;                                                           
    __delay_ms(3);
    control3=1;
    PORTD=binary_pattern[d] | 0x80;                       
    control4 = 0;                                                               
    __delay_ms(3);
    control4=1;
    PORTD=binary_pattern[e];                                               
    control5 = 0;                                                         
    __delay_ms(3);
    control5 = 1;                                                           
    PORTD=binary_pattern[f];                                                 
    control6 = 0;                                                         
    __delay_ms(3);
    control6 = 1;                                                       
 
}
[ /code ]
 

Attachments

  • Screenshot (2).png
    Screenshot (2).png
    167.9 KB · Views: 39

KlausST

Super Moderator
Staff member
Joined
Apr 17, 2014
Messages
20,352
Helped
4,441
Reputation
8,891
Reaction score
4,468
Trophy points
1,393
Activity points
134,557
Hi,

your display_mux routine takes more than 18ms.
then there is another 10ms wait in Read_RTCclock (I see no use of it)
so one loop takes mor then 28ms. Let´s say 30ms.

You know the clock changes once per 1000ms.
So you read the RTC 33 times without change in time.
then you calculate all the display data 33 times per second... without change in time..

You are free to do so.

But:
You could wire the SQR/OUT to the microcontroller´s port.
Every time there is a rising edge at this port read the RTC (could be done in main loop context)
after reading the RTC calculate all values .. and store the display data (port D) in an array.
(Once per second)

During INIT set up a timer for about 3ms (no need to be accurate). Just for the display_mux.
In this ISR just update the digit counter (0...5) and output the array data to portD.

Don´t use any _delay_ms at all.

Then there is plenty of processsing power for ALARM, reading push buttons, ... or to enter SLEEP mode.
No display flicker ... independent of processor load.

Klaus
 

mayasunny

Member level 3
Joined
Mar 21, 2019
Messages
56
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
481
You could wire the SQR/OUT to the microcontroller´s port.
Every time there is a rising edge at this port read the RTC (could be done in main loop context)
after reading the RTC calculate all values .. and store the display data (port D) in an array.
(Once per second)


Klaus
Thanks for your response, can explain a bit more in detail about this
 

betwixt

Super Moderator
Staff member
Joined
Jul 4, 2009
Messages
15,126
Helped
4,935
Reputation
9,890
Reaction score
4,741
Trophy points
1,393
Location
Aberdyfi, West Wales, UK
Activity points
128,433
I would configure the DS1307 to produce 1Hz output, connect it to the PIC INT pin so it interrupts once a second. Read the DS1307 once at start up and increment the time in software. That way you get the same accuracy as the DS1307 but only have to read it once. For the display multiplexing use an internal timer to change from one display to the next, that way you get reliable fixed speed (=constant brightness) display updating.

Brian.
 

KlausST

Super Moderator
Staff member
Joined
Apr 17, 2014
Messages
20,352
Helped
4,441
Reputation
8,891
Reaction score
4,468
Trophy points
1,393
Activity points
134,557
Hi,

What is unclear?
The RTC has an SQW/OUT .... just connect it with a PIC port pin, or a PIC interrupt input pin.

When programmed to output 1Hz, then it gives a pulse every second.

Klaus
 

Dan1138

Member level 3
Joined
Jan 30, 2018
Messages
58
Helped
9
Reputation
20
Reaction score
12
Trophy points
8
Activity points
562
@mayasunny,

It seems to me that this homework assignment is beyond what you have so far been taught.

Here is a complete, builds with MPLAB v5.50 and XC8 v2.32, demo application:
C:
/*
 * File:   main.c
 * Author: dan1138
 * Compiler: XC8 V2.32
 * IDE: MPLABX v5.50
 *
 * Created on July 26, 2021, 3:26 PM
 *
 *                       PIC18F4550
 *               +----------:_:----------+
 *    VPP  ->  1 : RE3/MCLR/VPP  PGD/RB7 : 40 <> DIGIT0/PGD
 *         <>  2 : RA0/AN0       PGC/RB6 : 39 <> DIGIT1/PGC
 *         <>  3 : RA1/AN1       PGM/RB5 : 38 <> DIGIT2
 *         <>  4 : RA2/AN2      AN11/RB4 : 37 <> DIGIT3
 *         <>  5 : RA3/AN3       AN9/RB3 : 36 <> DIGIT4
 *         <>  6 : RA4      INT2/AN8/RB2 : 35 <> DIGIT5
 *         <>  7 : RA5/AN4 INT1/AN10/RB1 : 34 <>
 *         <>  8 : RE0/AN5 INT0/AN12/RB0 : 33 <>
 *         <>  9 : RE1/AN6           VDD : 32 <- 5v0
 *         <> 10 : RE2/AN7           VSS : 31 <- GND
 *     5v0 -> 11 : VDD               RD7 : 30 <> SEGdp
 *     GND -> 12 : VSS               RD6 : 29 <> SEGg
 *         <> 13 : OSC1              RD5 : 28 <> SEGf
 *         <> 14 : OSC2              RD4 : 27 <> SEGe
 *         <> 15 : RC0            RX/RC7 : 26 <>
 *         <> 16 : RC1/CCP2       TX/RC6 : 25 <>
 *         <> 17 : RC2/CCP1       D+/RC5 : 24 <- (can only be used as GPIO input)
 *         <> 18 : RC3            D-/RC4 : 23 <- (can only be used as GPIO input)
 *    SEGa <> 19 : RD0               RD3 : 22 <> SEGd
 *    SEGb <> 20 : RD1               RD2 : 21 <> SEGc
 *               +-----------------------:
 *                        DIP-40
 *
 * Description:
 *
 *  Homework assignment see EDA board:
 *      https://www.edaboard.com/threads/ds1307-slows-with-7-segment-display.398985/
 *
 *  This is an application to show how to use the TIMER0 interrupt to
 *  refresh a multiplexed six digit 7-segment LED display matrix.
 */

#pragma config PLLDIV = 1, CPUDIV = OSC1_PLL2, USBDIV = 1
#pragma config FOSC = INTOSC_XT, FCMEN = OFF, IESO = OFF
#pragma config PWRT = OFF, BOR = OFF, BORV = 3, VREGEN = OFF
#pragma config WDT = OFF, WDTPS = 32768, CCP2MX = ON
#pragma config PBADEN = ON, LPT1OSC = OFF, MCLRE = ON
#pragma config STVREN = ON, LVP = OFF, ICPRT = OFF, XINST = OFF
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF
#pragma config CPB = OFF, CPD = OFF
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config WRTC = OFF, WRTB = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF
#pragma config EBTRB = OFF

#include <xc.h>

#define _XTAL_FREQ (8000000ul)
/*
 * Common cathode LED segment drivers for hexadecimal digits
 */
const char LEDDigit[] =
{
  /* gfedcba         _   */
  0b00111111,   /*  | |  */
                /*  |_|  */
                /*       */
  0b00000110,   /*    |  */
                /*    |  */
                /*   _   */
  0b01011011,   /*   _|  */
                /*  |_   */
                /*   _   */
  0b01001111,   /*   _|  */
                /*   _|  */
                /*       */
  0b01100110,   /*  |_|  */
                /*    |  */
                /*   _   */
  0b01101101,   /*  |_   */
                /*   _|  */
                /*   _   */
  0b01111101,   /*  |_   */
                /*  |_|  */
                /*   _   */
  0b00000111,   /*    |  */
                /*    |  */
                /*   _   */
  0b01111111,   /*  |_|  */
                /*  |_|  */
                /*   _   */
  0b01100111,   /*  |_|  */
                /*    |  */
                /*   _   */
  0b01110111,   /*  |_|  */
                /*  | |  */
                /*       */
  0b01111100,   /*  |_   */
                /*  |_|  */
                /*   _   */
  0b00111001,   /*  |    */
                /*  |_   */
                /*       */
  0b01011110,   /*   _|  */
                /*  |_|  */
                /*   _   */
  0b01111001,   /*  |_   */
                /*  |_   */
                /*   _   */
  0b01110001,   /*  |_   */
                /*  |    */
                /*       */
  0b00000000,   /* blank */
                /*       */
};

volatile unsigned char DigitSegments[6];
volatile unsigned char DigitSelected;
/*
 * Interrupt Service Routines
 */
void __interrupt(high_priority) ISR_hi(void)
{
    if((INTCONbits.T0IE) && (INTCONbits.T0IF)) /* TIMER0 asserts and interrupt every 1.024 milliseconds */
    {
        /*
         * Turn on one of six digits in the LED display matrix
         */
       INTCONbits.T0IF = 0;
       LATB |= 0b11111100;  /* Turn off all digit drivers */
       if(DigitSelected >= sizeof(DigitSegments)) DigitSelected = 0;
       LATD  = DigitSegments[DigitSelected];
       LATB &= ~(0x80>>DigitSelected);
       DigitSelected++;
    }
}
/*
 * Convert unsigned long to 6 decimal digits for the LED display
 */
void LED_ulToSegments(unsigned long data)
{
    unsigned char Digit;
    
    Digit = sizeof(DigitSegments);
    do
    {
        Digit--;
        DigitSegments[Digit] = LEDDigit[data % 10];
        data /= 10;
    } while(Digit);
}
/*
 * Make LED display blank
 */
void LED_blank(void)
{
    unsigned char Digit;
    
    Digit = sizeof(DigitSegments);
    do
    {
        DigitSegments[--Digit] = 0;
    } while(Digit);   
}
/*
 * Main application
 */
void main(void)
{
    unsigned long Count;
    
    INTCONbits.GIEH    = 0; /* disable all interrupt sources */
    INTCONbits.GIEL    = 0;
    INTCONbits.INT0IE  = 0;
    INTCONbits.RBIE    = 0;
    INTCONbits.TMR0IE  = 0;
    INTCON3bits.INT1IE = 0;
    INTCON3bits.INT2IE = 0;
    PIE1 = 0;
    PIE2 = 0;
    RCONbits.IPEN      = 0; /* Use legacy interrupt mode */
    /*
     * Select 8 MHz internal oscillator
     */
    OSCCON = 0x72;
    /*
     * Make all GPIOs digital
     */
    ADCON1 = 0x0F;          /* Disable all ADC analog inputs */
    CMCON  = 0x07;          /* Disable all Comparator analog inputs */
    /*
     * Setup LED multiplexer
     */
    INTCONbits.TMR0IE  = 0;
    TRISD = 0;              /* Make segment drivers outputs */
    TRISB &= 0b00000011;    /* Make digit drivers outputs */
    DigitSelected = 0;
    LED_blank();
    T0CON = 0b01000010;     /* TIMER0 off, FOSC/4 clock, prescale 1:8 */
    INTCON2bits.T0IP   = 1; /* Select high priority interrupt handler */
    TMR0 = 0;
    INTCONbits.TMR0IF  = 0;
    INTCONbits.TMR0IE  = 1;
    T0CONbits.TMR0ON   = 1; /* Turn on TIMER0 */
    /*
     * Enable system interrupts
     */
    INTCONbits.GIEL    = 1;
    INTCONbits.GIEH    = 1;
    /*
     * Process loop
     */
    Count = 0;
    for(;;)
    {
        __delay_ms(1000);
        LED_ulToSegments(Count++);
    }
}
See if this runs in your Proteus simulation.
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Top