Перейти к содержанию

Микроконтроллер ATmega8 и ATmega8A

ATmega8 — 8-битный микроконтроллер AVR с 8 КБ флеш-памяти, 1 КБ ОЗУ и частотой до 16 МГц, предшественник семейства ATmega88/168/328P. Ниже — характеристики, распиновка и фьюзы, чем ATmega8 отличается от ATmega8A и ATmega328P и как перенести проект на ATmega88 по указанию по применению Atmel AVR094.

Обновлено Редакция GAW

ATmega8 — микроконтроллер серии megaAVR с ядром AVR, который выпускала Atmel, а теперь Microchip. Это предшественник семейства ATmega48/88/168/328: та же разводка 28-выводного корпуса, похожий набор периферии, но другие регистры, фьюзы и меньше возможностей. С ATmega8 выпускались первые платы Arduino — в файле boards.txt ядра Arduino AVR до сих пор есть плата «Arduino NG or older» с вариантом ATmega8, — а программатор USBasp работает на ATmega8 или ATmega88. Актуальная версия кристалла — ATmega8A; данные ниже взяты из его даташита DS40001974B и указаний по применению Atmel.

Коротко

  • Память: 8 КБ флеш-памяти (4K слов), 1 КБ ОЗУ, 512 байт EEPROM; ресурс — 10 000 циклов записи флеш-памяти и 100 000 — EEPROM.
  • Частота и питание: ATmega8A — от 2,7 до 5,5 В, до 8 МГц при 2,7 В и до 16 МГц при 4,5–5,5 В. Старые ATmega8 рассчитаны на 4,5–5,5 В и 16 МГц, ATmega8L — на 2,7–5,5 В и 8 МГц.
  • Периферия: Timer0 (8 бит, только счёт), Timer1 (16 бит, два канала ШИМ), Timer2 (8 бит, один канал ШИМ, часовой кварц) — всего три канала ШИМ; 10-битный АЦП на 6 или 8 входов, USART, SPI, TWI (I²C), компаратор, сторожевой таймер.
  • Тактирование: внутренний RC-генератор 1, 2, 4 или 8 МГц, кварц, внешняя RC-цепочка или внешний генератор. С завода — RC 1 МГц (Low 0xE1, High 0xD9); для кварца выше 8 МГц нужен фьюз CKOPT.
  • Совместимость: выводы совпадают с ATmega88/168/328P, а регистры, векторы прерываний и фьюзы — нет. Сигнатура 0x1E 0x93 0x07 у ATmega8 и ATmega8A.
  • Чего нет: прерываний по изменению уровня PCINT, отладки debugWIRE, делителя системной частоты и датчика температуры.

Характеристики ATmega8

ПараметрЗначение
ЯдроAVR, 130 команд, 32 регистра общего назначения, умножение за 2 такта
Производительностьдо 16 MIPS на 16 МГц
Флеш-память8 КБ (4K слов), страницы по 32 слова, загрузочная секция от 256 байт до 2 КБ
ОЗУ (SRAM)1 КБ, адреса 0x0060–0x045F
EEPROM512 байт, запись байта — 8,5 мс
Тактовая частота0–16 МГц, предел зависит от напряжения питания
ПитаниеATmega8A — 2,7–5,5 В
Линии ввода-вывода23: порт B — 8, порт C — 7, порт D — 8
ТаймерыTimer0 и Timer2 — 8 бит, Timer1 — 16 бит
ШИМ3 канала: OC1A, OC1B, OC2
АЦП10 бит, 6 входов в DIP-28, 8 — в TQFP-32 и VQFN-32; внутренняя опора 2,56 В
ИнтерфейсыUSART, SPI, TWI — совместимый с I²C
Прерывания19 векторов по одному слову, внешние — только INT0 и INT1
Режимы снаIdle, ADC Noise Reduction, Power-down, Power-save, Standby
ПрошивкаISP по SPI, высоковольтное параллельное программирование, самопрограммирование из загрузочной секции
КорпусаPDIP-28, TQFP-32, VQFN-32

Ядро у ATmega8 то же, что у остальных классических ATmega: команды, флаги и такты — в статье «Система команд AVR». Набор команд у него чуть меньше, чем у ATmega328P: в даташите заявлено 130 команд против 131, нет, например, команды BREAK.

ATmega8, ATmega8L и ATmega8A

ATmega8 выпускался в двух исполнениях: ATmega8 на 4,5–5,5 В и до 16 МГц и низковольтный ATmega8L на 2,7–5,5 В и до 8 МГц. ATmega8A объединил их: указание по применению AVR523 называет его функционально идентичной прямой заменой ATmega8, у них одна сигнатура и одна прошивка. Отличаются электрические параметры — ATmega8A делают по другой технологии.

ATmega8ATmega8LATmega8A
Питание4,5–5,5 В2,7–5,5 В2,7–5,5 В
Частота0–16 МГц0–8 МГц0–8 МГц при 2,7 В, 0–16 МГц при 4,5–5,5 В
Активный режим, 4 МГц, 3 В—3 мА2 мА
Активный режим, 8 МГц, 5 В11 мА—6 мА
Idle, 4 МГц, 3 В—1 мА0,5 мА
Idle, 8 МГц, 5 В4,5 мА—2,2 мА

Токи типовые, при 25 °C. У ATmega8 и ATmega8L общий даташит, и ток при 3 В нормирован в нём только для ATmega8L, а при 5 В и 8 МГц — для ATmega8. AVR523 называет снижение потребления главным отличием ATmega8A: от 33 до 51 % в зависимости от режима. Менять при переходе на ATmega8A ничего не нужно — ни схему, ни прошивку, ни фьюзы.

ATmega8 и семейство ATmega88/168/328P

Следующее поколение — ATmega48/88/168, позже ATmega328 — Atmel сделала совместимым с ATmega8 по выводам. Но в AVR094 прямо сказано: ATmega88 не задуман как замена ATmega8, это кристалл со сходным набором возможностей. Что в нём добавилось по сравнению с ATmega8, по тому же документу:

  • расширенный диапазон: 4 МГц при 1,8 В, 10 МГц при 2,7 В, 20 МГц при 4,5 В;
  • меньшее потребление и более быстрая запись EEPROM — 3,4 мс вместо 8,5 мс;
  • делитель системной частоты и вывод тактового сигнала на порт;
  • отладка по debugWIRE;
  • прерывания по изменению уровня на любом выводе;
  • сторожевой таймер с режимом прерывания;
  • ШИМ и блоки сравнения у Timer0 и Timer2;
  • режим ведущего SPI у USART и регистры общего назначения GPIOR.

Что это значит на практике, разобрано в разделе о замене ATmega8 на ATmega88, а сам ATmega328P — в отдельной статье об ATmega328P.

Распиновка ATmega8

Разводка корпусов у ATmega8 и ATmega8A одинакова и совпадает с ATmega88/168/328P — отличаются только альтернативные функции некоторых выводов. Номера в рамках — выводы Arduino, как их нумерует ядро Arduino AVR для платы NG с ATmega8.

Распиновка ATmega8 в корпусе DIP-28Вид сверху, ключ вверху. Слева выводы 1–14: PC6/RESET, PD0/RXD, PD1/TXD, PD2/INT0, PD3/INT1, PD4/XCK/T0, VCC, GND, PB6/XTAL1, PB7/XTAL2, PD5/T1, PD6/AIN0, PD7/AIN1, PB0/ICP1. Справа сверху вниз выводы 28–15: PC5/ADC5/SCL, PC4/ADC4/SDA, PC3/ADC3, PC2/ADC2, PC1/ADC1, PC0/ADC0, GND, AREF, AVCC, PB5/SCK, PB4/MISO, PB3/MOSI/OC2, PB2/SS/OC1B, PB1/OC1A. Рамками отмечены номера выводов Arduino; аппаратный ШИМ у ATmega8 только на D9, D10 и D11.ATmega8DIP-28, вид сверху1PC6RESET2PD0RXDD03PD1TXDD14PD2INT0D25PD3INT1D36PD4XCK/T0D47VCC8GND9PB6XTAL1/TOSC110PB7XTAL2/TOSC211PD5T1D512PD6AIN0D613PD7AIN1D714PB0ICP1D815PB1OC1AD9~16PB2SS/OC1BD10~17PB3MOSI/OC2D11~18PB4MISOD1219PB5SCKD1320AVCC21AREF22GND23PC0ADC0A024PC1ADC1A125PC2ADC2A226PC3ADC3A327PC4ADC4/SDAA428PC5ADC5/SCLA5D9~вывод Arduino; ~ — аппаратный ШИМ (у ATmega8 только D9, D10, D11)VCC, GND, AVCC, AREF — питание и опорное напряжение АЦП
Распиновка ATmega8 и ATmega8A в корпусе DIP-28. Аппаратный ШИМ — только на OC1A, OC1B и OC2 (D9, D10, D11)
Распиновка ATmega8 в корпусе TQFP-32Вид сверху, вывод 1 — верхний на левой стороне, нумерация против часовой стрелки. Слева выводы 1–8: PD3, PD4, GND, VCC, GND, VCC, PB6/XTAL1, PB7/XTAL2. Снизу выводы 9–16: PD5, PD6, PD7, PB0, PB1, PB2, PB3, PB4. Справа снизу вверх выводы 17–24: PB5/SCK, AVCC, ADC6, AREF, GND, ADC7, PC0, PC1. Сверху справа налево выводы 25–32: PC2, PC3, PC4/SDA, PC5/SCL, PC6/RESET, PD0/RXD, PD1/TXD, PD2/INT0. ADC6 и ADC7 — только аналоговые входы, их нет в корпусе DIP-28.ATmega8TQFP-32, вид сверху1PD3INT1D32PD4XCK/T0D43GND4VCC5GND6VCC7PB6XTAL1/TOSC18PB7XTAL2/TOSC29PD5T1D510PD6AIN0D611PD7AIN1D712PB0ICP1D813PB1OC1AD9~14PB2SS/OC1BD10~15PB3MOSI/OC2D11~16PB4MISOD1217PB5SCKD1318AVCC19ADC6A620AREF21GND22ADC7A723PC0ADC0A024PC1ADC1A125PC2ADC2A226PC3ADC3A327PC4ADC4/SDAA428PC5ADC5/SCLA529PC6RESET30PD0RXDD031PD1TXDD132PD2INT0D2D9~вывод Arduino; ~ — аппаратный ШИМ (у ATmega8 только D9, D10, D11)VCC, GND, AVCC, AREF — питание; ADC6 и ADC7 — только аналоговые входы
Распиновка ATmega8 и ATmega8A в корпусе TQFP-32. Выводы питания: VCC — 4 и 6, GND — 3, 5 и 21; ADC6 и ADC7 есть только в TQFP-32 и VQFN-32

Чем разметка отличается от ATmega328P:

  • PD5 и PD6 — только вход счёта T1 и вход компаратора AIN0: выходов OC0B и OC0A нет, потому что у Timer0 нет блока сравнения.
  • PD3 — только INT1, выхода OC2B нет: у Timer2 один канал сравнения, его выход OC2 — на PB3 вместе с MOSI.
  • PB0 — только вход захвата ICP1, вывода тактового сигнала CLKO нет.
  • PCINT нет ни на одном выводе: внешние прерывания — только INT0 (PD2) и INT1 (PD3).

AVCC питает АЦП, линии PC0–PC3 и входы ADC6, ADC7; PC4 и PC5 питаются от VCC. Подключать AVCC нужно всегда, даже без АЦП, с АЦП — через фильтр; разница с VCC — не больше 0,3 В. Абсолютный максимум — 40 мА на вывод и 300 мА через выводы VCC и GND; выходные уровни нормированы при 20 мА и 5 В: низкий не выше 0,9 В, высокий не ниже 4,2 В. Внутренние подтягивающие резисторы — 20–50 кОм, на RESET — 30–80 кОм.

Тактирование ATmega8

Источники тактирования и фьюз CKOPT

CKSEL3:0ИсточникЧастота
1111–1010кварц или керамический резонатор0,4–16 МГц; выше 8 МГц — только с запрограммированным CKOPT
1001часовой кварц 32,768 кГц32,768 кГц
1000–0101внешняя RC-цепочка, f ≈ 1/(3RC)0,1–12 МГц
0100–0001внутренний RC-генератор8, 4, 2 или 1 МГц
0000внешний тактовый сигнал на XTAL10–16 МГц

Фьюз CKOPT у ATmega8 выбирает режим кварцевого генератора. Незапрограммированный (1) — пониженный размах на XTAL2, меньший ток и ограниченный диапазон: кварцы до 8 МГц, резонаторы тоже до 8 МГц. Запрограммированный (0) — размах от нуля до питания, работа в шумной обстановке и возможность тактировать другие микросхемы с XTAL2; с ним генератор работает с кварцами от 1 МГц и выше, а с резонаторами — до 16 МГц.

CKOPTCKSEL3:1Частота кварцаКонденсаторы C1, C2
11010,4–0,9 МГц, только керамические резонаторы—
11100,9–3,0 МГц12–22 пФ
11113,0–8,0 МГц12–22 пФ
0101, 110, 111от 1,0 МГц12–22 пФ

В других режимах CKOPT значит другое. С внешним тактовым сигналом и внешней RC-цепочкой он подключает внутренний конденсатор 36 пФ, с часовым кварцем — внутренние конденсаторы 36 пФ на XTAL1 и XTAL2, и тогда внешние не нужны. С внутренним RC-генератором CKOPT по даташиту всегда должен оставаться незапрограммированным.

Внутренний RC-генератор и калибровка

Внутренний генератор даёт 1, 2, 4 или 8 МГц (CKSEL3:0 = 0001, 0010, 0011, 0100). Калибровочных байтов четыре — по одному на частоту, они лежат в сигнатурной строке, но при сбросе в регистр OSCCAL автоматически загружается только байт для 1 МГц. С ним частота при 5 В и 25 °C отличается от номинала не больше чем на ±3 %, а подстройкой во время работы можно добиться ±1 %. Если выбран генератор 2, 4 или 8 МГц, калибровку для этой частоты программа должна записать в OSCCAL сама: прочитать байт программатором (в avrdude — память calibration), сохранить во флеш-памяти или EEPROM и при старте переписать в OSCCAL. Без этого точность частоты не гарантирована: заводская калибровка, загруженная при сбросе, относится только к 1 МГц.

Если программа пишет флеш-память или EEPROM, OSCCAL нельзя поднимать больше чем на 10 % выше номинала: этот генератор задаёт время записи, и запись может не пройти.

У ATmega8 нет делителя системной частоты вроде CLKPR у ATmega328P: частоту выбирают только фьюзами, а внутренний генератор — одним из четырёх значений.

Фьюзы ATmega8

У ATmega8 два байта фьюзов, расширенного байта нет. Бит, равный 0, — запрограммирован.

Байт76543210
HighRSTDISBLWDTONSPIENCKOPTEESAVEBOOTSZ1BOOTSZ0BOOTRST
LowBODLEVELBODENSUT1SUT0CKSEL3CKSEL2CKSEL1CKSEL0
  • BODEN = 0 включает детектор пониженного питания, BODLEVEL выбирает порог: 1 — 2,6 В (2,4–2,9 В), 0 — 4,0 В (3,7–4,5 В).
  • SUT1:0 вместе с CKSEL0 задают время запуска: для кварца — 16K тактов и дополнительно 0, 4,1 или 65 мс после сброса.
  • BOOTSZ1:0 — размер загрузочной секции: 11 — 128 слов (256 байт), 10 — 256 слов, 01 — 512 слов (1 КБ), 00 — 1024 слова (2 КБ) с началом по адресам слов 0xF80, 0xF00, 0xE00 и 0xC00. BOOTRST = 0 — старт с загрузчика.
  • RSTDISBL, WDTON, SPIEN, EESAVE — как у ATmega328P: вывод RESET как порт PC6, сторожевой таймер всегда включён, программирование по SPI, сохранение EEPROM при стирании кристалла.
НастройкаLowHighЧто получится
Заводская0xE10xD9RC-генератор 1 МГц, BOD выключен, старт с адреса 0
RC-генератор 8 МГц0xE40xD98 МГц без кварца, калибровку записать в OSCCAL программой
Кварц 8 МГц, BOD 2,6 В0x9F0xD9режим для ATmega8L и для ATmega8A с питанием от 2,7 В
Кварц 16 МГц, BOD 4,0 В0x1F0xC9CKOPT запрограммирован, вся флеш-память под программу
Кварц 16 МГц без BOD0xFF0xC9то же, детектор выключен
Arduino NG (ATmega8)0xDF0xCAкварц 16 МГц, CKOPT, загрузчик 1 КБ, BOD выключен

Значения для Arduino NG взяты из boards.txt ядра Arduino AVR: загрузчик занимает 1 КБ, под скетч остаётся 7168 байт, а загружается он на 19 200 бит/с. Записывают фьюзы avrdude, ключ -p m8:

avrdude -c usbasp -p m8 -B 10 -U lfuse:w:0x1F:m -U hfuse:w:0xC9:m

Частота SCK программатора должна быть ниже четверти тактовой частоты кристалла: новый ATmega8 работает на 1 МГц, и ключ -B 10 (около 100 кГц) здесь обязателен. Опасные ошибки те же, что у ATmega328P: выбор несуществующего источника тактирования лечится подачей внешнего такта на XTAL1, а RSTDISBL — только высоковольтным параллельным программированием. Подробнее — в разделе о фьюзах ATmega328P. У ATmega8 добавляется своя ловушка — кварц 16 МГц с незапрограммированным CKOPT. Это режим вне даташита: генератор с пониженным размахом рассчитан на кварцы только до 8 МГц, и ни запуск, ни устойчивая работа не гарантированы.

Периферия ATmega8 и отличия от ATmega328P

ATmega8ATmega328P
Флеш / ОЗУ / EEPROM8 КБ / 1 КБ / 512 байт32 КБ / 2 КБ / 1 КБ
Частота и питаниедо 16 МГц, 2,7–5,5 В (ATmega8A)до 20 МГц, 1,8–5,5 В
Timer0только счёт и прерывание по переполнениюдва канала сравнения, ШИМ на PD5 и PD6
Timer2один канал сравнения OC2 (PB3)два канала: OC2A (PB3) и OC2B (PD3)
Каналы ШИМ36
Прерывания PCINTнетна всех 23 линиях
Векторы прерываний19, по одному слову26, по два слова
USARTUBRRH и UCSRC по одному адресу, бит URSELотдельные UBRR0H и UCSR0C, режим ведущего SPI
Внутренняя опора АЦП2,56 В1,1 В
Автозапуск АЦПтолько непрерывный режим, бит ADFR8 источников запуска: ADATE и ADTS
Датчик температурынетвход ADC8
Сторожевой таймер16 мс — 2,1 с, только сброс16 мс — 8 с, сброс и (или) прерывание
Внутренний RC-генератор1, 2, 4 или 8 МГц, автоматическая калибровка — только для 1 МГц8 МГц, делитель CLKPR от 1 до 256
Внешняя RC-цепочкаестьнет
Режимы сна56 и отключение BOD во сне
ОтладканетdebugWIRE
Запись байта EEPROM8,5 мс3,3 мс
SBI и CBI на регистрах с флагамисбрасывают все установленные флаги регистраменяют только указанный бит
Запись 1 в PINxне действует, регистр только для чтенияпереключает бит PORTx
Сигнатура1E 93 071E 95 0F

Таймеры: ШИМ только на трёх выводах

  • Timer0 — 8-битный счётчик с делителем 1, 8, 64, 256 или 1024 и внешним входом T0 (PD4). Блоков сравнения у него нет, а значит, нет ни ШИМ, ни режима CTC: только прерывание по переполнению. Ядро Arduino для ATmega8 считает на нём millis() с тем же делителем 64, что и на ATmega328P.
  • Timer1 — 16 бит, как у ATmega328P: два канала сравнения OC1A (PB1) и OC1B (PB2), захват по ICP1 (PB0) или от компаратора, все 15 режимов, включая fast PWM с верхним значением в ICR1. Код для Timer1 переносится между ATmega8 и ATmega328P почти без изменений: меняются регистры прерываний TIMSK и TIFR, а биты принудительного сравнения FOC1A и FOC1B у ATmega328P переехали из TCCR1A в TCCR1C.
  • Timer2 — 8 бит, один канал сравнения OC2 (PB3), режимы normal, CTC, fast PWM и phase correct, делитель 1, 8, 32, 64, 128, 256 или 1024. Все настройки — в одном регистре TCCR2, а не в двух, как у ATmega328P. Timer2 может считать от часового кварца на TOSC1 и TOSC2, но, как и у ATmega328P, только когда ядро работает от внутреннего RC-генератора.

USART: общий адрес UBRRH и UCSRC

Главная ловушка ATmega8. Регистры UBRRH (старшие 4 бита делителя скорости) и UCSRC (формат кадра) делят один адрес ввода-вывода, и запись в него направляет старший бит байта — URSEL: 0 — запись в UBRRH, 1 — в UCSRC.

UBRRH = 0;                                        /* URSEL = 0: this goes to UBRRH */
UBRRL = 103;                                      /* 9600 baud at 16 MHz, +0.2 % */
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);   /* URSEL = 1: UCSRC, 8N1 */

Если забыть URSEL и написать UCSRC = (1 << UCSZ1) | (1 << UCSZ0), байт 0x06 попадёт в UBRRH: делитель станет 0x667 = 1639, и при 16 МГц скорость упадёт с 9600 примерно до 610 бит/с. С чтением сложнее: первое чтение адреса возвращает UBRRH, а UCSRC — только второе чтение подряд, в следующем такте, поэтому на время чтения запрещают прерывания. После сброса UCSRC уже равен 0x86 — формат 8N1, — так что для обычного кадра его можно вообще не трогать.

У ATmega328P этой особенности нет: UBRR0H и UCSR0C — отдельные регистры, бита URSEL нет, а на его месте в UCSR0C — бит выбора режима UMSEL01. Формулы и таблицы скоростей у обоих одинаковые: UBRR = 103 на 16 МГц для 9600 бит/с с ошибкой 0,2 %, проверить другие сочетания поможет калькулятор скорости UART. Как устроен кадр UART и почему важна точность скорости, разобрано в статье про UART.

АЦП, компаратор, прерывания и сторожевой таймер

  • АЦП — 10 бит, тактовая частота 50–200 кГц для полной точности, 13 тактов на преобразование (первое — 25), делитель 2–128 как у ATmega328P. Опорное напряжение — AREF, AVCC или внутренний источник 2,56 В. Автозапуск только один: непрерывный режим битом ADFR. Входы ADC4 и ADC5 совмещены с линиями TWI: работа TWI мешает преобразованиям только на этих двух каналах.
  • Аналоговый компаратор — AIN0 (PD6) и AIN1 (PD7); бит ACME, который подключает вместо AIN1 мультиплексор АЦП, лежит в регистре SFIOR.
  • Внешние прерывания — только INT0 (PD2) и INT1 (PD3), биты условий — в MCUCR, разрешения — в GICR.
  • Сторожевой таймер тактируется собственным генератором; таймаут при 5 В — от 16,3 мс до 2,1 с. Прерывания по таймауту нет: только сброс.
  • SPI и TWI устроены так же, как у ATmega328P: выводы PB2–PB5 и PC4, PC5. Подробно — в статьях про SPI и I²C.

Питание и режимы сна

Максимальная тактовая частота ATmega8 в зависимости от напряжения питанияОбласть допустимой работы ATmega8A: 8 МГц при 2,7 В, дальше граница растёт линейно до 16 МГц при 4,5 В, от 4,5 до 5,5 В — 16 МГц. При 3,3 В допустимо до 10,7 МГц, 16 МГц — только от 4,5 В.0481216201,82,73,34,55,05,5МГцнапряжение питания VCC, Вдопустимая область3,3 В: до 10,7 МГц16 МГц, 5 В8 МГц при 2,7 В16 МГц при 4,5 В
Наибольшая тактовая частота ATmega8A в зависимости от напряжения питания по рис. 26-1 даташита. Точка 3,3 В получена линейной интерполяцией

Граница допустимой частоты у ATmega8A идёт от 8 МГц при 2,7 В до 16 МГц при 4,5 В. При питании 3,3 В это около 10,7 МГц, поэтому 3,3-вольтовые схемы на ATmega8A обычно работают на 8 МГц — от кварца или внутреннего RC-генератора. Детектор пониженного питания подстраивают под частоту: для 16 МГц — порог 4,0 В (более высокого у ATmega8 нет), для 8 МГц — 2,6 В.

РежимЧто продолжает работатьЧем разбудитьТок ATmega8A при 25 °C
Активныйвсё—2 мА (4 МГц, 3 В), 6 мА (8 МГц, 5 В)
Idleвсё, кроме ядра и флеш-памятилюбое прерывание0,5 мА (4 МГц, 3 В), 2,2 мА (8 МГц, 5 В)
ADC Noise ReductionАЦП, внешние прерывания, TWI, Timer2, сторожевой таймерокончание преобразования, сброс — в том числе от сторожевого таймера и BOD, низкий уровень на INT0 или INT1, совпадение адреса TWI, Timer2, готовность EEPROM—
Power-downсторожевой таймер, внешние прерывания, адрес TWIсброс, сторожевой таймер, BOD, совпадение адреса TWI, низкий уровень на INT0 или INT1меньше 1 мкА без сторожевого таймера, меньше 10 мкА с ним (3 В)
Power-saveто же и Timer2 от часового кварцато же и Timer2—
Standbyкак Power-down, но генератор кварца работаетто же—

Токи в таблице — типовые; максимальные в Power-down при 3 В — 3 мкА без сторожевого таймера и 28 мкА с ним. Режим сна выбирают биты SM2:0 и SE в регистре MCUCR — у ATmega328P они переехали в отдельный регистр SMCR. Режима Extended Standby у ATmega8 нет: по даташиту его убрали, потому что выводы TOSC и XTAL совпадают.

Замена ATmega8 на ATmega88, ATmega168 или ATmega328P

Новый кристалл встанет в ту же панельку, но прошивка для ATmega8 на нём не заработает: её нужно пересобрать с другим -mmcu и поправить. Указание по применению AVR094 перечисляет все отличия ATmega8 от ATmega88; для ATmega168 и ATmega328P они те же, только вектор прерывания у них занимает два слова.

Векторы прерываний

У ATmega88 добавились прерывания PCINT, сторожевого таймера и вторых каналов сравнения таймеров 0 и 2, поэтому все векторы, кроме сброса, INT0 и INT1, сдвинулись. Таблица векторов, собранная avr-gcc для ATmega8, на ATmega88 вызовет не те обработчики.

ПрерываниеATmega8: номер, адресATmega88: номер, адресATmega168 и ATmega328P: адресИмя в avr-libc: ATmega8 → ATmega328P
Сброс1, 0x0001, 0x0000x0000—
INT0, INT12, 3: 0x001, 0x0022, 3: 0x001, 0x0020x0002, 0x0004без изменений
PCINT0–PCINT2—4–6: 0x003–0x0050x0006–0x000Aновые
Сторожевой таймер—7: 0x0060x000CWDT_vect, новый
Timer2: совпадение4: 0x0038: 0x007 (канал A), 9: 0x008 (канал B)0x000E, 0x0010TIMER2_COMP_vect → TIMER2_COMPA_vect
Timer2: переполнение5: 0x00410: 0x0090x0012без изменений
Timer1: захват, совпадения A и B, переполнение6–9: 0x005–0x00811–14: 0x00A–0x00D0x0014–0x001Aбез изменений
Timer0: совпадения A и B—15, 16: 0x00E, 0x00F0x001C, 0x001Eновые
Timer0: переполнение10: 0x00917: 0x0100x0020без изменений
SPI11: 0x00A18: 0x0110x0022без изменений
USART: приём, буфер пуст, передача12–14: 0x00B–0x00D19–21: 0x012–0x0140x0024–0x0028USART_RXC_vect → USART_RX_vect, USART_TXC_vect → USART_TX_vect
АЦП15: 0x00E22: 0x0150x002Aбез изменений
EEPROM готово16: 0x00F23: 0x0160x002CEE_RDY_vect → EE_READY_vect
Компаратор17: 0x01024: 0x0170x002EANA_COMP_vect → ANALOG_COMP_vect
TWI18: 0x01125: 0x0180x0030без изменений
SPM готово19: 0x01226: 0x0190x0032SPM_RDY_vect → SPM_READY_vect

В C достаточно поменять имена векторов в ISR(): avr-gcc сам построит таблицу. В ассемблере таблицу переписывают целиком, а у ATmega168 и ATmega328P вместо RJMP в векторах ставят JMP.

Регистры и биты

Почти все регистры ATmega8 у ATmega88 переехали на другие адреса, многие — в расширенное пространство ввода-вывода 0x60–0xFF. В программе на C с символическими именами это незаметно, а в ассемблере команды IN, OUT, SBI и CBI для таких регистров заменяют на LDS и STS: например, регистры USART, TWI, Timer1, Timer2 и АЦП доступны только через память данных. Переименования из AVR094:

ATmega8ATmega88/168/328PЧто изменилось
UDR, UCSRA, UCSRB, UBRRLUDR0, UCSR0A, UCSR0B, UBRR0Lдобавлен номер 0; так же биты: RXC → RXC0, U2X → U2X0, PE → UPE0, UCSZ0 → UCSZ00
UBRRH и UCSRC по одному адресуUBRR0H и UCSR0C — разные регистрыбита URSEL нет; UMSEL → UMSEL00
TCCR0TCCR0B (биты делителя) и новый TCCR0ATimer0 получил режимы ШИМ и CTC
TCCR2, OCR2TCCR2A, TCCR2B, OCR2ACOM2x и WGM20, WGM21 — в TCCR2A; делитель, WGM22 и FOC2A — в TCCR2B
TIMSK, TIFRTIMSK0–2, TIFR0–2по регистру на каждый таймер
GICREIMSK, MCUCRINT0, INT1 — в EIMSK; IVSEL, IVCE — в MCUCR
GIFREIFR—
MCUCREICRA, SMCRISC — в EICRA; SE и SM2:0 — в SMCR
MCUCSRMCUSR—
SFIORADCSRB, MCUCR, GTCCRACME — в ADCSRB, PUD — в MCUCR, PSR10 → PSRSYNC и PSR2 → PSRASY — в GTCCR
WDTCRWDTCSRдругие значения делителя, появился режим прерывания
SPMCRSPMCSR—
ADCSRA: ADFRADCSRA: ADATE и ADCSRB: ADTS2:0непрерывный режим — один из источников автозапуска
EECR: EEMWE, EEWEEECR: EEMPE, EEPE—
ASSR: OCR2UB, TCR2UBASSR: OCR2AUB, TCR2AUBдобавлены флаги для канала B

Фьюзы, тактирование и аналоговая часть

  • Фьюзы придётся считать заново. У ATmega88 три байта: BOOTSZ и BOOTRST переехали в расширенный байт (у ATmega328P они остались в старшем), детектор пониженного питания задают три бита BODLEVEL2:0, CKOPT исчез, появились CKDIV8, CKOUT и DWEN. Пороги BOD другие: 1,8, 2,7 и 4,3 В у ATmega88 против 2,6 и 4,0 В у ATmega8 — сопоставимые пороги у нового кристалла выше.
  • Тактирование. Источники почти те же, кроме внешней RC-цепочки — у ATmega88 её нет. Ко всем задержкам запуска добавлено 14 тактов, а значения CKSEL и SUT нужно подобрать заново по даташиту. Калиброванный внутренний генератор у ATmega88 один — 8 МГц (есть ещё неточный на 128 кГц); с завода он работает через делитель на 8, калибровочный байт загружается автоматически, а другую частоту задают делителем CLKPR, а не фьюзами.
  • Опорные напряжения. Внутренний источник для АЦП — 1,1 В вместо 2,56 В, для компаратора — 1,1 В вместо 1,23 В. Коэффициенты пересчёта кодов АЦП в напряжение придётся поменять.
  • Сторожевой таймер настраивается другими значениями делителя и отдельной последовательностью: бит WDE нельзя сбросить, пока установлен флаг WDRF в MCUSR.
  • Сигнатура ATmega88 — 0x1E 0x93 0x0A, у ATmega88PA — 0x1E 0x93 0x0F: в avrdude меняется ключ -p.

Порядок переноса

  1. Пересобрать проект с -mmcu=atmega88 (или atmega168, atmega328p) и исправить ошибки компиляции по таблице регистров выше — это быстрее всего находит устаревшие имена.
  2. Переписать инициализацию USART без URSEL, таймеров 0 и 2 — с учётом TCCRxA и TCCRxB, прерываний — с EIMSK, EICRA и TIMSKx.
  3. Поменять имена векторов в ISR(); в ассемблере переписать таблицу векторов и обращения к регистрам, переехавшим в расширенное пространство ввода-вывода.
  4. Пересчитать фьюзы под новый кристалл и записать их до первой прошивки: не забыть, что с завода включён делитель на 8.
  5. Проверить АЦП с внутренней опорой и сторожевой таймер — у них изменились напряжение и логика.

Минимальная схема ATmega8

Схема включения ATmega8 такая же, как у ATmega328P: разводка выводов совпадает, а развязку питания, сброс и кварц AVR042 рекомендует одинаково для всех AVR.

Минимальная схема включения ATmega8: кварц, сброс, питание, ISP и USB–UARTATmega8 в корпусе DIP-28. Кварц Q1 16 МГц между XTAL1 (вывод 9) и XTAL2 (вывод 10), от каждого вывода конденсатор 22 пФ на общий провод. RESET (вывод 1) подтянут к +5 В резистором R1 10 кОм и соединён с контактом RST разъёма ISP и через конденсатор C6 100 нФ — с выходом DTR преобразователя USB–UART. VCC (вывод 7) — к +5 В с конденсатором C1 100 нФ; AVCC (вывод 20) — к +5 В через дроссель L1 10 мкГн с конденсатором C2 100 нФ; AREF (вывод 21) — конденсатор C3 100 нФ на общий провод; выводы 8 и 22 — общий провод. SCK, MISO и MOSI (выводы 19, 18, 17) — к разъёму ISP. RXD (вывод 2) — к TXD преобразователя, TXD (вывод 3) — к его RXD.ATmega8DIP-287VCC20AVCC8GND22GND21AREF9XTAL110XTAL21RESET19SCK18MISO17MOSI2RXD3TXDQ116 МГцC422 пФC522 пФ+5 ВC1100 нФ+5 ВL110 мкГнC2100 нФC3100 нФ+5 ВR110 кОмC6100 нФISPRSTSCKMISOMOSIVCCGND+5 ВUSB–UARTTXDRXDGNDDTRVCC+5 В
Минимальная схема ATmega8 в корпусе DIP-28: кварц 16 МГц, сброс, развязка питания, разъём ISP и USB–UART. Для кварца 16 МГц фьюз CKOPT должен быть запрограммирован
  • Кварц 16 МГц с конденсаторами 22 пФ и фьюзы Low 0x1F, High 0xC9 — CKOPT запрограммирован. Для кварца до 8 МГц CKOPT можно не программировать: генератор с пониженным размахом потребляет меньше.
  • Без кварца XTAL1 и XTAL2 становятся линиями PB6 и PB7, а кристалл работает от внутреннего генератора 1–8 МГц — для UART без калибровки его точности обычно не хватает.
  • Развязка: по 100 нФ у выводов 7–8 и 20–22, AVCC — к питанию даже без АЦП, AREF — конденсатор 100 нФ на общий провод при опоре AVCC или 2,56 В.
  • Сброс: подтяжка 10 кОм. debugWIRE у ATmega8 нет, поэтому конденсатор от RESET на общий провод, который AVR042 советует для защиты от помех, ставить можно — но вместе с C6 он образует делитель и ослабляет импульс автосброса.
  • ISP — те же выводы MOSI, MISO, SCK и RESET (17, 18, 19 и 1), что и у ATmega328P. USB–UART с цепочкой DTR — C6 — RESET нужен, только если в кристалле есть загрузчик.

Пример на C: один исходник для ATmega8 и ATmega328P

Программа принимает символы через USART на 9600 бит/с, отправляет их обратно и цифрами 0–9 задаёт яркость светодиода на выводе PB3 (OC2 у ATmega8, OC2A у ATmega328P, D11 на Arduino). Кварц — 16 МГц. Различия регистров собраны в двух ветках #if, так что файл собирается для обоих кристаллов — это заготовка для переноса старого проекта.

/* USART echo at 9600 baud, 8N1, and an LED dimmer on PB3; 16 MHz crystal.
 * Builds for ATmega8 (-mmcu=atmega8) and ATmega88/168/328P (-mmcu=atmega328p). */
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#define BAUD 9600

#include <avr/io.h>
#include <stdint.h>
#include <util/setbaud.h>

#if defined(__AVR_ATmega8__)
/* ATmega8: UBRRH and UCSRC share one address, URSEL selects UCSRC */
static void uart_init(void)
{
  UBRRH = UBRRH_VALUE;                            /* URSEL = 0: this is UBRRH */
  UBRRL = UBRRL_VALUE;                            /* 103 at 16 MHz */
  UCSRA = USE_2X ? _BV(U2X) : 0;
  UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);   /* URSEL = 1: this is UCSRC, 8N1 */
  UCSRB = _BV(RXEN) | _BV(TXEN);
}
#define UART_RX_READY() (UCSRA & _BV(RXC))
#define UART_TX_READY() (UCSRA & _BV(UDRE))
#define UART_DATA UDR

static void pwm_init(void)
{
  DDRB |= _BV(PB3);                               /* OC2 */
  TCCR2 = _BV(WGM21) | _BV(WGM20) | _BV(COM21) | _BV(CS22);  /* fast PWM, clk/64 */
}
#define PWM_DUTY OCR2

#else
/* ATmega88/168/328P: separate UBRR0H and UCSR0C, timer 2 has TCCR2A and TCCR2B */
static void uart_init(void)
{
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0A = USE_2X ? _BV(U2X0) : 0;
  UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);             /* 8N1, no URSEL bit */
  UCSR0B = _BV(RXEN0) | _BV(TXEN0);
}
#define UART_RX_READY() (UCSR0A & _BV(RXC0))
#define UART_TX_READY() (UCSR0A & _BV(UDRE0))
#define UART_DATA UDR0

static void pwm_init(void)
{
  DDRB |= _BV(PB3);                               /* OC2A */
  TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20); /* fast PWM on OC2A */
  TCCR2B = _BV(CS22);                             /* clk/64 */
}
#define PWM_DUTY OCR2A
#endif

int main(void)
{
  uart_init();
  pwm_init();
  for (;;) {
    while (!UART_RX_READY()) {}
    uint8_t c = UART_DATA;
    if (c >= '0' && c <= '9') {
      PWM_DUTY = (uint8_t)((c - '0') * 28);       /* '0'...'9' -> OCR 0...252, duty (OCR + 1) / 256 */
    }
    while (!UART_TX_READY()) {}
    UART_DATA = c;                                /* echo */
  }
}

Частота ШИМ в обоих случаях — 16 МГц / (64 · 256) ≈ 976,6 Гц, а скважность в режиме fast PWM — (OCR + 1) / 256: даже при нуле на выходе остаётся узкий импульс в один такт таймера. У ATmega8 делитель 64 (бит CS22) и режим fast PWM (биты WGM21 и WGM20) задаются в одном регистре TCCR2, у ATmega328P CS22 лежит в TCCR2B, а WGM21 и WGM20 — в TCCR2A. Сборка и прошивка через USBasp:

avr-gcc -mmcu=atmega8 -Os -o echo.elf echo.c
avr-objcopy -O ihex -R .eeprom echo.elf echo.hex
avrdude -c usbasp -p m8 -U flash:w:echo.hex:i

Для ATmega328P меняются -mmcu=atmega328p и -p m328p. Светодиод на PB3 подключают через резистор: его номинал для нужного тока посчитает калькулятор резистора для светодиода. На время прошивки по ISP помните, что PB3 — это ещё и MOSI: нагрузка на нём не должна мешать программатору.

Типичные ошибки

СимптомВероятная причинаЧто сделать
Новый кристалл не отвечает программаторучастота 1 МГц, SCK программатора выше 250 кГц-B 10 в avrdude или перемычка медленного режима
USART работает на неверной скорости или формат кадра не тотUCSRC записан без URSEL, и байт попал в UBRRHUCSRC = (1 << URSEL) | ...
Кварц 16 МГц не запускается или работает со сбоямиCKOPT не запрограммированHigh с CKOPT = 0, например 0xC9
После перехода на 8 МГц от RC-генератора UART и задержки неточныв OSCCAL осталась калибровка для 1 МГцзаписать в OSCCAL калибровочный байт для 8 МГц
analogWrite() на D3, D5, D6 даёт только 0 или 1у ATmega8 нет ШИМ на этих выводахиспользовать D9, D10, D11
Флаг прерывания пропал после sbi в соседний битSBI и CBI у ATmega8 перезаписывают весь регистр и сбрасывают установленные флагименять биты регистров с флагами записью целого значения
Код ATmega328P не компилируется: нет TIMSK1, UCSR0A, PCICRдругие имена регистров или их нет вовсетаблица регистров из раздела о замене, PCINT заменить на INT0 и INT1
Прошивка для ATmega8 на ATmega88 зависает в прерыванияхтаблица векторов собрана для ATmega8пересобрать с нужным -mmcu, поправить имена векторов
Программатор пишет «Device signature = 0x1e930a»вместо ATmega8 стоит ATmega88-p m88 и проект, перенесённый на ATmega88

Если нужен 28-выводный AVR для нового устройства, проще сразу взять ATmega328P: та же разводка, вчетверо больше флеш-памяти и вдвое больше каналов ШИМ. Старший кристалл с 128 КБ флеш-памяти и JTAG разобран в статье об ATmega128, сравнение всех семейств и программаторов — в разделе об AVR, а общий обзор микроконтроллеров — в разделе «Микроконтроллеры».

Частые вопросы

Чем ATmega8 отличается от ATmega8A?

По функциям ничем: в указании по применению AVR523 Atmel называет ATmega8A функционально идентичной прямой заменой ATmega8, сигнатура у обоих 0x1E 0x93 0x07, прошивка и фьюзы переносятся без изменений. ATmega8A выпускается по другой технологии: он работает от 2,7 до 5,5 В на частотах до 16 МГц, тогда как ATmega8 рассчитан на 4,5–5,5 В, а для 2,7–5,5 В выпускался ATmega8L до 8 МГц. Типовой ток у ATmega8A меньше на 33–51 %: например, 6 мА вместо 11 мА в активном режиме на 8 МГц при 5 В.

Можно ли заменить ATmega8 на ATmega88, ATmega168 или ATmega328P?

По выводам — да, разводка корпусов DIP-28 и TQFP-32 одинаковая. Но прошивку придётся пересобрать и поправить: по AVR094 у ATmega88 26 векторов прерываний вместо 19, большая часть регистров переименована или переехала в расширенное пространство ввода-вывода, у USART больше нет общего адреса UBRRH и UCSRC, а фьюзы тактирования и детектора пониженного питания устроены иначе и CKOPT исчез. Кристалл с завода работает на 1 МГц, как и ATmega8, но уже от RC-генератора 8 МГц с делителем на 8.

Какие фьюзы поставить ATmega8 для кварца 16 МГц?

Low = 0x1F и High = 0xC9: CKSEL3:0 = 1111 и SUT1:0 = 01 выбирают кварц с запуском за 16K тактов, BOD включён с порогом 4,0 В, а запрограммированный CKOPT включает генератор с полным размахом — без него ATmega8 рассчитан на кварцы только до 8 МГц. Если детектор пониженного питания не нужен, Low = 0xFF. Плата Arduino NG с загрузчиком использует Low = 0xDF и High = 0xCA.

Почему ATmega8 работает на 1 МГц и как включить 8 МГц без кварца?

С завода фьюзы выбирают внутренний RC-генератор 1 МГц: Low = 0xE1. Для 8 МГц записывают Low = 0xE4 (CKSEL3:0 = 0100). Но автоматически при сбросе загружается только калибровочный байт для 1 МГц; калибровки для 2, 4 и 8 МГц хранятся в сигнатурной строке, и программа должна сама записать нужную в регистр OSCCAL — иначе частота может заметно отличаться от 8 МГц.

Почему на ATmega8 не работает analogWrite на выводах 3, 5 и 6?

У ATmega8 всего три аппаратных канала ШИМ: OC1A и OC1B таймера 1 на выводах PB1 и PB2 (Arduino D9 и D10) и OC2 таймера 2 на PB3 (D11). Таймер 0 умеет только считать и вызывать прерывание по переполнению, а у таймера 2 один канал сравнения вместо двух. Поэтому ядро Arduino для ATmega8 выдаёт ШИМ только на D9, D10 и D11.

Почему USART на ATmega8 работает не на той скорости?

Скорее всего, при записи UCSRC не установлен бит URSEL. У ATmega8 регистры UBRRH и UCSRC делят один адрес, и бит 7 записываемого байта выбирает регистр: 0 — UBRRH, 1 — UCSRC. Строка UCSRC = (1 << UCSZ1) | (1 << UCSZ0) без URSEL запишет 0x06 в старший байт делителя скорости, и при 16 МГц вместо 9600 бит/с получится около 610 бит/с. Правильно: UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0).

Источники

  1. Microchip. ATmega8A Data Sheet (DS40001974B), 2020 — распиновка, тактирование и CKOPT, калибровка RC-генератора, режимы сна, сторожевой таймер, векторы прерываний, таймеры, доступ к UBRRH и UCSRC, АЦП, загрузчик, фьюзы и сигнатура, электрические характеристики и рис. 26-1
  2. Atmel. ATmega8/ATmega8L Datasheet (2486AA–AVR–02/2013) — напряжения, частоты и токи ATmega8 и ATmega8L
  3. Atmel. AVR094: Replacing ATmega8 by ATmega88 (2553C–AVR–04/05) — таблицы векторов и регистров, переименованные биты, тактирование, BOD, доступ к UCSRC, опорные напряжения, фьюзы, сигнатуры, время записи EEPROM, напряжения и частоты
  4. Atmel. AVR523: Migration from ATmega8 to ATmega8A (8164A–AVR–05/09) — ATmega8A — функционально идентичная прямая замена; сравнение токов потребления
  5. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B), 2020 — векторы прерываний ATmega328P, поведение SBI и CBI, переключение выводов записью в PINx
  6. Atmel. AVR042: AVR Hardware Design Considerations (Atmel-2521R), 09/2016 — развязка питания, AVCC и AREF, цепь сброса, конденсаторы кварца
  7. Arduino. ArduinoCore-avr: boards.txt, variants/standard/pins_arduino.h, cores/arduino/wiring.c — плата Arduino NG or older с ATmega8: фьюзы, загрузчик, 7168 байт под скетч, 19 200 бит/с; выводы ШИМ D9–D11; Timer0 без ШИМ
  8. AVR-LibC: заголовки avr/iom8.h и avr/iom328p.h — имена регистров, битов и векторов прерываний
  9. AVRDUDE: руководство (avrdude.1) — USBasp работает на ATmega8 или ATmega88; ключ -B для частоты SCK