Извините, но решил написать здесь. Может есть у кого-нибудь код на асме для Мега8 ШИМ плавное зажигание светодиода? или подскажите пожалуйста алгоритм, чтобы я мог сравнить со своими додумками
Serhio писал(а):Извините, но решил написать здесь. Может есть у кого-нибудь код на асме для Мега8 ШИМ плавное зажигание светодиода? или подскажите пожалуйста алгоритм, чтобы я мог сравнить со своими додумками
Могу дать на C. Код под мегу 8. Светодиод вешать на ножку PB1
Здравствуйте. Написал примитивный код без прерываний для мигания 2х светодиодов, на таймере 1(aTMEGA32A).Свтодиод на канале А плавно гаснит, а на В зажигается. Предделитель поставил 1, период = 0,125мкс, но при задержки в 0,01с(_delay_ms(10)) период составляет 0,01*255+0,000125*255=2,55с. _delay_ms(100) - использую как-бы для "устаявшегося значения", но вопрос ни в этом.
1. Подскажите как реализовать задержку, не используя _delay_ms(10), потому как при этой функции микроконроллер просто отсчитывает время не делая больше ничего?
2. Таймер считает до 255 потому что мы взяли (0<<WGM13)|(1<<WGM12) = WGM1Х - Fast PWM 8 бит?
Затем решил перевести на прерывания, но пока без задержек. Коэф-нт деления поставил 1024, чтобы было видно затухание и зажигание соответственно. Написал код ниже:
#include<avr/io.h>
#include <avr/interrupt.h>
//Прерывание по совпадению канала А. Таймер 1
ISR (TIMER1_COMPA_vect) {
PORTD|=(1<<PD5);
OCR1A++;
}
//Прерывание по совпадению канала B. Таймер 1
ISR (TIMER1_COMPB_vect) {
PORTD|=(1<<PD4);
OCR1B--;
}
//Прерывание по переполнению Таймера 1
ISR (TIMER1_OVF_vect) {
// flz=1;
PORTD&=~(1<<PD5);
PORTD&=~(1<<PD4);
}
int main(void) {
//Главое все эти настройки регистров прописывать в главном теле
DDRD=(1<<PD4)|(1<<PD5);//PORTD ненадо настраивать
PORTD=(0<<PD4)|(0<<PD5);
TCCR1A=(0<<WGM11)|(1<<WGM10);
TCCR1B=(0<<WGM13)|(1<<WGM12)|(1<<CS12)|(0<<CS11)|(1<<CS10);
//Вкл. прер. по совпадению в А, В и переполнению Т1
TIMSK=(1<<OCIE1A)|(1<<OCIE1B)|(1<<TOIE1);
OCR1A=2;
OCR1B=253;
asm("sei");//Разрешаем все прерывания
TCNT1=0;
while(1) {
if(OCR1A==255 || OCR1B==0) {
OCR1A=0;
OCR1B=255;
}
}
}
}
2. Но как сделать более плавное затухание и зажигание? Частоту снизить не получится(если только взять внешний кварц с меньшей частотой), т.к. делитель самый высокий 1024.
Помогите разобраться с этими 3мя вопросами. С уважением Дмитрий.
1. Для этих целей используют таймеры. Если задач немного, то можно для каждой использовать свой таймер. В последних Атмегах их 3. Если задач больше, надо реализовывать конвейер. Об этом хорошо написано на http://easyelectronics.ru/
3. Если не хватает встроенного счетчика, можно устроить свой, подсчитывая число срабатываний таймера. Для этого в обработчике прерывания инкрементируем переменную, а в теле программы проверяем ее значение. Если больше, запускаем обработчик и обнуляем. На инкремент тратится мало тактов, на проверку - тоже. Так что задержек не будет
Orion33 писал(а):3. Если не хватает встроенного счетчика, можно устроить свой, подсчитывая число срабатываний таймера. Для этого в обработчике прерывания инкрементируем переменную, а в теле программы проверяем ее значение. Если больше, запускаем обработчик и обнуляем. На инкремент тратится мало тактов, на проверку - тоже. Так что задержек не будет
Пробывал добавить инкремент в обработчик прерываний, для снижения частоты(более долгом затухании и разгорании). Время затухания увелилось вдвое, но мерцание сильное. Надо подумать над плавностью смены сигнала. Хотя при делители 512 мерцания невидно.
Решено: надо использовать предделитель 512, а в обработчике прерываний просто добавлять 'конечные автоматы' или промежуточные значения if(flza==0) {..} else { if(flza==1) {flza=2;} else {flza=0;}} Наглядней через switch.
Может кто знает как проще сделать напишите пожалуста.
Orion33 писал(а):Если задач больше, надо реализовывать конвейер. Об этом хорошо написано на http://easyelectronics.ru/
Я как раз там статьи и читал про ШИМ, но она на асме, и попробывал написать на Си. Только я не понял про какой 'конвейер' идет речь?
Orion33 писал(а):Если задач больше, надо реализовывать конвейер. Об этом хорошо написано на http://easyelectronics.ru/
Я как раз там статьи и читал про ШИМ, но она на асме, и попробывал написать на Си. Только я не понял про какой 'конвейер' идет речь?
Там про RTOS есть цикл статей, точно название сейчас не помню. Смысл в том, что единый таймер через определенные промежутки времени опрашивает очередь, выполняет операцию из начала и сдигает очередь. Другие прерывания могут вмешиваться в эту очередь и вставлять свои обработчики согласно приоритету. Сложно, но ИМХО правильное решение. Если один раз разобраться, можно потом просто задачи новые в конвейер добавлять, а ядро останется всегда одним)