Подскажите по ШИМ

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
ipf
Встал на лапы
Сообщения: 131
Зарегистрирован: Вт сен 20, 2011 18:41:41
Откуда: Вьетнам

Подскажите по ШИМ

Сообщение ipf »

Подскажите как плавно включить а через 10 секунд плавно выключить все светодиоды на порту PORTD.

Сейчас включаю поочередно

void led_on(unsigned int mask){
unsigned char on_time;
for (on_time = 1; on_time < 100; on_time++) {
PORTC &= ~mask; // выключаем светодиод
delay(100-on_time); // отсчитываем время в выключенном состоянии
PORTC |= mask; // включаем светодиод
delay(on_time); // отсчитываем время во включенном состоянии
}


for (mask = 0x01; mask; mask <<= 1)
{
led_on(mask);
delay_ms(100);
}


как переделать под плавное включение всего порта сразу
Реклама
Serhio
Прорезались зубы
Сообщения: 249
Зарегистрирован: Вс авг 15, 2010 20:42:44
Откуда: Тюмень
Контактная информация:

Re: Подскажите по ШИМ

Сообщение Serhio »

Извините, но решил написать здесь. Может есть у кого-нибудь код на асме для Мега8 ШИМ плавное зажигание светодиода? или подскажите пожалуйста алгоритм, чтобы я мог сравнить со своими додумками :)
Реклама
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Подскажите по ШИМ

Сообщение GRAF »

ururur писал(а):как переделать под плавное включение всего порта сразу
Включить все светодиоды к одной ноге с аппаратной ШИМ через транзистор и резисторы.
ipf
Встал на лапы
Сообщения: 131
Зарегистрирован: Вт сен 20, 2011 18:41:41
Откуда: Вьетнам

Re: Подскажите по ШИМ

Сообщение ipf »

Serhio писал(а):Извините, но решил написать здесь. Может есть у кого-нибудь код на асме для Мега8 ШИМ плавное зажигание светодиода? или подскажите пожалуйста алгоритм, чтобы я мог сравнить со своими додумками :)
Могу дать на C. Код под мегу 8. Светодиод вешать на ножку PB1

Код: Выделить всё

#include <avr/io.h>//библиотека ввода/вывода
 
//Програма задержки
void wait (unsigned int a)
{ 
unsigned int i;
for (i=a;i>0;i--);
}
 
//Програма инициализации ШИМ
void pwm (void)
{
  TCCR1A=(1<<COM1A1)|(1<<WGM10); 
  TCCR1B=(1<<CS10);		 
  OCR1A=0x00;			//Начальная яркость нулевая
}
 
//Основная програма
int main(void)
{ 
unsigned char i;
 
 DDRB=0x02;   			//Делаем PB1  на выход
 pwm();
 
 while (1)
  { 
    for (i=0;i<255;i++)		//Плавно повышаем яркость 
	 {
	  OCR1A++;
	  wait(1000);                       // Ждем
	 }
    for (i=0;i<255;i++)		//Плавно понижаем яркость
	 {
	  OCR1A--;
	  wait(1000);                     Ждем
	 }
  }
 
 return 1;
}
Реклама
Эиком - электронные компоненты и радиодетали
Serhio
Прорезались зубы
Сообщения: 249
Зарегистрирован: Вс авг 15, 2010 20:42:44
Откуда: Тюмень
Контактная информация:

Re: Подскажите по ШИМ

Сообщение Serhio »

Благодарю :)

Подскажите пожалуйста как расчитать время задержки для ШИМ. Есть с обучалки задержка
Delay: out PortB,Temp

ldi Temp1,1
ldi Temp2,1
ldi Temp3,2

Loop: dec Temp1
brne Loop

dec Temp2
brne Loop

dec Temp3
brne Loop

ret

как узнать сколько миллисекунд она длится?
Реклама
EmDmAl
Открыл глаза
Сообщения: 51
Зарегистрирован: Чт мар 22, 2012 09:14:18
Откуда: Липецк

Re: Подскажите по ШИМ

Сообщение EmDmAl »

Здравствуйте. Написал примитивный код без прерываний для мигания 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 бит?

Код: Выделить всё

#include<avr/io.h>
#include<util/delay.h>
int main(void) {
 DDRD=(1<<PD4)|(1<<PD5);//PORTD ненадо настраивать
 TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(0<<WGM11)|(1<<WGM10);
 TCCR1B=(0<<WGM13)|(1<<WGM12)|(0<<CS12)|(0<<CS11)|(1<<CS10);
 OCR1A = 0;
 OCR1B = 255;
 asm("cli");//Запрещаем прерывания
  while(1) {
   OCR1A++;
   OCR1B--;
   _delay_ms(10);
   if(OCR1A==255) {
    _delay_ms(100);
	OCR1A = 0;
	OCR1B = 255;
    _delay_ms(100);
   }
  }
}
Затем решил перевести на прерывания, но пока без задержек. Коэф-нт деления поставил 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мя вопросами. С уважением Дмитрий.
Реклама
Orion33
Друг Кота
Сообщения: 4753
Зарегистрирован: Сб апр 21, 2012 19:21:43

Re: Подскажите по ШИМ

Сообщение Orion33 »

1. Для этих целей используют таймеры. Если задач немного, то можно для каждой использовать свой таймер. В последних Атмегах их 3. Если задач больше, надо реализовывать конвейер. Об этом хорошо написано на http://easyelectronics.ru/

3. Если не хватает встроенного счетчика, можно устроить свой, подсчитывая число срабатываний таймера. Для этого в обработчике прерывания инкрементируем переменную, а в теле программы проверяем ее значение. Если больше, запускаем обработчик и обнуляем. На инкремент тратится мало тактов, на проверку - тоже. Так что задержек не будет
EmDmAl
Открыл глаза
Сообщения: 51
Зарегистрирован: Чт мар 22, 2012 09:14:18
Откуда: Липецк

Re: Подскажите по ШИМ

Сообщение EmDmAl »

Orion33 писал(а):3. Если не хватает встроенного счетчика, можно устроить свой, подсчитывая число срабатываний таймера. Для этого в обработчике прерывания инкрементируем переменную, а в теле программы проверяем ее значение. Если больше, запускаем обработчик и обнуляем. На инкремент тратится мало тактов, на проверку - тоже. Так что задержек не будет
Пробывал добавить инкремент в обработчик прерываний, для снижения частоты(более долгом затухании и разгорании). Время затухания увелилось вдвое, но мерцание сильное. Надо подумать над плавностью смены сигнала. Хотя при делители 512 мерцания невидно.

Код: Выделить всё

#include<avr/io.h>
#include <avr/interrupt.h>
volatile char flza=0;//Флаг задержек А
volatile char flzb=0;//Флаг задержек В

//Прерывание по совпадению канала А. Таймер 1
ISR (TIMER1_COMPA_vect) {
	if(flza==0) {
	flza=1;
	PORTD|=(1<<PD5);
	OCR1A++;
	} else {flza=0;}
}
//Прерывание по совпадению канала B. Таймер 1
ISR (TIMER1_COMPB_vect) {
	if(flzb==0) {
	flzb=1;
	PORTD|=(1<<PD4);
	OCR1B--;
	} else {flzb=0;}
}
//Прерывание по переполнению Таймера 1
ISR (TIMER1_OVF_vect) {
	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);//WGM1Х - Fast PWM 8 бит
 TCCR1B=(0<<WGM13)|(1<<WGM12)|(1<<CS12)|(0<<CS11)|(1<<CS10);
 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;
	}
  }
}
EmDmAl
Открыл глаза
Сообщения: 51
Зарегистрирован: Чт мар 22, 2012 09:14:18
Откуда: Липецк

Re: Подскажите по ШИМ

Сообщение EmDmAl »

Решено: надо использовать предделитель 512, а в обработчике прерываний просто добавлять 'конечные автоматы' или промежуточные значения if(flza==0) {..} else { if(flza==1) {flza=2;} else {flza=0;}} Наглядней через switch.
Может кто знает как проще сделать напишите пожалуста.
Orion33 писал(а):Если задач больше, надо реализовывать конвейер. Об этом хорошо написано на http://easyelectronics.ru/
Я как раз там статьи и читал про ШИМ, но она на асме, и попробывал написать на Си. Только я не понял про какой 'конвейер' идет речь?
Orion33
Друг Кота
Сообщения: 4753
Зарегистрирован: Сб апр 21, 2012 19:21:43

Re: Подскажите по ШИМ

Сообщение Orion33 »

EmDmAl писал(а):
Orion33 писал(а):Если задач больше, надо реализовывать конвейер. Об этом хорошо написано на http://easyelectronics.ru/
Я как раз там статьи и читал про ШИМ, но она на асме, и попробывал написать на Си. Только я не понял про какой 'конвейер' идет речь?
Там про RTOS есть цикл статей, точно название сейчас не помню. Смысл в том, что единый таймер через определенные промежутки времени опрашивает очередь, выполняет операцию из начала и сдигает очередь. Другие прерывания могут вмешиваться в эту очередь и вставлять свои обработчики согласно приоритету. Сложно, но ИМХО правильное решение. Если один раз разобраться, можно потом просто задачи новые в конвейер добавлять, а ядро останется всегда одним)
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»