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'm having a problem with the interrupt routine for timer 0 on the P89C557E4 Philips chip. The interrupt routine doesn't work when running the program. when i simulate it, it works fine. below is the code:
#include <reg557.h> #define TIMER0_COUNT 0xDC11 /* 10000h - ((11,059,200 Hz / (12 * FREQ)) - 17) */ static unsigned timer0_tick; /* timer tick variable */ /*------------------------------------------------------------------------------ static void timer0_isr (void); This function is an interrupt service routine for TIMER 0. It should never be called by a C or assembly function. It will be executed automatically when TIMER 0 overflows. ------------------------------------------------------------------------------*/ static void timer0_isr (void) interrupt 1 using 1 { /*------------------------------------------------ Stop Timer 0, adjust the timer 0 counter so that we get another interrupt in 10ms, and restart the timer. ------------------------------------------------*/ TR0 = 0; /* stop timer 0 */ TL0 = TL0 + (TIMER0_COUNT & 0x00FF); TH0 = TH0 + (TIMER0_COUNT >> 8); TR0 = 1; /* start timer 0 */ /*------------------------------------------------ Increment the timer tick. This interrupt should occur approximately every 10ms. So, the resolution of the timer will be 100Hz not including interrupt latency. ------------------------------------------------*/ //timer0_tick++; CMSR4 = 0; } /*------------------------------------------------------------------------------ void timer0_initialize (void); This function enables TIMER 0. TIMER 0 generates a synchronous interrupt once every 100Hz. ------------------------------------------------------------------------------*/ void timer0_initialize (void) { EA = 0; /* disable interrupts */ timer0_tick = 0; TR0 = 0; /* stop timer 0 */ TMOD &= ~0x0F; /* clear timer 0 mode bits */ TMOD |= 0x01; /* put timer 0 into 16-bit no prescale */ TL0 = (TIMER0_COUNT & 0x00FF); TH0 = (TIMER0_COUNT >> 8); PT0 = 0; /* set low priority for timer 0 */ ET0 = 1; /* enable timer 0 interrupt */ TR0 = 1; /* start timer 0 */ EA = 1; /* enable interrupts */ } /*------------------------------------------------------------------------------ unsigned timer0_count (void); This function returns the current timer0 tick count. ------------------------------------------------------------------------------*/ unsigned timer0_count (void) { unsigned t; EA = 0; t = timer0_tick; EA = 1; return (t); } /*------------------------------------------------------------------------------ void timer0_delay ( unsigned count); This function waits for 'count' timer ticks to pass. ------------------------------------------------------------------------------*/ void timer0_delay ( unsigned count) { unsigned start_count; start_count = timer0_count (); /* get the starting count */ while ((timer0_count () - start_count) <= count) /* wait for count "ticks" */ { } } void main (void) { timer0_initialize(); while (1) { CMSR4 = !CMSR4; //timer0_delay( 1 ); } }
First of all, what do you mean by "doesn't work"? It's very hard to diagnose a problem remotely if you don't describe the systems in any detail. Second: are you aware you've commented out the increase operation of the timer0_tick variable?
ok, sorry. here is clearer example:
#include <reg557.h> #define TIMER0_COUNT 0xDC11 /* 10000h - ((11,059,200 Hz / (12 * FREQ)) - 17) */ static unsigned timer0_tick; /* timer tick variable */ /*------------------------------------------------------------------------------ static void timer0_isr (void); This function is an interrupt service routine for TIMER 0. It should never be called by a C or assembly function. It will be executed automatically when TIMER 0 overflows. ------------------------------------------------------------------------------*/ static void timer0_isr (void) interrupt 1 using 1 { /*------------------------------------------------ Stop Timer 0, adjust the timer 0 counter so that we get another interrupt in 10ms, and restart the timer. ------------------------------------------------*/ TR0 = 0; /* stop timer 0 */ TL0 = TL0 + (TIMER0_COUNT & 0x00FF); TH0 = TH0 + (TIMER0_COUNT >> 8); TR0 = 1; /* start timer 0 */ /*------------------------------------------------ Increment the timer tick. This interrupt should occur approximately every 10ms. So, the resolution of the timer will be 100Hz not including interrupt latency. ------------------------------------------------*/ timer0_tick++; } /*------------------------------------------------------------------------------ void timer0_initialize (void); This function enables TIMER 0. TIMER 0 generates a synchronous interrupt once every 100Hz. ------------------------------------------------------------------------------*/ void timer0_initialize (void) { EA = 0; /* disable interrupts */ timer0_tick = 0; TR0 = 0; /* stop timer 0 */ TMOD &= ~0x0F; /* clear timer 0 mode bits */ TMOD |= 0x01; /* put timer 0 into 16-bit no prescale */ TL0 = (TIMER0_COUNT & 0x00FF); TH0 = (TIMER0_COUNT >> 8); PT0 = 0; /* set low priority for timer 0 */ ET0 = 1; /* enable timer 0 interrupt */ TR0 = 1; /* start timer 0 */ EA = 1; /* enable interrupts */ } /*------------------------------------------------------------------------------ unsigned timer0_count (void); This function returns the current timer0 tick count. ------------------------------------------------------------------------------*/ unsigned timer0_count (void) { unsigned t; EA = 0; t = timer0_tick; EA = 1; return (t); } /*------------------------------------------------------------------------------ void timer0_delay ( unsigned count); This function waits for 'count' timer ticks to pass. ------------------------------------------------------------------------------*/ void timer0_delay ( unsigned count) { unsigned start_count; start_count = timer0_count (); /* get the starting count */ while ((timer0_count () - start_count) <= count) /* wait for count "ticks" */ { } } void delay() { int i; for (i=0;i<2000;i++); } void SendSerial(char cLetra) { S0BUF = cLetra; while(!TI); TI = 0; delay(); } void InitSerial () { S0CON = 0x40; // SCON: mode 1, 8-bit UART, enable rcvr TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload TH1 = 0xFD; // TH1: reload value for 1200 baud @ 16MHz 253 TR1 = 1; // TR1: timer 1 run TI = 0; // TI: set TI to send first char of UART PCON = 0x00; // Setar SMOD = 0 } void main (void) { InitSerial(); timer0_initialize(); while (1) { SendSerial( 0x30 + timer0_count() ); } }
Looking at the variable in the debugger doesn't necessarily mean a thing. You'll have to look at what actually happens in function timer0_counter(). Step into it in the debugger and watch the register values. Look at the generated assembly code. Odds are your problem is caused by the lack of a "volatile" qualifier in the definition of the global variable timer0_tick. Also watch out for linker warnings as you compile the project.
Simulation for the 557 is done with the default 8051 simulation driver (see http://www.keil.com/dd/chip/3242.htm). My guess is that this doesn't exactly match the 557 timer. I glanced at the data sheet but didn't see anything that jumped out as obviously different. Jon
Hi,first, thank you for your attention I've changed the main function to see what was happening with TF0:
void main (void) { InitSerial(); timer0_initialize(); while (1) { SendSerial( 0x30 | TF0 ); SendSerial( 0x30 + timer0_count() ); SendSerial( ' ' ); SendSerial( ' ' ); } }
BL51 BANKED LINKER/LOCATER V5.03 12/03/2003 12:29:48 PAGE 1 BL51 BANKED LINKER/LOCATER V5.03, INVOKED BY: C:\KEIL\C51\BIN\BL51.EXE Timer_main.obj TO Timer RAMSIZE (256) MEMORY MODEL: SMALL INPUT MODULES INCLUDED: Timer_main.obj (TIMER_MAIN) C:\KEIL\C51\LIB\C51S.LIB (?C_STARTUP) LINK MAP OF MODULE: Timer (TIMER_MAIN) TYPE BASE LENGTH RELOCATION SEGMENT NAME ----------------------------------------------------- * * * * * * * D A T A M E M O R Y * * * * * * * REG 0000H 0008H ABSOLUTE "REG BANK 0" DATA 0008H 0002H UNIT ?DT?TIMER_MAIN IDATA 000AH 0001H UNIT ?STACK * * * * * * * C O D E M E M O R Y * * * * * * * CODE 0000H 0003H ABSOLUTE 0003H 0008H *** GAP *** CODE 000BH 0003H ABSOLUTE 000EH 07F2H *** GAP *** CODE 0800H 0026H UNIT ?PR?MAIN?TIMER_MAIN CODE 0826H 0021H UNIT ?PR?TIMER0_ISR?TIMER_MAIN CODE 0847H 001EH UNIT ?PR?TIMER0_INITIALIZE?TIMER_MAIN CODE 0865H 001DH UNIT ?PR?_TIMER0_DELAY?TIMER_MAIN CODE 0882H 0011H UNIT ?PR?INITSERIAL?TIMER_MAIN CODE 0893H 000FH UNIT ?PR?DELAY?TIMER_MAIN CODE 08A2H 000CH UNIT ?C_C51STARTUP CODE 08AEH 000AH UNIT ?PR?_SENDSERIAL?TIMER_MAIN CODE 08B8H 0009H UNIT ?PR?TIMER0_COUNT?TIMER_MAIN OVERLAY MAP OF MODULE: Timer (TIMER_MAIN)
Hi, I've read the timer part in the datasheet and I think that timer0 and timer1 work just like in standard 80c51 chips. I've found that my problem might be in where the routine is being located in the memory (see message above). Please see if you can help me with that. Thanks.
The position of the timer handler routine is not your problem --- the actual handler is not supposed to be positioned at 0x000b (not 0x0003) in code memory. Only a jmp to the handler has to be there, and apparently it is:
* * * * * * * C O D E M E M O R Y * * * * * * * CODE 0000H 0003H ABSOLUTE 0003H 0008H *** GAP *** CODE 000BH 0003H ABSOLUTE
problem might be in where the routine is being located in the memory If you look at the code in a simulator or emulator you will see that at 0xwhatever the interrupt vector is there will be a call or jump to the code. This is how everybody and his brother (or would it be politically correct to say sibling) does it. Just visualize the max size of the ISR for int0 if the ISR had to be at the vector address and you had another ISR. Erik
The position of the timer handler routine is not your problem --- the actual handler is not supposed to be positioned at 0x000b (not 0x0003) in code memory. Only a jmp to the handler has to be there, and apparently it is That is right! since you said that the timer0_counter variable is being incremented as designed Hans, it is NOT being incremented, it is only when in debug mode. Did you try my suggestion about making that volatile? How do I do that? I took the static keyword off. Still doesn't work. But notice that TF0 is not being cleared, what means that the ISR is not being called. I looked at the hex file, and it seemed alright, so I asked people from Philips. Here is the first lines of the hex:
:03000B00020826C2 :10082600C0E0C0D0C28C7411258AF58A74DC258C90 :10083600F58CD28C0509E50970020508D0D0D0E008 :01084600327F
"Did you try my suggestion about making that volatile? How do I do that?" Use the volatile keyword. Look it up in your C book. Stefan
Hans, it is NOT being incremented, it is only when in debug mode. But in that same message, you said that in debug, you saw the variable move, but not the result returned by timer0_count(). That's the disparity I'm trying to resolve by that "volatile". And instead of looking at HEX output, you really should look at the assembly in your listing file (if you had uVision make one), or in the debugger.