В первой части статьи был рассмотрен аппаратный ШИМ генератор микроконтроллера. Всё в нем хорошо, но есть несколько "но":
- аппаратный ШИМ жёстко привязан к определенным выводам МК, его невозможно переназначить на другую ногу
- количество аппаратных ШИМ каналов ограничено, их количество зависит от модели МК
- разрядность аппаратного ШИМ невозможно изменить
В этом случае может пригодиться программный метод получения ШИМ сигнала. Делается он не сложно, но требователен к частоте работы микроконтроллера и занимает достаточно много процессорного времени, в отличие от аппаратного, работающего незаметно для основной программы. Но так как применяется он, как правило, для светодиодных мигалок, то это не столь важно.
Нам необходимо в начале периода ШИМ сигнала выставлять определенную ногу МК в 1 или 0 (в зависимости от того, какой сигнал нам нужен), а потом, по достижении заданной длительности импульса, инвертировать значение ножки. Делать это удобнее всего в прерывании по переполнению. Так мы и поступим, воспользуемся прерыванием по переполнению таймера T0. Управлять будем RGB светодиодом, поэтому и названия переменных и макроопределения для портов сделаем удобочитаемыми.
/*блок дефайнов***************************************************************************************************/ #define RED PORTB.0 #define GREEN PORTB.1 #define BLUE PORTB.2 /*****************************************************************************************************************/ /*объявляем прерменные********************************************************************************************/ unsigned char red=255, green, blue; //переменные, для изменения скважности ШИМ в программе unsigned char red_b, green_b, blue_b; //переменные, для буферизации значений скважности ШИМ unsigned char count; //переменная- счетчик вызовов обработчика прерываний unsigned char temp=1; //переменная для работы алгоритма смены цветов /*****************************************************************************************************************/
Когда наступает прерывание, необходимо увеличить программный счетчик на 1 и проверить, не переполнился ли он. Если таймер переполнен, то нужно на все ножки, на которые выводится ШИМ, вывести логическую 1, а так же сохранить переменные в буфер. Переменные в буфер сохраняются для того, чтобы данные о скважности обновлялись раз в начале каждого периода, это исключает непредсказуемое поведение выхода. Далее сравниваем значение счетчика со значением буфера скважности каждого канала. Если счетчик достиг этого значения- выводим в соответствующую ногу МК логический 0.
/*обработчик прерывания*******************************************************************************************/ interrupt [TIM0_OVF] void timer0_ovf_isr(void) { count++; if (count == 0){ //если счетчик переполнился и принял значение 0 red_b = red; //сохранием значения в буфер green_b = green; blue_b = blue; RED =1; //выставляем ноги, отвечающие за ШИМ в логическую 1 GREEN =1; BLUE =1; } if (red_b == count) { RED = 0;} //по достижении заданной скважности выводим логический 0 в ножку МК if (green_b == count) { GREEN = 0;} if (blue_b == count) { BLUE = 0;} } /*****************************************************************************************************************/
Для демонстрации работы будем выводить на светодиод плавную смену цвета по цветам радуги ( Каждый Охотник Желает Знать Где Сидит Фазан). Для этого воспользуемся нехитрым алгоритмом, который будем крутить в бесконечном цикле.
/*главная функция*************************************************************************************************/ void main(void) { PORTB=0x08; //конфигурируем порт DDRB=0x07; TCCR0=0x01; //настраиваем таймер TCNT0=0x00; TIMSK=0x01; //разрешаем генерацию прерывания по переполнению таймера T0 #asm("sei") //глобально разрешаем прерывания /*бесконечный цикл************************************************************************************************/ while (1) { if (temp==1) {if (green < 255) green += 1; else temp = 2;} if (temp==2) {if (red > 0) red -= 1; else temp = 3;} if (temp==3) {if (blue < 255) blue += 1; else temp = 4;} if (temp==4) {if (green > 0) green -= 1; else temp = 5;} if (temp==5) {if (red < 255) red += 1; else temp = 6;} if (temp==6) {if (blue > 0) blue -= 1; else temp = 1;} delay_ms(2); }; /*****************************************************************************************************************/ } /*****************************************************************************************************************/
- Soft_PWM.zip (39 Кб)
Комментарии (7) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
RGB светодиод подключен одновременно к трём портам: PB0, PB1, PB2?
У RGB светодиода 4 вывода, по одному на каждую цветовую составляющую и один общий (может быть как катод, так и анод). Общий вывод в зависимости от типа диода подключается к + питания или к общему -, а выводы кристаллов (цвета) к выводам порта МК, в данном случае PB0, PB1, PB2.
Я нигде не нашел примеров плавного открытия того же транзистора, например:
кнопку нажал - лампа плавно зажклась.
её же отпустил - так же плавно потухла
[Автор]
И еще вопрос, какой аналог команде
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
существует в ассемблере AVRStudio?
[Автор]
interrupt [TIM0_OVF] void timer0_ovf_isr(void) это обработчик прерывания по переполнения таймера. Я давно не писал на ассемблере и не могу сказать точно, как это делается. Изучите соответствующую литературу.