Currently, and for good reason, people dont do this in assembly much anymore. Most stuff can easily be done in other programming languages, like C. Maybe you want to look at Arduino (arduino.cc)
To learn more about hardware programming the AVR, you may want to look into any of the excellent books available on the topic, although most literature features C as a language. Most of the C oriented books will give you good hints at the programming. You may then use that in assembler.
Of course, you should also look at the papers at Atmel. They have an extensive library online.
Imho, unless you've proven C is not sufficient for your needs, you sould try that, and see how far you get.
Apart from that, Barrett "Atmel AVR Microcontroller Primer" has a decend description of the registers.
The AVR, like most microcontrollers, uses memory-mapped IO. In a nutshell, this means that a part of the memory space of the microcontroller is reserved for the peripherals. When you change a bit in this area of memory, you're not sending a signal to change a bit of memory, you're sending a signal to change the value of a peripheral.
To understand the details of how this works on your AVR, the Special Function Registers section of AVR-libc (and, more importantly, sfr_defs.h and iom328p.h) are recommended reading.
[Warning: Technical writing ahead, pay close attention] For example, PORTB
is defined as _SFR_IO8(0x05)
in iom328p.h
. In sfr_defs.h
, _SFR_IO8(io_addr)
is defined as _MMIO_BYTE((io_addr) + __SFR_OFFSET)
. __SFR_OFFSET
is 0x20
, the location just after the registers. The space after this address and before RAMSTART (0x100)
is used for the peripherals. Going back to our example, _MMIO_BYTE(mem_addr)
is defined as (*(volatile uint8_t *)(mem_addr))
. Therefore, when you write PORTB
, you're really writing *(volatile uint8_t *)(0x25)
, which defines a byte-wide pointer to the location in memory 0x25
. [/Warning]
So, when (in C) you write PORTB |= 0x01, you're really writing the value 1 to the peripheral at byte 0x25, or port B pin 0. If this pin is configured as output (using DDRB, which is at 0x24), PORTB |= 0x01 will cause port B pin 0 to go high. Phew!
So, if you use the assembly instructions (SBI - Set Bit in I/O Register):
sbi 0x24,1 ;Data direction set to output
sbi 0x25,1 ;Set port B pin 0 high
You'll set the pin high.
Of course, use inline assembler with GCC and #include <avr/io.h>
to get the conventional names and simplify your task.
Note that all of the peripherals use this scheme, not just the IO pins. Read iom328p.h if you're interested in the locations of other peripherals.
Best Answer
To divide by two:
LSR r4 which push b0 to to carry b1 to b0, ... b7 to b6 and zero to b7
ROR r5 which will push b0 to to carry b1 to b0, ... b7 to b6 and carry that is the b0 from r4 to b7
To divide by 4 use the sequence twice
LSL is used for multiplication.
The pictures are from Microchip Website AVR Assembler Instructions