Rainbow Electronics Поиск Switch to English
Продукция Горячие предложения Склад и цены Решения Статьи Разработчикам О компании Контакты Карта сайта
Главная страница
Уравление офисным освещением по Wi-Fi. Часть 3: Управляем светом

завершение цикла публикаций по теме

Сегодня мы, наконец, завершим данный цикл, соединив знания и наработки, полученные в первой и второй частях: будем управлять офисными светильники с помощью сенсорных кнопок по Wi-Fi, используя протокол ModBus TCP через шлюз ModBus-DALI.

ПОСМОТРЕТЬ КЛИП


Краткое содержание предыдущих серий

Мы научились, используя Wi-Fi модуль WINC1500 от Atmel, коннектится к сторонней точке доступа, а так же подключаться в качестве клиента к TCP-серверу и передавать в него данные. Так же была освоена работа с сенсорными кнопками и слайдерами, о чем было заснято соответствующее видео.

Вспомним общую концепцию. К отладке с микроконтроллером Atmel SAMD21 подключена плата расширения Q-touch, на которой расположены три кнопки, слайдер и ротор. Мы будем использовать одну кнопку для включения освещения, другую для выключения и слайдер для плавной регулировки яркости. Ко второму порту подключена плата с модулем WINC1500. Наше устройство (вернее, прототип) будет выступать в качестве TCP-клиента. Сервером будет выступать DALIGW1 — ModBus TCP устройство, преобразующее ModBus команды в команды протокола DALI (Digital Addressable Lighting Interface) — специальный протокол для цифрового управления освещением. Таким образом, мы будем получать значения положения сенсоров и формировать запросы в соответствии с протоколом Modbus и отправлять по Wi-fi в шлюз.

TCP клиент

Для простоты не будем создавать точку доступа, сканировать доступные сети и просить пользователя подключиться к одной из них, а зададим нужные настройки для нашей офисной локальной сети прямо в коде.
В начале работы можно открыть один из созданных ранее проектов (по предыдущим частям статьи) или проект-пример для Qtouch или WINC1500, и добавить нужные модули с помощью Wizard'а, как описывалось в одной из наших предыдущих статей.

Настраиваем в файле main.h параметры сети:
#define MAIN_WLAN_SSID                   "Habrahabr"    // имя сети
#define MAIN_WLAN_AUTH                    M2M_WIFI_SEC_WPA_PSK    // тип шифрования
#define MAIN_WLAN_PSK                     "123456789" // пароль к сети
#define MAIN_WIFI_M2M_PRODUCT_NAME        "Hello world!\n\r"
#define MAIN_WIFI_M2M_SERVER_IP                     0xc0a81490   // IP адрес сервера (шлюза)

#define MAIN_WIFI_M2M_SERVER_PORT         (502)   // порт сервера. обычно 502 для ModBus TCP

В main.c настраиваем библиотеку для работы с winc1500 в режиме tcp клиент.
     //Initialize the BSP. 
        nm_bsp_init();

        // Initialize socket address structure.
        addr.sin_family = AF_INET;
        addr.sin_port = _htons(MAIN_WIFI_M2M_SERVER_PORT);
        addr.sin_addr.s_addr = _htonl(MAIN_WIFI_M2M_SERVER_IP);

        // Initialize Wi-Fi parameters structure. 
        memset((uint8_t *)¶m, 0, sizeof(tstrWifiInitParam));

        // Initialize Wi-Fi driver with data and status callbacks.
        param.pfAppWifiCb = wifi_cb;
        ret = m2m_wifi_init(¶m);
        if (M2M_SUCCESS != ret)
         {
                printf("main: m2m_wifi_init call error!(%d)\r\n", ret);
                while (1);
        }

        // Initialize socket module 
        socketInit();
        registerSocketCallback(socket_cb, NULL);

        // Connect to router. 
        m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL);

Не забываем про наши любимые callback’и. Прописываем функции обработки события по сети.
Код callback'ов
static void socket_cb(SOCKET sock, uint8_t u8Msg, void *pvMsg)
{
        switch (u8Msg)
        {
           // Socket connected 
           case SOCKET_MSG_CONNECT:
           {
              tstrSocketConnectMsg *pstrConnect = (tstrSocketConnectMsg *)pvMsg;
                  if (pstrConnect && pstrConnect->s8Error >= 0)
                  {
                     printf("socket_cb: connect success!\r\n");             
                     if (button_pressed!=0)
                     {
                        send(tcp_client_socket, &data_to_send, 12, 0);
                            printf("socket_number after connection: %d\r\n", tcp_client_socket);
                     }
                     close(tcp_client_socket);
                     delay_ms(50);
                  } 
                  else
                  {
                          printf("socket_cb: connect error!\r\n");
                          close(tcp_client_socket);
                          tcp_client_socket = -1;
                  }
           }
           break;

           // Message send 
           case SOCKET_MSG_SEND:
           {
                  printf("socket_cb: send success!\r\n");
                  recv(tcp_client_socket, gau8SocketTestBuffer, sizeof(gau8SocketTestBuffer), 0);
           }
           break;

           // Message receive 
           case SOCKET_MSG_RECV:
           {
                  tstrSocketRecvMsg *pstrRecv = (tstrSocketRecvMsg *)pvMsg;
                  if (pstrRecv && pstrRecv->s16BufferSize > 0) 
                  {
                          printf("socket_cb: recv success!\r\n");
                          printf("TCP Client Test Complete!\r\n");
                  }
                  else
                  {
                          printf("socket_cb: recv error!\r\n");
                          close(tcp_client_socket);
                          tcp_client_socket = -1;
                  }
            }
            break;

        default:
                break;
        }
}

static void wifi_cb(uint8_t u8MsgType, void *pvMsg)
{
        
        printf("wifi_cb: u8MsgType= %d\n",u8MsgType);
        switch (u8MsgType) {
        case M2M_WIFI_RESP_CON_STATE_CHANGED:
        {
                tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg;
                if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED) 
                {
                        printf("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: CONNECTED\r\n");
                        m2m_wifi_request_dhcp_client();
                }
                else
                {
                        if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED) 
                        {
                           printf("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: DISCONNECTED\r\n");
                           wifi_connected = 0;
                           m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL);
                        }
                }
                break;
        }

        case M2M_WIFI_REQ_DHCP_CONF:
        {
                uint8_t *pu8IPAddress = (uint8_t *)pvMsg;
                wifi_connected = 1;
                printf("wifi_cb: M2M_WIFI_REQ_DHCP_CONF: IP is %u.%u.%u.%u\r\n", pu8IPAddress[0], pu8IPAddress[1], pu8IPAddress[2], pu8IPAddress[3]);
                printf("wifi_cb: M2M_WIFI_REQ_DHCP_CONF: getaway IP is %u.%u.%u.%u\r\n", pu8IPAddress[4], pu8IPAddress[5], pu8IPAddress[6], pu8IPAddress[7]);
                printf("wifi_cb: M2M_WIFI_REQ_DHCP_CONF: DNS IP is %u.%u.%u.%u\r\n", pu8IPAddress[8], pu8IPAddress[9], pu8IPAddress[10], pu8IPAddress[11]);
                printf("wifi_cb: M2M_WIFI_REQ_DHCP_CONF: mask is %u.%u.%u.%u\r\n", pu8IPAddress[12], pu8IPAddress[13], pu8IPAddress[14], pu8IPAddress[15]);
                break;
        }

        default:
                break;
        }
}



Практически это и есть весь код, необходимый для работы с winc в качестве tcp клиента.

Qtouch

Весь код, описанный во второй части нашей статьи для обработки кнопок и слайдера, переносится полностью, нужно лишь добавить формирование и отправку посылок по tcp.

Собираем все вместе

Протокол ModBus прост, открыт и горячо любим в системах автоматики, потому информации о нем в интернете можно найти массу. Вот что говорит вики. Мы, как уже упоминалось, будем использовать его модификацицию TCP, рассчитанную на работу в локальных сетях.
Так как задача у нас учебно-тренировочная, то реализовывать красивую библиотеку ModBus мы не станем (через отдельные функции, с указанием регистра, данных и пр.), а просто будем формировать соответствующий набор байтиков и отправлять их в открытый сокет. Пакет Modbus в нашем случае будет меняться только в части данных, записываемых в регистр (в соответствии с протоколом работы с нашим шлюзом). Используем команду записи в один регистр — код команды 0x06.
Поля пакета:
  • Transaction ID, Protocol ID в соответствии со спецификацией Modbus
  • длина = 6
  • Unit ID в соответствии со спецификацией Modbus
  • код команды 0x06
  • номер регистра 25 (0x0019)
  • значение регистра: код команды DALI, адрес светильника/группы светильников и данные для команды (в зависимости от типа команды).

Погружать читателя в специфику протокола DALI целью настоящей статьи не ставилось, потому просто перечислю используемые команды с кратким пояснением:
  • OFF — немедленно выключить указанный светильник, повесим на левую сенсорную кнопку
  • RECALL MAX LEVEL — плавно установить максимальную яркость светильника, правая кнопка
  • ON AND STEP UP — если светильник выключен, установить минимальную яркость. будем вызывать перед RECALL MAX LEVEL
  • DIRECT ARC POWER X- плавно установить указанную яркость X для светильника, повесим на слайдер

Примечание: «ученые спорят» о том как правильнее ModBus мастеру (в роли которого выступает наша отладка) общаться со слейвами — закрывать сокет после завершения текущего сеанса связи или держать его открытым. Мы в нашем примере пошли первым путем, исходя из того что на шине могут оказаться и другие мастера, желающие подключиться к нашему шлюзу. Но тут правильного подхода, скорее всего нет, и все зависит от мировоззрения разработчика.

На этом всё. Заключительная часть вышла не особенно объемной, но весь основной фарш был в первых двух частях. Надеюсь было интересно.
Итоговый код main
int main(void)
{
        uint8_t button1_state;
        uint8_t button2_state;
        uint8_t slider_state;
        uint8_t slider_position;
        tstrWifiInitParam param;
        int8_t ret;
        struct sockaddr_in addr;
        // Initialize and configure system and generic clocks.
        // Use conf_clocks.h to configure system and generic clocks.
        system_init();
        // Enable global interrupts.  
        system_interrupt_enable_global();
        //Initialize delay service.
        delay_init();
    //Initialize timer. (RTC actually)
        timer_init();
        //Initialize QTouch library and configure touch sensors.
        touch_sensors_init();
        // Configure port pins
        configure_port_pins();
        // Turn off all extension board LEDs
        port_pin_set_output_level(LED_0_PIN, 1);
        port_pin_set_output_level(LED_1_PIN, 1);
        port_pin_set_output_level(LED_2_PIN, 1);
        port_pin_set_output_level(LED_3_PIN, 1);
        port_pin_set_output_level(LED_4_PIN, 1);
        port_pin_set_output_level(LED_5_PIN, 1);
        port_pin_set_output_level(LED_6_PIN, 1);
        port_pin_set_output_level(LED_7_PIN, 1);
        port_pin_set_output_level(LED_8_PIN, 1);
        port_pin_set_output_level(LED_9_PIN, 1);
        port_pin_set_output_level(LED_R_PIN, 1);
        port_pin_set_output_level(LED_G_PIN, 1);
        port_pin_set_output_level(LED_B_PIN, 1);

        PWM_Count = 0;
        NVMCTRL->CTRLB.bit.SLEEPPRM = 3;
        system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
        // Initialize the UART console. 
        configure_console();
        printf(STRING_HEADER);

        //Initialize the BSP. 
        nm_bsp_init();

        // Initialize socket address structure.
        addr.sin_family = AF_INET;
        addr.sin_port = _htons(MAIN_WIFI_M2M_SERVER_PORT);
        addr.sin_addr.s_addr = _htonl(MAIN_WIFI_M2M_SERVER_IP);

        // Initialize Wi-Fi parameters structure. 
        memset((uint8_t *)¶m, 0, sizeof(tstrWifiInitParam));

        // Initialize Wi-Fi driver with data and status callbacks.
        param.pfAppWifiCb = wifi_cb;
        ret = m2m_wifi_init(¶m);
        if (M2M_SUCCESS != ret)
         {
                printf("main: m2m_wifi_init call error!(%d)\r\n", ret);
                while (1);
        }

        // Initialize socket module 
        socketInit();
        registerSocketCallback(socket_cb, NULL);

        // Connect to router. 
        m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL);

        while (1)
        {
                // Goto STANDBY sleep mode, unless woken by timer or PTC interrupt.
                system_sleep();
                // Start touch sensor measurement, if touch_time.time_to_measure_touch flag is set by timer.
                touch_sensors_measure();
                if (measure_tickif ((p_mutlcap_measure_data->measurement_done_touch == 1u)) 
                {
                        p_mutlcap_measure_data->measurement_done_touch = 0u;

                        // Get touch sensor states
                        button1_state = GET_MUTLCAP_SENSOR_STATE(0);
                        button2_state = GET_MUTLCAP_SENSOR_STATE(1);
                        rotor_state = GET_MUTLCAP_SENSOR_STATE(2);
                        slider_state = GET_MUTLCAP_SENSOR_STATE(3);

                        if (button1_state) 
                        {
                                if(button_pressed!=1)
                                {
                                        port_pin_set_output_level(LED_8_PIN, 0);
                                        button_pressed=1;
                                        form_modbus_packet(0x05,DALI_OFF );
                                        tcp_client_socket = socket(AF_INET, SOCK_STREAM, 0);
                                        ret=connect(tcp_client_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
                                }
                        }
                        else 
                        {
                                port_pin_set_output_level(LED_8_PIN, 1);
                                if (button_pressed==1)
                                {
                                        button_pressed=0;
                                }
                        }

                        if (button2_state)
                        {
                                if(button_pressed!=2)
                                {
                                        port_pin_set_output_level(LED_9_PIN, 0);
                                        button_pressed=2;
                                        form_modbus_packet(0x05,DALI_RECALL_MAX_LEVEL);
                                        tcp_client_socket = socket(AF_INET, SOCK_STREAM, 0);
                                        ret=connect(tcp_client_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
                                }
                        } 
                        else
                        {
                                port_pin_set_output_level(LED_9_PIN, 1);
                                if (button_pressed==2)
                                {
                                   button_pressed=0;
                                }
                        }

                        // Clear all slider controlled LEDs
                        port_pin_set_output_level(LED_0_PIN, 1);
                        port_pin_set_output_level(LED_1_PIN, 1);
                        port_pin_set_output_level(LED_2_PIN, 1);
                        port_pin_set_output_level(LED_3_PIN, 1);
                        port_pin_set_output_level(LED_4_PIN, 1);
                        port_pin_set_output_level(LED_5_PIN, 1);
                        port_pin_set_output_level(LED_6_PIN, 1);
                        port_pin_set_output_level(LED_7_PIN, 1);

                        // If slider is activated
                        if(slider_state)
                        {
                                 // Parse slider position
                                slider_position = GET_MUTLCAP_ROTOR_SLIDER_POSITION(1);
                                
                        //   slider_position = slider_position >> 5u;
                                printf("slider_position= %d\n",slider_position);
                                if (measure_tick==INACTIVITY_DELAY)
                                {
                                        button_pressed=4;
                                        form_modbus_packet(0x05,DALI_ON_AND_STEP_UP);
                                        tcp_client_socket = socket(AF_INET, SOCK_STREAM, 0);
                                        ret=connect(tcp_client_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
                                        delay_ms(500);                                 
                                }
                                else
                                {
                                   if (button_pressed==4)
                                   {
                                                button_pressed=0;
                                   }
                                   if ((button_pressed!=3)&&(previous_slider_position!=slider_position))
                                   {
                                                button_pressed=3;
                                                brightness=slider_position;//<<5u;
                                                if (brightness==255)
                                                {
                                                        brightness=254;
                                                }
                                                printf("brightness= %d \n",brightness);
                                                form_modbus_packet(0x04,brightness);
                                                tcp_client_socket = socket(AF_INET, SOCK_STREAM, 0);
                                                ret=connect(tcp_client_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
                                                previous_slider_position=slider_position;
                                   }
                                   else
                                   {
                                      if (button_pressed==3)
                                          {
                                                 button_pressed=0;
                                          }
                                   }
                                }

                                measure_tick=0;                                
                                switch(slider_position)
                                {
                                        case 0:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                break;
                                        case 1:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                break;
                                        case 2:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                port_pin_set_output_level(LED_2_PIN, 0);
                                                break;
                                        case 3:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                port_pin_set_output_level(LED_2_PIN, 0);
                                                port_pin_set_output_level(LED_3_PIN, 0);
                                                break;
                                        case 4:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                port_pin_set_output_level(LED_2_PIN, 0);
                                                port_pin_set_output_level(LED_3_PIN, 0);
                                                port_pin_set_output_level(LED_4_PIN, 0);
                                                break;
                                        case 5:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                port_pin_set_output_level(LED_2_PIN, 0);
                                                port_pin_set_output_level(LED_3_PIN, 0);
                                                port_pin_set_output_level(LED_4_PIN, 0);
                                                port_pin_set_output_level(LED_5_PIN, 0);
                                                break;
                                        case 6:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                port_pin_set_output_level(LED_2_PIN, 0);
                                                port_pin_set_output_level(LED_3_PIN, 0);
                                                port_pin_set_output_level(LED_4_PIN, 0);
                                                port_pin_set_output_level(LED_5_PIN, 0);
                                                port_pin_set_output_level(LED_6_PIN, 0);
                                                break;
                                        case 7:
                                                port_pin_set_output_level(LED_0_PIN, 0);
                                                port_pin_set_output_level(LED_1_PIN, 0);
                                                port_pin_set_output_level(LED_2_PIN, 0);
                                                port_pin_set_output_level(LED_3_PIN, 0);
                                                port_pin_set_output_level(LED_4_PIN, 0);
                                                port_pin_set_output_level(LED_5_PIN, 0);
                                                port_pin_set_output_level(LED_6_PIN, 0);
                                                port_pin_set_output_level(LED_7_PIN, 0);
                                                break;
                                        default:
                                                port_pin_set_output_level(LED_0_PIN, 1);
                                                port_pin_set_output_level(LED_1_PIN, 1);
                                                port_pin_set_output_level(LED_2_PIN, 1);
                                                port_pin_set_output_level(LED_3_PIN, 1);
                                                port_pin_set_output_level(LED_4_PIN, 1);
                                                port_pin_set_output_level(LED_5_PIN, 1);
                                                port_pin_set_output_level(LED_6_PIN, 1);
                                                port_pin_set_output_level(LED_7_PIN, 1);
                                                break;
                                }
                        }
                }//measurement done flag
                m2m_wifi_handle_events(NULL);

                if (wifi_connected == M2M_WIFI_CONNECTED)
                {
                        // Open client socket.
                        if (tcp_client_socket < 0)
                        {
                                if ((tcp_client_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
                                {
                                        printf("main: failed to create TCP client socket error!\r\n");
                                        continue;
                                }
                                // Connect server
                                
                                printf("socket_number new connection: %d\r\n", tcp_client_socket);
                                ret=connect(tcp_client_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
                                printf("ret value: %d\r\n", ret);
                                if (ret < 0)
                                {
                                        close(tcp_client_socket);
                                        tcp_client_socket = -1;
                                }
                        }
           }
    }//while(1)
}//main

версия для печати

Наверх
главная страница | продукция | горячее предложение | склад и цены | решения | статьи | разработчикам | о компании | контакты | карта сайта
Предприятия, компании и выставки России и СНГ

Rainbow Electronics, 2003-2024
https://betonmobile.ru/mobile-liga-stavok
Разработка сайта FlyNet
prev next list
rand
Rambler's Top100

RadioTOP-рейтинг радиотехнических сайтов
Гипермаркет Shop.Sec.Ru
Поиск электронныхкомпонентов
Поиск электронных компонентов по складам поставщиков России и СНГ.
Поиск электронных компонентов Индекс популярности микроконтроллеров на mcu.caxapa.ru
Справочник по микросхемам
на Русском языке