Регистры общего назначения.
Организация памяти.
В микроконтроллерах AVR семейства Mega реализована Гарвардская архитектура, в соответствии с которой разделены не только адресные пространства памяти программ и памяти данных, но также и шины доступа к ним. Способы адресации и доступа к этим областям памяти также различны. Такая структура позволяет центральному процессору работать одновременно как с памятью программ, так и с памятью данных, что существенно увеличивает производительность. Каждая из областей памяти данных (ОЗУ и EEPROM) также расположена в своем адресном пространстве.
Обобщенная карта памяти микроконтроллеров AVR семейства Mega приведена на следующем рисунке. Обратите внимание на следующее. Поскольку микроконтроллеры AVRимеют 16-битную систему команд, объем памяти программ на рисунке указан не в байтах, а в 16-битных словах. Символ «$» перед числом означает, что это число записано в шестнадцатеричной системе счисления.
Карта памяти микроконтроллеров семейства Mega
Память программ.
Память программ предназначена для хранения команд, управляющих работой микроконтроллера. Память программ также часто используется для хранения таблиц констант, не меняющихся во время работы программы.
Память программ представляет собой электрически стираемое ППЗУ (FLASH-ПЗУ). В связи с тем, что длина всех команд кратна одному слову (16 бит), память программ имеет 16-битную организацию. Соответственно, объем памяти микроконтроллеров семейства составляет от 4К (4x1024) до 64К (64x1024) 16-битных слов. В подавляющем большинстве моделей микроконтроллеров семейства Mega память программ логически разделена на две неравные части: область прикладной программы и область загрузчика. В последней может располагаться специальная программа (загрузчик), позволяющая микроконтроллеру самостоятельно управлять загрузкой и выгрузкой прикладных программ. Если же возможность самопрограммирования микроконтроллера не используется, прикладная программа может располагаться и в области загрузчика.
Для адресации памяти программ используется счетчик команд (Program Counter — PC). Размер счетчика команд составляет от 11 до 17 бит, в зависимости от объема адресуемой памяти.
По адресу $0000 памяти программ находится вектор сброса. После инициализации (сброса) микроконтроллера выполнение программы начинается с этого адреса (по этому адресу должна размещаться команда перехода к инициализационной части программы). Начиная с адреса $0001 (модели с памятью программ 8 Кбайт и меньше) или $0002 (остальные модели) памяти программ располагается таблица векторов прерываний. Размер этой области зависит от модели микроконтроллера.
При возникновении прерывания после сохранения в стеке текущего значения счетчика команд происходит выполнение команды, расположенной по адресу соответствующего вектора. Поэтому по данным адресам располагаются команды перехода к подпрограммам обработки прерываний. В моделях с памятью программ небольшого объема (8 Кбайт и менее) в таблицах векторов прерываний используются команды относительного перехода (rjmp), а в остальных моделях — команды абсолютного перехода (jmp).
В большинстве микроконтроллеров семейства Mega положение вектора сброса и/или таблицы векторов прерываний может быть изменено. Они могут располагаться не только в начале памяти программ, как описано выше, но и в начале области загрузчика.
Если в программе прерывания не используются либо таблица векторов прерываний располагается в области загрузчика, то основная программа может начинаться непосредственно с адреса $0001.
Как известно, память программ может использоваться не только для хранения кода программы, но также и для хранения различных констант. Для пересылки байта из памяти программ в память данных существуют две специальных команды — LPM и ELPM (последняя есть только в моделях, имеющих память программ 128 Кбайт и более). При использовании команды LPM адрес, по которому производится чтение, определяется содержимым индексного регистра Z. Приэтом старшие 15 битов содержимого регистра будут определять адрес слова (0...32К), младший бит будет определять, какой из байтов будет прочитан: 0 — младший байт, 1 — старший байт (см. рисунок -а). Команда ELPM, в отличие от команды LPM,способна адресовать до 16 Мбайт памяти. При использовании этой команды адрес слова будет определяться содержимым регистра ввода/вывода RAMPZ совместно со старшими 15 битами содержимого регистра Z. Младший бит регистра Z будет по-прежнему определять, какой из байтов слова будет прочитан (см. рисунок -б). Понятно, что количество задействованных битов регистра RAMPZ зависит от объема памяти программ — в моделях с объемом памяти программ 128 Кбайт используется только младший бит RAMPZ0, а в моделях с 256 Кбайт памяти используются уже два младших бита — RAMPZ1 и RAMPZ0. Для обеспечения совместимости с будущими моделями микроконтроллеров при записи значений в регистр RAMPZ незадействованные биты должны быть сброшены в 0.
Регистр RAMPZ расположен по адресу $3В ($5В) в основном пространстве регистров ввода/вывода микроконтроллеров ATmegal28x и ATmegal28xx/256xx, а его формат показан на следующем рисунке.
Косвенная адресация памяти программ
при использовании команды LPM (а) и команды ELPM (б)
Формат регистра RAMPZ
FLASH-ПЗУ, используемое в микроконтроллерах AVR, рассчитано, как минимум, на 10 000 циклов стирания/записи (типовое значение — 100 000 циклов).
Память данных.
Память данных микроконтроллеров семейства Mega разделена на три части: регистровая память, оперативная память (статическое ОЗУ) и энергонезависимое ЭСППЗУ (EEPROM).
Регистровая память включает 32 регистра общего назначения (РОН), объединенных в файл, и служебные регистры ввода/вывода (РВВ). В сложных моделях с развитой периферией имеется также область дополнительных (extended) регистров ввода/вывода (ДРВВ). Под РВВ в памяти микроконтроллера отводится 64 байта, а под ДРВВ — 160 или 416 байт (в зависимости от модели).
В обеих областях регистров ввода/вывода располагаются различные служебные регистры (регистр управления микроконтроллера, регистр состояния и т. п.), а также регистры управления периферийными устройствами, входящими в состав микроконтроллера. Общее количество РВВ и ДРВВ зависит от конкретной модели микроконтроллера.
Для хранения переменных помимо регистров общего назначения также используется статическое ОЗУ объемом от 512 байт до 8 Кбайт. Ряд микроконтроллеров семейства, кроме того, имеют возможность подключения внешнего статического ОЗУ объемом до 64 Кбайт.
Для долговременного хранения различной информации, которая может изменяться в процессе функционирования готовой системы (калибровочные константы, серийные номера, ключи и т. п.), в микроконтроллерах семейства может использоваться встроенная EEPROM-память. Ее объем составляет для различных моделей от 256 байт до 4 Кбайт. Эта память расположена в отдельном адресном пространстве, а доступ к ней осуществляется с помощью определенных РВВ.
Статическое ОЗУ.
В микроконтроллерах AVR семейства Mega используется линейная организация памяти. Объем статического ОЗУ для различных моделей семейства составляет от 512 байт до 8 Кбайт (см. предыдущую таблицу).
В адресном пространстве ОЗУ также расположены все регистры микроконтроллеров, под них отведены младшие 96 (256) адресов.Остальные адреса отведены под 512/1К/2К/4К...64К ячеек статического ОЗУ.
Организация статического ОЗУ
Регистры общего назначения.
Все регистры общего назначения объединены в регистровый файл быстрого доступа, структура которого показана на рисунке.В микроконтроллерах AVR все 32 РОН непосредственно доступны АЛУ, в отличие от 8-битных микроконтроллеров других фирм, в которых имеется только один такой регистр — рабочий регистр W (аккумулятор). Благодаря этому любой РОН может использоваться практически во всех командах и как операнд-источник, и как операнд-приемник. Такое решение (в сочетании с конвейерной обработкой) позволяет АЛУ выполнять одну операцию (извлечение операндов из регистрового файла, выполнение команды и запись результата обратно в регистровый файл) за один такт.
Структура регистрового файла
Последние 6 регистров файла (R26 ... R31) могут также объединяться в три 16-битных регистра X, Y и Z (см. рисунок),используемых в качестве указателей при косвенной адресации памяти данных.
Каждый регистр файла имеет свой собственный адрес в пространстве памяти данных. Поэтому к ним можно обращаться двумя способами — как к регистрам и как к памяти, несмотря на то, что физически эти регистры не являются ячейками ОЗУ. Такое решение является еще одной отличительной особенностью архитектуры AVR, повышающей эффективность работы микроконтроллера и его производительность.
Регистры ввода/вывода.
Все регистры ввода/вывода условно можно разделить на две группы: служебные регистры микроконтроллера и регистры, относящиеся к конкретным периферийным устройствам (в том числе регистры портов ввода/вывода).
Во всех микроконтроллерах AVR регистры ввода/вывода располагаются в так называемом пространстве ввода/вывода размером 64 байта. В большинстве моделей семейства Mega имеется также пространство дополнительных регистров ввода/вывода размером 160 или 416 байт. Введение дополнительных РВВ связано с тем, что для поддержки всех периферийных устройств, имеющихся в этих моделях, обычных 64-х РВВ недостаточно.
Распределение адресов пространства ввода/вывода (как основного, так и дополнительного) зависит от конкретной модели микроконтроллера или, если точнее, от состава и возможностей периферийных устройств данной модели. Размещение РВВ в пространстве ввода/вывода для всех моделей семейства, в качестве примера, приведено в таблице и в качестве библиотечного файла ниже.
В таблицах и далее при указании адресов РВВ в скобках указываются соответствующие им адреса ячеек ОЗУ. Соответственно, если адрес регистра указывается только в скобках, этот регистр расположен в пространстве дополнительных РВВ. Если адрес в таблице не указан, это означает, что для данной модели он зарезервирован, и запись по этому адресу запрещена (для совместимости с будущими моделями).
Регистры ввода/вывода моделей ATmega8515x
Регистры ввода/вывода моделей ATmega8515x (продолжение)
Назначение регистров ввода/вывода из библиотечного файла
// CodeVisionAVR C Compiler
// (C) 1998-2002 Pavel Haiduc, HP InfoTech S.R.L.
// I/O registers definitions for the ATmega8515(L)
#ifndef _MEGA8515_INCLUDED_
#define _MEGA8515_INCLUDED_
#pragma used+
sfrb OSCCAL=4;
sfrb PINE=5;
sfrb DDRE=6;
sfrb PORTE=7;
sfrb ACSR=8;
sfrb UBRRL=9;
sfrb UCSRB=0xa;
sfrb UCSRA=0xb;
sfrb UDR=0xc;
sfrb SPCR=0xd;
sfrb SPSR=0xe;
sfrb SPDR=0xf;
sfrb PIND=0x10;
sfrb DDRD=0x11;
sfrb PORTD=0x12;
sfrb PINC=0x13;
sfrb DDRC=0x14;
sfrb PORTC=0x15;
sfrb PINB=0x16;
sfrb DDRB=0x17;
sfrb PORTB=0x18;
sfrb PINA=0x19;
sfrb DDRA=0x1a;
sfrb PORTA=0x1b;
sfrb EECR=0x1c;
sfrb EEDR=0x1d;
sfrb EEARL=0x1e;
sfrb EEARH=0x1f;
sfrw EEAR=0x1e; // 16 bit access
sfrb UBRRH=0x20;
sfrb UCSRC=0x20;
sfrb WDTCR=0x21;
sfrb ICR1L=0x24;
sfrb ICR1H=0x25;
sfrw ICR1=0x24; // 16 bit access
sfrb OCR1BL=0x28;
sfrb OCR1BH=0x29;
sfrw OCR1B=0x28; // 16 bit access
sfrb OCR1AL=0x2a;
sfrb OCR1AH=0x2b;
sfrw OCR1A=0x2a; // 16 bit access
sfrb TCNT1L=0x2c;
sfrb TCNT1H=0x2d;
sfrw TCNT1=0x2c; // 16 bit access
sfrb TCCR1B=0x2e;
sfrb TCCR1A=0x2f;
sfrb SFIOR=0x30;
sfrb OCR0=0x31;
sfrb TCNT0=0x32;
sfrb TCCR0=0x33;
sfrb MCUCSR=0x34;
sfrb MCUCR=0x35;
sfrb EMCUCR=0x36;
sfrb SPMCR=0x37;
sfrb TIFR=0x38;
sfrb TIMSK=0x39;
sfrb GIFR=0x3a;
sfrb GICR=0x3b;
sfrb SPL=0x3d;
sfrb SPH=0x3e;
sfrb SREG=0x3f;
#pragma used-
// Interrupt vectors definitions
#define EXT_INT0 2
#define EXT_INT1 3
#define TIM1_CAPT 4
#define TIM1_COMPA 5
#define TIM1_COMPB 6
#define TIM1_OVF 7
#define TIM0_OVF 8
#define SPI_STC 9
#define USART_RXC 10
#define USART_UDRE 11
#define USART_TXC 12
#define ANA_COMP 13
#define EXT_INT2 14
#define TIM0_COMP 15
#define EE_RDY 16
#define SPM_RDY 17
// Needed by the power management functions (sleep.h)
#define __SLEEP_SUPPORTED__
#define __STANDBY_SUPPORTED__
#define __POWERDOWN_SUPPORTED__
#asm
#ifndef __SLEEP_DEFINED__
#define __SLEEP_DEFINED__
.EQU __se_bit=0x20
.SET power_ctrl_reg=mcucr
#endif
#endasm
#endif
// CodeVisionAVR C Compiler
// (C) 1998-2003 Pavel Haiduc, HP InfoTech S.R.L.
// I/O registers definitions for the ATmega8535(L)
#ifndef _MEGA8535_INCLUDED_
#define _MEGA8535_INCLUDED_
#pragma used+
sfrb TWBR=0;
sfrb TWSR=1;
sfrb TWAR=2;
sfrb TWDR=3;
sfrb ADCL=4;
sfrb ADCH=5;
sfrw ADCW=4; // 16 bit access
sfrb ADCSRA=6;
sfrb ADMUX=7;
sfrb ACSR=8;
sfrb UBRRL=9;
sfrb UCSRB=0xa;
sfrb UCSRA=0xb;
sfrb UDR=0xc;
sfrb SPCR=0xd;
sfrb SPSR=0xe;
sfrb SPDR=0xf;
sfrb PIND=0x10;
sfrb DDRD=0x11;
sfrb PORTD=0x12;
sfrb PINC=0x13;
sfrb DDRC=0x14;
sfrb PORTC=0x15;
sfrb PINB=0x16;
sfrb DDRB=0x17;
sfrb PORTB=0x18;
sfrb PINA=0x19;
sfrb DDRA=0x1a;
sfrb PORTA=0x1b;
sfrb EECR=0x1c;
sfrb EEDR=0x1d;
sfrb EEARL=0x1e;
sfrb EEARH=0x1f;
sfrw EEAR=0x1e; // 16 bit access
sfrb UBRRH=0x20;
sfrb UCSRC=0X20;
sfrb WDTCR=0x21;
sfrb ASSR=0x22;
sfrb OCR2=0x23;
sfrb TCNT2=0x24;
sfrb TCCR2=0x25;
sfrb ICR1L=0x26;
sfrb ICR1H=0x27;
sfrb OCR1BL=0x28;
sfrb OCR1BH=0x29;
sfrw OCR1B=0x28; // 16 bit access
sfrb OCR1AL=0x2a;
sfrb OCR1AH=0x2b;
sfrw OCR1A=0x2a; // 16 bit access
sfrb TCNT1L=0x2c;
sfrb TCNT1H=0x2d;
sfrw TCNT1=0x2c; // 16 bit access
sfrb TCCR1B=0x2e;
sfrb TCCR1A=0x2f;
sfrb SFIOR=0x30;
sfrb OSCCAL=0x31;
sfrb OCDR=0x31;
sfrb TCNT0=0x32;
sfrb TCCR0=0x33;
sfrb MCUCSR=0x34;
sfrb MCUCR=0x35;
sfrb TWCR=0x36;
sfrb SPMCR=0x37;
sfrb TIFR=0x38;
sfrb TIMSK=0x39;
sfrb GIFR=0x3a;
sfrb GICR=0x3b;
sfrb OCR0=0X3c;
sfrb SPL=0x3d;
sfrb SPH=0x3e;
sfrb SREG=0x3f;
#pragma used-
// Interrupt vectors definitions
#define EXT_INT0 2
#define EXT_INT1 3
#define TIM2_COMP 4
#define TIM2_OVF 5
#define TIM1_CAPT 6
#define TIM1_COMPA 7
#define TIM1_COMPB 8
#define TIM1_OVF 9
#define TIM0_OVF 10
#define SPI_STC 11
#define USART_RXC 12
#define USART_DRE 13
#define USART_TXC 14
#define ADC_INT 15
#define EE_RDY 16
#define ANA_COMP 17
#define TWI 18
#define EXT_INT2 19
#define TIM0_COMP 20
#define SPM_READY 21
// Needed by the power management functions (sleep.h)
#define __SLEEP_SUPPORTED__
#define __POWERDOWN_SUPPORTED__
#define __POWERSAVE_SUPPORTED__
#define __STANDBY_SUPPORTED__
#define __EXTENDED_STANDBY_SUPPORTED__
#asm
#ifndef __SLEEP_DEFINED__
#define __SLEEP_DEFINED__
.EQU __se_bit=0x40
.EQU __sm_mask=0xB0
.EQU __sm_powerdown=0x20
.EQU __sm_powersave=0x30
.EQU __sm_standby=0xA0
.EQU __sm_ext_standby=0xB0
.EQU __sm_adc_noise_red=0x10
.SET power_ctrl_reg=mcucr
#endif
#endasm
#endif
// CodeVisionAVR C Compiler
// (C) 1998-2004 Pavel Haiduc, HP InfoTech S.R.L.
// I/O registers definitions for the ATmega88(V)
#ifndef _MEGA88_INCLUDED_
#define _MEGA88_INCLUDED_
#pragma used+
sfrb PINB=3;
sfrb DDRB=4;
sfrb PORTB=5;
sfrb PINC=6;
sfrb DDRC=7;
sfrb PORTC=8;
sfrb PIND=9;
sfrb DDRD=0xa;
sfrb PORTD=0xb;
sfrb TIFR0=0x15;
sfrb TIFR1=0x16;
sfrb TIFR2=0x17;
sfrb PCIFR=0x1b;
sfrb EIFR=0x1c;
sfrb EIMSK=0x1d;
sfrb GPIOR0=0x1e;
sfrb EECR=0x1f;
sfrb EEDR=0x20;
sfrb EEARL=0x21;
sfrb EEARH=0x22;
sfrw EEAR=0x21; // 16 bit access
sfrb GTCCR=0x23;
sfrb TCCR0A=0x24;
sfrb TCCR0B=0x25;
sfrb TCNT0=0x26;
sfrb OCR0A=0x27;
sfrb OCR0B=0x28;
sfrb GPIOR1=0x2a;
sfrb GPIOR2=0x2b;
sfrb SPCR=0x2c;
sfrb SPSR=0x2d;
sfrb SPDR=0x2e;
sfrb ACSR=0x30;
sfrb MONDR=0x31;
sfrb SMCR=0x33;
sfrb MCUSR=0x34;
sfrb MCUCR=0x35;
sfrb SPMCSR=0x37;
sfrb SPL=0x3d;
sfrb SPH=0x3e;
sfrb SREG=0x3f;
#pragma used-
#define WDTCSR (*(unsigned char *) 0x60)
#define CLKPR (*(unsigned char *) 0x61)
#define PRR (*(unsigned char *) 0x64)
#define OSCCAL (*(unsigned char *) 0x66)
#define PCICR (*(unsigned char *) 0x68)
#define EICRA (*(unsigned char *) 0x69)
#define PCMSK0 (*(unsigned char *) 0x6b)
#define PCMSK1 (*(unsigned char *) 0x6c)
#define PCMSK2 (*(unsigned char *) 0x6d)
#define TIMSK0 (*(unsigned char *) 0x6e)
#define TIMSK1 (*(unsigned char *) 0x6f)
#define TIMSK2 (*(unsigned char *) 0x70)
#define ADCL (*(unsigned char *) 0x78)
#define ADCH (*(unsigned char *) 0x79)
#define ADCW (*(unsigned int *) 0x78) // 16 bit access
#define ADCSRA (*(unsigned char *) 0x7a)
#define ADCSRB (*(unsigned char *) 0x7b)
#define ADMUX (*(unsigned char *) 0x7c)
#define DIDR0 (*(unsigned char *) 0x7e)
#define DIDR1 (*(unsigned char *) 0x7f)
#define TCCR1A (*(unsigned char *) 0x80)
#define TCCR1B (*(unsigned char *) 0x81)
#define TCCR1C (*(unsigned char *) 0x82)
#define TCNT1L (*(unsigned char *) 0x84)
#define TCNT1H (*(unsigned char *) 0x85)
#define ICR1L (*(unsigned char *) 0x86)
#define ICR1H (*(unsigned char *) 0x87)
#define OCR1AL (*(unsigned char *) 0x88)
#define OCR1AH (*(unsigned char *) 0x89)
#define OCR1BL (*(unsigned char *) 0x8a)
#define OCR1BH (*(unsigned char *) 0x8b)
#define TCCR2A (*(unsigned char *) 0xb0)
#define TCCR2B (*(unsigned char *) 0xb1)
#define TCNT2 (*(unsigned char *) 0xb2)
#define OCR2A (*(unsigned char *) 0xb3)
#define OCR2B (*(unsigned char *) 0xb4)
#define ASSR (*(unsigned char *) 0xb6)
#define TWBR (*(unsigned char *) 0xb8)
#define TWSR (*(unsigned char *) 0xb9)
#define TWAR (*(unsigned char *) 0xba)
#define TWDR (*(unsigned char *) 0xbb)
#define TWCR (*(unsigned char *) 0xbc)
#define TWAMR (*(unsigned char *) 0xbd)
#define UCSR0A (*(unsigned char *) 0xc0)
#define UCSR0B (*(unsigned char *) 0xc1)
#define UCSR0C (*(unsigned char *) 0xc2)
#define UBRR0L (*(unsigned char *) 0xc4)
#define UBRR0H (*(unsigned char *) 0xc5)
#define UDR0 (*(unsigned char *) 0xc6)
// Interrupt vectors definitions
#define EXT_INT0 2
#define EXT_INT1 3
#define PCINT0 4
#define PCINT1 5
#define PCINT2 6
#define WDT 7
#define TIM2_COMPA 8
#define TIM2_COMPB 9
#define TIM2_OVF 10
#define TIM1_CAPT 11
#define TIM1_COMPA 12
#define TIM1_COMPB 13
#define TIM1_OVF 14
#define TIM0_COMPA 15
#define TIM0_COMPB 16
#define TIM0_OVF 17
#define SPI_STC 18
#define USART_RXC 19
#define USART_DRE 20
#define USART_TXC 21
#define ADC_INT 22
#define EE_RDY 23
#define ANA_COMP 24
#define TWI 25
#define SPM_READY 26
// Needed by the power management functions (sleep.h)
#define __SLEEP_SUPPORTED__
#define __POWERDOWN_SUPPORTED__
#define __POWERSAVE_SUPPORTED__
#define __STANDBY_SUPPORTED__
#asm
#ifndef __SLEEP_DEFINED__
#define __SLEEP_DEFINED__
.EQU __se_bit=0x01
.EQU __sm_mask=0x0E
.EQU __sm_adc_noise_red=0x02
.EQU __sm_powerdown=0x04
.EQU __sm_powersave=0x06
.EQU __sm_standby=0x0C
.SET power_ctrl_reg=smcr
#endif
#endasm
#endif
К регистрам ввода/вывода можно напрямую обратиться с помощью команд IN и OUT,выполняющих пересылку данных между одним из 32-х РОН и пространством ввода/вывода.
В системе команд имеется также четыре команды побитового доступа, использующие в качестве операндов регистры ввода/вывода:
- команды установки/сброса отдельного бита (SBI и CBI);
- команды проверки состояния отдельного бита (SBIS и SBIC).
К сожалению, эти команды могут обращаться только к 1-й половине основного пространства ввода/вывода (адреса $00...$1F).
Помимо непосредственной адресации (с помощью команд IN и OUT),к РВВ можно обращаться и как к ячейкам ОЗУ с помощью соответствующих команд ST/SD/SDD и LD/LDS/LDD (для дополнительных РВВ этот способ является единственно возможным). В первом случае используются адреса РВВ, принадлежащие основному пространству ввода/вывода ($00...$3F). Во втором случае адрес РВВ необходимо увеличить на $20.
Среди РВВ есть один регистр, используемый наиболее часто в процессе выполнения программ. Это регистр состояния SREG. Он располагается по адресу $3F ($5F) и содержит набор флагов, показывающих текущее состояние микроконтроллера. Большинство флагов автоматически устанавливаются в 1 или сбрасываются в 0 при наступлении определенных событий (в соответствии с результатом выполнения команд). Все биты этого регистра доступны как для чтения, так и для записи; после сброса микроконтроллера все биты регистра сбрасываются в 0. Формат этого регистра показан на рисунке, а его описание приведено в таблице.
Формат регистра состояния SREG
Кроме того, в последних моделях микроконтроллеров семейства появились 3 регистра ввода/вывода общего назначения — GPIOR0, GPIOR1 и GPIOR2. В этих регистрах можно хранить любую информацию, однако основное их назначение — сохранение глобальных переменных и регистра SREG. Регистры GPIOR0...2 располагаются в младшей половине основного пространства ввода/вывода и соответственно могут использоваться в командах побитового доступа SBI/CBI и SBIS/SBIC.
Биты регистра состояния SREG