We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hi,
i am a student and needs some help. Can someone help solve some of my doubts?
Hmm..may i know what does it means by SYSCLK/12/10? How can i go about calculating the timer values using the SYSCLK/12/10 if i want to use the codes below to make the LED blink at 1Hz?
Thanx=)
//------------------------------------------------------------------------------------ // MAIN Routine //------------------------------------------------------------------------------------ void main (void) { // disable watchdog timer WDTCN = 0xde; WDTCN = 0xad; SFRPAGE = CONFIG_PAGE; // Switch to configuration page PORT_Init (); SFRPAGE = TMR3_PAGE; // Switch to Timer 3 page Timer3_Init (SYSCLK /120/10); // Init Timer3 to generate interrupts // at a 10 Hz rate. EA = 1; // enable global interrupts SFRPAGE = LEGACY_PAGE; // Page to sit in for now while (1) { // spin forever } } //------------------------------------------------------------------------------------ // PORT_Init //------------------------------------------------------------------------------------ // // Configure the Crossbar and GPIO ports // void PORT_Init (void) { XBR2 = 0x40; // Enable crossbar and weak pull-ups P1MDOUT |= 0x40; // enable P1.6 (LED) as push-pull output } //------------------------------------------------------------------------------------ // Timer3_Init //------------------------------------------------------------------------------------ // // Configure Timer3 to auto-reload and generate an interrupt at interval // specified by <counts> using SYSCLK/12 as its time base. // // void Timer3_Init (int counts) { TMR3CN = 0x00; // Stop Timer3; Clear TF3; // use SYSCLK/12 as timebase RCAP3 = -counts; // Init reload values TMR3 = 0xffff; // set to reload immediately EIE2 |= 0x01; // enable Timer3 interrupts TR3 = 1; // start Timer3 } //------------------------------------------------------------------------------------ // Interrupt Service Routines //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ // Timer3_ISR //------------------------------------------------------------------------------------ // This routine changes the state of the LED whenever Timer3 overflows. // // NOTE: The SFRPAGE register will automatically be switched to the Timer 3 Page // When an interrupt occurs. SFRPAGE will return to its previous setting on exit // from this routine. // void Timer3_ISR (void) interrupt 14 { TF3 = 0; // clear TF3 LED = ~LED; // change state of LED }
Student means studying - the study required here is:
Hi, i have read up on the operation of timer 3, it mentioned that it can either use SYSCLK(divided by either 1,2 or 12). does the 1,2 or 12 represents the no of cycles needed to carry out the instruction? And for SYSCLK/12/10, for the value 10, does it represent the 10Hz rate?
This is the value for the sysclk:
//------------------------------------------------------------------------------------ // Global CONSTANTS //------------------------------------------------------------------------------------ #define SYSCLK 3062500 // approximate SYSCLK frequency in Hz sbit LED = P1^6; // green LED: '1' = ON; '0' = OFF
"Hi, i have read up on the operation of timer 3, it mentioned that it can either use SYSCLK(divided by either 1,2 or 12).
Remember: when the Datasheet talks about "SYSCLK", it is talking about the physical signal on the chip - it knows nothing about any symbol in your source code that might just happen to also be named "SYSCLK"
"does the 1,2 or 12 represents the no of cycles needed to carry out the instruction?"
No - it means exactly what it says:
"SYSCLK divided by 1" is a signal with the same frequency as SYSCLK;
"SYSCLK divided by 2" is a signal with half the frequency of SYSCLK;
"SYSCLK divided by 12" is a signal with one-twelfth the frequency of SYSCLK
"for SYSCLK/12/10, for the value 10, does it represent the 10Hz rate?"
What 10Hz rate?
Again, "SYSCLK/12/10" is just plain arithmetic: take the value of SYSCLK, divide it by 12, then divide the result by 10.
#define SYSCLK 3062500 // approximate SYSCLK frequency in Hz
Now, anywhere the text "SYSCLK" appears in your source code, the preprocessor will preplace it with the text "3062500"
Whether or not that actually reflects anything relevant to your hardware is another question...
"Now, anywhere the text "SYSCLK" appears in your source code, the "
Hi, thanx..so if i want make the LED blink at 1Hz, do i change the TMR3 value?
Now, anywhere the text "SYSCLK" appears in your source code, the
Hmm..for this program..to make the LED blink at 1Hz, is it a must to use the SYSCLK/12/10?or can i use the while loop?
void Timer3_Init (void) { While (count<100) { TMR3CN = 0x00; // Stop Timer2; configure for auto-reload RCAP3 = 0x2710; // Init reload value TMR3 = 0xffff; // set to reload immediately EIE2 | = 1; // enable Timer2 interrupts TR3 = 1; // start Timer2 count++; } }
Your code have some hints that you are not using a standard 8051, but you have not identified the chip nor given any info on it.
1) What is your external crystal frequency? 2) What is the CPU clock division for 1 instruction cycle? Standard 8051 is 12 clocks/instruction, many others are 6 or 2 clocks/instruction. 3) The symbol SYSCLK in your program is just a text symbol with a nice name. It bears no influence on the actual clock rate of your CPU. 4) Is Timer3_Init() an actual function in your code, or is it pseudocode? It has problems in so many levels:
- It simply does not compile. 'While' is not a C keyword. Unless you have a macro named 'While'. - Your code seems to refer to timer 3, but the comments say 'timer 2' instead. This is a bug per se. - You seem to be configuring the timer for compare mode, with interrupt on match. - Now comes the weird part: you are placing the timer initialization code inside a loop. Assuming that count is a global variable (bad idea), the loop will iterate zero or more times, up to 100 times depending on the value of count on entry. - Do you have a interrupt service routine to process the compare interrupt?
You need to determine a few referential information before you proceed, like the clocks/instruction rate of your processor, and the correct init sequence to setup the timer resources. With this, you can load the correct values in the compare register and eventually use the timer compare flag to signal the event, or have the interrupt handler to set the event.
<html> "Your code have some hints that you are not using a standard 8051, but you have not identified the chip nor given any info on it."
Hi, hmm..i am using the C8051F12X. 1) the external clock frequency is 22.1184 MHz.The crystal frequency is 11.0592MHz. 2)it should be 12clocks/instruction 3)Timer3_Init() is an actual function in the program
"Your code seems to refer to timer 3, but the comments say 'timer 2' instead. This is a bug per se." hmm..in the comments i typed wrongly.It should be referring to timer3.Thanx=)
Actually, i have managed to make the LED blink at 1Hz.. This is the code:
//------------------------------------------------------------------------------------ // Blinky.c //------------------------------------------------------------------------------------ // Copyright (C) 2005 Silicon Laboratories, Inc. // // AUTH: BD // DATE: 1 JUL 2002 // // This program flashes the green LED on the C8051F120 target board about five times // a second using the interrupt handler for Timer3. // Target: C8051F12x // // Tool chain: KEIL Eval 'c' // //------------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------------ #include <c8051f120.h> // SFR declarations //----------------------------------------------------------------------------- // 16-bit SFR Definitions for 'F12x //----------------------------------------------------------------------------- sfr16 RCAP3 = 0xCA; // Timer3 reload value sfr16 TMR3 = 0xCC; // Timer3 counter //------------------------------------------------------------------------------------ // Global CONSTANTS //------------------------------------------------------------------------------------ #define SYSCLK 3062500 // appproximate frequency in Hz sbit LED = P1^6; // green LED: '1' = ON; '0' = OFF //------------------------------------------------------------------------------------ // Function PROTOTYPES //------------------------------------------------------------------------------------ void PORT_Init (void); void Timer3_Init (int count); void Timer3_ISR (void); //------------------------------------------------------------------------------------ // MAIN Routine //------------------------------------------------------------------------------------ void main (void) { // disable watchdog timer WDTCN = 0xde; WDTCN = 0xad; SFRPAGE = CONFIG_PAGE;// Switch to configuration page PORT_Init (); SFRPAGE = TMR3_PAGE; // Switch to Timer 3 page Timer3_Init (); // Init Timer3 to generate //interrupts at a 10 Hz rate. EA = 1; // enable global interrupts SFRPAGE = LEGACY_PAGE; // Page to sit in for now while (1) { // spin forever } } //------------------------------------------------------------------------------------ // PORT_Init //------------------------------------------------------------------------------------ // // Configure the Crossbar and GPIO ports // void PORT_Init (void) { XBR2 = 0x40;// Enable crossbar and weak pull-ups P1MDOUT |= 0x40; /*enable P1.6 (LED) as push-pull output*/ } //------------------------------------------------------------------------------------ // Timer3_Init //------------------------------------------------------------------------------------ // // Configure Timer3 to auto-reload and generate an interrupt at interval // specified by <counts> using SYSCLK/12 as its time base. // // void Timer3_Init (int count) { TMR3CN = 0x00; // Stop Timer3; Clear TF3; // use SYSCLK/12 as timebase RCAP3 =-count; // Init reload values TMR3 = 0xffff; // set to reload immediately EIE2|= 0x01; // enable Timer3 interrupts TR3= 1; // start Timer3 } //------------------------------------------------------------------------------------ // Interrupt Service Routines //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ // Timer3_ISR //------------------------------------------------------------------------------------ // This routine changes the state of the LED whenever Timer3 overflows. // // NOTE: The SFRPAGE register will automatically be switched to the Timer 3 Page // When an interrupt occurs. SFRPAGE will return to its previous setting on exit // from this routine. // void Timer3_ISR (void) interrupt 14 { int b; TF3 = 0; // clear TF3 b++; if (b ==5) { LED = ~LED; //toggle state of LED b=0; } }
hmm..though it works but i would like to know if i am able to make the LED blinks at 1Hz if i change the TMR3 value, which when the RCAP3 values underflows to the same value as TMR3,it will restart the timer and cause interrupts(if enabled).Is there any way to calculate the value? cause my teacher told me to change the value of TMR3 but i didnt mananged to do so..
Thanx for ur reply=)
1) the external clock frequency is 22.1184 MHz.The crystal frequency is 11.0592MHz. I guess that you mean that the crystal is a 11.0592 and the PLL makes the sysclk 22.1182. 2)it should be 12clocks/instruction the f12x is a one clocker !!! Please read the manual
a final note: the f12x hax a SFR that controls the clocking of the timers
Erik
In your code:
void Timer3_ISR (void) interrupt 14 { int b; TF3 = 0; // clear TF3 b++; if (b ==5) { LED = ~LED; //toggle state of LED b=0; } }
You are using the variable 'b' with a static lifetime, i.e., its value is retained between executions of the function. HOWEVER, you are not declaring 'b' as static. An optimizing compiler can do whatever it wants with the value of 'b' when your handler is not running. The only reason why your code works is that C51 will not reuse the interrupt handler local vars because it can't prove it's usage pattern. But that is not valid for other processors, or for other functions that are not declared as interrupt.
Check out what is the meaning of the keyword static, and how it applies to your usage of 'b'.
Another thing: please answer what is the value of 'b' when your program first runs. Hint: N-E-V-E-R trust that uninitialized variables have any meaningful initial value, especially local vars.
"1) the external clock frequency is 22.1184 MHz.The crystal frequency is 11.0592MHz. I guess that you mean that the crystal is a 11.0592 and the PLL makes the sysclk 22.1182."
to: Erik
Thanx=) i will go check that out.
"An optimizing compiler can do whatever it wants with the value of 'b' when your handler is not running."
Actually, it has nothing to do with optimisation.
The whole point of local variables is that they do cease to exist between calls to the function - unless you specifically make them static.
hmm..okie..does it means that i add in the variable declaration--static int b;--at the global constant..and declare b=0 in the ISR?Thanx=)
"does it means that i add in the variable declaration--static int b;--at the global constant"
No, it doesn't.
Back to the textbook!
i add in the variable declaration--static int b;--at the global constant..and declare b=0 in the ISR?
Almost there. 1) Yes, you must declare 'b' as static unsigned char b; (why waste one int when one char can do). This will NOT make 'b' global, its scope is still local to the function, but its lifetime will be infinite, i.e., it will retain its value across the whole execution time of the program.
2) To initialize 'b', you should declare it with initialization: static unsigned char b = 0; Thus, the first time your program runs, the value of 'b' will automagically be zero.
Andy wrote: "Actually, it has nothing to do with optimisation. The whole point of local variables is that they do cease to exist between calls to the function ..."
You are right, of course. My point is exactly that. The only reason for that particular code to run as written is that the storage allocated for the locals in interrupt handlers can't be reused for main code.
Were that function a non-interrupt function, it would crash and burn.
"Almost there. 1) Yes, you must declare 'b' as static unsigned char b; (why waste one int when one char can do)."
Hi, Thanx for ur help=)