Главная > MSP430 > Управляем светодиодами через WEB-интерфейс, или первый шаг к умному дому

Управляем светодиодами через WEB-интерфейс, или первый шаг к умному дому

Опять пришли выходные, и мне опять нечего делать. В прошлый раз от скуки я изготовил гальванический элемент, чем шокировал общественность, посоветовавшую мне гулять с девушками вместо подобных занятий. Однако должен разочаровать сих доброжелателей — девушки у меня нет и не предвидится. Потому сегодня я буду управлять светодиодами через WiFi.

Я уже рассказывал, что купил роутер. По причине того, что сейчас мне лень его ковырять мой WL-520GU на гарантии, он пока что будет работать вполне стандартно — главные герои сегодняшней затеи компьютер и нетбук. Роутер же будет всего лишь соединять их в сеть.

Итак, сегодня я хочу с нетбука, включенного в WLAN, управлять светодиодами на LaunchPad‘e через WEB-интерфейс.

Как настоящий индеец, начну с конца, т.е., с прошивки контроллера. Логика ее работы сводится к приему байта через UART (использую свой софтовый UART) и включению светодиода, соответствующего принятой команде. Система команд гениально проста:

R — зажечь красный;
G — зажечь зеленый;
r — погасить красный;
g — погасить зеленый.

Собственно, код (писано в IAR):

#include "msp430g2231.h"
#include "ta_uart.h"

volatile unsigned char cmd_received=0;

void UART_RX_Handler(unsigned char ch)
{
  cmd_received=ch;
}

void Set15_25MHzClk(void)
{
  //Setting MCLK=SMCLK= ~15.25MHz
  BCSCTL1=RSEL3 | RSEL2 | RSEL1 | RSEL0;
  DCOCTL=DCO1 | DCO0;
}

void main(void)
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  
  Set15_25MHzClk();
  
  P1DIR=BIT0 | BIT6;
  P1OUT=0;
  
  UART_DefaultTimerConfig();
  
  UART_SetRxMode();
  
  UART_SetRxHandler(UART_RX_Handler);
  
  __enable_interrupt();
  
  while (1)
  {
    if (cmd_received=='R')
    {
      P1OUT|=BIT0;
      
      cmd_received=0;
    }
    
    if (cmd_received=='r')
    {
      P1OUT&=~BIT0;
      
      cmd_received=0;
    }
    
    if (cmd_received=='G')
    {
      P1OUT|=BIT6;
      
      cmd_received=0;
    }
    
    if (cmd_received=='g')
    {
      P1OUT&=~BIT6;
      
      cmd_received=0;
    }
  }
}

Со стороны ПК общаться с микроконтроллером будет программа на C, которую сервер (я не стал мудрить и выбрал Apache) будет вызывать как CGI-приложение.

CGI — волшебный интерфейс, дающий возможность пристыковать программу на любом языке к серверу. Условие только одно — язык должен поддерживать стандартные потоки ввода-вывода и переменные окружения. Взаимодействие происходит следующим образом: сначала клиент загружает HTML-страницу с формой. Я написал такую (писано в 1st Page 2000):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
        <title>Remote LaunchPad LEDs control</title>
</head>

<body>

<h1 align="center">Remote LaunchPad LEDs control</h1>

<form method="get" action="http://192.168.1.2/cgi-bin/setled.exe">
<input type="hidden" name="mode" value="LED"\>
<input type="checkbox" name="R" value="on"/>Turn red LED on
<input type="checkbox" name="G" value="on"/>Turn green LED on
<input type="submit" value="Update LEDs"/>
</form>

</body>
</html>

— никаких красивостей, спартанская простота. Два чекбокса, каждый для своего светодиода, и кнопка отправки запроса. Когда мы кликаем на кнопку отправки, браузер посылает серверу запрос в адресной строке (при использовании метода GET; я выбрал именно его, ибо килобайты мне передавать не надо). Он выглядит как-то так:

http://192.168.1.2/cgi-bin/setled.exe?mode=LED&R=on&G=on

Или, например, так:

http://192.168.1.2/cgi-bin/setled.exe?mode=LED&G=on

Видно, что он содержит имена выбранных элементов формы и их значения. Сервер, получив запрос, кладет все, что правее знака «?» в переменную окружения QUERY_STRING и вызывает приложение, указанное в описании формы. Приложение читает QUERY_STRING, делает то, о чем его просили, и по мере необходимости пишет в stdout. Все, что приложение написало в stdout, сервер бережно перехватывает и отправляет клиенту.

Итак, код CGI-приложения (писано в Code::Blocks+MinGW, обычное консольное приложение, pure C):

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>

#include "PortDriver.h"

char success_htmsg[]={"\
<html>\
<body>\
<h2 align=center>Success!</h2>
\
<h5 align=center><a href=http://192.168.1.2/>Click here to go back</a></h5>\
</body>\
</html>"};

char fail_htmsg[]={"\
<html>\
<body>\
<h2 align=center>Failed to set LEDs state</h2>
\
<h3 align=center>Probably LaunchPad is not attached to PC.</h3>
\
<h5 align=center><a href=http://192.168.1.2/>Click here to go back</a></h5>\
</body>\
</html>"};

int main(void)
{
    HANDLE h;
    char *query;

    h=InitPort("\\\\.\\COM10",4800);
    query=getenv("QUERY_STRING");
    printf("Content-Type: text/html; charset=us-ascii\n\n");

    if (h==INVALID_HANDLE_VALUE)
    {
        printf("%s\n\n",fail_htmsg);

        return 0;
    }

    if (strstr(query,"R=on")!=NULL)
    {
        SendData(h,'R');
    }
    else
    {
        SendData(h,'r');
    }

    if (strstr(query,"G=on")!=NULL)
    {
        SendData(h,'G');
    }
    else
    {
        SendData(h,'g');
    }

    printf("%s\n\n",success_htmsg);

    return 0;
}

В его работе тоже все просто — открывается COM-порт (тут я тоже использую небольшой самописный модуль, который кочует у меня из проекта в проект), если порт открыть не получается, выдается сообщение (сформированная HTML-страница) об ошибке. В случае же успеха в строке запроса, переданной в QUERY_STRING, ищутся определенные параметры, после чего LaunchPad’у отправляется соответствующая команда, а клиенту сообщется, что все хорошо.

Тут кто-то может спросить — а где же те потоки, которыми я пугал общественность, описывая работу CGI, ведь везде обычные printf’ы? Все правильно. Дело в том, что обычный, родной и знакомый printf как раз и пишет в stdout. Только обычно stdout это консоль, а тут его перехватывает сервер. Так что никаких глобальных перемен не нужно. Т.е. все, что выведено с помощью printf’а, будет отдано клиенту в целости и сохранности — приложение просто выводит HTML-код страницы.

Собственно, программа кладется в директорию cgi-bin, HTML-страница с формой под именем index.html — в htdocs. LaunchPad втыкается в USB, и все начинает работать. Можно из другого конца квартиры включать/выключать светодиодики. Ну, или из другого конца мира, если пустить сервер в WAN. Но я не хочу, чтобы кто-то еще игрался с моими светодиодиками, и потому сервер смотрит исключительно в локалку. А на WiFi у меня WPA2 и фильтрация по MAC.

В аттаче лежат все файлы для желающих повторить мой подвиг.

Рубрики:MSP430
  1. 07/12/2012 в 10:51

    У меня в LaunchPad MSP430G2553, это с UART.
    Хотелось бы узнать как подключается физически микросхема msp430g2231 для софтового UART?

    • YS
      07/12/2012 в 20:07

      В исходнике модуля UART есть комментарий.

      UART реализован на порту P1. TX — BIT1, RX — BIT2.

  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s