.title "Digital Clock" .sbttl "Using the PIC24" .equ __24FJ64GA002, 1 .include "p24FJ64GA002.inc" .global __reset ;The label for the first line of code. .global __T1Interrupt ;Declare Timer 1 ISR name global .global __CNInterrupt .bss .section .const,psv ; line1: .ascii "zz" .text ;Start of Code section __reset: mov #__SP_init, W15 ; Initalize the Stack Pointer mov #__SPLIM_init, W0 ; Initialize the Stack Pointer Limit Register mov W0, SPLIM nop ; Add NOP to follow SPLIM initialization bset AD1PCFG, #PCFG4 bset AD1PCFG, #PCFG5 call init_I2C ; call read_clock mov #OSCCONL, W1 mov.b #0x01, W0 mov #0x46, W2 mov #0x57, W3 mov.b W2,[W1] mov.b W3,[W1] bset OSCCON, #1 ; enable secondary oscillator ; Start oscillator switch operation ; mov.b W0, [W1] call init_timer ; call init_I2C bset TRISA, #0 bset TRISA, #1 bset TRISA, #2 ; bset AD1PCFG, #PCFG0 bset AD1PCFG, #PCFG1 bset AD1PCFG, #PCFG4 bset AD1PCFG, #PCFG5 bset AD1PCFG, #PCFG9 bset AD1PCFG, #PCFG10 bset AD1PCFG, #PCFG11 bset AD1PCFG, #PCFG12 bset CNEN1, #CN11IE bset CNEN1, #CN12IE bset CNEN1, #CN13IE bset CNEN1, #CN14IE bset CNEN1, #CN15IE ; bset CNPU1, #CN11PUE bset CNPU1, #CN12PUE bset CNPU1, #CN13PUE bset CNPU1, #CN14PUE bset CNPU1, #CN15PUE bclr IFS1, #CNIF bset IEC1, #CNIE ; mov #0x00, W1 ; mov #0x46, W2 ; mov #0x08, W3 ; mov #LATBH, W4 mov #0, W6 mov #0, W7 ;mov TRISB, W0 ;mov #0xFF93, W1 ;and W0, W1, W0 ;mov W0, TRISB bclr TRISB, #5 bclr TRISB, #6 bclr TRISB, #8 bclr TRISB, #9 ; bset LATB, #9 ; BI <- HIGH (full intensity) bset LATB, #8 ; LE <- HIGH (disable) bclr LATB, #5 ; clear CLK mov #0x55, W1 mov #0x47, W2 mov #0x19, W3 call init_ADC call init_PWM wait_clock_read: mov #200, W0 wait_loop: repeat #10000 nop dec W0, W0 bra NZ, wait_loop call read_clock cp0 W0 bra NZ, wait_clock_read start: cp W6, #1 bra Z, inc_sec cp W7, #0 bra Z, start dec W7, W7 call write_clock bra done_inc inc_sec: mov #0, W6 ; clear timer interrupt flag ; bset AD1CON1, #1 ; start sampling mov ADC1BUF0, W0 sl W0, #3, W0 ; mov #4096, W0 mov W0, OC2RS ; ; repeat #8 ; nop ; bclr AD1CON1, #SAMP ; start new conversion ; inc W1, W1 daw.b W1 mov #0x60, W0 cp W0, W1 bra Z, inc_min bra done_inc inc_min: mov #0, W1 inc W2, W2 daw.b W2 mov #0x60, W0 cp W0, W2 bra Z, inc_hour bra done_inc inc_hour: mov #0, W2 inc W3, W3 daw.b W3 mov #0x24, W0 cp W0, W3 bra NZ, not_midnight mov #0, W3 not_midnight: done_inc: mov W3, W11 call displayit mov W2, W11 call displayit mov W1, W11 call displayit bclr PORTB, #8 call wait bset PORTB, #8 call wait bra start displayit: mov #8, W10 shift_loop: btsc W11, #7 bra not_0 bclr LATB, #6 bra done_bit_test not_0: bset LATB, #6 done_bit_test: sl W11, #1, W11 call wait bset LATB, #5 call wait bclr LATB, #5 dec W10, W10 bra NZ, shift_loop return wait: repeat #100 nop return __T1Interrupt: bclr IFS0, #T1IF mov #1, W6 retfie __CNInterrupt: push W0 bclr IFS1, #CNIF btsc PORTB, #11 bra test_inc_min mov #0x0000, W0 mov W0, TMR1 ; clear TMR1 register mov #0, W6 ; clear timer interrupt flag mov #0, W1 ; call write_clock bra done_CNI1 test_inc_min: btsc PORTB, #12 bra test_dec_min inc W2, W2 daw.b W2 mov #0x0060, W0 cp W2, W0 bra NZ, done_CNI1 mov #0, W2 bra done_CNI1 test_dec_min: btsc PORTB, #13 bra test_inc_hour mov #0x0059, W0 sub W0, W2, W2 inc W2, W2 daw.b W2 mov #0x0060, W0 cp W2, W0 bra NZ, done_dec_min mov #0, W2 done_dec_min: mov #0x0059, W0 sub W0, W2, W2 bra done_CNI1 test_inc_hour: btsc PORTB, #14 bra test_dec_hour inc W3, W3 daw.b W3 mov #0x0024, W0 cp W3, W0 bra NZ, done_CNI1 mov #0, W3 bra done_CNI1 test_dec_hour: btsc PORTB, #15 bra done_CNI1 mov #0x0029, W0 sub W0, W3, W3 inc W3, W3 daw.b W3 mov #0x0030, W0 cp W3, W0 bra NZ, done_dec_hour mov #0x0006, W3 done_dec_hour: mov #0x0029, W0 sub W0, W3, W3 done_CNI1: inc W7, W7 done_CNI2: pop W0 retfie ; ----------------------------------------------------- ; !!!!!!!!!!!!!!!!!! Functions !!!!!!!!!!!!!!!!!!!!!!!! ; ----------------------------------------------------- init_PWM: bset RPOR4, #RP9R0 bset RPOR4, #RP9R1 bclr RPOR4, #RP9R2 bclr RPOR4, #RP9R3 bset RPOR4, #RP9R4 ; OC2 output (18) assigned to pin RB9 (pin#18, RP9) mov #8000, W0 mov W0, PR2 ; PWM frequency 2e6/8000 = 250 Hz (fosc=4e6, fcy=2e6) ; I kept this smaller than 8192 (which is 8 times full ADC ; so that full pot setting safely produces 100% duty cycle mov #0, W0 mov W0, OC2RS ; PWM OFF (0% duty cycle) mov W0, OC2R ; PWM OFF (0% duty cycle) bclr OC2CON, #OCTSEL ; clock source is TIMER2 bset OC2CON, #OCM2 bset OC2CON, #OCM1 bclr OC2CON, #OCM0 ; PWM mode on OCx, Fault pin, OCFx, disabled (mode 110) bclr T2CON, #TCKPS1 bclr T2CON, #TCKPS0 ; prescale value 1:1 bset T2CON, #TON ; turn timer1 ON return init_ADC: bclr AD1CHS, #0 bclr AD1CHS, #1 bclr AD1CHS, #2 bclr AD1CHS, #3 ; channel 0 ; bclr AD1CON1, #FORM1 bclr AD1CON1, #FORM0 ; integer output bset AD1CON1, #ASAM ; auto sample ; bset AD1CON1, #ADON ; enable ADC ; bset AD1CON1, #SAMP ; start sampling nop nop nop nop bclr AD1CON1, #SAMP ; start conversion ; return init_SPI: bset SPI1CON1, #MSTEN ; enable SPI1 Master Mode ; bclr SPI1CON1, #SPRE2 bclr SPI1CON1, #SPRE1 bclr SPI1CON1, #SPRE0 ; 8:1 bclr SPI1CON1, #PPRE1 bclr SPI1CON1, #PPRE0 ; 64:1 -> 4 MHz/8/64 = 7.8125 kHz ; bclr SPI1STAT, #SPIROV ; required by datasheet ; bset SPI1CON2, #SPIBEN ; enable enhaned buffer mode ; ; bset SPI1STAT, #SPIEN ; enabel SPI return init_I2C: mov #19, W0 mov W0, I2C2BRG ; set BAUD rate (fcy=2 MHz -> fSCL = 99 kHz) ; bclr I2C2CON, #A10M ; 7-bit slave address bset I2C2CON, #I2CEN ; enable I2C module #1 return ; ::::::::::::: ; I2C Functions ; ::::::::::::: write_clock: call I2C_start ; mov #0b11010000, W11 ; DS1307 slave address call I2C_write ; send address with WRITE selected ; mov #0x0000, W11 call I2C_write ; send register number as 0 (seconds register) ; mov W1, W11 call I2C_write ; send SECONDS ; mov W2, W11 call I2C_write ; send MINUTES ; mov W3, W11 call I2C_write ; send HOURS ; call I2C_stop return ;;; READ ;;; read_clock: call I2C_start ; mov #0b11010000, W11 ; BS1307 slave address call I2C_write ; send address with WRITE selected btsc I2C2STAT, #ACKSTAT retlw #1, W0 ; mov #0x0000, W11 call I2C_write ; send register number as 0 (seconds register) ; call I2C_restart ; mov #0b11010001, W11 ; BS1307 slave address call I2C_write ; send address with READ selected ; call I2C_read ; read seconds mov W11, W1 call I2C_ack ; call I2C_read ; read minutes mov W11, W2 call I2C_ack ; call I2C_read ; read hours mov W11, W3 call I2C_nack ; call I2C_stop retlw #0, W0 I2C_start: bset I2C2CON, #SEN ; start condition wait_start: btsc I2C2CON, #SEN ; start condition in progress? bra wait_start ; yes, wait return I2C_stop: bset I2C2CON, #PEN ; stop condition wait_stop: btsc I2C2CON, #PEN ; stop condition in progress? bra wait_stop ; yes, wait return I2C_restart: bset I2C2CON, #RSEN ; repeated start condition wait_rstart: btsc I2C2CON, #RSEN ; repeated start condition in progress? bra wait_rstart ; yes, wait return I2C_write: mov W11, I2C2TRN wait_write: btsc I2C2STAT, #TBF bra wait_write wait_slave_ack: btsc I2C2STAT, #TRSTAT bra wait_slave_ack return I2C_read: bset I2C2CON, #RCEN ; master receive enable wait_read: btsc I2C2CON, #RCEN bra wait_read mov I2C2RCV, W11 return I2C_ack: bset I2C2CON, #ACKEN ; send ack wait_ack: btsc I2C2CON, #ACKEN bra wait_ack return I2C_nack: bset I2C2CON, #ACKDT bset I2C2CON, #ACKEN ; send nack wait_nack: btsc I2C2CON, #ACKEN bra wait_nack bclr I2C2CON, #ACKDT return ;init_timer: ; bclr T1CON, #TON ; turn timer1 OFF ; ; bset T1CON, #TCKPS1 ; bclr T1CON, #TCKPS0 ; set prescaler to 64 ; ; bclr T1CON, #TCS ; select internal clock ; ; mov #0x0000, W0 ; mov W0, TMR1 ; clear TMR1 register ; mov #31250, W0 ; mov W0, PR1 ; set timer1 period to 31250 -> f=2e6/64/631250=1 Hz ; ; bclr IPC0, #14 ; bclr IPC0, #13 ; bset IPC0, #12 ; set timer1 priority to 001 ; bclr IFS0, #T1IF ; clear timer1 interrupt status flag ; bset IEC0, #T1IE ; enable timer1 interrupts ; ; bset T1CON, #TON ; turn timer1 ON ; return init_timer: bclr T1CON, #TON ; turn timer1 OFF bclr T1CON, #TCKPS1 bclr T1CON, #TCKPS0 ; set prescaler to 1 bset T1CON, #TCS ; select secondary oscillator mov #0x0000, W0 mov W0, TMR1 ; clear TMR1 register mov #32767, W0 mov W0, PR1 ; set timer1 period to 32768 -> f=32768/1/(32767+1)=1 Hz bclr IFS0, #T1IF ; clear timer1 interrupt status flag bset IEC0, #T1IE ; enable timer1 interrupts bset T1CON, #TON ; turn timer1 ON return .end ;End of program code in this file