уменьшение размера прошивки)

whoim
Offline
Зарегистрирован: 03.11.2011

 Ага, чтобы включить fastpwm на pb0 и pb1, мне нужно 

TCCR0A |= ( ( 1 << COM0A1 ) | ( 1 << COM0B1 ) | ( 1 << WGM01 ) | ( 1 << WGM00 ) ); // non inverting fast pwm

верно? скваженостью рулить отдельно через значения OCR0A и OCR0B?

Если мы Не хотим шим на выводы а хотим управлять вручную через процедуры - настраиваем TIMSK0, тогда ноги освобождаются и управление передается в процедуры..

Пока верно? Спасибо большое!

Несмотря на то, что у 45 тини два таймера, цель - помимо разобраться в целом - перейти на 13 тини, поэтому буду даже на 45 наседать на таймер 0. Осталось найти замену millis() ))))

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 Ага, чтобы включить fastpwm на pb0 и pb1, мне нужно 

TCCR0A |= ( ( 1 << COM0A1 ) | ( 1 << COM0B1 ) | ( 1 << WGM01 ) | ( 1 << WGM00 ) ); // non inverting fast pwm

верно?

fast PWM с уровнем LOW между значениями OCR0A/OCR0B и 255. С помощью COMxN[0:1] можно еще два варианта дергания ногами настроить.

Цитата:

скваженостью рулить отдельно через значения OCR0A и OCR0B?

да

Цитата:

Если мы Не хотим шим на выводы а хотим управлять вручную через процедуры - настраиваем TIMSK0, тогда ноги освобождаются и управление передается в процедуры..

Одно другому не мешает - можно и выводы дергать (ненулевые значения в COMxN[0:1]) и нужные прерывания подключить (через соотв. биты TIMSKx)

Цитата:

Пока верно? Спасибо большое!

Несмотря на то, что у 45 тини два таймера, цель - помимо разобраться в целом - перейти на 13 тини, поэтому буду даже на 45 наседать на таймер 0. Осталось найти замену millis() ))))

Заменой millis может стать подключение прерывания по переполнению таймера/счетчика (ISR(TIMER0_OVF_vect) {}), которое будет вызываться каждые 256/1/8000000 сек = 32 микросекунды.

Инкрементируем внутри процедуры обработки прерывания по переполнению счетчик и когда он достигнет значения 31, сбрасываем его и увеличиваем на 1 счетчик миллисекунд. Получится чуть-чуть меньше миллисекунды (на 8 микросекунд), но и эту погрешность можно устранить, раз в 4 миллисекунды совершая сброс/инкремент не на 31-м, а на 32-м прерывании.

whoim
Offline
Зарегистрирован: 03.11.2011

 fast PWM с уровнем LOW между значениями OCR0A/OCR0B и 255. С помощью COMxN[0:1] можно еще два варианта дергания ногами настроить

Вот этот момент так и не могу понять.. Правильно я понимаю - биты COM0A[0:1] управляют выводом ШИМа на PB0 и его "типом", а COM0B[0:1] его выводом и типом на PB1?

остальное понял, замечательно что можно одновременно аппаратно дергать ногами и юзать программно таймер!

step962
Offline
Зарегистрирован: 23.05.2011

Правильно.

[quote=whoim]

замечательно что можно одновременно аппаратно дергать ногами и юзать программно таймер!

[/qoute]

Что Arduino и делает, руля часами (прерывания в таймере0) и предоставляя 6 каналов ШИМ (по два на каждый из таймеров 0,1,2) одновременно.

whoim
Offline
Зарегистрирован: 03.11.2011

 Для упрощения процесса (на переходной стадии между ардуино и винавр) - millis() при настройках таймера в fastpwm продолжит работу, просто будет "врать" при настройке предделителя отличном от стандарта?

Кстати, частота 45 тини 8мгц (устраиваемая меня), у 13-й же 9,6 мгц. Надо не забыть при пересчете )

whoim
Offline
Зарегистрирован: 03.11.2011

 Ну что ж, если верить протеусу - частота не превышает 490гц при любых настройках предделителя. При компилировании в Ардуино.

Полезу ставить винавр..

whoim
Offline
Зарегистрирован: 03.11.2011

 Да, в винавр все четко

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 Ну что ж, если верить протеусу - частота не превышает 490гц при любых настройках предделителя. При компилировании в Ардуино.

Ну так 8000000/64/256=488,3 Гц.

Вполне возможно, ардуиновские настройки таймеров выполняются после пользовательских (кто его знает, куда компилятор сует соответствующие коды).

Здесь можно попытаться обмануть компилятор, сунув коды настройки в loop и выполнив их там один раз при первом проходе, а потом обходить.

whoim
Offline
Зарегистрирован: 03.11.2011

 step962, я уже вовсю переписываю программу в winavr. ШИМ как Вы поняли уже запустил, сейчас заканчиваю пробник расчета времени (аналог миллис). Правильно я рассчитываю?

unsigned short tcounter = 0; //счетчик таймера, используется для вычисления задержек времени
unsigned long millis = 0; //счетчик прошедших миллисекунд с начала работы 
unsigned long delay_millis = 0; //переменная для сохранения значения millis и последующего сравнения

..

// отслеживаем прерывания по переполнению (TOIE2)
  TIMSK |= (1<<TOIE0);

..

void ISR(int TIMER0_COMPA_vect) {
	tcounter++;
	
	//обработка счетчика таймера для расчета времени
	if(tcounter == 4) { //для частоты 3906гц, каждые 3906 / 1000 такта увеличиваем микросекунду
		tcounter = 0;
		millis++;
	}
	return;
}

..

Проверка, если вышеприведенное верно, не будет отличаться особо от работы с millis();

leshak
Offline
Зарегистрирован: 29.09.2011

step962 пишет:

Здесь можно попытаться обмануть компилятор, сунув коды настройки в loop и выполнив их там один раз при первом проходе, а потом обходить.

Не получится.

Между setup() и loop() вообщем-то  ничего особого не происходит

arduino-1.0\hardware\arduino\cores\arduino\main.cpp

 

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USB.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}
 

 

step962
Offline
Зарегистрирован: 23.05.2011

 Все зависит от той точности, которую вы хотите получить. Если погрешность в 2% не страшна, то можно оставить и так. Нет - придется дополнительные проверки вводить и, например, при каждом 50-м вызове прерывания сброс счетчика tcounter производить при достижении значения 3, а не 4. 

 

И да, ISR определяется совсем без типа - даже без void.

whoim
Offline
Зарегистрирован: 03.11.2011

step962 пишет:

 Все зависит от той точности, которую вы хотите получить. Если погрешность в 2% не страшна, то можно оставить и так. Нет - придется дополнительные проверки вводить и, например, при каждом 50-м вызове прерывания сброс счетчика tcounter производить при достижении значения 3, а не 4. 

 

И да, ISR определяется совсем без типа - даже без void.

Погрешность даже в 10% была бы не страшна) Все задержки - "на глаз" )

ISR без инт немного ругается варнингом) (говорит что по дефолту там инт, и я его поставлю туды)

step962
Offline
Зарегистрирован: 23.05.2011

 Ой, просмотрел - в ISR ни в коем случае return нельзя делать - механизм вызова прерываний и возврата из них отличается от принятого в функциях. Поэтому и компилятор ругается: видит return, не видит возвращаемого типа ну и обижается...

И перед TIMER0_COMPA_vect определение типа не требуется - это константа (номер вектора прерывания), а не параметр.

Сделайте так:

 ISR(TIMER0_COMPA_vect) {
	tcounter++;
	
	//обработка счетчика таймера для расчета времени
	if(tcounter == 4) { //для частоты 3906гц, каждые 3906 / 1000 такта увеличиваем микросекунду
		tcounter = 0;
		millis++;
	}
//	return;
}

..

 

whoim
Offline
Зарегистрирован: 03.11.2011

 Понял, поправил, да и из других своих процедур поубирал return, если им возвращать нечего. Тут вылезло что то странное - при записи в OCR0A и OCR0B значений, например, 200 - ШИМ пропадает на МК, устанавливается высокий уровень на пинах..

Проверяю сейчас все.

----

UPD нашел. При записи 255 его "заносит" на полную, на 254 все ОК )

leshak
Offline
Зарегистрирован: 29.09.2011

whoim пишет:

 step962, я уже вовсю переписываю программу в winavr.

Нифига себе сходил за хлебушком. :)  Хотя конечно, с точки зрения образования, ветка получилась зело интерестная.

Попробовал скомпилить ваш скетч из первого поста с помощью code.google.com/p/arduino-tiny/

Вышло "Binary sketch size: 672 bytes".

Правда там "самый маленький камень" который можно выбрать ATinny25, у которого 2048 byte maximum. Но возможно, что и Atinny13 не так уж сильно отличается, и добавить его поддержку будет не трудно (особенно после столь глубого изучения даташитов). А возможно и просто "залить" в него прошивку для ATinny25 получится. Может они только объемом памяти отличаются.

whoim
Offline
Зарегистрирован: 03.11.2011

 Дело в том, что скетч вырос уже раза в 4 с того времени) Меньше 1140 помоему в ардуино не удавалось его сделать. Но то полбеды - никак не смог запустить адруино и 13 тини - не находил в сети пинмаппинга..

Да и все таки я думаю.. пора. Потихоньку, полегоньку..

step962
Offline
Зарегистрирован: 23.05.2011

 Естественно.

у таймера при этом (OCRxN=255) оба события - прерывание по сравнению и прерывание по переполнению счетчика - происходят одновременно.

whoim
Offline
Зарегистрирован: 03.11.2011

 Что то затык у меня на этом..

//организация задержки
   delay_millis = millis;
   while((delay_millis + 10) > millis) {}

ничонепонимаю - убираю это - работает. Похоже, вечный цикл получился..

leshak
Offline
Зарегистрирован: 29.09.2011

whoim пишет:

 Дело в том, что скетч вырос уже раза в 4 с того времени)

Но ведь его рост, в большой степени вызван тем, что реализуете те функции которые уже есть в библиотеках. Руками.

Использование библиотек подразумевает что скетч "опять должен сократится". Уменьшится количество кода которое "вы написали".

whoim пишет:

Меньше 1140 помоему в ардуино не удавалось его сделать.

Размер зависит от того под какую плату компилите. У меня, ваш скетч, под Mega1280 компилится в 1536bytes, а он же под Atiny25 в 672bytes.

whoim пишет:

Но то полбеды - никак не смог запустить адруино и 13 тини - не находил в сети пинмаппинга..

Ну сейчас думаю уже проблем с тем "какая нога что значит" - нет. К тому же этот "пинмаппинг" вы сами можете задать, как вам хочется в файле pins_arduino.h для вашей платы.

whoim пишет:

Да и все таки я думаю.. пора. Потихоньку, полегоньку..

Ну с этим трудно поспорить. Сказать что "вы зря потратили время на разбирательство" - может только глупый человек. Стратегически, конечно, ваш путь более правильный. Однозначно.

Я просто предложил "альтернативный вариант". Сейчас на него сворачивать, безусловно, смысла нет. Но IMHO "держать в голове" - стоит. Вдруг в каком-то следующем проекте потребуется что-то "накидать по быстрому". Думаю так будет все-таки быстрее, чем "вручную" все конфигурировать, если нужно "всего-лишь подергать ногой", или что-то подобное.

leshak
Offline
Зарегистрирован: 29.09.2011

whoim пишет:

 Что то затык у меня на этом..

//организация задержки
   delay_millis = millis;
   while((delay_millis + 10) > millis) {}

ничонепонимаю - убираю это - работает. Похоже, вечный цикл получился..

А что такое millis, тут? Похоже на переменную, а не вызов функции. Не и, естественно, раз она не меняется внутри цикла - цикл вечен.

whoim
Offline
Зарегистрирован: 03.11.2011

 Про "более правильный путь" и я согласен. Но недавно выслушивал человека, который не видит никакой нужды "знать" как оно работает "изнутри" - и размер кода его мало волнует. В общем, та же тенденция, что и на PC - увеличение "всего" в железе тут же отражается на размерах программ и стилях программирования ))

И я не говорю что тот путь правилен или этот. Для разных задач и разных целей..

Сейчас моя первая цель - разобраться. Знать "изнутри". Вот, например, и компромисс - я попробовал библиотеку delay.h и выяснил, что строчка _delay_ms(15) решает мою задачу без увеличения размера прошивки. Так почему нет? ))

whoim
Offline
Зарегистрирован: 03.11.2011

leshak пишет:

whoim пишет:

 Что то затык у меня на этом..

//организация задержки
   delay_millis = millis;
   while((delay_millis + 10) > millis) {}

ничонепонимаю - убираю это - работает. Похоже, вечный цикл получился..

А что такое millis, тут? Похоже на переменную, а не вызов функции. Не и, естественно, раз она не меняется внутри цикла - цикл вечен.

//Отслеживаем переполнение
void ISR (TIMER0_COMPA_vect) {
 tcounter++;
	
 //обработка счетчика таймера для расчета времени
 if(tcounter == 4) { //для частоты 3906гц, каждые 3906 / 1000 такта увеличиваем микросекунду
	tcounter = 0;
 	millis++;
 	}
 }

 

leshak
Offline
Зарегистрирован: 29.09.2011

whoim пишет:

//обработка счетчика таймера для расчета времени if(tcounter == 4) { //для частоты 3906гц, каждые 3906 / 1000 такта увеличиваем микросекунду tcounter = 0; millis++; } }

А как millis и tcounter объявлены? volatile не забыли? Иначе вы можете только думать что это одна и таже переменная (внутри обработчика и снаружи), а компилятор-оптимизатор мог раскидать по разным адресам памяти ее.

whoim
Offline
Зарегистрирован: 03.11.2011

 Забыл) Сейчас проверю

---

UPD нет, не помогает. Да ладно, _delay_ms работает, позже изучу либу, посмотрю как сделано.

leshak
Offline
Зарегистрирован: 29.09.2011

whoim пишет:

 Про "более правильный путь" и я согласен. Но недавно выслушивал человека, который не видит никакой нужды "знать" как оно работает "изнутри" - и размер кода его мало волнует. В общем, та же тенденция, что и на PC - увеличение "всего" в железе тут же отражается на размерах программ и стилях программирования ))

И я не говорю что тот путь правилен или этот. Для разных задач и разных целей..

Согласен. "Для разных задачь". Но сейчас, "плевать на размер" - более часто подходит чем наоборот. Чисто из экономических соображений. Стоимость квалификации "который знает изнутри" - выше. Скорость разработки (опять-таки деньги и сроки) и т.д. и т.п. Добавить лишний гигабайт памяти, нынче, дешевле чем оплатить час работы программера. И результат "сразу на руках" :)

Я вот тоже, вначале пытался "жатся в маленькие камни", а потом плюнул начал брать только "пожирнее". Разница в цене, совершенно не соотвествует времени затраченного на оптимизацию.

whoim
Offline
Зарегистрирован: 03.11.2011

 Ну, в моем случае аттини13 ~ 40руб, аттини45 ~175 руб. Цена готового устройства около 800 руб (если найдутся желающие конечно). Ну как бы.. можно и потрудится, тем более что "для сэбэ" ведь )

whoim
Offline
Зарегистрирован: 03.11.2011

 Да, есть места, где все таки нужен расчет прошедшего времени - и это не задержка. И оно не работает.

Приведу, может кто высмотрит ошибку..

volatile unsigned short tcounter = 0; //счетчик таймера, используется для вычисления задержек времени
volatile unsigned long millis = 0; //счетчик прошедших миллисекунд с начала работы 
volatile unsigned long delay_millis_1 = 0; //переменная для сохранения значения millis и последующего сравнения
...
void timer_on(void) {
  //PWM Settings
  TCCR0A |= ((1 << COM0A1)|(1 << COM0B1)|(1 << WGM01)|(1 << WGM00)); // non inverting fast pwm, OC0A + OC0B pins
  TCCR0B |= (1 << CS01); //делитель 8, частота 8000000/8/255=3906,5гц
  //TCCR0B |= ((1 << CS01)|(1 << CS00)); //делитель 64, частота 8000000/64/255=490,19гц
  //TCCR0B |= (1 << CS00); //делитель 0, частота 8000000/255=31372гц
  
  // отслеживаем прерывания по переполнению (TOIE2)
  TIMSK |= (1<<TOIE0);
  
  //скважность каналов 0
  OCR0A = 0;
  OCR0B = 0;
  //sei(); //включаем прерывания
  //состояние - выкл (скважность 0)
  state=false;
  return;
  }
...
//Отслеживаем переполнение
void ISR (TIMER0_OVF_vect) {
 tcounter++;
	
 //обработка счетчика таймера для расчета времени
 if(tcounter == 4) { //для частоты 3906гц, каждые 3906 / 1000 такта увеличиваем микросекунду
	tcounter = 0;
 	millis++;
 	}
 }
...
//тут собсно проверка
int main(void) {
//главный цикл
while(1) {
  //если пришло время проверки
  if (delay_millis_1 < millis - 100) {
			delay_millis_1 = millis;
...
}

Срабатывает "сразу". Вывести значение millis особо некуда, попробую сейчас дрыгать другими ногами для проверки..

leshak
Offline
Зарегистрирован: 29.09.2011

whoim пишет:

 Ну, в моем случае аттини13 ~ 40руб, аттини45 ~175 руб. Цена готового устройства около 800 руб (если найдутся желающие конечно). Ну как бы.. можно и потрудится, тем более что "для сэбэ" ведь )

Ну вот я про это и говорю. Разница 135руб. То есть <5$. Если взять "стоимость часа спеца в $50", то это разница "меньше минуты его работы". Если он провазявкается с портированием хотя-бы неделю, то страшно представить сколько конечных устройств нужно продать что-бы окупить этот переход.

Но даже если вы "не спец" и ваше время не стоит $50. Но, как-бы то нибыло, не думаю что ваше время стоит меньше $5 час.

Так что, выходит, чисто экономически это абсолютно не целесообразно. Только как "учеба" или "just for fun".  "Выгодно" это может стать только при крупносерийном произвостве. Когда каждый цент умножается на десятки и сотни тысяч (и то, "сроки разработки" могут заставить выбрать более дорогой вариант).

whoim
Offline
Зарегистрирован: 03.11.2011

Не вызывается ISR (TIMER0_COMPA_vect) . Полез снова в даташит )

step962
Offline
Зарегистрирован: 23.05.2011

 Не заметил в приведенных вами кодах вызова функции timer_on().

И строку

void ISR (TIMER0_OVF_vect) {

стоит все же переписать в виде

ISR (TIMER0_OVF_vect) {

после удаления return куомпилятор вроде не должен ругаться. Или ворчит-таки?
 

И еще:

везде, где у вас используется присваивание "|=", посмотрите, а стоит ли сохранять уже установленные биты? Вот в TCCR0A, например, точно стоит все неустанавливаемые биты обнулить:

TCCR0A = ((1 << COM0A1)|(1 << COM0B1)|(1 << WGM01)|(1 << WGM00));

или по крайней мере посмотреть в даташите, а не инициализируются ли они (неустанавливаемые биты) единичками? Ведь вы же хотите в этой инструкции выбрать для каналов именно режим вывода 2, а никак не 3?

Вообще, |= и &= имеет смысл использовать, если у вас соответствующий байт/порт/регистр и в других местах изменяется и вы хотите целенаправленно "подправить" один-два бита в байте/порте/регистре. Или "набираете" нужную конфигурацию в нескольких операторах. Или используете библиотеку, которая что-то там тоже устанавливает. 

whoim
Offline
Зарегистрирован: 03.11.2011

step962 пишет:

 Не заметил в приведенных вами кодах вызова функции timer_on().

И строку

void ISR (TIMER0_OVF_vect) {

стоит все же переписать в виде

ISR (TIMER0_OVF_vect) {

после удаления return куомпилятор вроде не должен ругаться. Или ворчит-таки?
 

И еще:

везде, где у вас используется присваивание "|=", посмотрите, а стоит ли сохранять уже установленные биты? Вот в TCCR0A, например, точно стоит все неустанавливаемые биты обнулить:

TCCR0A = ((1 << COM0A1)|(1 << COM0B1)|(1 << WGM01)|(1 << WGM00));

или по крайней мере посмотреть в даташите, а не инициализируются ли они (неустанавливаемые биты) единичками? Ведь вы же хотите в этой инструкции выбрать для каналов именно режим вывода 2, а никак не 3?

Вообще, |= и &= имеет смысл использовать, если у вас соответствующий байт/порт/регистр и в других местах изменяется и вы хотите целенаправленно "подправить" один-два бита в байте/порте/регистре. Или "набираете" нужную конфигурацию в нескольких операторах. Или используете библиотеку, которая что-то там тоже устанавливает. 

 

timer_on есть, я подразумевал что он будет)

void уже убрал! Завелось все, все работает. Уже не помню, кажется на sie ругался и я его закоментил, а надо было asm("sei"); использовать

Про установку битов понял, поправлю сейчас

whoim
Offline
Зарегистрирован: 03.11.2011

 ну что же, прошу к оценке и здоровой критике)

Напомню цель: управление PWM мощными лампами (ближний либо дальний свет авто), сигнал Разрешено (зажигание), Запрет (ближний/дальний/аварийный даитчик масла/ручник, все через диоды), Моргать (по раздельности фарами, ака жеймсбонд)

   
   
#define F_CPU 8000000UL  // 8 MHz
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>

//логические
#define true 1
#define false 0

//пины МК
#define LAMP1 PB0 //лампа 1
#define LAMP2 PB1 //лампа 2
#define BLINK PB2 //вход мигания
#define ACC PB3 //вход зажигания
#define BAD PB4 //входы запрета

//остальное
#define MAX 204 //максимальный уровень ШИМ (0..255) (204 = 80%)
#define OFF_DELAY 980 //задержка перед выключением, (8000мс желаемая задержка / (1000мс /122,5гц текущей частоты таймера))

//переменные
volatile unsigned char state = false; //состояние ламп
volatile unsigned short tcounter = 0; //счетчик таймера, используется для вычисления задержек времени
volatile unsigned long millis = 0; //счетчик прошедших миллисекунд с начала работы 
volatile unsigned long delay_millis_1 = 0; //переменная для сохранения значения millis и последующего сравнения
volatile unsigned long delay_millis_2 = 0; //переменная для сохранения значения millis и последующего сравнения
volatile unsigned long off_time = 0; //переменная для сохранения значения millis и последующего сравнения
volatile unsigned char off_flag = false; //флаг задержки выключения

//Вспомогательные функции и процедуры

void timer_on(void) {
  //PWM Settings
  TCCR0A = ((1 << WGM01)|(1 << WGM00)); // non inverting fast pwm, OC0A + OC0B pins потом
  //выбор предделителя
  //TCCR0B = (1 << CS00); //делитель 0, частота 8000000/255=31372гц
  //TCCR0B = (1 << CS01); //делитель 8, частота 8000000/8/255=3906,5гц
  //TCCR0B = ((1 << CS01)|(1 << CS00)); //делитель 64, частота 8000000/64/255=490,19гц
  TCCR0B = (1 << CS02); //делитель 256, частота 8000000/256/255=122,5гц
  //TCCR0B = ((1 << CS02)|(1 << CS00)); //делитель 1024, частота 8000000/1024/255=30,6гц
  
  // отслеживаем прерывания по переполнению (TOIE2)
  TIMSK = (1<<OCIE0A);
  
  //скважность каналов 0
  OCR0A = 0;
  OCR0B = 0;
  
  asm("sei"); //разрешить прерывания
  
  state=false; //флаг в выключено
  }


//Отслеживаем переполнение
ISR (TIMER0_COMPA_vect) {
/*tcounter++;
	
 //обработка счетчика таймера для расчета времени
 if(tcounter == 31) { //для частоты 31372гц, каждые 31372гц / 1000 такта увеличиваем микросекунду
	tcounter = 0;
 	millis++;
 }
 */ //отключаем, на частоте ниже 1000 гц не имеет смысла, заменяем на
 millis++; //с расчетом и исправлением значений задержек
}
 

void lamp_on(void) {

 //включаем пины ШИМ
 TCCR0A |= ((1 << COM0A1)|(1 << COM0B1));

 //скачок для старта (для мощных ламп)
 OCR0A = 254;
 OCR0B = 254;
 _delay_ms(30);
 OCR0A = 0;
 OCR0B = 0;
   
 for (int x=0; x <= MAX; x++) {
   OCR0A = x;
   OCR0B = x;
   //организация задержки
   _delay_ms(15);
   } 
 state=true; //устанавливаем признак - лампы включены 
 }

void lamp_off(void) {

 for (int x=MAX; x >= 0; x--) {
   OCR0A = x;
   OCR0B = x;
   //организация задержки
   _delay_ms(15);
   }
 state=false; //устанавливаем признак - лампы выключены 
 //выключаем пины ШИМ
 TCCR0A ^= ((1 << COM0A1)|(1 << COM0B1));
}
 
 //моргать
void blink(void) {
	//на всякий включаем пины ШИМ
	TCCR0A |= ((1 << COM0A1)|(1 << COM0B1));
	//выключить все
	OCR0A = 0;
	OCR0B = 0;
	_delay_ms(200);
	
	//моргаем первой лампой два раза
	OCR0A = 254;
	_delay_ms(80);
	OCR0A = 0;
	_delay_ms(80);
	OCR0A = 254;
	_delay_ms(80);
	OCR0A = 0;
	_delay_ms(400); //пауза после первой фары
	//моргаем второй фарой два раза
	OCR0B = 254;
	_delay_ms(80);
	OCR0B = 0;
	_delay_ms(80);
	OCR0B = 254;
	_delay_ms(80);
	OCR0B = 0;
	_delay_ms(400); //пауза после второй фары
	
	state = false; //флаг, так как все выключено
	//выключаем пины ШИМ
	TCCR0A ^= ((1 << COM0A1)|(1 << COM0B1));
}
    
//Главное тело программы
int main(void) {
   
 //настройки
 DDRB = 0b00000011;
 PORTB = 0b00011100;
 timer_on();
	
	//главный цикл
	while(1) {
	  //если пришло время проверки
		if (delay_millis_1 < millis - 100) {
			delay_millis_1 = millis;
			//если выключено, есть разрешение и нет запрета - включить
			if (state==false && !(PINB&(1<<ACC)) && (PINB&(1<<BAD))) {
				lamp_on();
			}
			//если включено и позволяют сигналы - выключить
			if (state) {
				if ((PINB&(1<<ACC)) || !(PINB&(1<<BAD))) {
					if (!(PINB&(1<<BAD))) { //если пришел сигнал по линии запрета выключаем сразу
						OCR0A = 0;
						OCR0B = 0;
						//выключаем пины ШИМ
						TCCR0A ^= ((1 << COM0A1)|(1 << COM0B1));
						state = false;
					}
					else {
						//высчитываем задержки
						if (off_flag == false) {
							off_time = millis;
							off_flag = true;
						}
						if (off_time < millis - OFF_DELAY) {
							off_flag = false;
							lamp_off();
						}
					}
				} //if PINB 
			} //if выключить
			
			//пока сигнал "моргать"
			while(!(PINB&(1<<BLINK))) {
				blink();
			}//моргать
		} //if время проверки
		
	asm volatile ("nop"); //бездельничаем
		
	} //while(1)
 } //main()

 

 Program: 732 bytes

--------
UDP текст программы - выключение ШИМа на пинах когда он не нужен. Лампочка не поет, нет ощущения что сидишь в трансформаторной будке)

whoim
Offline
Зарегистрирован: 03.11.2011

 К сожалению, на реальном устройстве на частоте 4кгц уже нагреваются мосфеты, на 30 они неуправляемы, несмотря на раскачу двумя плечами. Без драйвера видимо не обойтись если хочешь около 30 кгц.

Есть желание попробовать тот самый режим с "коррекцией фазы" и 15кгц, но наверно чуть позже пристану :)

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

Есть желание попробовать тот самый режим с "коррекцией фазы" и 15кгц, но наверно чуть позже пристану :)

При тех же остальных настройках вместо режима "3" выбрать "1". Частота автоматически уменьшается в два раза (за счет счета ;) счетчика :)) в обе стороны)

И фсиоо...

whoim
Offline
Зарегистрирован: 03.11.2011

 Понял, вечерком запробую, так, для теста. Добавил отключение пинов ШИМа когда не нужно, теперь не жужжит при выключенном состоянии)