EmbeddedRelated.com
Forums

Keil compiler & 8051 simulator

Started by Roman Mashak May 10, 2004
Hello, All!

    I'm studying the 8051 microcontroller and exploring now sample code I've
found. I'm using:
    - Keil C compiler v6.21
    - assembler compiler v6.20c
    - simulation DLL v2.20b

    There sre some items I can't understand. Anyway, the code I included to
this message, is doing the following:

    1) initialize Timer 2
    2) calculate the number of timer increments
    3) define 16-bit reload value
    4) split reload 16-bit value onto two 8-bit values....
    etc.

........
#define TICK_MS 30
#define OSC_FREQ (12000000UL)
#define OSC_PER_INST (12)

void Init_Timer2(const tByte TICK_MS)
   {
   tLong Inc, Reload_long;
   tWord Reload_16;
   tByte Reload_08H, Reload_08L;

   // Timer 2 is configured as a 16-bit timer,
   // which is automatically reloaded when it overflows
   T2CON   = 0x04;   // Load Timer 2 control register

   // Number of timer increments required (max 65536)
   Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST;

   // 16-bit reload value
   Reload_16 = (tWord) (65536UL - Inc);
//   Reload_long = (tLong) (65536UL - Inc);

   // 8-bit reload values (High & Low)
   Reload_08H = (tByte)(Reload_16 / 256);
   Reload_08L = (tByte)(Reload_16 % 256);

   // Used for manually checking timing (in simulator)
   //P2 = Reload_08H;
   //P3 = Reload_08L;

   TH2     = Reload_08H;   // Load Timer 2 high byte
   RCAP2H  = Reload_08H;   // Load Timer 2 reload capt. reg. high byte
   TL2     = Reload_08L;   // Load Timer 2 low byte
   RCAP2L  = Reload_08L;   // Load Timer 2 reload capt. reg. low byte

   // Timer 2 interrupt is enabled, and ISR will be called
   // whenever the timer overflows.
   ET2     = 1;

   // Start Timer 2 running
   TR2   = 1;

   EA = 1;            // Globally enable interrupts
   }

    When I'm doing tracing of the code, I find that the value of  Reload_16
is set to 0x00D0 (in hex), but it should be:

   Inc =  ( 30 * (12000000/1000) ) / 12 = 30000, that's OK, clear...
    Reload_16 =  65536-30000  = 35536,  0x8AD0 in hex

    But how?

    And then Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0,  so I
still don't understand....

    I'm sorry if my question is too silly, so please direct me onto some
useful resource. Thanks in advance!

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru


Because 65536 = 0x010000 = to big for an int. So effectively you are
subtracting from zero.

Try 65535.

Phil W


"Roman Mashak" <mrv@tusur.ru> wrote in message
news:c7pdht$17ja$1@mpeks.tomsk.su...
> Hello, All! > > I'm studying the 8051 microcontroller and exploring now sample code
I've
> found. I'm using: > - Keil C compiler v6.21 > - assembler compiler v6.20c > - simulation DLL v2.20b > > There sre some items I can't understand. Anyway, the code I included
to
> this message, is doing the following: > > 1) initialize Timer 2 > 2) calculate the number of timer increments > 3) define 16-bit reload value > 4) split reload 16-bit value onto two 8-bit values.... > etc. > > ........ > #define TICK_MS 30 > #define OSC_FREQ (12000000UL) > #define OSC_PER_INST (12) > > void Init_Timer2(const tByte TICK_MS) > { > tLong Inc, Reload_long; > tWord Reload_16; > tByte Reload_08H, Reload_08L; > > // Timer 2 is configured as a 16-bit timer, > // which is automatically reloaded when it overflows > T2CON = 0x04; // Load Timer 2 control register > > // Number of timer increments required (max 65536) > Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST; > > // 16-bit reload value > Reload_16 = (tWord) (65536UL - Inc); > // Reload_long = (tLong) (65536UL - Inc); > > // 8-bit reload values (High & Low) > Reload_08H = (tByte)(Reload_16 / 256); > Reload_08L = (tByte)(Reload_16 % 256); > > // Used for manually checking timing (in simulator) > //P2 = Reload_08H; > //P3 = Reload_08L; > > TH2 = Reload_08H; // Load Timer 2 high byte > RCAP2H = Reload_08H; // Load Timer 2 reload capt. reg. high byte > TL2 = Reload_08L; // Load Timer 2 low byte > RCAP2L = Reload_08L; // Load Timer 2 reload capt. reg. low byte > > // Timer 2 interrupt is enabled, and ISR will be called > // whenever the timer overflows. > ET2 = 1; > > // Start Timer 2 running > TR2 = 1; > > EA = 1; // Globally enable interrupts > } > > When I'm doing tracing of the code, I find that the value of
Reload_16
> is set to 0x00D0 (in hex), but it should be: > > Inc = ( 30 * (12000000/1000) ) / 12 = 30000, that's OK, clear... > Reload_16 = 65536-30000 = 35536, 0x8AD0 in hex > > But how? > > And then Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0, so
I
> still don't understand.... > > I'm sorry if my question is too silly, so please direct me onto some > useful resource. Thanks in advance! > > With best regards, Roman Mashak. E-mail: mrv@tusur.ru > >
Roman Mashak wrote:

> Hello, All! > > I'm studying the 8051 microcontroller and exploring now sample code I've > found. I'm using: > - Keil C compiler v6.21 > - assembler compiler v6.20c > - simulation DLL v2.20b > > There sre some items I can't understand. Anyway, the code I included to > this message, is doing the following: > > 1) initialize Timer 2 > 2) calculate the number of timer increments > 3) define 16-bit reload value > 4) split reload 16-bit value onto two 8-bit values.... > etc. > > ........ > #define TICK_MS 30 > #define OSC_FREQ (12000000UL) > #define OSC_PER_INST (12) > > void Init_Timer2(const tByte TICK_MS) > { > tLong Inc, Reload_long; > tWord Reload_16; > tByte Reload_08H, Reload_08L; > > // Timer 2 is configured as a 16-bit timer, > // which is automatically reloaded when it overflows > T2CON = 0x04; // Load Timer 2 control register > > // Number of timer increments required (max 65536) > Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST; > > // 16-bit reload value > Reload_16 = (tWord) (65536UL - Inc); > // Reload_long = (tLong) (65536UL - Inc);
How is tWord defined? If it is unsigned char, you would get rhe results you specify. Otherwise, watch the execution in the simulator and find out. Thad
Hello, Phil!
You wrote  on Tue, 11 May 2004 15:21:51 +1000:

 PW> Try 65535.

    I tried... In this case Reload_16=0x00CF, that's 207. So, it's not the
reason, I guess.

 PW> Phil W

 PW> "Roman Mashak" <mrv@tusur.ru> wrote in message
 PW> news:c7pdht$17ja$1@mpeks.tomsk.su...
 ??>> Hello, All!
 ??>>
 ??>>     I'm studying the 8051 microcontroller and exploring now sample
 ??>> code
 PW> I've
 ??>> found. I'm using:

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru


Hello, Thad!
You wrote  on Mon, 10 May 2004 23:41:19 -0600:

 ??>> Timer 2 control register    // Number of timer increments required
 ??>> (max 65536)   Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) /
 ??>> (tLong)OSC_PER_INST;    // 16-bit reload value   Reload_16 = (tWord)
 ??>> (65536UL - Inc); //   Reload_long = (tLong) (65536UL - Inc);

 TS> How is tWord defined?  If it is unsigned char, you would get rhe
 TS> results you specify.  Otherwise, watch the execution in the simulator
 TS> and find out.
    tWord is defined as 'unsigned int'.

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru


"Roman Mashak" <mrv@tusur.ru> wrote:

>#define TICK_MS 30
>void Init_Timer2(const tByte TICK_MS)
This should not even compile
> When I'm doing tracing of the code, I find that the value of Reload_16 >is set to 0x00D0 (in hex), but it should be: > > Inc = ( 30 * (12000000/1000) ) / 12 = 30000, that's OK, clear... > Reload_16 = 65536-30000 = 35536, 0x8AD0 in hex > > But how? > > And then Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0, so I >still don't understand....
I would suspect what the simulator is showing you did you actually inspect T2H and T2L ? The variables you are looking at are likely to be assigned to registers and/or optimised away completely. Try turning off all compiler optimisation.
Roman Mashak wrote:
> Hello, All! > > I'm studying the 8051 microcontroller and exploring now sample > code I've found. I'm using: > - Keil C compiler v6.21 > - assembler compiler v6.20c > - simulation DLL v2.20b > > There sre some items I can't understand. Anyway, the code I > included to this message, is doing the following: > > 1) initialize Timer 2 > 2) calculate the number of timer increments > 3) define 16-bit reload value > 4) split reload 16-bit value onto two 8-bit values.... > etc. > > ........ > #define TICK_MS 30 > #define OSC_FREQ (12000000UL) > #define OSC_PER_INST (12) > > void Init_Timer2(const tByte TICK_MS) > { > tLong Inc, Reload_long; > tWord Reload_16; > tByte Reload_08H, Reload_08L; > > // Timer 2 is configured as a 16-bit timer, > // which is automatically reloaded when it overflows > T2CON = 0x04; // Load Timer 2 control register > > // Number of timer increments required (max 65536) > Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST; > > // 16-bit reload value > Reload_16 = (tWord) (65536UL - Inc); > // Reload_long = (tLong) (65536UL - Inc); > > // 8-bit reload values (High & Low) > Reload_08H = (tByte)(Reload_16 / 256); > Reload_08L = (tByte)(Reload_16 % 256); > > // Used for manually checking timing (in simulator) > //P2 = Reload_08H; > //P3 = Reload_08L; > > TH2 = Reload_08H; // Load Timer 2 high byte > RCAP2H = Reload_08H; // Load Timer 2 reload capt. reg. high byte > TL2 = Reload_08L; // Load Timer 2 low byte > RCAP2L = Reload_08L; // Load Timer 2 reload capt. reg. low byte > > // Timer 2 interrupt is enabled, and ISR will be called > // whenever the timer overflows. > ET2 = 1; > > // Start Timer 2 running > TR2 = 1; > > EA = 1; // Globally enable interrupts > } > > When I'm doing tracing of the code, I find that the value of > Reload_16 is set to 0x00D0 (in hex), but it should be: > > Inc = ( 30 * (12000000/1000) ) / 12 = 30000, that's OK, clear... > Reload_16 = 65536-30000 = 35536, 0x8AD0 in hex > > But how? > > And then Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0, > so I still don't understand.... > > I'm sorry if my question is too silly, so please direct me onto > some useful resource. Thanks in advance! > > With best regards, Roman Mashak. E-mail: mrv@tusur.ru
Try this change. It may not be the "correct" solution, but it seems to work: void Init_Timer2( const tByte tick) { static tLong Inc, Reload_long; static tWord Reload_16; tByte Reload_08H, Reload_08L; // Timer 2 is configured as a 16-bit timer, // which is automatically reloaded when it overflows T2CON = 0x04; // Load Timer 2 control register // Number of timer increments required (max 65536) Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST; // 16-bit reload value Reload_long = (tLong) (65536UL - Inc); Reload_16 = (tWord) Reload_long; // 8-bit reload values (High & Low) Reload_08H = (tByte)(Reload_16 / 256); Reload_08L = (tByte)(Reload_16 % 256);
"Roman Mashak" <mrv@tusur.ru> wrote in news:c7pdht$17ja$1@mpeks.tomsk.su:

> Hello, All! > > I'm studying the 8051 microcontroller and exploring now sample code > I've > found. I'm using: > - Keil C compiler v6.21 > - assembler compiler v6.20c > - simulation DLL v2.20b > > There sre some items I can't understand. Anyway, the code I included > to > this message, is doing the following: > > 1) initialize Timer 2 > 2) calculate the number of timer increments > 3) define 16-bit reload value > 4) split reload 16-bit value onto two 8-bit values.... > etc.
This is how I remember doing it. First, let the pre-processor do the math, not the CPU. E.g. /* 1000 T2 ticks is my example timer interval, the minus sign ** makes it all work for incrementing timers. */ #define NUM_TICKS -1000 #define T2_RELOAD_HI (NUM_TICKS >> 8) #define T2_RELOAD_LO (NUM_TICKS & 0xFF00) ... /* Be sure T2 is stopped. Load T2 up to run at NUM_TICKS ** interval. */ RCAP2H = T2_RELOAD_HI; // Useless comment removed RCAP2L = T2_RELOAD_LO; // Useless comment removed T2H = T2_RELOAD_HI; // Useless comment removed T2L = T2_RELOAD_LO; // Useless comment removed /* Start T2 */ I seem to remember something about need to write to TL2 first or last, maybe I'm thinking of something else.
Hello, Not!
You wrote  on Tue, 11 May 2004 10:00:44 -0600:

 NRM> Try this change.  It may not be the "correct" solution, but it seems
 NRM> to work:

 NRM> void Init_Timer2( const tByte tick)
 NRM>    {
 NRM>    static   tLong Inc, Reload_long;
 NRM>    static   tWord Reload_16;
 NRM>    tByte Reload_08H, Reload_08L;

 NRM>    // Timer 2 is configured as a 16-bit timer,
 NRM>    // which is automatically reloaded when it overflows
 NRM>    T2CON   = 0x04;   // Load Timer 2 control register

 NRM>    // Number of timer increments required (max 65536)
 NRM>    Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST;

 NRM>    // 16-bit reload value
 NRM>    Reload_long = (tLong) (65536UL - Inc);
 NRM>    Reload_16 = (tWord) Reload_long;

    Thank you very much! It's really worked out.
    It seems compiler cannot make type casting correctly and assign 'tLong'
value to 'tWord' variable ?

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru


Hello, nospam!
You wrote  on Tue, 11 May 2004 14:22:18 +0100:

 ??>> void Init_Timer2(const tByte TICK_MS)

 n> This should not even compile
    Nevertheless it did...
 ??>>    When I'm doing tracing of the code, I find that the value of
 ??>> Reload_16 is set to 0x00D0 (in hex), but it should be:   Inc =  ( 30 *
 ??>> (12000000/1000) ) / 12 = 30000, that's OK, clear...   Reload_16 =
 ??>> 65536-30000  = 35536,  0x8AD0 in hex    But how?    And then
 ??>> Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0,  so I still
 ??>> don't understand....

   Now I changed code a little using the advice from this conference. I
assigned variables Inc and Reload_16 as 'static':

   static tLong Inc, Reload_long;
   static tWord Reload_16;
   staic tByte Reload_08H, Reload_08L;

    And I changed to  65536 to 65535  ->   Reload_16 = (tWord) (65535UL -
Inc);

    Reload_08H = (tByte)(Reload_16 / 256);
   Reload_08L = (tByte)(Reload_16 % 256);

    In this case I got the following:

    'Inc' is calculated correctly,  'Reload_16'  also....
    Reload_08H got 0x8A (OK), Reload_08L is 0xCF - why?  If we make '%'
operation (35535 % 256) - it should take division remainder, i.e. 80.

    And now is the most intersting: TH2 and TL2. TH2 is assigned correctly,
i.e. 0x8A, but TL2 is 0xD1 now, so it was increased with 2, why?

    Thank you for any help!

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru