Заранее прошу не пинать и не отправлять в поиск Google! Все видел и все читал! Суть проблемы: Понадобился диммер на Attiny85 с управлением по i2c. И схема и скетч подобного устройства ранее обсуждались на форуме. По аналогии решил повторить. схема скетч Код (C++): // автономный диммер на ATtiny85 с управлением по I2C // ********************************************************************* // фьюзы: HIGH = 0xDF; LOW = 0xE2; EXTENDED = 0xFF // Алгоритм: // * таймер установлен, но отключен // * обнаружено пересечение нуля // * таймер начинает отсчет с нуля // * компаратор установлен в значение "задержка включения" // * счетчик достигает значения компаратора // * компаратор ISR включает симистор // * счетчик установлен на переполнение - ширина импульса // * счетчик достигает переполнения // * переполнение ISR выключает симистор // * симистор закрыт при следующем пересечении нуля #include <TinyWireS.h> #define I2C_SLAVE_ADDR (0x41) //адрес устройства #define DETECT 1 //физический пин 6, детектор ноля, прерывание 0 #define GATE 3 //физический пин 2, выход на симистор #define PULSE 5 //константа счетчика импульсов, определяет ширину управляющего импулса // I2C pins: PB2 - SCL физический пин 7, PB0 - SDA физический пин 5 // const byte averageFactor = 10; //smoothing level (0 = not smoothing) // int sensorValue = 0; volatile byte i2cValue, ocr, jj; void setup() { delay(2000); //задержка нужна чтобы не хватать мусор из шины при инициализации ocr = 0; // выключение нагрузки при инициализации // set up pins TinyWireS.begin(I2C_SLAVE_ADDR); pinMode(DETECT, INPUT); //zero cross detect digitalWrite(DETECT, HIGH); //enable pull-up resistor pinMode(GATE, OUTPUT); //triac gate control DDRB &= ~(1 << DETECT); //обнаружение пересечения нуля PORTB |= (1 << DETECT); //включить подтягивающий резистор DDRB |= 1 << GATE; //управление симистором GIMSK = 1 << PCIE; PCMSK = 1 << PCINT1; OCR1A = 50; //инициализация компаратора TIMSK = _BV(OCIE1A) | _BV(TOIE1); //прерывание при сравнении совпадений A | разрешить прерывание переполнения таймера sei(); // разрешить прерывания TinyWireS.onRequest(requestEvent); } ISR (PCINT0_vect) // Детектор нуля { for(uint8_t ii=0; ii<200; ii++) jj++; if (PINB&(1<<PINB1)) { return;} TCNT1 = 0; // сбросить таймер - считать с нуля OCR1A = ocr; TCCR1 = B00001010; // предварительный делитель на 1024, см. таблицу 12.5 таблицы tiny85 } ISR(TIMER1_COMPA_vect) // прерывания по совпадению значения Timer1 со значением регистра OCR1A { PORTB |= (1 << GATE); // включили симистор TCCR1 = 0; TCNT1 = 255 - PULSE; //длительность триггерного импульса, когда TCNT1 = 255, Timer1 переполняется TCCR1 = B00001010; } ISR(TIMER1_OVF_vect) // прерывние по переполнению Timer1 { PORTB &= ~(1 << GATE); //выключили симистор TCCR1 = 0; // сброс таймера остановить непреднамеренные срабатывания } void loop() { if (TinyWireS.available()) i2cValue = TinyWireS.receive();// проверка значений полученных по i2c что бы отсеять ненужное if ((i2cValue < 1) || (i2cValue > 254)) ocr = 0; // все что меньше 1 и больше 254 выключает нагрузку else if (i2cValue == 3) digitalWrite(GATE, LOW); // управляем симистором для проверки I2C else if (i2cValue == 9) digitalWrite(GATE, HIGH); // управляем симистором для проверки I2C // else ocr = map(i2cValue, 0, 254, 145, 15); // рабочий диапазон от 1-254 ?? else ocr=i2cValue; TinyWireS_stop_check(); } void requestEvent() { TinyWireS.send(i2cValue); } Схему собрал на макетке. Прошил Attiny85, выставил фьюзы: HIGH = 0xDF; LOW = 0xE2; EXTENDED = 0xFF Однако, судя по форуму - у всех диммер работает - у меня нет!! Все проверил - перепроверил - все соответствует оригиналу. НО диммер не работает, хоть тресни! Чуствую - проблема с установками таймеров - а где именно - не пойму. Но ведь и схема и скетч рабочие, у всех работает. Для проверки железа использовал blink а также управлял симистором по i2c - симистор включается и выключается. Но диммер "не диммерит". На ноге DETECT - как и полагается - короткие импульсы от детектора нуля частотой 100 герц. На ноге - GATE - похожие импульсы но более четко сформированные. При изменении значения ocr ничего не меняются. Ткните носом - что не так. Работать с прерываниями на уровне регистров Attiny пока трудновато, матчасть только начинаю осваивать. Заранее благодарен.
Так если у всех работает, значит таймеры настроены правильно. А если по I2C передавать 0 и 255, лампочка выключается и включается? Почему строчка Код (C++): // else ocr = map(i2cValue, 0, 254, 145, 15); // рабочий диапазон от 1-254 ?? закомментирована и в ocr пишется значение i2cValue? На какой частоте работает Тинька? На 8МГц, пределитель таймера - на 512. Я настраивал Тиньку на максимум, 16МГц и пределитель на 1024. Так переход через ноль более точно определяется. Значит в 10мс полупериода будет 156,25 тиков таймера. Так же как и у меня. Поэтому был сделан мапинг, и максимальное значение OCR1A не должно превышать 150 (6 тиков - переход через ноль + включение симистора). Код (C++): ISR (PCINT0_vect)// Детектор нуля { for(uint8_t ii=0; ii<200; ii++) jj++; - это нехорошо. Не нужно задержек в прерывании. И нужно добавить сброс предделителей таймера (перед сбросом таймера, в прерывании от Zero-Cross) Нужно добавить: Код (C++): GTCCR |= 2; // сбросим счетчики предделителей перед: Код (C++): TCNT1 = 0; // сбросим таймер :
1.строка с Map закомментирована только на время отладки. Аналогично ocr=i2cValue; все восстановил, ocr получает значение из Map 2.сброс счетчика предделителя GTCCR |=2; ничего не дал 3. лишние задержки в прерывании убрал. 4. Самоe неприятное: - если по I2C передаю 0 - на ноге GATE -0, импульсов нет = если по I2C передаю - 255 - на ноге GATE -импульсы, похожие на импульсы от Zero-Cross, но более четко сформированные. кстати, симистор по I2C нормально управляется отладочными командами, т.е. железо работает Таким образом получается получается: ISR(TIMER1_COMPA_vect) включает симистор. ISR(TIMER1_OVF_vect) симистор выключает независимо от установленных параметров ....??? Вопрос - почему и что не так? 5. по поводу частоты Attiny: возможно здесь собака и зарыта - временные параметры диммера (частота работы Тиньки, делители и т.д.) не соответствую параметрам сети (50Гц), Attiny (ее таймеры) работает не синхронно с сетью. Я полагал, что с указанными в начале вопроса фьюзами Тинька работает на частоте 8Мгц а все указанные делители и константы расчитаны именно на эту частоту. Самому определить параметры пока не по силам, поэтому и воспользовался готовым и отработанным решением. вот мои фьюзы: HIGH = 0xDF; LOW = 0xE2; EXTENDED = 0xFF так что же не так? Какие фьюзы выставлены в Вашй Тиньке и, если можно, покажите свой скетч
Тема с моим диммером была удалена по моей просьбе, сегодня я ее восстановил, написал удаленные мной первые два сообщения. Там и схема и код.