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

в 5:00, , рубрики: coolrf, nRF24L01+, NRF24LE1, Программинг микроконтроллеров, умный дом

Продолжаем тему программирования радиомодулей 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 планируют спроектировать другой вариант диммера в заводском корпусе и изменив схему устройства, но данный пример прошивки, возможно с небольшими изменениями, так же будет работать на нем.

Принимаю критику и предложения в комментариях. Спасибо.

Автор: MaksMS

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js