El AVR, como la mayoría de los microcontroladores, utiliza IO asignada en la memoria . En pocas palabras, esto significa que una parte del espacio de memoria del microcontrolador está reservado para los periféricos. Cuando cambia un poco en esta área de la memoria, no está enviando una señal para cambiar un poco de memoria, está enviando una señal para cambiar el valor de un periférico.
Para comprender los detalles de cómo funciona esto en su AVR, Registros de funciones especiales Se recomienda leer la sección de AVR-libc (y, lo que es más importante, sfr_defs.hy iom328p.h).
[Advertencia: Escritura técnica por delante, preste mucha atención] Por ejemplo, PORTB
se define como _SFR_IO8(0x05)
en iom328p.h
. En sfr_defs.h
, _SFR_IO8(io_addr)
se define como _MMIO_BYTE((io_addr) + __SFR_OFFSET)
. __SFR_OFFSET
es 0x20
, la ubicación justo después de los registros. El espacio después de esta dirección y antes de RAMSTART (0x100)
se usa para los periféricos. Volviendo a nuestro ejemplo, _MMIO_BYTE(mem_addr)
se define como (*(volatile uint8_t *)(mem_addr))
. Por lo tanto, cuando escribe PORTB
, realmente está escribiendo *(volatile uint8_t *)(0x25)
, que define un puntero de byte a la ubicación en la memoria 0x25
. [/ Advertencia]
Entonces, cuando (en C) escribes PORTB | = 0x01, realmente estás escribiendo el valor 1 en el periférico en el byte 0x25, o el puerto B pin 0. Si este pin está configurado como salida (usando DDRB, que está en 0x24), PORTB | = 0x01 hará que el pin 0 del puerto B pase a nivel alto. ¡Uf!
Por lo tanto, si usa las instrucciones de ensamblaje (SBI - Establecer bit en el registro de E / S):
sbi 0x24,1 ;Data direction set to output
sbi 0x25,1 ;Set port B pin 0 high
Pondrás el pin alto.
Por supuesto, use el ensamblador en línea con GCC y #include <avr/io.h>
para obtener los nombres convencionales y simplificar su tarea.
Tenga en cuenta que todos de los periféricos usan este esquema, no solo los pines IO. Lea iom328p.h si está interesado en las ubicaciones de otros periféricos.