Задачи:
Изучить принцип работы и программирование таймера в режиме ШИМ
Поработать более плотно с арифметикой и логикой на ассемблере.
Работа:
1. Используя следующий пример кода на языке C, реализующий базовую настройку таймера в режим Fast PWM с фиксированной скважностью, реализовать такую же функциональность на языке Assembler. Убедиться, что светодиод будет мигать с частотой около 4 раз в секунду.
#include <avr/io.h>
int main(void)
{
// LED pin setup
DDRA |= (1 << DDRA5); // Set up LED pin as output
GTCCR |= (1 << REMAP); // Map compare B PWM output to LED pin
// Timer setup
// Turn on Fast PWM 8 bit mode, enable PWM signal on compare B
TCCR0A |= (1 << COM0B1)|(1 << COM0B0)|(1 << WGM00);
TCCR0B |= (1 << WGM02)|(1 << CS00)|(1 << CS02); // Set up prescaler
OCR0B = 0x80; // 0x80 produces 50% duty
while (1) {}
}
2. Используя следующий пример кода на языке С, модифицировать код так, чтобы появилась возможность динамически изменять скважность ШИМ сигнала во время работы устройства, создавая эффект «дыхания». Для этого в прерывании таймера по переполнению необходимо изменять значение в регистре сравнения с небольшим шагом от минимального (0) до максимального (0xFF) и обратно. Чтобы управлять скоростью «дыхания», изменения необходимо делать не каждое прерывание, а раз в N прерываний. В примере кода на языке C указанное N задаётся define'ом IRQs_FOR_DUTY_CHANGE.
Код на языке C, реализующий данную задачу:
#include <avr/io.h>
#include <avr/interrupt.h>
// Every IRQs_FOR_DUTY_CHANGE timer interrupts PWM duty will be changed
#define IRQs_FOR_DUTY_CHANGE 10
uint8_t irq_counter = 0; // Counter of IRQs for changing PWM duty
uint8_t delta = 1; // Delta applied to OCR0B on duty change. Can be 1 or -1
int main(void)
{
// LED pin setup
DDRA |= (1 << DDRA5); // Set up LED pin as output
GTCCR |= (1 << REMAP); // Map compare B PWM output to LED pin
// Timer setup
// Turn on Fast PWM 8 bit mode, enable PWM signal on compare B
TCCR0A |= (1 << COM0B1)|(1 << COM0B0)|(1 << WGM00);
TCCR0B |= (1 << WGM02)|(1 << CS00); // Set up prescaler
TIMSK0 |= (1 << TOIE0); // Enable Overflow interrupt
sei();
while (1) {}
}
ISR(TIM0_OVF_vect) {
irq_counter++;
// If enough irqs have already happened
if (irq_counter == IRQs_FOR_DUTY_CHANGE) {
irq_counter = 0; // Reset the counter
OCR0B += delta; // Change PWM duty
// Test for min/max values of OCR0B to change delta if needed
if (OCR0B == 0xFF) {
delta = -1;
}
if (OCR0B == 0) {
delta = 1;
}
}
}
3. Сравнить получившийся размер программ и количество занимаемой оперативной памяти в случае работы на языках C и Assembler. Для этого необходимо посмотреть на лог компиляции и найти там строки или таблицу вида:
Program Memory Usage : 106 bytes 8,3 % Full
Data Memory Usage : 17 bytes 15,4 % Full
Рекомендации по выполнению:
Поскольку в коде используется только 2 переменных и одна константа, удобно хранить их все в разных регистрах общего назначения. Присвойте им имена с помощью директивы .def (см. пример кода из л.р. 2).
Для реализации ветвлений используйте комбинации инструкций CP и BREQ, или одну инструкцию CPSE, если «тело» ветвления состоит из одной инструкции.
Вычитание единицы в случае работы с восьмибитными переменными (или регистрами общего назначения) можно заменить на сложение с числом 0xFF и получить одинаковый результат.
Вопросы к защите:
Перечислить режимы работы таймера.
Рассказать подробно об указанном режиме.
Дать определение ШИМ сигнала, изобразить его, рассказать о его параметрах (скважность, коэффициент заполнения, частота).
Объяснить, почему Phase-correct режим имеет такое название.
Привести примеры использования ШИМ сигнала.
Пройти по своему Assembler’ному коду и пояснить, как работают ветвления.
Практическая задача:
По заданным параметрам ШИМ сигнала подобрать режим работы таймера, необходимые предделители ядра и таймера, значения в регистрах сравнения.
