ATMega 16 project help

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good afternoon everyone! I'm a new member and I'm currently learning programming in AVR studio for ATMega16. I've been assigned a project, which is probably very easy for you guys, but I'm struggling as I'm new to this world.

 

For starters, I'd need help with timers. There are several timers that I need to use in the project (for example, 3 seconds, 30 seconds, 45 seconds, 60 seconds..). I've been browsing the internet and I found a bunch of stuff so I'm getting quite lost. I just need a simple timer that counts to 30 seconds, for example. 

 

If anyone can help, link me to an example, or so, I'd be grateful! :) Also, sorry if I missed the subforum.

 

Cheers! :)

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You only need one timer. Perhaps set it to "tick" 10 or 100 times a second. At 10 per second then you know 3 seconds have elapsed after 30 ticks, 45 seconds after 450 ticks and so on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yea, that's a good idea, that's what I'm planning to do. However, I'm having problems with assembling it (writing the code down), because I've just recently started doing the project, and there is barely any literature given. Are there any code examples that do the exactly same thing?

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to AVR Freaks!

 

Your question has several layers to it. First, the top layer, maybe.

 

I would start out with a 1 second timer. Every time it "rolls over", it will produce a "tick". You can simply count ticks in simple software variables to get your other intervals (3 seconds, and such). One variable for each time interval. This is defines the "architecture" of the solution.

 

So, how do you get those 1 second ticks? That will depend on a number of things including the required accuracy and the clock rates available. Are you using a 32.768KHz crystal, for example. Or, do you only have the native internal oscillator or do you have an external crystal. 

 

Once you tell us a bit more about some of these hardware details, a few sensible hints can be given.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Jim and thanks for the answer!

 

As far as I know, I have available external crystal oscillator, but I assume I am free to use the internal oscillator. I don't know so much about oscillators either - We're doing it on EasyAvr5 board, if that helps.

 

Washo

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The schematic shows an on-board 8MHz crystal oscillator (external to the MCU). So, you have the option of using the rare true "External Oscillator" fuse setting or using the internal oscillator. I'm not familiar with the Mega32, specifically, so I will bow out here.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to the forum!

Spend some time in the tutorial forum studying how to use the timers and other features of the AVR.

Then begin by writing down what you want your project to do at a high level.

Once that is done you can divide the project down in to manageable parts and add some detail.

Ask for help where you get stuck.

 

Good luck and have fun

 

Jim (no not all freaks are named Jim, but it helps)

 

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Washoe:

 

What language do you use? Asm or C?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Visovian,

 

we use the assembler.

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Example of 3 counters using Timer1.

Simple code, without interrupts.

; Atmega16, 8 MHz

.include "M16DEF.INC"

.def counter_2sec  = r17
.def counter_5sec  = r18
.def counter_10sec = r19

;----------------------------

.cseg

    ;init stack
    ldi r16,low(RAMEND)
    out SPL,r16
    ldi R16,high(RAMEND)
    out SPH,r16

    ;init ports
    ldi R16, 0xff
    out DDRB,R16   ;portb output

    ;init timer1
    clr         r16
    out TCCR1A, r16;
    ldi r16,    (1<<CS12)            ; set bit TCCR1B.CS12 -> prescaler = 256
    out TCCR1B, r16               ; 

    ; how many timer ticks do we need for 1 sec?
    ; ticks = time[sec] *  F_CPU[Hz] / prescaler = 1 * 8000000 / 256 = 31250
    ; timer1 max value = 0xffff (65535 ticks), then it overflows to 0 (the 16bit value of timer1 is in 8bit registers TCNT1H:TCNT1L)
    ; we need it to overflow after 31250 ticks, so let us preset the timer value to 0xffff - 31250
    ldi r16,    high(0xff-31250) 
    out TCNT1H, r16
    ldi r16,    low(0xff-31250) 
    out TCNT1L, r16              ;now timer overflows after 1 second

    clr counter_2sec    
    clr counter_5sec    
    clr counter_10sec
;-------------------------------------------------------------

Mainloop: 
  
    ; test if timer1 overflow flag (bit TIFR.TOV1) is set
    in   r16, TIFR
    sbrs r16, TOV1  ; skip if flag set
    rjmp End        
  
    ; if (timer1 overflowed)  then
    ; preload timer
    ldi r16,    high(0xff-31250) 
    out TCNT1H, r16
    ldi r16,    low(0xff-31250) 
    out TCNT1L, r16

    ldi r16,    (1<<TOV1) ; clear overflow flag ( writting '1' to the flag! )
    out TIFR,   r16

    inc counter_2sec     ; increment all counters
    inc counter_5sec
    inc counter_10sec
     
    cpi counter_2sec, 2  ; 2 sec elapsed? 
    brne M2              ; no, goto M2
    call Toggle_PB0      ; yes
    clr counter_2sec

M2: 
    cpi counter_5sec, 5  
    brne M3  
    call Toggle_PB1      ;after 5 overflows (every 5 sec)
    clr counter_5sec

M3:
    cpi counter_10sec, 10
    brne End  
    call Toggle_PB2
    clr counter_10sec
    
    ; endif (timer1 overflowed)
    


End:    

rjmp Mainloop

;-------------------------------------------------------------
; put Led's on PB0,1,2

Toggle_PB0:       ; PORTB = PORTB xor 1 
    ldi r20,1        
    in r16,PORTB
    eor r16,r20     
    out PORTB,r16
ret

;------------------------
Toggle_PB1:
    ;code
ret

;------------------------
Toggle_PB2:
    ;code
ret

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey Visovian, you've really helped me enormously. Now that you write it, I understand almost everything, but it would be very hard for me to re-write it (same when you're learning some language like German e.g., you can understand it at the beginning, but can't talk much :D)

 

I have a question - if I wanted to set prescaler on 1024, that would mean that I need to set bit CS10 to 1 as well. Can you tell me how do I add that?

 

Also, if I have to add values like, 45 seconds, 60 seconds, does that require some special code fixing, or I can do it in a simple way, like this, just other numbers?

 

And third, what happens with LEDs, do they light or not - (couldn't clearly ready it out)? Ideally, I would like to have LED(s) light until it counts down till 10 seconds. Like, LED is on, once it reaches 10 seconds, LED is off. 

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To change to /1024 I'm guessing:

   ldi r16,    (1<<CS12)            ; set bit TCCR1B.CS12 -> prescaler = 256

would become:

   ldi r16,    (1<<CS12) | (1<<CS10)            ; set bit TCCR1B.CS12 and CS10 -> prescaler = 1024

The key thing here is actually learning something more like C than Asm. The << operator in C (and this assembler as it happens) means "shift the thing on the left by as many bit positions as given on the right". So 1 << n means "put a 1 bit at n bits into the byte". So if you want to set bit 3 you use (1 << 3) and so on. CS12 is probably defined as 2 in fact as the CS2/1/0 bits tend to be the bottom 3 bit (2, 1 and 0) in the control byte for the timer. So equally CS10 is probably defined as 0 and therefore (1 << 0) means "a bit bit in position 0". Finally once you have "a one bit in position 2" and "a one bit in position 0" the way you "glue them together" is using the OR operation which in C is denoted by the | symbol and this assembler uses the same. So "(1 << CS12)  | (1 << CS10)" means 00000101 in binary. In decimal (or hex) that would be 5 so I guess you could have just used:

   ldi r16,    5            ; set bit TCCR1B.CS12 and CS10 -> prescaler = 1024

or, of the assembler will accept the syntax even:

   ldi r16,    0b101            ; set bit TCCR1B.CS12 and CS10 -> prescaler = 1024

to give it in binary. Perhaps even

   ldi r16,    0b00000101            ; set bit TCCR1B.CS12 and CS10 -> prescaler = 1024

which is sometimes easier to read. But most folks prefer the (1 << name) style because when you later do something like:

ldi r16, (1 << ADIE) | (1 << ADATE)
out ADCSRA, r16

that would be much more documentary to the reader ("I'm setting the ADIE and ADATE bits") than just seeing something like:

ldi r16, 0b01000010
out ADCSRA, r16

which says nothing about which two bits are being set.

 

Oh and sometimes, when you are setting a "group" of bits (like the CS bits for a timer) some folks prefer the form:

ldi r16, (5 << CS10)

which says "move the complete group of bits represented by 5 to have their right hand end based on the CS10 bit position"

Last Edited: Mon. Jun 11, 2018 - 01:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey clawson, now I finally understand the game revolving around few different types of doing the exactly same thing. I finally understand the << meaning :) Thank you very much. I haven't been able to find that in our given literature (professor's skimpy power-point presentations), so I can say I learned something new :)

 

I will leave this open for the other 2 questions I wrote down. Also, I might have some more questions about the project in the future (timers are just 1 part, although a big one), so I'll keep this topic open. Thanks again!

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you really being taught Asm before a higher level language like C? It's a curious approach. It's true that a lot of us (because of history and the way things were 20, 30, 40+ years ago) did actually learn/use Asm first and I suppose it is "closer to the hardware" but I'm not sure that order of doing things is so relevant these days. Generally you program in a high (sometimes very high) level language and you only dip down into Asm when you hit something really tricky - so it tends to be an advanced thing you can leave to learn later. Among other things that means you almost certainly know what (1 << ) and '|' are all about before you hit the Asm.

Washoe wrote:
Also, if I have to add values like, 45 seconds, 60 seconds, does that require some special code fixing, or I can do it in a simple way, like this, just other numbers?
Well his example code showed you 2, 5 and 10 second timers. You either add to those to have 45 and 60 as well or perhaps you can simply re-use one of those by changing 5 to 45 or whatever? (but if you do that do take time out to rename counter_5sec to be counter_45sec so a later reader of this code (could be you!) will not be confused by a counter that is named as if it is for 5 seconds but is really being used for 45 seconds!
Washoe wrote:
And third, what happens with LEDs, do they light or not - (couldn't clearly ready it out)?
There's a clue in the name he used! The things that are being triggered after 2, 5 or 10 seconds are called "Toggle_PBx". That means that each time the LED switches state, so if it was off (the default state for output bits probably) it will turn on and if it was on it will turn off. He only included the code to do that toggling for one (PB0), he's left it as an exercise for you to implement the other ";code". The toggling is done with EOR. that is Exclusive OR. When you EOR a bit with 1 then it switches state, so 1 becomes 0 and 0 becomes 1. In other words:

1 EOR 0 = 1
1 EOR 1 = 0

He's putting the 1 in the lowest bit of R20 and then EORing this with whatever was in "PORTB" (read to R16) then writing this back to PORTB.

 

Of course it can depend how you have your LEDs wired too. Sometimes 0 means "on" and 1 means "off" rather than the more usual 1 = "on" and 0 = "off".

Washoe wrote:
Like, LED is on, once it reaches 10 seconds, LED is off.
So in the init code (the bit before the main loop) you not only set the output port(s) to be "output" but you also set the LED control bits to the "on" position. Then continue to have the timer do a "toggle" when the time is reached. So if it was on it now turns off and so on. Of course another 10 seconds later it will tun one again for another ten seconds and so on. If you don't want that pattern to repeat (IOW a "one-shot" then when the even occurs you need to do something to say "and now stop ticking this timer". You could, for example have a special value you put into the counter to say "timer not running" like 0xFF perhaps (aka -1). When at the the point you increment the timers you first test any to see f they already hold 0xFF and if they do you skip the increment. So that one will never "tick" again. (except that in another timer, or perhaps as a result of some other event, you might at some stage change the 0xFF (don't count) marker back to 0 so the timer restarts its counting pattern.

 

It's a good idea to plan out things like that on paper first so you have an idea of how you are going to do things - then only write the code once you have a clear plan.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I'm currently on 4th year, and we had some programming - basics - in C on 1st year. Since I'm NOT studying programming/computing, but electrical energy stuff (energy transmission, energy sources, various machines, etc...), this is quite hard for me. This subject we have is an "exception" in our curriculum and should be on a very basic level, but is, sadly much more difficult than the "required" subjects we have.

 

Back on topic, yes, I understand you clawson and I think I'll be able to do that on my own. That's something I can do with my very basic knowledge, but things like timers, I couldn't. 

 

I'll leave this open for potential questions, if that's okay with the forum rules. Once I complete things with timers, I will need to do something like: Read value from potentiometer (analog input), and display it on LED display. I presume that'll require some more help, but I haven't reached there yet.

 

Thank you!

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Check this video its easy and explained very neatly. Good Luck!!!

https://www.youtube.com/watch?v=...

Electronics Student

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have another question, related to the code Visovian wrote. When I run the program, it goes into endless loop from here:

 

Mainloop: 

 
    ; test if timer1 overflow flag (bit TIFR.TOV1) is set
    in   r16, TIFR
    sbrs r16, TOV1  ; skip if flag set
    rjmp End   

 

To here:

 

End:    

rjmp Mainloop

 

I've ran it for 2200 cycles and it still goes there. Now, should I run it for 30k cycles to get one second, or? I'm a little bit confused.

 

Cheers!

~ Washo ~

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it's really a second then in simulation (because it is astronomically slow compared to a real AVR) it could take minutes before something happens. So either use patience or, perhaps a better idea, for simulation adjust the CS selection (presumably CS10) so the timer runs much faster.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yea, I set it to prescaler 1024. Now it takes cca 7k ticks - I presume, after cycle counter reaches 7000, the program should move down?

 

EDIT: I tested and it doesn't really happen. The rest of the program works flawlessly. Maybe I'm missing something because I'm a real noob xD

 

EDIT2: Nevermind, it WORKS. Begginer mistakes :)

~ Washo ~

Last Edited: Wed. Jun 13, 2018 - 09:43 AM