No announcement yet.

MEL Trainer Chap 9 Example code questions

  • Time
  • Show
Clear All
new posts

  • MEL Trainer Chap 9 Example code questions

    I have the ME Labs Trainer and am working with the Chapter 9 code "Timer-Driven Assembly Language Interrupt" My goal is to understand the code well enough to port the code over to my PIC of choice and eventually develop interrupt code on my own.

    In the code relating to the actual interrupt there are comments in the lines of code but no explanation in the tutorial as to what is being done. I would like to know the purpose and how these particular Hex values were arrived at. I understand the assembly commands generally but not why the code is used. The lines in question are as follows:

    movlw 0xA7 ; Load W with 0xA7
    addwf TMR1L, F ; Add preset value to TMR1 LSB
    btfsc STATUS, 2 ; If no byte overflow, skip next instruction
    incf TMR1H, F ; If byte overflow, increment MSB of TMR1
    movlw 0x3C ; Load W with 0x3C
    addwf TMR1H, F ; Add preset value to TMR1 MSB

    Are these values used like in the previous chapter examples to adjust the time duration? If so how were they computed? I don't follow the manipulation of TMR1H byte. Why add 0xA7? Also what does incrementing the MSB do? What does adding 0x3C do? The narrative in the .pdf manual does not give any explanation what is going on with these lines.

  • #2
    Originally posted by abecker
    what is going on with these lines.
    put simply timer1 = timer1 + 15527

    its a bog standard 16 bit addition of a 16 bit constant to a 16bit var on a 8 bit pic done in asm

    timer1 low byte = timer1 low + const low
    if result overflows (status,C) then inc timer1 high byte
    timer1 high= timer1 high + const high


    • #3
      In Chapter 7, Paragraph 7.6 toward the end, the topic introduces the process of slowing the timer (overflow) down by introducing a constant number of counts into the timer variable to adjust the time between overflows. It bases the value on some calculations which are shown.

      Is this the purpose of the Chapter 9 assembly code that I have identified in my initial post?


      • #4
        I believe I have determined the calculations that were used to set the tick duration:

        The value 15527 is added to TMR1 meaning that only 50,009 counts are now required for it to overflow to 65,536.

        The tutorial states that the instruction clock is used as the time base. The timer counts up at the rate of .000008 sec per count.

        With 50,000 counts per overflow * .000008 the result is that each tick = .4 sec.

        This is consistent with the way the trainer hardware behaves in that each led lights at this speed.

        Could someone confirm/dispute my conclusions?


        • #5
          You are correct, or would be if the Trainer Tutorial was correct. The chapter is in error in that it states the system clock is 4MHz, but it is actually 16MHz in the final version of the program file. (Unless I am confused about being confused.)

          The following paragraphs are corrected to show the actual times and frequencies:

          Bit 7-6 (Timer1 Clock Source Select bits) are set to 00, which selects the instruction clock as the clock source for
          Timer1. The instruction clock is the Oscillator Frequency divided by 4, noted in the Data Sheet as "Fosc/4". Since our
          Oscillator frequency is 16MHz (discussed above), the instruction clock is 4MHz.
          Bit 5-4 (Timer1 Input Clock Prescale Select bits) are set to 11, which selects the "1:8 Prescale value". This means that
          the timer will be incremented once for each 8 instruction clock cycles. Since the instruction clock runs at 4MHz, or four
          million cycles per second, the time for one clock cycle is 250 billionths of a second (250 nanoseconds, written as 250nS). If
          the timer increments on every eighth cycle, that means that the timer will increment once every 2uS. This is important
          for the sake of time calculations below.
          Your analysis is correct, except that the instruction clock is actually 4MHz and the timer counts up at a rate of one count every 2uS. I'm make sure to punish the guy who released the tutorial with that mistake in it.

          That means that an additional LED will light every 100mS.

          The Assembly code adds 15527 to the existing count in Timer1. Using addition, instead of a simple write-literal, is a technique used to compensate for those few instruction cycles that are consumed from the time the timer triggers the interrupt until the code actually stops the timer. I don't remember exactly, but I suspect that I tweaked the 15527 (hex 3CA7) value after testing and measuring with an oscilloscope.

          This is the program code (9-1_Timer1_Interrupt.pbp) I'm using for reference. I hope this is what ended up in the final release. The line 'INCLUDE "14-1_Init.pbp"' brings in the init code which sets the system clock to 16MHz.

          ' microEngineering Labs Trainer-1 Example Program
          ' Target microcontroller: PIC16F1937
          ' Include configuration and initialization code.  The included file must exist
          ' in the folder where this program is saved.
          INCLUDE "14-1_Init.pbp"     
          DEFINE INTHAND  ticker  ' Declare the name of the Assembly Language ISR
          red     VAR PORTE.0     ' name the red-dome drive pin
          OUTPUT red              ' make the red-dome drive pin an output
          tick1    VAR BYTE BANK0 ' Variable to hold the timer in 
          T1CON = %00110001     ' Enable Timer1 with prescale value 1:8
          PIE1 = %00000001      ' Timer1 interrupt enabled  
          INTCON = %11000000    ' global & peripheral interrupts enabled  
          GOTO main_loop
          ticker                ; Begin the Interrupt Service Routine
              clrf    BSR         ; Point to BANK0
              bcf     T1CON, 0    ; Stop Timer1
              movlw   0xA7        ; Load W with 0xA7
              addwf   TMR1L, F    ; Add preset value to TMR1 LSB
              btfsc   STATUS, 2   ; If no byte overflow, skip next instruction
              incf    TMR1H, F    ; If byte overflow, increment MSB of TMR1
              movlw   0x3C        ; Load W with 0x3C
              addwf   TMR1H, F    ; Add preset value to TMR1 MSB
              bsf     T1CON, 0    ; Start Timer1
              bcf     PIR1, TMR1IF    ; clear Timer1 interrupt flag
              incf    _tick1, F    ; increment tick variable
              retfie  ; Return (using automatic context-restore)
              IF PORTB.0 = 1 THEN     ' If the button is not pressed...
                  tick1 = 0           ' Reset the tick variable to zero
                  PORTA = 0         ' Turn off the LEDs
              ELSEIF (PORTB.0 = 0) AND (tick1 <= 7) THEN  ' If the button pressed and tick1 is less than 7   
                  PORTA.0[tick1] = 1    ' Turn on a single LED, position specified by tick1 variable
              ELSEIF (PORTB.0 = 0) AND (tick1 > 7) THEN   ' If button pressed and tick1 is greater than 7
                  DO WHILE tick1 < 50     ' loop here until tick1 reaches 51
                      red = 1             ' light the red dome
                  red = 0             ' after exiting from the loop, shut off the dome
          GOTO main_loop      ' Do it forever
          Charles Leo
          ME Labs, Inc.


          • #6

            Thanks for the explanation. When I initially studied the code I took into account the settings in the 14-1_Init.pbp which was INCLUDEd in the project code. I wondered why the 16MHz clock setting in the 14-1_Init file didn't square with the text explanation in the manual, but when I got to digesting the manual info. I had forgotten about the 16 MHz.

            In any case the 15,527 offset worked out OK when I ported the code over to my 16F72 clocked at 4MHz and I am happy to report that the lighting of the led's during the test was at such a speed that it was quite recognizable in the end.

            This exploration also introduced me to the assembly language technique of adding the "biasing" value to the 16 bit timer variable, a technique which appears to be a crucial method to make a successful interrupt when it is used as a program pacing application.

            My ultimate goal however is to take a "snapshot" of an input port to remember which pin caused the interrupt. That may or may not be something I do on a timed basis.