Pic12683 Timer1 in Sleep Mode

Status
Not open for further replies.

Manpreet1604

Junior Member level 1
Joined
Nov 20, 2015
Messages
15
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,422
Hello Iam working on PIC12f683 I need to run timer1 in sleep mode according to data sheet Timer1 can work on 32khz internal oscillator.
Datasheet 6.2.2 state that If an external clock oscillator is needed (and the microcontroller is using the INTOSC without CLKOUT), Timer1 can use the LP oscillator as a clock source. and Datasheet section 6.4 state that A low-power 32.768 kHz crystal oscillator is built-in between pins OSC1 (input) and OSC2 (amplifier output). The oscillator is enabled by setting the T1OSCEN control bit of the T1CON register. The oscillator will continue to run during Sleep.
but how to use sleep mode in this chip no other mode is available in this chip any help is appreciated.
Timer 1 is working in normal mode even @ 32khz frq
 

Attachments

  • Timer1.txt
    3.5 KB · Views: 191

Hi,

If I'm not mistaken you did not select "ext clock" as clock source.
Read datasheet section 6, especially 6.2.

You did not give any informations about a problem.
Please provide a proper error description and your test conditions.


Klaus
 

Datasheet 6.2.2: If an external clock oscillator is needed (and the microcontroller is using the INTOSC without CLKOUT), Timer1 can use the LP oscillator as a clock source.

So I can not use "ext clock" therefor i set config to "config FOSC = INTOSCIO" i.e internal clock.

Datasheet 6.8: Timer1 Operation During Sleep Timer1 can only operate during Sleep when setup in Asynchronous Counter mode.

Datasheet 6.5: If control bit T1SYNC of the T1CON register is set, the external clock input is not synchronized. The timer continues to increment asynchronous to the internal phase clocks.

"Therefor i used T1CONbits.nT1SYNC=1;//Timer1 set up in Asynchronous mode"

Dtasheet 6.11 Timer1 Control Register:

bit 3 T1OSCEN: LP Oscillator Enable Control bit
If INTOSC without CLKOUT oscillator is active:
1 = LP oscillator is enabled for Timer1 clock
0 = LP oscillator is off Else: This bit is ignored. LP oscillator is disabled.

bit 2 T1SYNC: Timer1 External Clock Input Synchronization Control bit
TMR1CS = 1:
1 = Do not synchronize external clock input
0 = Synchronize external clock input
TMR1CS = 0:
This bit is ignored. Timer1 uses the internal clock

bit 1 TMR1CS: Timer1 Clock Source Select bit
1 = External clock from T1CKI pin (on the rising edge)
0 = Internal clock (FOSC/4)

Therefor i am using bellow setting but not working
T1CONbits.TMR1CS=1;//External instruction cycle clock
T1CONbits.T1OSCEN=1;//LP oscillator is enabled for Timer1 clock
T1CONbits.TMR1ON = 1;

Even I cannot set config bit in LP mode controller stop working.
datasheet is confusing how to set timer1 in sleep mode
 

Hi,

6.4 states the internal oscillator .... but with the external XTAL connected to OSC1 and OSC2
Please see Figure6-1. How OSCx are connected to the oscillator..how it is wired to the MUX and which value of TMR1CS you need to choose.

Register 12-1 description says:
bit 2-0 FOSC<2:0>: Oscillator Selection bits
111 = RC oscillator: CLKOUT function on GP4/OSC2/CLKOUT pin, RC on GP5/OSC1/CLKIN
....
001 = XT oscillator: Crystal/resonator on GP4/OSC2/CLKOUT and GP5/OSC1/CLKIN
000 = LP oscillator: Low-power crystal on GP4/OSC2/CLKOUT and GP5/OSC1/CLKIN

Klaus
 

According to Fig 6-1

#pragma config FOSC = INTOSCIO T1CONbits.TMR1CS=1;//internal instruction cycle clock T1CONbits.T1OSCEN=1;//LP oscillator is enabled for Timer1 clock T1CONbits.nT1SYNC=1;//Timer1 set up in Asynchronous mode T1CONbits.TMR1ON = 1;

Timer 1 should work on this setting but it is not.
what wrong

void interrupt ISR (void){ TMR1H = 0xFF; //Clear timer1 Registers H&L before enabling timer1 TMR1L = 0x00; // T1CONbits.TMR1ON = 1; if (PIR1bits.TMR1IF == 1){//check flag PIR1bits.TMR1IF = 0;// clear counter1++; if (counter1==100){ LED1 =~LED1; LED2 =~LED2; counter1=1; } }
 
Last edited by a moderator:

Bad coding!

1. You have an ISR but nothing triggering it.
2. If you properly enable the ISR and only use T1 there is no need to test the TMR1IF bit, it has to be set or you wouldn't be in the ISR!
3. You load 0xFF00 into TMR1 but the comment says you clear it.
4. potential RMW problem driving (I assume) LED outputs
5. poor code structure, the last four lines should not be inside the ISR.

Also check you have the prescaler bits set correctly. It defaults to 1:1 so if you have the crystal and loading capacitors wired correctly and apply the software fixes above, the LEDs should change state 32768 / (256 * 99) = every 1.29 seconds. The first two cycles may be different because the initial values in TMR1 and 'count' are not set.

Brian.
 

I agreed with you Brian I am just noob in coding and my coding skills very high which you already see above but i have understanding of hardware
I am able to blink an led using timer1 and 0 but now iam learning about sleep mode.
I Read that we can exist from sleep mode by Interrupt or WDT interrupt.
as i go through datasheet of pic12f683 i found that Timer 1 on this controller can able to work in sleep mode without using extra crystal OSC or hardware.
Now I want to blink LED in Sleep mode and checking my power consumption.

if iam not wrong according to datasheet to run timer in sleep mode bellow setting is used.

config FOSC = INTOSCIO
nT1SYNC=1
T1OSCEN=1
TMR1CS=1
TMR1ON = 1

is that possible to run timer1 in sleep mode in this chip if yes please help me to write a code
 

I won't write the code for you but I will help you to write it yourself.

Before looking at instructions you need to understand how sleep mode and interrupts work. I will try to explain:

Sleep mode in that device is just a switch that disconnects the clock from the processing circuitry. When the switch is 'on' everything woks as normal, when you use the SLEEP instruction the switch turns off and the processor goes into suspended animation, it just freezes and ceases to run any further code. Note that because SLEEP is itself an instruction, it will switch the clock off at the end of executing it and not before, this means it can cleanly resume at a later time. As all internal operations are synchronized to the clock, everything except Timer 1 will freeze, including the state of the pins and being a MOS device, the current consumption will also drop to almost zero. It will suspend with the pins in their current input or output state and with any current flowing through the pins still there, in other words it won't disconnect from the outside World when it sleeps so you have to be careful to take into account that pins may still source or sink.

Interrupts are one of the most useful features on any microcontroller and the 12F683 is no exception. When you write a program you think of it as having 'flow', the path the instructions will follow as you pass through it or enter loops or subroutines. Interrupts work differently because in most cases they are triggered by an event outside of the program flow. For example you could have a program with a long delay loop in it that also has to react to a change on one of the pins, it wouldn't be able to do both because it wouldn't be able to read the pin until the delay routine finished. Interrupts do exactly as their name suggests, they break the normal flow and grab the attention of the processor regardless of what code it is executing at the time. It follows that interrupts are reliant on circuits in the controller rather than software instructions to trigger them. In that example, a signal on the pin could 'interrupt' the delay loop, do something important then when finished it could tell the delay loop to resume.

Interrupts can come from several sources, look at section 12.4 on the data sheet where they are all listed. The GP2/INT source allows a pin to be used to directly trigger an interrupt, GPIO change allows any input pins changing state to trigger an interrupt and the others come from the peripherals built into the silicon.

The one you should be interested in is the "Timer 1 overflow interrupt". Timer 1 always counts upwards, when it reaches maximum value (all 1's in the timer registers) the next count will make it roll over back to all zeroes and at the same time trigger the overflow interrupt. Consider that Timer 1 is a hardware counter and it keeps on running independently of the software so unless the program reads its value, it has no knowledge of what it holds at any time. When that roll over happens, and if you have enabled the TMR1IE bit and GIE bits in the INTCON register, an interrupt will be triggered and only then will the code in the ISR routine be called.

On that device there is only one ISR vector, so all the sources of interrupts cause the same ISR code to be called. Several of the interrupt enable bits can be set at the same time, for example, as well as Timer1 overflow you could have the ADC interrupt enabled, that's is why there is a line in the ISR to check which of the sources was the cause. For Timer1 the TMR1IF bit will be set. If there are several sources, you have to check each bit and branch to the appropriate code to deal with it. Note that you should reset the interrupt bit in your code but never change the GIE bit because that could effect the operation of other interrupt sources. The 'golden rule' with ISRs is get out of them as quickly as possible, especially if you have enabled multiple sources because other triggers might be missed before the routine finishes.

So what you need to do is remove the lines
Code:
if (counter1==100){   
       LED1 =~LED1;   
       LED2 =~LED2;         
     
       counter1=1; 
}
and put them in the main() loop somewhere, then set the bits in the INTCON register to enable Timer1 overflow interrupts.

There are other issues with your code but see if you can put that fix in first then I'll explain the other problems.

Brian.
 

Thanks Brian
I have make some changes according to you with help of some examples available online please have a look.
I understand that Sleep is instruction which force controller to get sleep and force the OSC and other peripheral stop latch last state in it output and to wake-up from sleep we have to use interrupt it can be from Hardware side or from software side like WTD or TMR1IF.

Please Correct me if Iam wrong "if I put the Sleep command Timer1 will still working as you explain above if I set the TMR1CS=1 then Timer1 clock is replaced or switch over on internal 32.768 Khz OSC but to use timer1 in sleep mode Asynchronous Mode has to set therefor nT1SYNC=1 and datasheet also states that to enable LP OSC for Timer1 T1OSCEN=1.

where to put this all setting or their is some other way or hack.
please review my code
 

Attachments

  • New Text Document.txt
    3.1 KB · Views: 143

Hi,

All the settings usually are placed before the "while(1)".....at least it needs to be processed before the "sleep".

Klaus
 

I haven't compiled it to check if it works but apart from one improvement it basically looks OK now.

Remember I said you should leave an ISR as quickly as possible, that is because when an interrupt is triggered the PIC automatically clears the GIE bit to prevent it being called again before it has finished. Small PICs can't cope with interrupted interrupts! It doesn't stop the interrupt flags being set and on leaving the ISR it will check them and if necessary enter the ISR again to process them, but it does stop a second or subsequent interrupt from the same source being detected. At the end of an ISR, it automatically restores GIE to make it ready for re-triggering. In your example everything runs very slowly so it probably wouldn't be a problem but its worth understanding how to do it for when you develop faster running code.

I would change the interrupt routine so it does this:
Code:
#include <xc.h>
#include <stdlib.h>
#include <pic12f683.h>
#define _XTAL_FREQ 8000000

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)


#define LED1 GPIObits.GP4 // Pin No. 3
#define LED2 GPIObits.GP5 // Pin No. 2
#define LED3 GPIObits.GP0 // Pin No. 7
#define LED4 GPIObits.GP1 // Pin No. 6

volatile char counter1=0;
char T1_InterruptTriggered = 0;
char SW_InterruptTriggered = 0;

void T1_ISR(void);
void SW_ISR(void);

void interrupt chk_isr(void) 
{
    if(PIR1bits.TMR1IF==1)
    {
        T1_InterruptTriggered = 1;
        PIR1bits.TMR1IF = 0;
    }
    if(INTCONbits.INTF == 1)
    {
        SW_InterruptTriggered = 1;
        INTCONbits.INTF = 0;
    }
}

void main (void){         
    
    ANSEL = 0x00;  // turn off analog inputs
    ADCON0 = 0x00; //Turn off ADC
    CMCON0 = 0x07; //Turn off Comparators
    VRCON = 0x00; //Turn off Voltage Reference
    
    //OSCCON=0b01110111;
        
    PIE1bits.TMR1IE=1;// enable timer1 interrupt
    PIR1bits.TMR1IF=0;// clear timer1 overflow flag    
    INTCONbits.GIE=1; //Enable all global interrupts
    INTCONbits.PEIE=1; //Enable all periferal interrupts
    T1CONbits.TMR1CS=1;//internal instruction cycle clock
    T1CONbits.T1OSCEN=1;//LP oscillator is enabled for Timer1 clock
    T1CONbits.nT1SYNC=1;//Timer1 set up in Asynchronous mode
    PIE1bits.TMR1IE=1;// enable timer1 interrupt
    PIR1bits.TMR1IF=0;// clear timer1 overflow flag
    T1CONbits.TMR1ON = 1;
    
    T1CONbits.T1CKPS0=1;//Prescalar assigned to timer1
    T1CONbits.T1CKPS1=1;//Prescalar assigned to timer1
   
    INTCONbits.INTE = 1;//enable External interrupt
    INTCONbits.INTF = 0;//clear external interrupt flag 
    IOCbits.IOC2 = 1;//make GP2 as External Interrupt
       
    OPTION_REGbits.nGPPU= 1; //enable internal weak pull up resistors  
    WPUbits.WPU2 = 1; //pull up enabled on GP2 INPUT
    
    
    TRISIObits.TRISIO0=0;
    TRISIObits.TRISIO1=0;
    TRISIObits.TRISIO4=0;
    TRISIObits.TRISIO5=0;   
    
    LED1=0; // set initial state of pin
    LED2=0;
    LED3=0;
    LED4=0;

    if(T1_InterruptTriggered) T1_ISR();
    if(SW_InterruptTriggered) SW_ISR();
    
    SLEEP(); 
    
    while(1){
       
       if(counter1 == 10){
           LED1=1;
           counter1=1;
       }
    }
            
}

void T1_ISR(void)
{
    T1_InterruptTriggered = 0;
    counter1++;
    LED2 = ~LED2;
    TMR1H= 0x00;
    TMR1L= 0x00;
}

void SW_ISR(void)
{
    SW_InterruptTriggered = 0;
    LED4 = 1;       
}

You will that the change is to set variables in the ISR but do the actual work in the main loop. This is normally a far safer way to write code. I'm not exactly sure when you want LED2 to flash but checking 'counter1' inside the while() loop doesn't look right, those lines probably shouldn't be in a loop at all and the check for '=10' inside the T1_SR() routine. Maybe like "if(++counter1 == 10) {counter1 = 0; LED2 = ~LED2; ....".

Brian.
 

The code in Post #11 doesn't look right to me.
You test the 'xx_InterruptTriggered' variables before you enter the main loop. Frankly the chances of the ISR having been called during the startup and tiny. Should these tests be in the main loop?
You seem to be using the XC8 compiler - in that case leave the <xc.h> include in but remove the processor specific include - that will just cause confusion.
You alter the 'xx_InterruptTriggered' variables in the ISR and read them in the main code, therefore you need to declare them 'volatile'.
I've not checked the logic against the goals (earlier in this thread) but there seems to be a lot of unnecessary code. You initialise LED3 but never use it; in 'T1_ISR' you reset the time counters to 0 - but the call the ISR they must have rolled over from 0xFFFF to 0x0000; you don't have a delay function/macro call so defining '_XTAL_FREQ' is pointless; you set TMR1IE and TMR1IF twice to the same values....
Susan
 

The names chosen by Manpreet1604 are a little confusing. The 'xx_ISR' routines are prototyped but not called before the main loop and they are executed as subroutines if the variable is set. I think adding 'xx_ISR' gives the impression they are the Interrupt routine itself rather than code executed if the interrupt bits are set. The main interrupt routine is called 'chk_isr()'.

I pointed out there were other issues in post #8, intending to raise the other points Susan spotted but thought it better to sort out the ISR issues first so it could at least run.

Brian.
 

@brian - I think we are in violent agreement. I did notice the 'interrupt' keyword on the actual ISR and I do realise the other (badly named) functions are now ISRs - the PIC12F only have a single interrupt vector so there can only be one 'primary' ISR (even if it calls other functions).
My point was that the ONLY place where the 'trigger' flags is checked is BEFORE the main loop. If the Fsoc is really 8Mhz then the code that does the testing is probably executed within 10's or 100's of uSec after the interrupts are enabled and never again! The ISR might set the flags but that is a useless operation if they are never tested again.
Susan
 

Then I'm missing something

XC8 sets the execution address at main() and I can't see where they are checked, or indeed can be checked before that point.

There is some merit in adding a double underscore to the ISR routine "void __interrupt chk_isr(void) " but that depends on the C model that was selected and the version of XC8.

True, putting the SLEEP() before checking the variables makes more sense because one of them must be responsible for waking it up but all of that is in the main() loop anyway.

Some other anomalies:
Resetting TMR1 to zero after is has just rolled over to zero doesn't do much unless they are place markers to use a different value later, if that is so the same value should be used from the outset or the first time around the loop may have the wrong timing.

RMW risk when flipping LED2 state.

The external interrupt pin isn't set as an input.

GP3 looks to be used as an output but it is only usable as an input and in any case is internally connected to VDD.

Not sure about the clock switching at start up - I'll have to check the data sheet on that one.

Brian.
 

True, putting the SLEEP() before checking the variables makes more sense because one of them must be responsible for waking it up but all of that is in the main() loop anyway.
Go back and look at the code you showed in Post #11
Code:
    if(T1_InterruptTriggered) T1_ISR();
    if(SW_InterruptTriggered) SW_ISR();
    
    SLEEP(); 
    
    while(1){
       
       if(counter1 == 10){
           LED1=1;
           counter1=1;
       }
    }
The problem is that the top 3 lines of code shown able SHOULD be in the main loop but aren't.
Susan
 

I can't see how they are not in main() but I agree they should be in the while() loop.
Code:
    while(1)
    {
      SLEEP();    
      if(T1_InterruptTriggered) T1_ISR();
      if(SW_InterruptTriggered) SW_ISR();
      
      if(counter1 == 10)
      {
        LED1=1;
        counter1=1;
      }
    }
The xx_ISR rutines could easily be incorporated into the while() loop but I tried to retain the original code in post #1 as closely as possible.

Brian.
 

Thanks brain and susan it must be in while loop and it is working but not in sleep mode now please confirm that pic 12F683 will require external crystal or not
If no how
As i trigger cs to 1 everything stop working
 

Yes, an external crystal, typically 32.768KHz will be needed.
See data sheet chapters 6.4 and 6.8 for details.

Brian.
 

@brian - as I said earlier, we are in violent agreement. Just to finish this side issue (at least for the OP) I must admit I read your 'main() loop' as 'main loop' meaning the 'while(1)' infinite loop.
(Also being on opposite sides of the world doesn't help speedy interactions. I was also going to make a joke about you being in Wales but me being south of New South Wales but I'll leave it there. )
Susan
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…