Программирование диммера на радиомодуле nrf24le1 от COOLRF

от автора

Продолжаем тему программирования радиомодулей nrf24le1 — на этот раз мы научим диммер от COOLRF работать. После публикации мною статьи про программирование радиомодулей мне предложили поучаствовать в разработке прошивки и предоставили данный диммер для экспериментов.
В итоге получился вариант управления диммером через центральный модуль 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/