Continue to Site

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] Delay routine drifting

Status
Not open for further replies.

Ricardo_Electropepper

Member level 3
Member level 3
Joined
Mar 18, 2014
Messages
59
Helped
4
Reputation
8
Reaction score
4
Trophy points
8
www.electropepper.org
Activity points
407
Hello guys,
Im using a pic 12f1822 set up for the internal clock at 1MHZ.
So i used this delay code generator, and inserted into my C code, my problem is that i can see on the osciloscope that the clock is kind of drifting in time, i tried changing values around but im now stuck.
Here goes the code :


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <pic12f1822.h>                                                                                                                 /* Setup chip configuration */                                                                                                          __code int __at(_CONFIG1) __CONFIG = _FOSC_INTOSC &
 _WDTE_OFF &
 _PWRTE_OFF &
 _MCLRE_ON &
 _CP_OFF &
 _CPD_OFF &
 _BOREN_OFF &
 _CLKOUTEN_OFF &
 _IESO_OFF &
 _FCMEN_OFF;                                                                                                              
 
void setup(void);                                                                                                                 
void delay_ms(int milis);                                                                                                               
unsigned char minute = 60;                                                                                                              
 
 
void main(void) {                                                                                                                       
    setup();                                                                                                                            
    while(1) {                                                                                                                          
        delay_ms(1000);                                                                                                                 
        LATA |= (1<<2);                                                                                                                 
        delay_ms(1000);                                                                                                                 
        LATA &= ~(1<<2);                                                                                                                
    }                                                                                                                                   
}                                                                                                                                       
 
void setup(void) {                                                                                                                      
    OSCCON = 0b01011000;                                                                                                                
    LATA = 0;                                                                                                                           
    TRISA = 0x00;                                                                                                                       
    PORTA = 0x00;
 
// Reserv 2 bytes for assembly delay routine
__asm                                                                                                                                   
cblock 0x20                                                                                                                             
d1                                                                                                                                      
endc                                                                                                                                    
__endasm;                                                                                                                               
}                                                                                                                                       
 
void delay_ms(int milis) {                                                                                                              
                                                                                                                                        
    while (milis--) {
 
// 1 ms at 1MHZ clock                                                                                                                   
        __asm                                                                                                                           
        Delay:                                                                                                                          
                    ;244 cycles                                                                                                         
        movlw   0x51                                                                                                             
        movwf   d1                                                                                                                      
        Delay_0:                                                                                                                        
        decfsz  d1, f                                                                                                                   
        goto    Delay_0                                                                                                                 
                    ;2 cycles                                                                                                           
        goto    $+1                                                                                                                     
                    ;4 cycles (including call)                                                                                          
        __endasm;                                                                                                                       
    }                                                                                                                                   
}

 

That can not be the problem, i used mikroC first with their built-in delay_ms routine, what i wrote above is my own delay_ms routine with SDCC compiler.
The mikroC delay_ms routine worked perfectly.
 

Post asm code generated by both compilers. Can SDCC Compiler debug code ? If yes try to find out time taken for to execute delay_ms(1) .
 

Hi dont mix the code like this just write a code in C and calibrate to 1ms. It will never drift.

The Reason might be you are using the same ram location or register used by the C variable, Who knows.

Its only allowed to use asm to execute some the instructions which cant be included by a C compiler.
 

I was thinking about that Venkadesh_M, its looks like that, like its adding 2 or 3 units its time it loops, left overs from the previous routine even thought it always loads the register in the beginning of each loop.
Anyway im going to use internal timer1, i can switch on and off whenever i want, and i found a great guide for it, Delay function for PIC.
 

So i applied what i learned from the previous link, i re-wrote my code, it compiles no problem but when i uploaded to the PIC nothing happens.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <pic12f1822.h>
 
 
/* Setup chip configuration */
__code int __at(_CONFIG1) __CONFIG = _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF;
 
void setup(void);
void delay_ms(int milis);
unsigned char minute = 60;
volatile unsigned char d_l;
 
 
static void isr(void) __interrupt 0 __using(0) {
 
    if(TMR1IE==1 && TMR1IF==1)//timer 1 interrupt overflow detect
    {
        d_l=0; //latch disable as soon as interrupt detected
        TMR1IF=0;//clear overflow flag
    }
 
}
 
 
void main(void) {
 
    setup();
 
 
    while(1) {
 
        delay_ms(1000);
        LATA |= (1<<2);
        delay_ms(1000);
        LATA &= ~(1<<2);
    }
 
void setup(void) {
 
    OSCCON = 0b01011000; // 1MHZ internal clock
    LATA = 0;
    TRISA = 0x00;
    PORTA = 0x00;
 
 
 
//  Disable synchronization bit
    NOT_T1SYNC = 1;
 
//  Clock source selection (Fosc)
    TMR1CS0 = 1;
    TMR1CS1 = 0;
 
//  Prescaler config 1:1    
    T1CKPS0 = 0;
    T1CKPS1 = 0;
 
//  Disable Timer1 Gate
    TMR1GE = 0;
 
//  Enable Timer1 interrupt
    TMR1IE = 1;
    PEIE = 1;
    GIE = 1;
}
 
void delay_ms(int milis) {
 
    int i;
    for(i = 0; i <= milis - 1; i++) {
 
        d_l = 1; //enable delay latch
        TMR1H = 0x03;
        TMR1L = 0xE8;
        TMR1ON = 1;// ENable timer 1
        while (d_l>0);  //latch till 1ms interrupt happens
        TMR1ON = 0;// disable timer 1
    }
}



- - - Updated - - -

Sorry there, my bad, it is working i loaded the wrong value to TMR1.
But for my surprise i get exactly the same drifting has with the first assembly routine, even thought still with the mickroC compiler the timer is stable.
So they are probably calibrating the INTOSC at startup or something, does anyone knows anything about is ?
 

Now i tried using TMR0 for PIC12F1822 and i got the same drift in time, next has a last attempt i tried the same code on a PIC16F88 with exactly the same result, here's the code :

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "pic16f88.h"
#define LED RB3
 
/* Setup chip configuration */
__code int __at(_CONFIG1) __CONFIG = _CP_OFF & _WDT_OFF & _BODEN_OFF & _INTRC_IO & _PWRTE_OFF & _MCLR_OFF & _LVP_OFF;
 
 
 
void delay_ms(int ms);
void setup (void);
volatile unsigned char d_l;
 
 
static void isr(void) __interrupt 0 {
 
    if(TMR0IE==1 && TMR0IF==1)//timer 1 interrupt overflow detect
    {
        d_l=0; //latch disable as soon as interrupt detected
        TMR0IF=0;//clear overflow flag
    }
 
}
 
 
void main(void) {
 
    setup();
    LED = 0;
 
    while(1) {
        delay_ms(1000);
        LED = 1;
        delay_ms(1000);
        LED = 0;
    }
 
}
 
void setup() {
 
    ANSEL = 0;
    OSCCON = 0b01001100; 
    TRISB = 0x00;
    TRISA = 0xFF;
    PORTA = 0x00;
    PORTB = 0x00;
 
 
//  Clock source selection (Fosc/4)
    T0CS = 0;
 
//  Turn off prescaler
    PSA = 1;
 
//  Enable Timer0 interrupt
    TMR0IE = 1;
    GIE = 1;
}
 
void delay_ms(int ms) {
 
    while (ms--) {
 
        d_l = 1; //enable delay latch
        TMR0 = 0x05;
        while (d_l);  //latch till 1ms interrupt happens
    }
}

 

hello,

The probleme is not about the FOSC , even you can get very litle shift ,
but with using 1MHz as Fosc .. cycle is = 4/Fosc(Mhz) => 4µS ec
in your Delay subroutine you cumulate some extra cycle to do all C instruction inside the 2 loop
and with 1000mS => 1000 times x any cycles of 4µS
so you can better have to use the interrupt to do the elapsed count of mS
without disturbing the amount of count into timer0, because , count again just after reloading the value 5..

With MikroC.. you can use the watch window and the clock to measure how many cycle you spend with your
solution...


Code:
volatile unsigned int cnt;

static void isr(void) __interrupt 0 {
 
    if(TMR0IE==1 && TMR0IF==1)//timer 1 interrupt overflow detect
    { 
       TMR0=0x05;  // reload timer0
       if (dl==0)  // timer0 continue to count during next instructions
       {
        cnt --;
        if (cnt==0) 
        {
          dl=1; // //latch elapsed time occured
          TMR0ON=0;  // stop timer
          TMR1IE=0;  // stop IT, maybe not necessary
       }
     TMR0IF=0;//clear overflow flag ;     }
    }
    
  void delay_ms(int ms) 
  {
     d_l = 0; // flag reset
     cnt=ms;
     TMR0 = 0x05;
     TMR0IE=1;
     TMR0IF=0;
     TMR1ON=1;
     while (d_l==0);  //wait till time elapsed
    }
 

Agreed, the interrupt isn't being used in the present code, just the interrupt flag so the delay routine is still a blocking one. A much better aproach is to reload the timer inside the ISR, set a global flag to say the timer caused an interrupt then clear the interrupt bit before leaving the ISR. You main program loop can then check the flag and if not set can let the main program do something useful instead of sitting in a loop.

Brian.
 

When you have mikroC Compiler why do you want to use SDCC Compiler ? Is it a better Compiler ?
 

Hi milan,

SDCC compiler is free small device C compiler, which is mainly used for 8051 family.

Hi betwixt,

When we know, this is gonna be the whole program. Why do we needed to worry about the blocking and all. It has the advantage of simplicity. Also when OP comes and asks to do some other job in the parallel delay time, That time He will get it better.
 

I fully agree but when advising someone I like to forewarn them that there is a better method which only involves a slightly more complicated program. It is far easier to design a versatile delay routine from the start then add extra code if needed later than 'corner yourself' with a blocking routine that has to be rewritten if the program is expanded.

I suspect the problem in this case is not 'drift' but instability though. Trying to assess the accuracy of a 0.5Hz square wave on an oscilloscope would be quite difficult. I would guess the real problem is supply line noise or some other electrical factor.

Brian.
 

Hy guys, i haven't had time in the weekend to look at it further and i haven't manage to get my hands on the oscilloscope at work, next week i'll post more about it.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top