В итоге получился вариант управления диммером через центральный модуль Arduino+Ethernet-nRF24L01 (W5100) или nRF24L01+USB из USBasp а так же с помощью локальной кнопки.
Алгоритм диммирования
Сигнал перехода через ноль активизирует таймер, время которого зависит от установленного уровня мощности 0..100% что соответствует 0.01….0 секунды. Таймер включает симистор.
Далее, после примерно 10 миллисекунд (если я правильно прикинул) сигнал включения симистора снимается, НО симистор остается открытым пока не было перехода через ноль. Далее цикл повторяется.
Возможно читатели хабра предложат и более лучший вариант управления симистором…
Код прошивки
В данный момент прошивка умеет:
- Управление включением/выключением кнопкой на выключателе.
- Управление яркостью при длительном (более 1.5с) нажатии кнопки.
- Удаленный контроль состояния и уровня установленной яркости.
- Удаленное управление включением/выключением и яркостью.
Для отчета интервалов управления мощности используется таймер № 1.
Для установки интервалов для подавления дребезга и других пауз используется таймер RTC на внутреннем генераторе 32768 Гц.
Для компиляции прошивки необходим SDK.
// модификация 23.07.14 #define chclient 1 // номер клиента 1... #define nofloat 0 // без float , данные передаются умноженные на 10.Очень экономит место. #define RTCDEC 8191 //65535=2 сек, 32767=1 сек,16383 = 0.250 сек ,8191 = 0.125 сек. Константы ниже используют это значение за такт: #define TIMESEND 2 // интервал приема/отправки данных по радио. #define TIMEKEY 4 // пауза кнопки для защиты от дребезга. (0.125*4=0.5с) #define TIMELONGKEY 3 // долгое нажатие кнопки,вычисляется как TIMEKEY*TIMELONGKEY*0.125=время. 3*4*0.125=1.5с #define BUTTONPIN 4 // пин, к которому подключена кнопка. #define DIMMPIN GPIO_PIN_ID_P0_2 // пин, к которому подключен симистор. #define stepdimm 10 // шаг управления яркостью используя кнопку #define MAXSTEP 100 // количество шагов диммирования #include "../libs.h" #include "../nRFLE.c" typedef struct{ unsigned char identifier;// номер передатчика.МЕНЯТЬ НЕЛЬЗЯ int countPWM; unsigned char keymode; int Error_Message; // счетчик ошибок long count;// счетчик передач для контроля качества канала #if nofloat int temperature_Sensor; int Humidity_Sensor; #else float temperature_Sensor; float Humidity_Sensor; #endif } nf1; nf1 clientnf; #define DIMSTART 16000000/12/100/MAXSTEP uint16_t valuepwm=0; // хранит значение мощности в тиках таймера void setdimmer(uint8_t value){ // функция управления диммирования valuepwm=65535-DIMSTART*(MAXSTEP-value); if(value ==0 | clientnf.keymode==0) { interrupt_control_ifp_disable(); gpio_pin_val_clear(DIMMPIN); } else interrupt_control_ifp_enable(); } uint8_t stdimm; interrupt_isr_ifp() // прерывание при переходе через ноль { timer1_stop(); if(clientnf.countPWM !=0) { timer1_set_t1_val(valuepwm); timer1_run(); } else gpio_pin_val_clear(DIMMPIN); stdimm=1; } interrupt_isr_t1() { // прерывание на таймере if (stdimm) { gpio_pin_val_set(DIMMPIN); timer1_set_t1_val(65535-100); stdimm=0; } else gpio_pin_val_clear(DIMMPIN); } void dimmon(uint8_t mode) // функция управлением вкл/выкл { if (mode) interrupt_control_ifp_enable(); else { interrupt_control_ifp_disable(); timer1_stop(); gpio_pin_val_clear(DIMMPIN); } clientnf.keymode=mode; } unsigned long countrtc=0; // переменная счетчика времени используя rtc unsigned char servernf[32]; interrupt_isr_rtc2() // счетчик ртс импульсов используя прерывание. { countrtc++; } //====================main======================== void main() { int state=0; unsigned int count=0; //counter for loop uint8_t st=0,countpause=0,rewers=0; // for key unsigned long statesend=0,radiosend=0; // конфигурация RTC--> CLKLFCTRL=1; // 0 -внешний кварц на P0.1 и P0.0. 1 - внутренний генератор. rtc2_configure(RTC2_CONFIG_OPTION_COMPARE_MODE_0_RESET_AT_IRQ ,RTCDEC); rtc2_run(); pwr_clk_mgmt_wakeup_configure(PWR_CLK_MGMT_WAKEUP_CONFIG_OPTION_WAKEUP_ON_RTC2_TICK_IF_INT_ENABLED,0); interrupt_control_rtc2_enable(); // <--конфигурация RTC interrupt_configure_ifp(INTERRUPT_IFP_INPUT_GPINT0,INTERRUPT_IFP_CONFIG_OPTION_ENABLE | INTERRUPT_IFP_CONFIG_OPTION_TYPE_FALLING_EDGE); interrupt_control_ifp_enable(); interrupt_control_t1_enable() ; timer1_configure(TIMER1_CONFIG_OPTION_MODE_1_16_BIT_CTR_TMR,0); timer1_run(); sti(); gpio_pin_configure(BUTTONPIN,GPIO_PIN_CONFIG_OPTION_DIR_INPUT|GPIO_PIN_CONFIG_OPTION_PIN_MODE_INPUT_BUFFER_ON_PULL_UP_RESISTOR); // для кнопки на вход и подтянуть резистором. gpio_pin_configure(DIMMPIN,GPIO_PIN_CONFIG_OPTION_DIR_OUTPUT); // Тестовое мигание при запуске --> #if 1 gpio_pin_val_set(DIMMPIN); delay_ms(500); gpio_pin_val_clear(DIMMPIN); delay_ms(500); #endif //<-- Тестовое мигание при запуске radiobegin(); // openAllPipe(); // открываем прием/передачу, назначаем адреса. setChannel(100); setDataRate(2); // 1 - 250кб , 2 - 1 мб , 3 -2 мб. setAutoAck(false); setCRCLength(2); // 0 - crc off ,1 - 8bit ,2 - 16bit setPALevel(3) ; // мощность 0..3 clientnf.identifier=chclient; clientnf.countPWM=30; //main program loop while(1) { // --- if (countrtc-radiosend >=TIMESEND) { //rf_power_up(1); rf_write_tx_payload((const uint8_t*)&clientnf, 32, true); //transmit received char over RF //wait until the packet has been sent or the maximum number of retries has been reached while(!(rf_irq_pin_active() && rf_irq_tx_ds_active())); rf_irq_clear_all(); //clear all interrupts in the 24L01 rf_set_as_rx(true); //change the device to an RX to get the character back from the other 24L01 //wait a while to see if we get the data back (change the loop maximum and the lower if // argument (should be loop maximum - 1) to lengthen or shorten this time frame for(count = 0; count < 25000; count++) { if((rf_irq_pin_active() && rf_irq_rx_dr_active())) { state=1; if (clientnf.count <= 2147483646) clientnf.count++; /// счетчик передач для контроля качества канала else clientnf.count = 0; rf_read_rx_payload((const uint8_t*)&servernf, 32); //get the payload into data break; } //if loop is on its last iteration, assume packet has been lost. if(count == 24999) clientnf.Error_Message++; } rf_irq_clear_all(); //clear interrupts again rf_set_as_tx(); //resume normal operation as a TX if (servernf[0]==chclient){ if (servernf[1]==10) { // включение/выключение по радио dimmon(servernf[3]); } else if (servernf[1]==11) { // управление яркостью по радио clientnf.countPWM=servernf[3]; setdimmer(clientnf.countPWM); } } radiosend=countrtc; } #if 1 #define dimm clientnf.countPWM #define keymode clientnf.keymode if (digitalRead(BUTTONPIN)==0){ // кнопка нажата if (countrtc-statesend>=TIMEKEY) { if (st){ st=0; keymode=!keymode; dimmon (keymode); } else if (countpause>=TIMELONGKEY){ if (!keymode) dimmon(1); // если было выключено,то включим else { if(rewers) { if(dimm-stepdimm>=0) dimm=dimm-stepdimm; else rewers=0; }else{ if(dimm+stepdimm<=MAXSTEP) dimm=dimm+stepdimm; else rewers=1; } setdimmer(dimm); } } else countpause++; statesend=countrtc; } } else {// кнопка отжата if (!st){ st=1; countpause=0; rewers=!rewers; // менять направление изменения яркости при каждом отжатии кнопки } } #endif // end loop } }
Видеодемонстрация работы диммера
Что мы имеем:
- диммер COOLRF.
- nrf24le1 радиомодуль не того формата, и, соответственно он не подходит на родное место установки — по этому он выведен на проводках.
- Монтажная панелька, на которой подключена кнопка с подтягивающим резистором.
- лампочка на 60вт.
Попробую расписать все по-порядку:
Сначала на видео демонстрируется управление лампочкой через кнопку:
Короткое нажатие выключает или включает лампочку, длинное нажатие изменяет яркость, если лампочка была выключена, то она включается и начинается изменение яркости. При каждом отпускании кнопки меняется направление изменения яркости.
Далее видим как лампочкой можно управлять с компьютера (точнее ноута). В тесте используется Arduino+Ethernet-nRF24L01 для удаленного управления диммером.
На 26 секунде можно заметить WEB страничку ардуинки, на которой показывает состояние беспроводных устройств:
1 строчка — это как раз наш диммер, где переменная Analog показывает текущую установленную мощность, а переменная test_data показывает состояние включена или выключена лампочка.
2 строчка — это беспроводной датчик, который тут добавлен просто для теста.
Управление диммером показано на самодельной веб страничке( веб сервер на ноуте), на которой присутствуют кнопки заданной яркости 10,20,50 и 100%, кнопки включения/выключения, а так же поля ручной отправки данных на беспроводные устройства.
Данная тестовая страничка написана на PHP и она отправляет GET запросы на веб сервер ардуинки. Аналогично можно управлять и через nRF24L01+USB.
Как я понял COOLRF планируют спроектировать другой вариант диммера в заводском корпусе и изменив схему устройства, но данный пример прошивки, возможно с небольшими изменениями, так же будет работать на нем.
Принимаю критику и предложения в комментариях. Спасибо.
ссылка на оригинал статьи http://habrahabr.ru/post/230785/
Добавить комментарий