Sari la conținut
ELFORUM - Forumul electronistilor

Un ceas cu PCF8583 / PIC16F877A


kaporalu

Postări Recomandate

Un simplu ceas facut pe EasyPIC5 de la http://www.mikroe.com

Scris in mikroBasic Pro.

Nu a vrut sa mearga cu pull-up de 10K pe busul I2C

Cu 2.2K nu se mai pierde comunicatia (placa are multe trasee lungi, inclusiv PORTC).

 

 

 

program clock1

 

'************************************************

' Digital clock with PCF8583 on EasyPIC5 board (http://www.mikroe.com)

'

' by KapoRalu, feb.2011

'

' MCU: PIC16F877A, quartz 8 MHz

' Osc=HS, only Brown Out Detect is ON

'************************************************

' Buttons connected on RB0 and RB1 to GND, pull-up resistors to +5V

' Button RB0: switch berween normal clock display (HH.MM) and seconds display (like "SS)

' * in clock adjust mode, increment hour/min, reset seconds to zero (synchronise)

' Button RB1: Time adjust mode. Each pressing change the next item:

' - first press = adjust hours

' - second press = adjust minutes

' - third = reset seconds to zero (hours/minutes are not affected!)

' - fourth = back to normal clock

'***********************************************

' Date not yet implemented

' No alarms yet

' 24 hours format

'

' Real Time Clock board with PCF8583, connected at PortC.

' I2C lines connected to +5V, with pull up rsistors, 2.2Kohm

'***was necessary to use 2K2 to compensate hi-capacitance of lines of EasyPIC5 board

'*** with 10Kohm, I2C bus is not working as supposed.

'

' Address pin A0 of PCF8583 (pin3) connected to 0V.

' I2C lines: SCL (pin6 PCF8583) connected to RC3

' SDA (pin5 PCF8583) connected to RC4

' Pin7 (INT) of PCF8583 connected to RC2 and pull-up resistor 10Kohm on +5V, RTC board

' Pin7 = 1Hz pulses 50% duty factor (not used here!)

' PCF8583 registers:

' Addr $00: D7 D6 D5 D4 D3 D2 D1 D0 = CONTROL/STATUS

' | | | | | | | |

' | | | | | | | \= Timer Flag (seconds pulses 50% duty factor if ALARM bit is 0)

' | | | | | | \---= Alarm Flag (minutes pulses 50% duty factor if Alarm bit is 0)

' | | | | | \------= Alarm enable bit (0 = disable alarm , 1= enable alarm control)

' | | | | \---------= Mask Flag (0=read locations x05-x06 unmasked, 1=read date/month count directly)

' | | | |

' | | \--+------------= function mode: 00=clock 32768Hz (used in RTC card)

' | | 01=clock 50Hz

' | | 10=event counter mode

' | | 11=test modes

' | \------------------= hold last count flag (0=count, 1=store and hold last count in latches)

' \---------------------= stop counting flag (0=count, 1=stop, reset driver)

' IMPORTANT: D7 need to be 1 (clock stopped) before writing time in registers

' and 0 again to start the clock

'

' Addr $01: D7 D6 D5 D4 D3 D2 D1 D0 = hundredth of seconds

' | | | | | | | |

' | | | | \--+--+--+-= 1/100 seconds, BCD format (0...9)

' \--+--+--+-------------= 1/10 seconds, BCD format (0...9)

'

' Addr $02: D7 D6 D5 D4 D3 D2 D1 D0 = seconds

' | | | | | | | |

' | | | | \--+--+--+-= seconds (units), BCD format (0...9)

' \--+--+--+-------------= seconds (ten's), BCD format (0...9)

'

' Addr $03: D7 D6 D5 D4 D3 D2 D1 D0 = minutes

' | | | | | | | |

' | | | | \--+--+--+-= minutes (units), BCD format (0...9)

' \--+--+--+-------------= minutes (ten's), BCD format (0...9)

'

' Addr $04: D7 D6 D5 D4 D3 D2 D1 D0 = hours

' | | | | | | | |

' | | | | \--+--+--+-= hours (units), BCD format (0...9)

' | | \--+-------------= hour (ten's) , BCD format (0,1 or 2)

' | \-------------------= AM/PM Flag (0=AM, 1=PM)

' \----------------------= hour format (0= 24H format, bit D6 not changed;

' 1= 12H format, bit D6 updated)

' Addr $05: D7 D6 D5 D4 D3 D2 D1 D0 = year/date (day of month)

' | | | | | | | |

' | | | | \--+--+--+-= date (units), BCD format (0...9)

' | | \--+-------------= date (ten's) , BCD format (0...3)

' \--+-------------------= year, BCD format (0...3). Read as "0" if mask flag is 1 (bit D3, Addr x00)

' PCF8583 use only 4 year calendar, 0 is "leap year" (with 29 Feb date)

' years 1,2,3 are "common years" (last day of Feb: 28

'

' Addr $06: D7 D6 D5 D4 D3 D2 D1 D0 = weekday/month

' | | | | | | | |

' | | | | \--+--+--+-= month (units), BCD format (0...9)

' | | | \-------------= month (ten's), 0 or 1

' \--+--+----------------= day of week, BCD format (0...6).Read as "0" if mask flag is 1 (bit D3, Addr x00)

'

' To adress the RTC via I2C bus need to use the slave access byte:

' D7 D6 D5 D4 D3 D2 D1 D0

' 1 0 1 0 0 0 x x

' | |

' | \-= R/nW bit, 1= read command, 0=write command

' \----= A0 (pin3 PCF8583) 0=GND,1=Vcc (to select 1 of 2 slaves present on I2C bus)

'

' How to read data from RTC:

' a) send START signal

' b) write slave address (here is $A0 = %10100000, for pin3-A0 connected to GND)

' c) write register address from where start reading (ex. to start read seconds, address is $02)

' d) send START signal (repeat)

' e) write slave address, bit D0=1 (R/nW 1 = request to READ)

' f1) read seconds (first address = $02) and acknowledge

' f2) read minutes (next address = $03) and acknowledge *** Address is auto-incremented by RTC

' f3) read hours (next address = $04) and acknowledge

' f4) read year/date (next address = $05) and acknowledge

' g) read weekday/month (next address = $06) and ***NOT*** acknowledge (Not ack = end of reading)

' h) send STOP signal

'

' How to write data to RTC:

' a) send START signal

' b) write slave address (here is $A0 = %10100000, for pin3-A0 connected to GND)

' c) write $00 (CONTROL register address)

' d) write $80 (%10000000) = STOP THE CLOCK !!!!! ****************************************************

' e1) write next address ($01 =1/100 of seconds) *** also here, registers are auto-incremented

' e2) write next address ($02 =seconds)

' e3) write next address ($03 =minutes)

' e4) write next address ($04 =hours)

' e5) write next address ($05 =year/date)

' e6) write next address ($06 =week day/month)

' f) send STOP signal

' g) send START signal

' h) write slave address ($A0)

' i) write $00 (CONTROL register address)

' j) write $00 (to reset bit D7) = START THE CLOCK !!! *******************

' k) send STOP signal (now I2C bus is free, RTC is updated and running)

'**************************************************************************

' Here, hardware I2C is used (PIC16F877A)

' For other MCUs without I2C port, use mikroBasic commands: Soft_I2C_...

'*************************************************************************

'

dim dr, sr, mr, hr as byte 'decimal, sec, min, hrs as read from RTC

dim tens, sec, min, hrs as byte 'decimal, sec, min, hrs transformed

dim menu as byte 'menu selection 1=clock, 2=seconds

dim x, zz, v as byte

dim blink as byte 'status of seconds dots 1=on,0=off

dim d3, d2, d1, d0 as byte 'digits to be displayed hh:mm

dim led as byte[4] 'led is the 7-LED code for each 7-seg display

 

'------------------------------

sub function num2RTC(dim number as byte) as byte 'calc the BCD number to be

'written in RTC

result=Dec2BCD(number/10) 'HI digit (tens)

result = result << 4 '4 times to left =0000 1010 became 1010 0000

x=Dec2BCD(number mod 10) 'LO digit (units)

result=result or x 'the final BCD to be written

end sub

 

'--------------------- Reads time and date information from RTC (PCF8583)

sub procedure Read_Time()

I2C1_Start() 'Issue start signal

I2C1_Wr($A0) 'Address PCF8583, see PCF8583 datasheet

I2C1_Wr(1) 'Address the config Register

I2C1_Repeated_Start() 'Issue repeated start signal

I2C1_Wr($A1) 'Address PCF8583 for reading R/W=1

dr=I2C1_Rd(1) 'Read 1/10 seconds byte (1 = reception acknowledged)

sr=I2C1_Rd(1) 'Read seconds byte

mr=I2C1_Rd(1) 'Read min byte

hr=I2C1_Rd(0) 'Read hrs byte (0= finish reading)

I2C1_Stop()

end sub

'---------------------

 

'---------------------Write time to RTC

sub procedure Write_Time()

hr = num2RTC(hrs) 'calc. the BCD (to be written) of hours

mr = num2RTC(min) 'calc. the BCD of minutes

sr = num2RTC(sec) 'calc. the BCD of seconds

I2C1_Start() 'Issue start signal

I2C1_Wr($A0) 'Address PCF8583, see PCF8583 datasheet

I2C1_Wr(0) 'Start from address 0 (configuration memory location)

I2C1_Wr(0x80) 'Write 0x80 to configuration memory location (stop counter...)

I2C1_Wr(dr) 'Write to cents memory location (as read before, unchanged!)

I2C1_Wr(sr) 'Write to seconds memory location

I2C1_Wr(mr) 'Write to minutes memory location

I2C1_Wr(hr) 'Write to hours memory location

I2C1_Stop() 'Issue stop signal

I2C1_Start() 'Issue start signal

I2C1_Wr($A0) 'Address PCF8530

I2C1_Wr(0) 'Start from address 0

I2C1_Wr(0) 'Write 0 to configuration memory location (enable counting)

I2C1_Stop() 'Issue stop signal

end sub

'------------------------------

 

'------- Formats date and time (was read as BCD digits from RTC)

sub procedure Transform_Time()

tens = ((dr and $F0) >> 4) 'tens will be 0...9, used as blink signal

sec = ((sr and 0xF0) >> 4)*10 + (sr and 0x0F) ' Transform seconds

min = ((mr and 0xF0) >> 4)*10 + (mr and 0x0F) ' Transform mins

hrs = ((hr and 0x30) >> 4)*10 + (hr and 0x0F) ' Transform hours

blink = ($01 and (not(tens/5))) 'blink signal 1 or 0

end sub

'---------------------------------

 

'---------------------------------

sub function Mask(dim num as byte) as byte ' this function returns masks

select case num ' for common cathode 7-seg. display

case 0 result = $3F

case 1 result = $06

case 2 result = $5B

case 3 result = $4F

case 4 result = $66

case 5 result = $6D

case 6 result = $7D

case 7 result = $07

case 8 result = $7F

case 9 result = $6F

end select

end sub

'---------------------------

sub procedure Selectmenu() 'choose by key what to display

if Button(PORTB,0,100,0) then

Delay_ms(100)

inc (menu)

if menu = 3

then

menu = 1

else

end if

end if

select case menu

case 1 'normal clock hh:mm

d3=hrs/10

led[3]=Mask(d3)

if d3 = 0 then 'blank leading zero hours

led[3]=0

end if

d2=hrs mod 10

led[2]=Mask(d2)

d1=min/10

led[1]=Mask(d1)

d0=min mod 10

led[0]=Mask(d0)

if blink=1 then

led[2] = led[2] or $80 'turn ON also decimal point

end if

case 2 ' display seconds, "ss

d1=sec/10

d0=sec mod 10

led[3] = $00

led[2] = $22

led[1]=Mask(d1)

led[0]=Mask(d0)

end select

end sub

'---------------------------------------

 

'------------------ Display on 7-segments

sub procedure Display7seg()

zz=1

for v = 0 to 3

PORTA = zz 'select the digit

PORTD = led[v] 'turn ON LEDs

Delay_ms(1) 'how much time digit is ON

'at 1ms, refresh rate is approx 180Hz

'duty factor is approx 20%

zz = zz << 1 'select next digit

if zz > 8 then 'is the leftmost digit? (RA3)

zz = 1 'if yes, go to rightmost (RA0)

end if

PORTA = 0

PORTD = 0

next v

end sub

'--------------------------------------

 

'--------------------------------------

sub procedure Adjust_time()

dim adjuster as byte

adjuster = 1 'adjuster = 1, adj hours

'adjuster = 2, adj minutes

'adjuster = 3, reset seconds to zero

while (adjuster < 4) 'adjuster = 4, back to normal clock

Read_Time() ' Read time from RTC(PCF8583)

Transform_Time() ' Format date and time'

if Button(PORTB,1,100,0) then

delay_ms(500)

inc (adjuster)

end if

select case adjuster

case 1 'display and adjust hours

d3=hrs/10

d2=hrs mod 10

d1=min/10

d0=min mod 10

led[3]=Mask(d3)

if d3 = 0 then 'blank leading zero

led[3]=0

end if

led[2]=Mask(d2) or $80

led[1]=Mask(d1)

led[0]=Mask(d0)

if (tens.0) then 'fast blinking of hours

led[3]=0

led[2]=$80

end if

Display7seg()

if Button(PORTB,0,50,0) then

inc (hrs)

if hrs > 23 then

hrs=0

end if

Write_Time()

delay_ms(200)

end if

case 2 'display and adjust minutes

d3=hrs/10

d2=hrs mod 10

d1=min/10

d0=min mod 10

led[3]=Mask(d3)

if d3 = 0 then 'blank leading zero

led[3]=0

end if

led[2]=Mask(d2) or $80

led[1]=Mask(d1)

led[0]=Mask(d0)

if (tens.0) then 'fast blink of minutes

led[1]=0

led[0]=0

end if

Display7seg()

if Button(PORTB,0,50,0) then

inc (min)

if min > 59 then

min=0

end if

Write_Time()

delay_ms(200)

end if

case 3 'display and reset seconds to "0"

d1=sec/10

d0=sec mod 10

led[3]=0

led[2]=$22 'display seconds symbol ( " )

led[1]=Mask(d1)

led[0]=Mask(d0)

if (tens.0) then 'fast blink of sec. symbol

led[2]=0

end if

Display7seg()

if Button(PORTB,0,50,0) then

sec = 0

Write_Time() 'write time to RTC immediately

delay_ms(500)

end if

end select

wend

menu=1 ' back to normal clock display

end sub

'----------------------------------------------

 

'------------------ Performs project-wide init

sub procedure Init_Main() 'PORTA = digital (here, PIC16F877A MCU!!!!)

CMCON = CMCON or $07 ' turn off comparators

ADCON1 = ADCON1 or $07 ' turn off analog inputs

ADCON1.3 = 0

PORTA = 0

TRISA = 0

TRISB = 255 ' PortB for buttons

PORTB = 255

TRISC = $FF

PORTC = $FF

TRISD = 0 '7-digit LED connected on PortD

PORTD = 0

I2C1_Init(100000) 'Init I2C, 100KHz

menu = 1

blink=0

zz=1

v=0

tens=0

sec=0

min=0

hrs=0

d3=0

d2=0

d1=0

d0=0

end sub

'---------------------

 

main:

Delay_ms(100)

Init_Main() ' Perform initialization

delay_ms(300)

Read_Time()

while TRUE ' Endless loop

Read_Time() ' Read time from RTC(PCF8583)

Transform_Time() ' calc. the time'

Selectmenu() ' if PORTB.0 keypress, change display hh:mm or "ss

Display7seg()

if Button(PORTB,1,100,0) then 'PORTB.1 pressed?

delay_ms(500)

Adjust_time()

end if

wend

end.

Link spre comentariu
  • Răspunsuri 2
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • kaporalu

    2

  • picolo

    1

Zile populare

Top autori în acest subiect

Salut,In primul rand , cine a scris harababura asta de cod?Este necesara o minima decenta chiar in relatia cu un compilator care accepta la compilare indiferent de modul de prezentare.Inteleg ca lucrezi in basic, dar nici chiar asa.Nu prea cred ca-si vor pierde multi timpul cu ceva prezentat in modul asta.Incearca o indentarea a codului sa inteleaga ceva si niste oameni obisnuiti.

Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări