Книга по работе с WinAVR и AVR Studio / AVR_13_2011
.pdf
СПРАВОЧНЫЙ МАТЕРИАЛ
|
|
|
Роман Абраш |
Книга по работе |
|
||||||
|
|
|
|
|
|
|
|
|
|
||
|
|
|
г. Новочеркасск |
с WinAVR и AVR Studio |
|
||||||
|
|
E-mail: arv@radioliga.com |
|
||||||||
|
|
|
|
|
программе пользователя. Наличие этого |
|
Макросы-функции, определен- |
||||
|
|
|
Продолжение. |
|
|
||||||
|
|
|
|
макроса дает указание компоновщику раз- |
|
ные в модуле |
|
||||
|
|
Начало в №1-12/2010 |
|
|
|
||||||
|
|
|
местить соответствующий объект в строго |
|
Так как большинство макросов выпол- |
||||||
|
|
|
|
|
определенной области памяти, соответ- |
|
нены в виде макросов-функций, далее они |
||||
|
AVR-СПЕЦИФИЧНЫЕ МОДУЛИ |
ственно требованиям используемого мик- |
|
будут рассмотрены без упоминания того, |
|||||||
|
К специфичным для AVR относятся мо- |
роконтроллера. |
|
что это не функции на самом деле. |
|
||||||
|
дули, реализующие ряд функций, выполне- |
Пример: BOOTLOADER_SECTION void |
|
|
|
|
|
||||
|
ние которых возможно исключительно на |
func1(void); - функция func1() будет разме- |
|
boot_spm_interrupt_enable() |
|
||||||
|
платформе AVR-микроконтроллеров, т.е. |
щена в области памяти микроконтроллера, |
|
boot_spm_interrupt_enable() |
|
||||||
|
аппаратно-зависимые функции. В основном |
отведенной для загрузчика. |
|
Описание: разрешает прерывания пос- |
|||||||
|
эти функции реализуют поддержку особен- |
|
|
|
ле исполнения инструкции записи в память |
||||||
|
ностей архитектуры микроконтроллеров, |
GET_LOW_FUSE_BITS |
|
программ. |
|
||||||
|
например, встроенную EEPROM или воз- |
GET_LOW_FUSE_BITS – константа, за- |
|
|
|
|
|
||||
|
можность записи в память программ. |
дающая адрес чтения младшего байта fuse- |
|
boot_spm_interrupt_disable() |
|
||||||
|
|
|
|
|
битов микроконтроллера для применения в |
|
boot_spm_interrupt_disable() |
|
|||
|
avr/boot.h – Поддержка |
boot_lock_fuse_bits_get() |
|
Описание: запрещает прерывания пос- |
|||||||
|
загрузчиков AVR |
|
|
|
ле исполнения инструкции записи в память |
||||||
|
Модуль определяет ряд макросов, уп- |
GET_LOCK_BITS |
|
программ. |
|
||||||
|
рощающих разработку программ пользова- |
GET_LOCK_BITS – константа, зада- |
|
|
|
|
|
||||
|
теля, реализующих алгоритм самозагруз- |
ющая адрес чтения байта lock-битов мик- |
|
boot_is_spm_interrupt() |
|
||||||
|
ки программы (boot-loading). Это возможно |
роконтроллера для применения в |
|
boot_is_spm_interrupt() |
|
||||||
|
не для любого микроконтроллера AVR. Мак- |
boot_lock_fuse_bits_get() |
|
Описание: проверяет, разрешены ли |
|||||||
|
росы модуля позволяют работать со всей |
|
|
|
прерывания после исполнения инструкции |
||||||
|
областью памяти программ микроконтрол- |
GET_EXTENDED_FUSE_BITS |
|
записи в память программ. |
|
||||||
|
леров. |
|
|
GET_EXTENDED_FUSE_BITS – кон- |
|
|
|
|
|
||
|
Макросы не используют глобальное |
станта, задающая адрес чтения байта рас- |
|
boot_rww_busy() |
|
||||||
|
запрещение прерываний, это оставлено на |
ширенных fuse-битов микроконтроллера |
|
boot_rww_busy() |
|
||||||
|
совести программиста. Пример функции са- |
для применения в boot_lock_fuse_bits_get() |
|
Описание: проверяет, занята ли секция |
|||||||
|
мозаписи памяти программ см. на врезке. |
|
|
|
RWW памяти программ. |
|
|||||
|
|
|
|
|
GET_HIGH_FUSE_BITS |
|
|
|
|
|
|
|
Определения модуля |
GET_HIGH_FUSE_BITS – константа, |
|
boot_spm_busy() |
|
||||||
|
|
|
|
|
задающая адрес чтения старшего байта |
|
boot_spm_busy() |
|
|||
|
BOOTLOADER_SECTION |
fuse-битов микроконтроллера для примене- |
|
Описание: проверяет, завершена ли |
|||||||
|
BOOTLOADER_SECTION – модифика- |
ния в boot_lock_fuse_bits_get() |
|
инструкция записи в память программ. |
|||||||
|
тор атрибутов переменной или функции в |
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
boot_spm_busy_wait() |
|
||
|
|
|
|
|
|
|
|
boot_spm_busy_wait() |
|
||
|
|
|
Врезка. Пример функции самозаписи памяти программ. |
|
|
Описание: ожидает, пока не завершит- |
|||||
|
|
|
|
|
ся инструкция записи в память программ. |
||||||
|
|
|
|
|
|
|
|
||||
|
#include <inttypes.h> |
|
|
|
|
|
boot_lock_fuse_bits_get() |
|
|||
|
#include <avr/interrupt.h> |
|
|
|
|
||||||
|
|
|
|
boot_lock_fuse_bits_get(address) |
|
||||||
|
#include <avr/pgmspace.h> |
|
|
|
|
||||||
|
|
|
|
Описание: возвращает считанный байт |
|||||||
|
void boot_program_page (uint32_t page, uint8_t *buf){ |
|
|
||||||||
|
|
|
fuse-битов или lock-битов микроконтрол- |
||||||||
|
uint16_t i; |
|
|
|
|
|
|||||
|
|
|
|
|
|
лера в зависимости от значения address, |
|||||
|
uint8_t sreg; |
|
|
|
|
|
|||||
|
|
|
|
|
|
которое может принимать одно из следую- |
|||||
|
// запрещаем прерывания |
|
|
|
|
|
|||||
|
|
|
|
|
|
щих значений: GET_LOW_FUSE_BITS, |
|||||
|
sreg = SREG; |
|
|
|
|
|
|||||
|
|
|
|
|
|
G E T _ E X T E N D E D _ F U S E _ B I T S , |
|||||
|
cli(); |
|
|
|
|
|
|||||
|
|
|
|
|
|
GET_HIGH_FUSE_BITS |
или |
||||
|
eeprom_busy_wait(); |
// ожидаем, завершения предыдущей записи |
|
|
|||||||
|
|
|
GET_LOCK_BITS. |
|
|||||||
|
boot_page_erase (page);// стираем указанную страницу |
|
|
|
|||||||
|
|
|
Примечание: возвращается физичес- |
||||||||
|
boot_spm_busy_wait(); |
// ожидаем завершения стирания |
|
|
|||||||
|
|
|
ки реальное значение соответствующего |
||||||||
|
// цикл заполнения страницы памяти |
|
|
|
|||||||
|
|
|
|
байта, т.е. запрограммированные биты яв- |
|||||||
|
for (i=0; i<SPM_PAGESIZE; i+=2){ |
|
|
|
|||||||
|
|
|
|
ляются нулями, а незапрограммированные |
|||||||
|
// заполняем словами «в обратном порядке» |
|
|
|
|||||||
|
|
|
|
биты – единицами. |
|
||||||
|
uint16_t w = *buf++; |
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||
|
w += (*buf++) << 8; |
|
|
|
|
|
boot_signature_byte_get() |
|
|||
|
boot_page_fill (page + i, w); |
|
|
|
|
||||||
|
|
|
|
boot_signature_byte_get(addr) |
|
||||||
|
} |
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
Описание: возвращает байт из обла- |
||||
|
boot_page_write (page);// записываем заполненную страницу |
|
|
||||||||
|
|
|
сти сигнатуры микроконтроллера. Для |
||||||||
|
boot_spm_busy_wait(); |
// ожидаем завершения записи |
|
|
|||||||
|
|
|
микроконтроллеров, поддерживающих |
||||||||
|
// разрешение перехода к RWW секции памяти. Это нужно, если |
|
|
||||||||
|
|
|
калибровочные байты встроенных RC-гене- |
||||||||
|
// после самозаписи должен быть осуществлен переход к основной программе |
|
|
||||||||
|
|
|
раторов, этот макрос так же может возвра- |
||||||||
|
boot_rww_enable(); |
|
|
|
|
|
|||||
|
|
|
|
|
|
щать и эти значения. Значение addr может |
|||||
|
// восстановление состояния прерываний, как было при входе в функцию |
|
|
||||||||
|
|
|
находиться в пределах от 0 до 0x1F – см. |
||||||||
|
SREG = sreg; |
|
|
|
|
|
|||||
|
|
|
|
|
|
документацию на примененный микрокон- |
|||||
|
} |
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
троллер. |
|
|||
|
|
|
|
|
|
|
|
|
|||
5 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Радиолюбитель – 01/2011 |
||
|
|
|
|
|
|
|
|
|
|
||
СПРАВОЧНЫЙ МАТЕРИАЛ
boot_page_fill() |
boot_rww_enable_safe() |
eeprom_is_ready() |
|||
boot_page_fill(address, data) |
boot_rww_enable_safe() |
eeprom_is_ready() |
|||
Описание: записывает во временный |
Описание: выполняет то же действие, |
Описание: макрос, возвращающий не |
|||
буфер страницы по указанному адресу |
что и boot_rww_enable(), но перед этим до- |
нулевое значение, если EEPROM готова для |
|||
address заданные данные data. |
жидается завершения ранее начатой опе- |
очередного обращения, 0 – в противном слу- |
|||
Примечание: address – это адрес бай- |
рации самопрограммирования. |
чае. |
|||
та, data – это 16-битное значение (слово). |
|
|
|
||
AVR адресуют память побайтно, но за |
boot_lock_bits_set_safe() |
eeprom_busy_wait() |
|||
один раз записывают слово! Правиль- |
boot_lock_bits_set_safe(lock_bits) |
eeprom_busy_wait() |
|||
ное использование макроса заключается |
Описание: выполняет то же действие, |
Описание: макрос, выполняющий цикл |
|||
в том, чтобы от обращения к обращению |
что и boot_lock_bits_set(), но перед этим |
ожидания завершения операции записи в |
|||
увеличивать значение address на 2, а в |
дожидается завершения ранее начатой опе- |
EEPROM. |
|||
data помещать сразу по 2 байта, как еди- |
рации самопрограммирования. |
Функции модуля |
|||
ное слово. |
|
||||
|
|
|
avr/eeprom.h – Поддержка |
Большинство функций реализованы как |
|
boot_page_erase() |
EEPROM AVR |
static inline-функции или макросы-функции. |
|||
boot_page_erase(address) |
Этот модуль содержит ряд простых |
|
|
||
Описание: выполняет стирание страни- |
функций и макросов, реализующих основ- |
eeprom_read_byte() |
|||
цы памяти программ. |
ные операции для работы со встроенным |
uint8_t eeprom_read_byte (const uint8_t |
|||
Примечание: address – это адрес бай- |
EEPROM микроконтроллеров AVR. Все фун- |
*p) |
|||
та, а не слова. |
кции действуют по принципу «ожидания», |
Параметры: |
|||
|
|
|
т.е. достаточно длительные. Если требует- |
const uint8_t *p – указатель на байт в |
|
boot_page_write() |
ся реализация работы по прерываниям для |
EEPROM |
|||
boot_page_write(address) |
максимально эффективного кода, она дол- |
Возвращаемое значение: считанный |
|||
Описание: выполняет запись буфера в |
жна быть реализована пользователем са- |
из EEPROM байт. |
|||
указанную address страницу памяти про- |
мостоятельно. |
Описание: функция выполняет считы- |
|||
грамм. |
Все функции выполняют проверку го- |
вание байта по указанному адресу из |
|||
Примечание: address – это адрес бай- |
товности EEPROM для очередного обраще- |
EEPROM. |
|||
та, а не слова. |
ния, но они не контролируют состояние ав- |
|
|
||
|
|
|
томата записи в память программ (т.е. са- |
eeprom_read_word() |
|
boot_rww_enable() |
мопрограммирования). Если ваша програм- |
uint16_t eeprom_read_word (const |
|||
boot_rww_enable() |
ма содержит код самопрограммирования, |
uint16_t *p) |
|||
Описание: включает доступ к RWW- |
вы должны самостоятельно реализовать |
Параметры: |
|||
секции памяти программ. |
проверку завершения любой операции са- |
const uint16_t *p – указатель на слово в |
|||
|
|
|
мопрограммирования перед обращением к |
EEPROM |
|
boot_lock_bits_set() |
EEPROM. |
Возвращаемое значение: считанное |
|||
boot_lock_bits_set(lock_bits) |
Так как функции используют фиксиро- |
из EEPROM слово. |
|||
Описание: устанавливает биты защи- |
ванные регистры для работы, они не реен- |
Описание: функция выполняет считы- |
|||
ты загрузчика (BLB-биты). |
терабельны, т.е. если эти функции вызы- |
вание 16-битного значения из EEPROM. |
|||
Примечания: |
ваются и из обычного цикла программы и |
|
|
||
1. Параметр lock_bits в данном макро- |
из обработчиков прерываний, следует зап- |
eeprom_read_dword() |
|||
се должен содержать единицы в тех пози- |
рещать глобально прерывания перед об- |
uint32_t eeprom_read_dword (const |
|||
циях, которые должны быть запрограмми- |
ращениям к этим функциям из основной |
uint32_t *p) |
|||
рованы, т.е. записаны в ноль. |
программы. |
Параметры: |
|||
2. Макрос устанавливает только BLB- |
Определения модуля |
const uint32_t *p – указатель на двой- |
|||
биты защиты. |
ное слово в EEPROM |
||||
3. Как и любые биты защиты, единож- |
Модуль вводит ряд определений (кон- |
Возвращаемое значение: считанное |
|||
ды установленные BLB-биты могут быть |
стант и макросов), часть из которых позво- |
из EEPROM двойное слово. |
|||
стерты только при полном стирании памяти |
ляет упростить совместимость исходного |
Описание: функция выполняет считы- |
|||
микроконтроллера. |
текста со средой разработки IAR. |
вание 32-битного числа из EEPROM. |
|||
boot_page_fill_safe() |
_EEPUT() |
eeprom_read_block() |
|||
boot_page_fill_safe(address, data) |
_EEPUT(addr, val) |
void eeprom_read_block (void *dst, const |
|||
Описание: выполняет то же действие, |
Описание: макрос, осуществляющий |
void *src, size_t n) |
|||
что и boot_page_fill(), но перед этим дожи- |
запись байта val в EEPROM по адреса addr. |
Параметры: |
|||
дается завершения ранее начатой опера- |
Введен для совместимости с IAR. |
void *dst – указатель на начало области |
|||
ции самопрограммирования. |
|
в ОЗУ |
|||
|
|
|
_EEGET() |
const void *src – указатель на начало |
|
boot_page_erase_safe() |
_EEGET(var, addr) |
области EEPROM |
|||
boot_page_erase_safe(address) |
Описание: макрос, осуществляющий |
size_t n – количество байт |
|||
Описание: выполняет то же действие, |
чтение байта из EEPROM по адресу addr. |
Возвращаемое значение: нет. |
|||
что и boot_page_erase(), но перед этим до- |
Введен для совместимости с IAR. |
Описание: функция выполняет считы- |
|||
жидается завершения ранее начатой опе- |
|
вание n байтов из EEPROM по адресу src |
|||
рации самопрограммирования. |
EEMEM |
и размещает их в ОЗУ, начиная с адреса |
|||
|
|
|
EEMEM |
dest. |
|
boot_page_write_safe() |
Описание: атрибут, указывающий на |
|
|
||
boot_page_write_safe(address) |
то, что переменная должна размещаться в |
eeprom_write_byte() |
|||
Описание: выполняет то же действие, |
EEPROM. Пример использования: EEMEM |
void eeprom_write_byte (uint8_t *p, uint8_t |
|||
что и boot_page_write(), но перед этим до- |
int k; - переменная k должна быть размеще- |
value) |
|||
жидается завершения ранее начатой опе- |
на в EEPROM. |
Параметры: |
|||
рации самопрограммирования. |
|
uint8_t *p – указатель на ячейку в |
|||
|
|
|
|
EEPROM |
|
|
|
|
|
|
5 5 |
Радиолюбитель – 01/2011 |
|
|
|
|
|
|
|
|
|
|
|
СПРАВОЧНЫЙ МАТЕРИАЛ
uint8_t value – записываемый байт |
|
Врезка. Пример использования. |
||||
Возвращаемое значение: нет. |
|
|||||
|
|
|
|
|
||
Описание: функция выполняет запись |
#include <avr/io.h> |
|
|
|
||
байта value в EEPROM по адресу p. |
|
|
|
|||
FUSES ={ |
|
|
|
|||
|
|
|
|
|||
eeprom_write_word() |
.low = LFUSE_DEFAULT, |
|
|
|
||
.high = (FUSE_BOOTSZ0 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), |
||||||
void eeprom_write_word (uint16_t *p, |
||||||
.extended = EFUSE_DEFAULT, |
|
|
|
|||
uint16_t value) |
|
|
|
|||
}; |
|
|
|
|
||
uint16_t *p – указатель на ячейку в |
|
|
|
|
||
|
|
|
|
|
||
EEPROM |
int main(void){ |
|
|
|
||
uint16_t value – записываемое слово |
|
|
|
|||
return 0; |
|
|
|
|||
Возвращаемое значение: нет. |
|
|
|
|||
} |
|
|
|
|
||
Описание: функция выполняет запись |
|
|
|
|
||
|
|
|
|
|
||
16-битного числа value в EEPROM по адре- |
avr/fuse.h – Поддержка |
|
|
|
||
су p. |
|
FUSES представляет собой структуру с тре- |
||||
|
||||||
|
fuse-битов AVR |
|
мя полями типа int8_t – low, high и extended. |
|||
eeprom_write_dword() |
Модуль позволяет разместить в осо- |
|
Наконец, если МК содержит более 3-х fuse- |
|||
void eeprom_write_dword (uint32_t *p, |
бой секции ELF-файла информацию о со- |
|
байтов, FUSES определена как массив бай- |
|||
uint32_t value) |
стоянии fuse-битов, которую может извле- |
|
тов соответствующей длины. |
|||
uint32 *p – указатель на ячейку в |
кать программное обеспечение програм- |
|
Следует учитывать, что компоновщик |
|||
EEPROM |
матора для установки fuse-битов при про- |
|
использует только значения переменной |
|||
uint32 value – записываемое двойное |
граммировании микроконтроллера. Раз- |
|
FUSES, которые были указаны на этапе |
|||
слово |
мещение этой информации в ELF-файле |
|
начальной инициализации, и игнорирует все |
|||
Возвращаемое значение: нет. |
осуществляется при компоновке програм- |
|
изменения, которые могли быть сделаны в |
|||
Описание: функция выполняет запись |
мы. К сожалению, в HEX-формате сведе- |
|
ходе выполнения программы. |
|||
32-битного числа value в EEPROM по адре- |
ния о состоянии fuse-битов размещены |
|
Пример использования см. на врезке. |
|||
су p. |
быть не могут. |
|
Важно, что всегда необходимо инициа- |
|||
|
Данный модуль – универсальный, т.е. |
|
лизировать все поля структуры FUSES. |
|||
eeprom_write_block() |
ориентирован на весь спектр поддержи- |
|
Суть |
рассматриваемого модуля |
||
void eeprom_write_block (const void *src, |
ваемых микроконтроллеров. Необходимо |
|
заключена в том, что получаемый в |
|||
void *dst, size_t n) |
обязательно подключать к проекту модуль |
|
результате компиляции elf-файл содержит |
|||
Параметры: |
io.h, в котором определяются глобальные |
|
абсолютно всю информацию, необходимую |
|||
void *src – указатель на начало области |
параметры, используемые затем в моду- |
|
для правильного программирования |
|||
ОЗУ |
ле fuse.h. Сам модуль fuse.h подключа- |
|
микроконтроллера. Остается только решить |
|||
void *dst – указатель на начало области |
ется в этом случае автоматически, поэто- |
|
вопрос, |
какое именно программное |
||
в EEPROM |
му нужды в явном его подключении нет. |
|
обеспечение в состоянии воспользоваться |
|||
size_t n – количество байт |
В зависимости от типа примененно- |
|
этой информацией. В какой-то мере эту |
|||
Возвращаемое значение: нет. |
го микроконтроллера fuse-биты могут |
|
задачу может решить утилита avrdude, |
|||
Описание: функция осуществляет за- |
располагаться в младшем, старшем |
|
входящая в состав WinAVR, однако, только |
|||
пись n байт из области ОЗУ src в область |
или расширенном fuse-байте. Для каж- |
|
в связке с другой утилитой avr-objcopy. |
|||
EEPROM dest. |
дого отдельно взятого fuse-бита вводят- |
|
Avrdude – это универсальный программатор, |
|||
Следует признать, что модуль |
ся константы-маски, соответствующие |
|
поддерживающий огромное количество |
|||
eeprom.h от релиза к релизу WinAVR пре- |
наименованию fuse-бита, например, |
|
схем для прошивки микроконтроллеров |
|||
терпевает существенные модификации, в |
FUSE_SPIEN, FUSE_RSTDSBL и т.д.34 . |
|
AVR, а утилита avr-objcopy позволяет |
|||
частности, неоднократно менялись места- |
Если необходимо установить несколько |
|
извлекать из elf-файла информационные |
|||
ми параметры функций блочного чтения- |
fuse-битов в одном байте, нужно объединять |
|
блоки о flash, eeprom и fuse-битах (из |
|||
записи, что, разумеется, порождает опре- |
их при помощи битовой операции AND, т.е. |
|
соответствующих секций) и сохранять их в |
|||
деленные сложности с совместимостью |
так: (FUSE_SPIEN & FUSE_RSTDISBL & |
|
виде hex-файлов, которые уже могут |
|||
ранее разработанного кода и новой вер- |
….). |
|
использоваться avrdude для прошивки. К |
|||
сии компилятора. Поэтому рекомендуется |
Для каждого из fuse-байтов конкретно- |
|
сожалению, обе эти утилиты имеют немалое |
|||
тщательно изучить документацию на све- |
го микроконтроллера определены значения |
|
количество опций запуска, поэтому в рамках |
|||
жий релиз WinAVR, т.к. в нем могут быть |
fuse-битов по умолчанию, которые следует |
|
данного изложения не рассматриваются |
|||
сюрпризы. |
применять, если изменять их не требуется: |
|
(это планируется сделать позже). |
|||
Из числа приятных сюрпризов, появив- |
LFUSE_DEFAULT для младшего байта, |
|
avr/interrupt.h – Прерывания |
|||
шихся с версии WinAVR 20100110, можно |
HFUSE_DEFAULT для старшего и |
|
||||
назвать появление «бережных» функций |
EFUSE_DEFAULT для расширенного. |
|
Общие сведения |
|||
записи EEPROM eeprom_update_xxxx(), |
Модуль определяет всего одну глобаль- |
|
||||
где xxxx – это суффикс byte, word, |
ную переменную-структуру FUSES, к зада- |
|
При обработке прерываний происходит |
|||
dword или block. Параметры этих фун- |
нию начальных значений для которой и сво- |
|
конфликт между декларируемой Си неза- |
|||
кций такие же, как у соответствующих |
дится вся работа с fuse-битами. Данная пе- |
|
висимостью от аппаратуры, и жесткой при- |
|||
eeprom_write_xxxx(), а отличие в том, что |
ременная в зависимости от микроконтрол- |
|
вязке векторов прерываний к этой самой |
|||
новые функции перед тем, как записать |
лера может быть разного типа: если микро- |
|
аппаратуре. Таким образом, любая реали- |
|||
новое значение в ячейку EEPROM, прове- |
контроллер содержит всего один fuse-байт, |
|
зация обработки прерываний на Си стано- |
|||
ряют ее текущее значение и, если оба зна- |
то эта переменная является просто пере- |
|
вится уникальной для конкретной среды |
|||
чения одинаковы, то запись в ячейку не про- |
менной типа int8_t; если микроконтроллер |
|
программирования. |
|||
изводится. Так как ресурс записей EEPROM |
имеет 2 fuse-байта, то FUSES представля- |
|
В WinAVR принято, что каждому оп- |
|||
AVR ограничен 100000 записей, использо- |
ет собой структуру с 2-я полями low и high |
|
ределенному вектору прерывания сопо- |
|||
вание новых функций позволяет увеличить |
соответственно типа int8_t каждое; для мик- |
|
ставлена особым образом поименован- |
|||
живучесть EEPROM без принятия каких-то |
роконтроллеров с тремя fuse-байтами |
|
ная функция-обработчик. Определение в |
|||
особых мер. |
|
|
|
|
|
|
Рекомендуется использовать эти фун- |
34 Т.к. fuse-биты отличаются в зависимости от модели микроконтроллера, следует ознакомиться с их наименованием |
|||||
кции всегда. |
по соответствующей документации к выбранному контроллеру; в настоящей документации они не приводятся. |
|||||
5 6 |
Радиолюбитель – 01/2011 |
|
СПРАВОЧНЫЙ МАТЕРИАЛ
программе функции, названной в соответ- |
определить обработчик, который не дела- |
(оканчиваются на суффикс _vect, например, |
|
ствии с определенными соглашениями, при- |
ет ничего. |
ADC_vect). Кроме этого можно использо- |
|
водит к тому, что компилятор генерирует для |
Наконец, во многих случаях может |
вать константу BADISR_vect для задания об- |
|
нее нестандартный код пролога и эпилога, |
оказаться, что неизбежно генерируемый |
работчика «по умолчанию». |
|
в частности, обязательно сохраняет SREG |
компилятором для обработчика прерыва- |
Второй параметр attributes – необяза- |
|
в начале и восстанавливает в конце, а так |
ния код пролога и эпилога оказывается |
тельный, определяет опциональные вари- |
|
же использует для возврата из функции ко- |
слишком велик. Было бы удобно в таком |
анты реализации соответствующего обра- |
|
манду RETI. Кроме того, в таблице векто- |
случае использовать обработчик, реали- |
ботчика. Допустимо использовать несколь- |
|
ров прерываний для каждой определенной |
зованный на ассемблере, либо попы- |
ко атрибутов из числа следующих (атрибу- |
|
пользователем функции-обработчика поме- |
таться обойтись средствами Си для по- |
ты разделяются запятыми): |
|
щается команда перехода к соответствую- |
лучения более оптимального кода. Сде- |
ISR_BLOCK – атрибут по умолчанию, |
|
щей функции. |
лать это можно при помощи параметра |
означает запрет прерываний, пока не отра- |
|
Далее кратко перечислены основные |
ISR_NAKED, указываемого для ISR(). В |
ботает текущий обработчик |
|
характерные особенности реализации об- |
этом случае компилятор не генерирует |
ISR_NOBLOCK – разрешает глобально |
|
работчиков прерываний WinAVR. Подроб- |
вообще никакого пролога и эпилога, по- |
прерывания сразу после пролога обработ- |
|
ности следует искать в описаниях соответ- |
этому программист сам должен обеспе- |
чика |
|
ствующих макросов. |
чить сохранение контекста программы (в |
ISR_NAKED – указывает, что вся реа- |
|
Детали реализации этого подхода ос- |
частности, содержимого SREG), и, глав- |
лизация кода обработчика делается про- |
|
таются за кадром, т.к. программисту доста- |
ное, использовать макрос reti() для выхо- |
граммистом (нет никакого пролога и эпило- |
|
точно определить при помощи макроса ISR() |
да из обработчика. |
га) |
|
функцию – и она будет назначена (и соот- |
Для каждого микроконтроллера опре- |
ISR_ALIASOF(v) – позволяет назначить |
|
ветственно оформлена) обработчиком оп- |
делены свои константы для указания со- |
текущему обработчику несколько векторов |
|
ределенного прерывания. |
ответствующего вектора прерывания. Эти |
(см. врезку для ISR_ALIASOF). |
|
Особенность аппаратного строения AVR |
константы содержат в своем составе |
|
|
заключается в том, что во время работы |
суффиксc _vect. Для совместимости с |
SIGNAL() |
|
одного обработчика прерываний все про- |
предыдущими версиями WinAVR сохране- |
SIGNAL(vector) – макрос определения |
|
чие прерывания запрещены. Такая ситуа- |
на и возможность определять обработчик |
обработчика, сохраненный исключительно |
|
ция в некоторых случаях может быть неже- |
прерывания при помощи «сигналов», т.е. |
для совместимости со старым кодом. Не ре- |
|
лательной, для чего можно (естественно, |
констант, имеющих «префикс» SIG_ (пре- |
комендуется использование в новых разра- |
|
осознавая последствия, к которым это мо- |
фиксы и суффиксы соответствующих век- |
ботках. В качестве параметра vector дол- |
|
жет привести) разрешить прерывания при- |
торов определены в заголовочных фай- |
жен получать константу с префиксом SIG_ |
|
нудительно внутри функции-обработчика, |
лах для каждого типа микроконтролле- |
из заголовочного файла конкретного мик- |
|
используя макрос sei(). Но можно поступить |
ров). Рекомендуется использовать «но- |
роконтроллера (например, SIG_ADC). |
|
и проще, указав для макроса ISR() параметр |
вую» форму _vect. |
|
|
ISR_NOBLOCK, что заставит компилятор |
Макросы и определения |
EMPTY_INTERRUPT() |
|
поместить соответствующую инструкцию |
EMPTY_INTERRUPT(vector) – макрос |
||
глобального разрешения прерываний сра- |
|
определения «пустого» обработчика, т.е. |
|
зу после пролога функции (т.е. инициали- |
sei() |
состоящего только из команды RETI. В ка- |
|
зирующего участка кода). |
sei() – глобальное разрешение преры- |
честве параметра принимаются те же зна- |
|
При разработке программ не исключе- |
ваний |
чения, что и для ISR(). |
|
на ситуация, когда случайно будет сгенери- |
|
|
|
ровано прерывание, для которого нет на- |
cli() |
ISR_ALIAS() |
|
значенного обработчика (ситуация «баг про- |
cli() – глобальное запрещение преры- |
ISR_ALIAS(vector, target_vector) – мак- |
|
граммы»). По умолчанию компилятор гене- |
ваний |
рос, связывающий два вектора в один об- |
|
рирует код, который в этом случае приве- |
|
работчик. Не рекомендуется использование |
|
дет к переходу на адрес 0х0000, т.е. пове- |
reti() |
в новых разработках. В качестве парамет- |
|
дение кода равносильно сбросу микрокон- |
reti() – макрос принудительно помеща- |
ра vector и target_vector используется лю- |
|
троллера. Однако такое поведение можно |
ет в код программы инструкцию RETI, обес- |
бая из констант, как и для ISR(), причем |
|
изменить, определив особый обработчик |
печивая возврат из прерывания. |
параметр target_vector к моменту вызова |
|
«неверного прерывания», который автома- |
|
макроса должен быть уже определен (см. |
|
тически назначается все «незанятым» век- |
ISR() |
врезку ISR_ALIAS): |
|
торам прерываний. Делается это при помо- |
ISR(vector, attributes) – макрос для оп- |
|
|
щи указания для ISR() «плохого» вектора |
ределения обработчика прерываний. |
ISR_ALIASOF() |
|
BADISR_vect.Такойобработчикбудетисполь- |
Первый параметр vector – это одна |
ISR_ALIASOF(target_vector) – макрос, |
|
зован для всех векторов прерываний, для |
из констант, определяющих номер век- |
используемый в качестве опционального |
|
которых не указаны явно их обработчики. |
тора прерывания. Реальные константы |
параметра ISR() для того, чтобы связать об- |
|
Так же часто может возникать ситуа- |
определены в соответствующем заголовоч- |
работчик, определенный ISR(), еще и с век- |
|
ция, когда один и тот же обработчик дол- |
ном файле модели микроконтроллера |
торомtarget_vector(см.врезкуISR_ALIASOF). |
|
жен использоваться для нескольких пре- |
|
|
|
рываний. Можно, конечно, определить не- |
Врезка ISR_ALIAS |
|
|
|
|
||
сколько абсолютно идентичных функций, |
// определяем обработчик внешнего запроса прерывания №0 |
||
|
|
||
однако, можно и сэкономить память, ука- |
ISR(INT0_vect){ |
|
|
|
|
||
зав для ISR() параметр ISR_ALIASOF(). |
PORTB = 42; |
|
|
|
|
||
Еще одной занимательной ситуаци- |
} |
|
|
|
|
||
ей, связанной с прерываниями, является |
// назначаем этот обработчик и для запроса №1 |
|
|
|
|
||
пробуждение микроконтроллера по пре- |
ISR_ALIAS(INT1_vect, INT0_vect); |
|
|
|
|
||
рыванию из «спящего» режима. В этом |
|
|
|
Врезка ISR_ALIASOF |
|
||
случае обработчик прерывания вызыва- |
|
||
// определяем обработчик внешнего запроса прерывания №0 и одновременно №1 |
|||
ется, однако, часто в нем никаких полез- |
|||
ISR(INT0_vect, ISR_ALIASOF(INT1_vect)){ |
|
||
ных действий выполняться не должно. |
|
||
PORTB = 42; |
|
||
Для таких случаев предусмотрен мак- |
|
||
} |
|
||
рос EMPTY_INTERRUPT(), позволяющий |
|
||
|
|
||
|
|
|
5 7 |
Радиолюбитель – 01/2011 |
|
|
|
|
|
|
СПРАВОЧНЫЙ МАТЕРИАЛ
BADISR_vect |
FLASHEND – соответствует адресу пос- |
PGM_VOID_P |
BADISR_vect – константа «псевдовек- |
ледней ячейки памяти программ, т.е. фак- |
PGM_VOID_P – макрос, определяющий |
тора», обозначающая любой явно не задан- |
тически определяет размер сегмента кода. |
указатель на объект в сегменте кода |
ный вектор. По умолчанию соответствует |
SPM_PAGESIZE – соответствует разме- |
|
переходу на начало программной памяти, |
ру страницы для операций самопрограмми- |
pgm_read_byte_near() |
вызывая переинициализацию всего кода |
рования (т.е. записи из программы в сег- |
pgm_read_byte_near(address_short) – |
при поступлении «необрабатываемого» |
мент кода). |
макрос, возвращающий значение байта, |
прерывания. |
|
считанного из программной памяти по ад- |
|
avr/pgmspace.h – Поддержка |
ресу address_short (в первых 64К). |
ISR_BLOCK |
обращения к сегменту кода AVR |
|
ISR_BLOCK – опциональный атрибут, |
В этом модуле определяются ряд фун- |
pgm_read_word_near() |
используемый в ISR(), и обозначающий, что |
кций и макросов, позволяющих обращать- |
pgm_read_word_near(address_short) – |
прерывания будут запрещены в течение |
ся к данным, хранящимся в памяти про- |
макрос, возвращающий значение 16-битно- |
работы всего обработчика прерывания. |
грамм, т.е. сегменте кода. Для этого необ- |
го числа, считанного из программной памя- |
Если этот атрибут не задан явно (т.е. исполь- |
ходимо, чтобы микроконтроллер поддержи- |
ти по адресу address_short (в первых 64К). |
зуется ISR() без атрибутов вообще), преры- |
вал инструкции LPM или ELPM. |
|
вания все равно будут запрещены. |
Функции этого модуля – попытка облег- |
pgm_read_dword_near() |
|
чить процесс адаптации программ для IAR, |
pgm_read_dword_near(address_short) – |
ISR_NOBLOCK |
однако полной совместимости нет по прин- |
макрос, возвращающий значение 32-бит- |
ISR_NOBLOCK – опциональный атри- |
ципиальным особенностям GCC. |
ного числа, считанного из программной па- |
бут, используемый в ISR(), и обозначающий, |
Если вы работаете со строками, кото- |
мяти по адресу address_short (в первых |
что прерывания будут разрешены в тече- |
рые постоянно размещены в ОЗУ, вы мо- |
64К). |
ние работы всего обработчика прерывания. |
жете использовать функции для работы с |
|
Это позволит быстрее отреагировать на |
ними из модуля string.h – Строки, но для |
pgm_read_byte_far() |
ожидающие в очереди другие запросы пре- |
неизменных строк более удачным будет |
pgm_read_byte_far(address_long) – мак- |
рываний, однако увеличивает требования |
размещение их в сегменте кода. В этом слу- |
рос, возвращающий значение байта, счи- |
к объему стека. |
чае вы можете работать с ними при помо- |
танного из программной памяти по адресу |
|
щи функций этого модуля, которые совпа- |
address_long (32 бита, нет ограничения в |
ISR_NAKED |
дают по имени с аналогичными из string.h, |
64К). |
ISR_NAKED – опциональный атрибут, |
но имеют суффикс _Р – признак того, что |
|
используемый в ISR(), и обозначающий, что |
строка находится в программной памяти |
pgm_read_word_far() |
компилятор не должен добавлять пролог и |
(такой принцип так же использовался и в |
pgm_read_word_far(address_long) – мак- |
эпилог к функции. В этом случае програм- |
модуле stdio.h – Стандартный ввод-вывод). |
рос, возвращающий значение 16-битного |
мист обязан сам выполнить все необходи- |
Однако следует учитывать, что функции |
числа, считанного из программной памяти |
мые меры, включая выход из обработчика |
из настоящего модуля могут работать толь- |
по адресу address_long (32 бита, нет огра- |
макросом reti(). |
ко со строками, размещенными в первых |
ничения в 64К). |
|
64К адресного пространства микроконтрол- |
|
avr/io.h – Специфичные |
лера, т.к. не используют инструкцию ELPM. |
pgm_read_dword_far() |
для AVR функции ввода-вывода |
Это не страшно в обычных случаях. Но мо- |
pgm_read_dword_far(address_long) – |
Этот заголовочный файл по существу |
жет вызвать проблемы, если имеется много |
макрос, возвращающий значение 32-битно- |
реализует автоматическое подключение |
текстовых констант или же используется са- |
го числа, считанного из программной памя- |
одного конкретного файла, соответствую- |
мозагрузка кода. При написании программы |
ти по адресу address_long (32 бита, нет ог- |
щего выбранному микроконтроллеру. Во |
вы не должны беспокоиться о месте разме- |
раничения в 64К). |
всяком случае, для определения констант и |
щения строк, т.к. компоновщик автоматичес- |
|
макросов портов ввода-вывода и т.п. пери- |
ки разместит все данные в программной |
pgm_read_byte() |
ферии программист более не должен при- |
памяти сразу после векторов прерывания. |
pgm_read_byte(address_short) – аналог |
менять никаких усилий, кроме подключения |
Так же следует помнить о том, что все |
pgm_read_byte_near() |
этого файла к проекту и задания типа мик- |
используемые для обращения к сегменту |
|
роконтроллера. Фактически происходит |
кода указатели представляют себя адре- |
pgm_read_word() |
подключение целого ряда заголовочных |
са байтов (хотя программная адресация у |
pgm_read_word(address_short) – аналог |
файлов, в которых определены константы |
AVR – 16-битная). |
pgm_read_word_near() |
и макросы для обращения к различной пе- |
|
|
риферии микроконтроллера (см. например |
Определения модуля |
pgm_read_dword() |
avr/sfr_defs.h – Регистры специальных фун- |
Модуль определяет ряд констант, атри- |
pgm_read_dword(address_short) – ана- |
кций AVR). |
бутов и макросов, облегчающих разработ- |
лог pgm_read_dword_near() |
Рассмотрение всех этих определений |
ку программ, работающих с данными в сег- |
|
опущено, т.к. подразумевается, что про- |
менте кода. |
Типы, вводимые модулем |
граммист, работающий с AVR, вполне ин- |
|
Модуль вводит ряд типов, которые про- |
формирован о его периферии. Из прочего |
PROGMEM |
сто облегчают определение констант в сег- |
стоит обратить внимание лишь на следую- |
PROGMEM – макрос, устанавливающий |
менте кода. По смыслу все эти типы анало- |
щие константы: |
атрибут, указывающий, что переменная на |
гичны определенным в inttypes.h – Целочис- |
RAMEND – соответствует адресу пос- |
самом деле представляет собой константу |
ленные преобразования, только содержат |
ледней существующей ячейки ОЗУ, т.е. в |
в сегменте кода |
префикс prog_, означающий, что соответ- |
сущности, определяет размер ОЗУ выбран- |
|
ствующий объект размещается в памяти |
ного микроконтроллера. |
PSTR() |
программ. В связи с этим расшифровка |
XRAMEND – соответствует адресу пос- |
PSTR(s) – макрос, используемый для |
значения типов не приводится. |
ледней существующей ячейки внешнего |
определения указателя на строку s, разме- |
prog_void |
или дополнительно адресуемого ОЗУ (если |
щенную в сегменте кода |
prog_char |
его поддержка имеется в микроконтролле- |
|
prog_uchar |
ре). |
PGM_P |
prog_int8_t |
E2END – соответствует адресу после- |
PGM_P – макрос, определяющий ука- |
prog_uint8_t |
дней ячейки встроенного EEPROM |
затель на символ в сегменте кода |
prog_int16_t |
5 8 |
Радиолюбитель – 01/2011 |
|
СПРАВОЧНЫЙ МАТЕРИАЛ
prog_uint16_t |
strcmp_P() |
|
strpbrk_P() |
|||
prog_int32_t |
int strcmp_P (const char *s1, PGM_P s2) |
|
char * strpbrk_P (const char *s, PGM_P |
|||
prog_uint32_t |
Функция аналогична strcmp(), за исклю- |
accept) |
||||
prog_int64_t |
чением того, что s2 находится в программ- |
|
Функция аналогична strpbrk(), за исклю- |
|||
prog_uint64_t |
ной памяти. |
чением того, что accept находится в про- |
||||
|
|
|
|
граммной памяти |
||
Функции модуля |
strcpy_P() |
|
|
|
||
Так как все функции не более чем ана- |
char * strcpy_P (char *s1, PGM_P s2) |
|
strrchr_P() |
|||
логи string.h – Строки, вместо подробного |
Функция аналогична strcpy(), за исклю- |
|
PGM_P strrchr_P (PGM_P s, int val) |
|||
описания будут указаны ссылки на функ- |
чением того, что s2 находится в программ- |
|
Функция аналогична strrchr(), за исклю- |
|||
ции для работы со строками в ОЗУ. Един- |
ной памяти. |
чением того, что s находится в программ- |
||||
ственное, на что должен обратить програм- |
|
ной памяти |
||||
мист, это типы передаваемых в функции па- |
strcspn_P() |
|
|
|
||
раметров и возвращаемых значений: как |
size_t strcspn_P (const char *s, PGM_P |
|
strsep_P() |
|||
правило, все указатели в функциях этого |
reject) |
|
char * strsep_P (char **sp, PGM_P delim) |
|||
модуля – это указатели на объекты в сег- |
Функция аналогична strcspn(), за исклю- |
|
Функция аналогична strsep(), за исклю- |
|||
менте кода. |
чением того, что reject находится в про- |
чением того, что delim находится в про- |
||||
|
|
|
граммной памяти. |
граммной памяти |
||
memchr_P() |
|
|
|
|
||
PGM_VOID_P memchr_P (PGM_VOID_P |
strlcat_P() |
|
strspn_P() |
|||
s, int val, size_t len) |
size_t strlcat_P (char *dest, PGM_P src, |
|
size_t strspn_P (const char *s, PGM_P |
|||
Функция ищет в области программной |
size_t siz) |
accept) |
||||
памяти s символ, возвращая указатель на |
Функция аналогична strlcat(), за исклю- |
|
Функция аналогична strspn(), за исклю- |
|||
него или NULL, если не найдено. Подробно- |
чением того, что src находится в программ- |
чением того, что accept находится в про- |
||||
сти см. в memrchr() |
ной памяти |
|
граммной памяти |
|||
memcmp_P() |
strlcpy_P() |
|
strstr_P() |
|||
int memcmp_P (const void *s1, |
size_t strlcpy_P (char *dest, PGM_P src, |
|
char * strstr_P (const char *s1, PGM_P s2) |
|||
PGM_VOID_P s2, size_t len) |
size_t siz) |
|
Функция аналогична strstr(), за исклю- |
|||
Функция сравнивает область ОЗУ s1 и |
Функция аналогична strlcpy(), за исклю- |
|
чением того, что s2 находится в программ- |
|||
памяти программ s2. Подробности см. в |
чением того, что src находится в программ- |
|
ной памяти |
|||
memcmp() |
ной памяти |
|
|
|
||
|
|
|
|
|
memmem_P() |
|
memcpy_P() |
strlen_P() |
|
void * memmem_P (const void *s1, size_t |
|||
void * memcpy_P (void *dest, |
size_t strlen_P (PGM_P s) |
|
len1, PGM_VOID_P s2, size_t len2) |
|||
PGM_VOID_P src, size_t len) |
Функция аналогична strlen(), за исклю- |
|
Функция аналогична memmem(), за ис- |
|||
Функция копирует в область ОЗу dest |
чением того, что s находится в программ- |
|
ключением того, что s2 находится в про- |
|||
содержимое области памяти программ src. |
ной памяти |
граммной памяти |
||||
Подробности см. в memcpy() |
|
|
|
|
||
|
|
|
strncasecmp_P() |
|
strcasestr_P() |
|
memrchr_P() |
int strncasecmp_P (const char *s1, PGM_P |
|
char * strcasestr_P (const char *s1, PGM_P |
|||
PGM_VOID_P memrchr_P (PGM_VOID_P |
s2, size_t n) |
s2) |
||||
s, int val, size_t len) |
Функция аналогична strncasecmp(), за |
|
Функция аналогична strcasestr(), за ис- |
|||
Функция ищет в области программной |
исключением того, что s2 находится в про- |
ключением того, что s2 находится в про- |
||||
памяти s символ. Подробности см. в |
граммной памяти |
граммной памяти |
||||
memrchr() и memchr_P() |
|
|
|
|
||
|
|
|
strncat_P() |
|
|
|
strcasecmp_P() |
char * strncat_P (char *dest, PGM_P src, |
|
|
|
||
int strcasecmp_P (const char *s1, PGM_P |
size_t len) |
|
|
|
||
s2) |
Функция аналогична strncat(), за исклю- |
|
|
|
||
Функция сравнивает строку s1 в ОЗУ |
чением того, что src находится в программ- |
|
|
|
||
со строкой в памяти программ s2 без учета |
ной памяти |
|
|
|
||
регистра символов. См. strcasecmp() |
|
|
|
|
||
|
|
|
strncmp_P() |
|
|
|
strcat_P() |
int strncmp_P (const char *s1, PGM_P s2, |
|
|
|
||
char * strcat_P (char *dest, PGM_P src) |
size_t n) |
|
|
|
||
Функция осуществляет конкатенацию |
Функция аналогична strncmp(), за ис- |
|
|
|
||
строки src из памяти программ к строке dest |
ключением того, что s2 находится в про- |
|
|
|
||
в ОЗУ. См. strcat() |
граммной памяти |
|
|
|
||
strchr_P() |
strncpy_P() |
|
|
|
||
PGM_P strchr_P (PGM_P s, int val) |
char * strncpy_P (char *dest, PGM_P src, |
|
|
|
||
Функция ищет символ в строке s в про- |
size_t n) |
|
|
|
||
граммной памяти. См. strchr() |
Функция аналогична strncpy(), за исклю- |
|
|
|
||
|
|
|
чением того, что src находится в программ- |
|
|
|
strchrnul_P() |
ной памяти |
|
|
|
||
PGM_P strchrnul_P (PGM_P s, int val) |
|
|
|
|
||
Функция, аналогичная strchr_P(), за ис- |
strnlen_P() |
|
|
|
||
ключением того, что всегда возвращает не- |
size_t strnlen_P (PGM_P src, size_t len) |
|
|
|
||
NULL указатель: если символ не найден, |
Функция аналогична strnlen(), за исклю- |
|
|
|
||
возвращается указатель на завершающий |
чением того, что src находится в программ- |
|
|
|
||
|
Продолжение в №2/2011 |
|
||||
ноль строки s |
ной памяти |
|
|
|||
|
|
|
|
|
|
5 9 |
Радиолюбитель – 01/2011 |
|
|
|
|
|
|
|
|
|
|
|
|
|
