Assembler timer

Discussion in 'Homework Help' started by TwoPlusTwo, Dec 4, 2010.

  1. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Hi, I am trying to write a program for a timer. The operation is given as follows:

    - The diodes show the number of seconds/minutes elapsed since start/restart.

    - By pressing Switch2 the diodes show the number of minutes.

    - By pressing Switch3 the diodes show the number of seconds.

    - After 60 minutes the timer is reset.

    I am pretty much a complete beginner when it comes to Assembler programming, so I feel like this is way out of my league. But I think I figured out which registers to set at least. And I also know that I need to set the program up for interrupts and initialize the stack pointer. The following is what I have so far.

    .include "M32def.inc"
    .def temp=R16

    .org 0 jmp start
    .org 2 jmp Sw2
    .org 4 jmp Sw3

    start:
    ;---PortB as out-port---
    ldi temp, 0xFF
    out DDRB, temp

    ;---Initialize for interrupts INT0 and INT1---
    ldi temp, 0xC0
    out GICR, temp ; set bits 6 and 7 to enable interrupts from INT0 and INT1
    ldi temp, 0x0A
    out MCUCR, temp ;set bits 3 and 1 to trigger interrupts when the switches are pressed down

    ;---other registers---
    ldi temp, 0x0B
    out TCCR1B, temp ; count frequency = 65.5k (0xF424)
    ldi temp, 0xF4
    out OCR1AH, temp
    ldi temp, 0x24
    out OCR1AL, temp ; interrupt every second, when the contents of the count registers
    ldi temp, 0x0f ; is equal to the "output compare" registers.
    out TIMSK, temp ; set bit 4 to enable Timer1 CompA match interrupt.

    ;---Initialize stack pointer-----
    ldi temp, HIGH (RAMEND)
    out sph, temp
    ldi temp, LOW (RAMEND)
    out spl, temp

    sei ; global interrupt enable

    Of course, I have neither the main program nor the two subroutines. Is what I have so far correct, though? And how should I approach writing the stuff that I'm missing?

    Bit of a long question here, but hopefully someone who knows this stuff can give me a few pointers.

    Thanks!
     
    Last edited: Dec 12, 2010
  2. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Code ( (Unknown Language)):
    1. .include "M32def.inc"
    2. def temp=R16  ;[COLOR=red] Should be .def not def....[/COLOR]
    3.  
    4. .org 0 jmp start
    5. .org 2 jmp Sw2
    6. .org 4 jmp Sw3
    7.  
    8. start:
    9. ---PortB as out-port---  [COLOR=red]; comments must begin with a semicolon...[/COLOR]
    10. ldi temp, 0xFF
    11. out DDRB, temp
    12.  
    13. ---Initialize for interrupts INT0 and INT1---
    14. ldi temp, 0xC0
    15. out GICR, temp
    16. ldi temp, 0x08
    17. out MCUCR, temp
    18.  
    19. ---Set other registers---
    20. ldi temp, 0x0B
    21. out TCCRIB, temp  [COLOR=red]; The label should be TCCR1B not TCCRIB....[/COLOR]
    22. ldi temp, 0xF4
    23. out OCRIAH, temp [COLOR=red]; The label should be OCR1AH not OCRIAH...[/COLOR]
    24. ldi temp, ox24  [COLOR=red]; The hex constant should be 0x24 not ox24...[/COLOR]
    25. out OCRIAL, temp  [COLOR=red]; The label should be OCR1AL not OCRIAL..[/COLOR]
    26.  
    27. ---Stack-pointer-----
    28. ldi temp, 0x02
    29. out sph, temp
    30. ldi temp, 0x5F
    31. out spl, temp
    32.  
    33. sei
    34.  
    35.  
    Some edits that you need among others....

    hgmjr
     
    Last edited: Dec 4, 2010
  3. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Thanks a lot! I edited the original post to fix these things.
     
  4. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Code ( (Unknown Language)):
    1. .include "M32def.inc"
    2. def temp=R16  ;[COLOR=red] Should be .def not def....[/COLOR]
    3.  
    4. .org 0 jmp start
    5. .org 2 jmp Sw2
    6. .org 4 jmp Sw3
    7.  
    8. start:
    9. ---PortB as out-port---  [COLOR=red]; comments must begin with a semicolon...[/COLOR]
    10. ldi temp, 0xFF
    11. out DDRB, temp
    12.  
    13. ---Initialize for interrupts INT0 and INT1---
    14. ldi temp, 0xC0
    15. out GICR, temp
    16. ldi temp, 0x08
    17. out MCUCR, temp
    18.  
    19. ---Set other registers---
    20. ldi temp, 0x0B
    21. out TCCRIB, temp  [COLOR=red]; The label should be TCCR1B not TCCRIB....[/COLOR]
    22. ldi temp, 0xF4
    23. out OCRIAH, temp [COLOR=red]; The label should be OCR1AH not OCRIAH...[/COLOR]
    24. ldi temp, ox24  [COLOR=red]; The hex constant should be 0x24 not ox24...[/COLOR]
    25. out OCRIAL, temp  [COLOR=red]; The label should be OCR1AL not OCRIAL..[/COLOR]
    26.  
    27. ---Stack-pointer-----
    28. ldi temp, [COLOR=red]HIGH(RAMEND)  ; This method is AVR micro non-specific...[/COLOR]
    29. out sph, temp
    30. ldi temp, [COLOR=red]LOW(RAMEND) ; This method is AVR micro non-specific...[/COLOR]
    31. out spl, temp
    32.  
    33. sei
    34.  
    35.  

    Added changes to the initialization of the stack pointer that can be used
    across all members of the AVR family.

    hgmjr
     
  5. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Updates made!
     
  6. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    I didn't have time to work any more on this last week, but I really want to finish it now. I've drawn the flow chart that we were given and attached it. I also added some more comments to the original sketch.

    My thinking now goes like this:

    Now that I have an interrupt every second, I need to define a register (sec) that counts those interrupts. It needs to be reset at 60 seconds, and increment another minute counting register (min) everytime that happens. Is this correct?

    Next, I need to write the subroutine like the flow chart indicates, sending the contents of sec and min to PortB when their respective switches have been pressed.

    In the flow chart there is also a register called showmin. I'm guessing this is controlled by the switches, where one makes it go high and the other makes it go low. So that when the switches activate the subroutine, it can start by comparing the value of showmin to 0 and then select the appropriate way to go. For that I need to use the breq command.

    If all this is right, I need to know how to increment the sec counting register every time there is a CompA match interrupt. And also how to make that register count only to 60 and increment the minute counting register every time it overflows.
     
    Last edited: Dec 12, 2010
  7. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Here is a flow chart for an interrupt routine for updating the timer. I'll try write it out, and hopefully I can get some feedback on whether or not I got it right.
     
    Last edited: Dec 12, 2010
  8. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Here's my attempt. How does it look?

    sub:
    push temp
    in temp, sreg
    push temp

    inc sec
    cpi sec, 60
    breq minute

    End:
    pop temp
    out sreg, sreg
    pop temp

    minute:
    inc min
    clr sec
    cpi min, 60
    breq End
    clr min
    rjmp End

    ret
     
  9. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Allow me to suggest a change in the strategy used.

    It is always a good idea to keep the amount of time spent inside an interrupt service routine to an absolute minimum.

    How about if you simply use the interrupt service routine to increment a memory location once every second and then write your code for testing secs and mins in your main loop.

    hgmjr
     
  10. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    I think maybe this is what the flow charts we were given suggests as well. I could have a loop that goes something like this:

    loop:
    cpi showmin, 0
    breq displaysec
    cli
    out min, PortB
    sei

    displaysec:
    cli
    out sec, PortB
    sei

    And let the value of showmin be determined by which switch has been pressed.

    That's how I understand the flow chart at least. Not sure I get why I have to disable interrupts (cli) and enable them again (sei) though.
     
  11. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Here is your code encloded in code tags. These tags are indicated by the # sign up in the post edit feature.

    hgmjr
     
  12. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Ok, so I tried putting it all together. How does it look? Maybe I shouldn't keep so much of the program in the subroutines, but I think that is what I'm asked to do. I really appreciate your help so far, hgmjr. You're a life saver!

    Code ( (Unknown Language)):
    1. .include "M32def.inc"
    2. .def temp=R16
    3. .def seconds=R17
    4. .def min=R18
    5. .def showmin=R19
    6.  
    7. .org 0 jmp start
    8. .org 2 jmp Sw2
    9. .org 4 jmp Sw3
    10. .org 0x0C count
    11. .org 0x2A
    12.  
    13. start:
    14. ;---PortB as out-port---
    15. ldi temp, 0xFF
    16. out DDRB, temp
    17.  
    18. ;---Initialize for interrupts INT0 and INT1---
    19. ldi temp, 0xC0
    20. out GICR, temp   ; set bits 6 and 7 to enable interrupts from INT0 and INT1
    21. ldi temp, 0x0A      
    22. out MCUCR, temp  ;set bits 3 and 1 to trigger interrupts when the switches are pressed down
    23.  
    24. ;---Other registers---
    25. ldi temp, 0x0B
    26. out TCCR1B, temp   ; count frequency = 65.5k (0xF424)
    27. ldi temp, 0xF4
    28. out OCR1AH, temp  
    29. ldi temp, 0x24        
    30. out OCR1AL, temp  ; interrupt every second, when the contents of the count registers
    31. ldi temp, 0x0f     ; is equal to the "output compare" registers.
    32. out TIMSK, temp    ; set bit 4 to enable Timer1 CompA match interrupt.
    33.  
    34. ;---Initialize stack pointer-----
    35. ldi temp, HIGH (RAMEND)
    36. out sph, temp
    37. ldi temp, LOW (RAMEND)
    38. out spl, temp
    39.  
    40. sei   ; global interrupt enable
    41.  
    42. ;---Switches---
    43. Sw2:
    44. clr showmin
    45. reti
    46.  
    47. Sw3:
    48. ldi showmin, 0xff
    49. reti
    50.  
    51. ;---Show on diodes---
    52. loop:
    53. cpi showmin, 0
    54. breq showsec
    55. cli
    56. out min, PortB
    57. sei
    58. rjmp loop
    59.  
    60. showsec:
    61. cli
    62. out seconds, PortB
    63. sei
    64. rjmp loop
    65.  
    66. ;---Seconds and minutes---
    67. count:
    68. push temp
    69. in temp, sreg
    70. push temp
    71.  
    72. inc seconds
    73. cpi seconds, 60
    74. breq minute
    75.  
    76. end:
    77. pop temp
    78. out sreg, sreg
    79. pop temp
    80. reti
    81.  
    82. minute:
    83. inc min
    84. clr seconds
    85. cpi min, 60
    86. breq end
    87. clr min
    88. rjmp end
     
    Last edited: Dec 12, 2010
  13. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Give me a bit of time to digest your program.

    hgmjr
     
  14. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    A couple of things that I have encountered immediately are:

    1. You cannot use sec as a variable since it is a keyword.
    2. There are a couple of other syntax errors.

    hgmjr
     
  15. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Ok, thanks. I changed it to seconds.
     
  16. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Take a look at your statement for your timer1 interrupt vector. You will notice that it set up for the incorrect vector 0xC. OxC corresponds to the ICP (input capture interrupt).

    By the way, do you already have the hardware set so that you can test your program?

    hgmjr
     
  17. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    oops, it was supposed to be 0x0C, not 0xC. I don't have the hardware at home, but I'll be able to test the program at my school lab the next time I'm there.
     
  18. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    The vector table entry for timer1 is not 0x0c.

    I noticed that the output to PORTB for minutes and seconds is in binary format. Is the intent to express them in BCD instead?

    hgmjr
     
  19. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Code ( (Unknown Language)):
    1. .include "M32def.inc"
    2. .def temp  =R16
    3. [COLOR=red].def seconds =R17[/COLOR]
    4. .def min  =R18
    5. .def showmin =R19
    6.  
    7. .org 0
    8. [COLOR=red]jmp start[/COLOR]
    9. [COLOR=red].org INT0addr[/COLOR]
    10. [COLOR=red]jmp Sw2[/COLOR]
    11. [COLOR=red].org INT1addr [/COLOR]
    12. [COLOR=red]jmp Sw3[/COLOR]
    13. [COLOR=red].org OC1Aaddr [/COLOR]
    14. [COLOR=red]jmp count[/COLOR]
    15.  
    16. .[COLOR=red]org INT_VECTORS_SIZE  // Set the start of executable code at the end of the interrupt table... [/COLOR]
    17. start:
    18. ;---PortB as out-port---
    19.  ldi temp, 0xFF
    20.  out DDRB, temp
    21. ;---Initialize for interrupts INT0 and INT1---
    22.  ldi temp, 0xC0
    23.  out GICR, temp   ; set bits 6 and 7 to enable interrupts from INT0 and INT1
    24.  ldi temp, 0x0A      
    25.  out MCUCR, temp  ;set bits 3 and 1 to trigger interrupts when the switches are pressed down
    26. ;---Other registers---
    27.  ldi temp, 0x0B
    28.  out TCCR1B, temp   ; count frequency = 65.5k (0xF424)
    29.  ldi temp, 0xF4
    30.  out OCR1AH, temp  
    31.  ldi temp, 0x24        
    32.  out OCR1AL, temp  ; interrupt every second, when the contents of the count registers
    33.  ldi temp, 0x0f     ; is equal to the "output compare" registers.
    34.  out TIMSK, temp    ; set bit 4 to enable Timer1 CompA match interrupt.
    35. ;---Initialize stack pointer-----
    36.  ldi temp, HIGH (RAMEND)
    37.  out sph, temp
    38.  ldi temp, LOW (RAMEND)
    39.  out spl, temp
    40.  sei   ; global interrupt enable
    41. [COLOR=red]rjmp loop ; This jump jumps around the two interrupt service routines...[/COLOR]
    42. ;---Switches---
    43. Sw2:
    44.  clr showmin
    45.  reti
    46. Sw3:
    47.  ldi showmin, 0xff
    48.  reti
    49. ;---Show on diodes---
    50. loop:
    51.  cpi showmin, 0
    52.  breq showsec
    53.  cli
    54. [COLOR=red]out PortB, min  ; Corrected syntrax error...[/COLOR]
    55.  sei
    56.  rjmp loop
    57.  
    58. showsec:
    59.  cli
    60. [COLOR=red]out PORTB, seconds    ; Corrected syntrax error...[/COLOR]
    61.  sei
    62.  rjmp loop
    63.  
    64. ;---Seconds and minutes---
    65. count:
    66.  push temp
    67.  in temp, sreg
    68.  push temp
    69.  inc seconds
    70.  cpi seconds, 60
    71.  breq minute
    72. end:
    73.  pop temp
    74.  out sreg, temp
    75.  pop temp
    76.  reti
    77. minute:
    78.  inc min
    79.  clr seconds
    80.  cpi min, 60
    81.  breq end
    82.  clr min
    83.  rjmp end
    84.  
    Assuming that this is your first effort, I commend you. Assembly Language is not a easy language to pick up. It appeals to programmers who like the low level control it provides. It also allows you to write the tightest code possible.

    Here is my early corrective effort. There may still be some tweaks needed but it is pretty close.

    You will notice that I make liberal use of labels rather than using what are referred to in the programming world as "MAGIC" values. You can get the labels by looking in the include file where they are defined. I highlighted in red lines that I touched.

    hgmjr
     
  20. TwoPlusTwo

    Thread Starter Member

    Oct 14, 2010
    51
    0
    Actually, the assignment is to display the time in binary form on the diodes, which makes it a pretty useless clock in real life, unless the person who operates it is some sort of binary savant:D

    I looked over your corrections and they all pretty much make sense to me. I might have been using the wrong table from my course book when I set the interrupt vectors, so in the future I'll make sure to just use the include file in stead. The labels in there are definitely much easier to relate to than a bunch of hex numbers.

    And again, thank you so much for taking the time to go over my work. You and the other contributors to the forum are doing a great thing helping all of us rookies. I hope to be able to contribute the same way when I get better. Until then I'm probably just going to keep asking lots of questions:D
     
Loading...