Продолжаем тему программирования радиомодулей 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