Программирование диммера на радиомодуле 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вт. [embedded content]

Попробую расписать все по-порядку: Сначала на видео демонстрируется управление лампочкой через кнопку: Короткое нажатие выключает или включает лампочку, длинное нажатие изменяет яркость, если лампочка была выключена, то она включается и начинается изменение яркости. При каждом отпускании кнопки меняется направление изменения яркости.Далее видим как лампочкой можно управлять с компьютера (точнее ноута). В тесте используется Arduino+Ethernet-nRF24L01 для удаленного управления диммером.На 26 секунде можно заметить WEB страничку ардуинки, на которой показывает состояние беспроводных устройств:1 строчка — это как раз наш диммер, где переменная Analog показывает текущую установленную мощность, а переменная test_data показывает состояние включена или выключена лампочка.2 строчка — это беспроводной датчик, который тут добавлен просто для теста.Управление диммером показано на самодельной веб страничке (веб сервер на ноуте), на которой присутствуют кнопки заданной яркости 10,20,50 и 100%, кнопки включения/выключения, а так же поля ручной отправки данных на беспроводные устройства.Данная тестовая страничка написана на PHP и она отправляет GET запросы на веб сервер ардуинки. Аналогично можно управлять и через nRF24L01+USB.

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

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

© Habrahabr.ru