Pull to refresh

Электронный замок с беспроводным управлением на базе Energia Launchpad

Reading time12 min
Views38K


Глядя на множество хабро-статей на базе Arduino мне показалось несколько странным отсутствие интересных беспроводных решений из мира Energia Launchpad. Пора исправить эту вселенскую несправедливость!
Сегодня я познакомлю вас с отладочной платой CC3200-launchpad, расскажу об ее преимуществах перед ESP8266, подключу к ней пару launchpad по радиоканалу и буду щелкать большими советскими релюхами. Поехали!

CC3200-LAUNCHXL Ланчпад с большой буквы


Сегодняшний рассказ я начну с микроконтроллера CC3200[1] от Texas Instruments.
Этот контроллер представляет собой симбиоз ядра TIVA-C Cortex-M4 и Simplelink Wi-Fi процессора CC3100 в одном корпусе


Рисунок 1: Структурная схема контроллера

Немного о приятных и интересных свойствах данного камня, применимо к встраиваемым микромощным решениям[2]:
  1. 80МГц ядро Cortex-M4;
  2. ОЗУ 256Кбайт;
  3. Драйвера периферии в ПЗУ, отсутствует встроенная Flash память программ;
  4. Поддержка внешней микросхемы Serial Flash памяти — вешай сколько хочется;
  5. Аппаратное шифрование AES, DES, SHA2, MD5, CRC;
  6. 2xI2S, 1xSD-card, 2xUART, 1xSPI, 1x2C, 8-разрядный интерфейс камеры;
  7. 4 таймера с 16-бит ШИМ;
  8. 4 канала 12-разрядного АЦП
  9. Сертифицированный 802.11g/b/n Wi-Fi модуль с поддержкой шифрования WEP, WPA2-PSK и WPA-Enterprise. Работа как в режиме устройства, так и в режиме хоста
  10. 256-bit AES для SSLv3 и TSLv1. Да-да, он тащит SSL!
  11. Микромощное потребление и множество режимов управления питанием


CC3200 vs ESP8266

С одной стороны ESP8266 обладает следующими преимуществами:
Во-первых, он очень маленький и интегрированный — хренька размером и стоимостью с монетку требует лишь пару батареек питания и ее уже можно втыкать в утюг или чайник.
Во-вторых, у него хорошо проработаны режимы питания — если подойти с умом, то получается диетический продукт.
В-третьих, у него простой старт — достаточно подключить его к компьютеру, открыть среду Arduino и можно работать.

С другой стороны, CC3200 — мощный процессор, способный держать в себе множество активных задач. Кроме того, у него намного более богатая периферия — хочешь — подключай камеру, хочешь аудиоустройства(по I2S) или SD-карту. Хочешь — еще с десяток всякой всячины навешай — выдержит и железо и прошивка. Ну и конечно же SSL. Здесь мой маленький параноик просто ликует от счастья.
Но тут же просыпается жаба и начинает душить вашего покорного слугу — ланчпад у производителя стоит 30 баксов/штука. В РФ есть шанс купить за 40-50 долларов+доставка. Бесплатная доставка у TI кончилась.

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

CC3200-LAUNCHXL Быстрый старт[3]


Рисунок 2: комплектация

Как и подобается любому ланчпаду, CC3200 приходит в аккуратной картонной коробке с базовой комплектацией — сама плата, шнур micro-USB, пара джамперов и пара буклетов.
Плата — типичный представитель 40-контактных launchpad, несет на себе сам контроллер CC3200 в 64-ногом корпусе QFN. Не самый страшный корпус для ручной пайки. Также, на плате имеется программатор на базе FT2232 чипа(официальная поддержка openOCD). Микросхема Flash памяти на 8Мбит данных.
Отдельно стоит упомянуть трехосевой +-16G акселерометр BMA222[4] и бесконтактный ИК датчик температуры TMP006[5]


Рисунок 3: ланчпад в деталях

Одним словом — все что нужно растущему разработчику IoT.

Подключим плату к питанию изучим имеющуюся на нем демо-прошивку.
Прошивка предлагает немного датащитов, и 4 микродемки. И все это в режиме точки доступа, с http сервером на борту.
Дабы не быть многословным, небольшой видеообзор:



CC3200 SDK[6]

С помощью CCS UniFlash[7] обновим наш SDK.


Рисунок 4: CCS UniFlash внешний вид

Для начала, плату необходимо перевести в режим программирования Flash, для чего замкнуть пины 2 разъема SOP. После этого, подключаемся к UART порту, форматируем Flash память по объем 1Мбайт. После чего указываем путь к нашему ServicePack. на момент написания статьи актуальный Service Pack: 1.0.0.10.0, SDK: 1.1.0.

Программирование в среде Code Composer Studio 6.0.1[8]

Для больших проектов и нормальной отладки идеальным вариантом является разработка программ в среде Code Composer Studio (хозяйке на заметку — CCS6 бесплатен для любого применения при использовании компилятора GCC). Производитель поддерживает также и IAR.

Установка и настройка CCS IDE
Первым делом, сконфигурируем джамперы как указано на рисунке:


Рисунок 5: установка джамперов для программирования в среде CCS

Кроме того, устанавливая Code Composer Studio не забудем выставить галочку возле соответствующего пакета:


Рисунок 6: установка CCS с поддержкой CC3200

Любителям TI-RTOS[9] рекомендую после установки в магазине расширений установить пакет TI-RTOS for SImplelink


Рисунок 7: установка TI-RTOS для CC3100&CC3200

Импортируем один из демо-проектов. Я выбрал HTTP server[10].
Наша задача — добавить таргет для подключения к плате. Для этого заходим в пункт меню View->Target Configurations, импортируем файл C:\TI\CC3200SDK_1.1.0\cc3200-sdk\tools\ccs_patch\cc3200.ccxml и после этого, в его контекстном меню указываем, что он будет использоваться по умолчанию.


Рисунок 7: настройка дебаг-интерфейса

Жмем F11 для запуска Debug-режима, потом F8 для запуска программы и лезем в приложение Wi-Fi Starter для Android[11] или iOS[12]

Wi-Fi Starter
Указав название точки доступа и пароль к ней, нажимаем кнопку старт


Рисунок 8: Поиск и настройка устройств

Как только устройство будет найдено, оно отобразится во вкладке Devices

Рисунок 9: Список подключенных устройств
тапаем по нему и попадаем на страничку в браузере, которая говорит о том, что все работает. там же можно перенастроить данные для Wi-Fi подключения и перевести устройство в режим точки доступа.


Рисунок 10: Демо-приложение

Дальше мы можем лезть куда нам надо и не надо и писать свои приложения.

Создание электронного замка


Перейдем уже наконец к практике!
Давайте сделаем электронный замок с датчиком открывания двери и радиобрелком для управления, и чтобы при несанкционированном доступе мне приходила СМС неприличного содержания.
Для этого нам понадобится:
  • CC3200 launchpad в роли Wi-Fi шлюза
  • TIVA-C launchpad[13] в роли платы управления электронным замком
  • MSP430F5529[14] launchpad в роли платы радиобрелока
  • и три штуки радиомодулей Anaren CC110L boosterpack в роли радиомодулей[15].

Принцип действия следующий:
Исполнительный механизм снабжен двухпозиционным соленоидом и датчиком периметра. В нашем случае роль соленоида будет исполнять двухпозиционное советское реле РП-12[16], а роль датчика периметра фотореле РФ-8300, столь знакомое сердцу посетителя советского метро (ни один турникет не пострадал). Логика работы следующая: С помощью радиокоманды можно выставить либо дежурный режим, либо режим охраны. В режиме охраны соленоид «запирает» дверь, и срабатывание датчика приведет к тревоге. Переход в дежурный режим отпирает дверь. Статус регулярно передается на Wi-Fi шлюз через радиоканал.

Брелок имеет две кнопки — поставить на охрану/снять с охраны. Передача команд осуществляется непосредственного на исполнительное устройство. тип передачи данных UDP, т.е. без подтверждения приема пакета (губа треснет). Данные передаем без шифрования по той же причине. Исполнительное устройство передает свое состояние на wi-fi шлюз. В случае тревоги Wi-Fi шлюз инициирует передачу SMS.

Зафиксируем команды:

enum {IDLE=0x01, ACTIVE, ALERT};

Программирование в среде Energia[17]

Для поклонников Arduino применимо к launchpad существует замечательный форк в виде среды программирования Energia. Он активно поддерживается сообществом:


Рисунок 11: Список плат, поддерживаемых версией Energia-15

Для того, чтобы CC3200 можно было запрограммировать из Energia, необходимо сделать маленький хак — верхний пин TCK соединить с нижним пином SOP-2:


Рисунок 12: Подключение режима автопрограммирования

Брелок

Здесь все просто. Нажали кнопку 1 — передали на механизм команду «ACTIVE».
нажали кнопку 2 — передали на механизм команду «IDLE».

Рисунок 13. Составные части брелка
Накопипастим из примеров простенькую программку:

Листинг программы для брелка
#include <SPI.h>
#include <AIR430BoostETSI.h>

//define addresses. 
#define ADDRESS_LOCAL    0x02
#define ADDRESS_REMOTE   0x03

//FSM states. And commands
enum {
  IDLE=0x01, ACTIVE, ALERT};

unsigned char txData[60] = { 
  "\0" };

const int setButton = PUSH1; //set to active mode
const int releaseButton = PUSH2;//set to idle mode
const int ledPin =  GREEN_LED; 
const int redPin = RED_LED;

void setup() {
  //define pinouts and add serial outputr
  pinMode(ledPin, OUTPUT);      
  pinMode(redPin, OUTPUT);
  Serial.begin(9600);

  pinMode(setButton, INPUT_PULLUP);     
  pinMode(releaseButton, INPUT_PULLUP);  
  Radio.begin(ADDRESS_LOCAL, CHANNEL_1, POWER_MAX);
  Serial.println("RF start");
  txData[0] = ADDRESS_LOCAL;//set zer0 byte as our address
}

void loop(){
  //check set button
  if (digitalRead(setButton) == LOW){
    //if button is pressed, send command
    Serial.println("Active mode");
    digitalWrite(redPin, HIGH);
    txData[1] = ACTIVE;//Set command
    txData[2] = 0x00;
    Radio.transmit(ADDRESS_REMOTE, (unsigned char*)&txData, 2);
  }
  else{
    digitalWrite(redPin, LOW);
  }
  //check release button
  if (digitalRead(releaseButton) == LOW){
    Serial.println("IDLE mode");
    digitalWrite(ledPin, HIGH);
    txData[1] = IDLE;//Set command
    txData[2] = 0x00;
    //send packet
    Radio.transmit(ADDRESS_REMOTE, (unsigned char*)&txData, 2);
  }
  else{
    digitalWrite(ledPin, LOW);
  }
  sleepSeconds(1);//Low-power mode delay
  delay(50);//to Clock stabilization
}


Исполнительный механизм

Задача исполнительного механизма — управлять двустабильным соленоидом. У такого соленоида имеется две обмотки, подавая напряжение на одну обмотку мы втягиваем сердечник, на другую — отпускаем. Постоянно держать напряжение на обмотках не требуется. Наше реле РП-12 немного не такое — у него обмотка одна, а выбор действия определяется полярностью. Обойдемся парой диодов.

Рисунок 14: Большое советское реле без купюр. Виден электромагнит и двухпозиционный сердечник. Подавая сигнал разной полярности на сердечник добиваемся переключения реле.

Подключать будем через симисторы MOC3052 по следующей схеме:


Рисунок 15: Схема подключения симистора.

У меня в загашниках нашлась платка с двумя симисторами, так что не пришлось городить макетку.
Датчик контроля периметра на фотореле РФ-8300 работает автономно, группой замыкающих контактов подавая сигнал на актуатор.

поклонникам Google Cardboard
Линзы эти этих релюх просто созданы для того, чтобы стоять в очках виртуальной реальности.

Получив от брелка команду, выполняем ее, и дублируем на wi-Fi шлюз.
Копипастим программку:

Листинг программы для актуатора
#include <SPI.h>
#include <AIR430BoostETSI.h>

#define ADDRESS_LOCAL    0x03
#define ADDRESS_REMOTE   0x01

unsigned char rxData[60] = {
  "\0" };
  
unsigned char txData[60] = {  
  "\0" };
/*
Finite state machine:
1. IDLE mode
2. Action Mode
3. Alert mode
1 -> 2 Received command 0x01
2 -> 1 received command 0x02
2 -> 3 sensor triggered. Send alert
*/
enum {IDLE=0x01, ACTIVE, ALERT};
unsigned int fsm = IDLE;

static unsigned char sensor = 11;
static unsigned char releopen = 9;
static unsigned char releclose = 10;
static unsigned char releopenled = BLUE_LED;
static unsigned char relecloseled = GREEN_LED;

// -----------------------------------------------------------------------------
// Main example

void setup()
{
  pinMode(sensor, INPUT_PULLUP);
  pinMode(releopen, OUTPUT);
  digitalWrite(releopen, HIGH);
  pinMode(releopenled, OUTPUT);
  pinMode(relecloseled, OUTPUT);
  pinMode(releclose, OUTPUT);
  digitalWrite(releclose, HIGH);
  pinMode(12, OUTPUT);
  pinMode(12, LOW); //return pin for sensor
 
  Radio.begin(ADDRESS_LOCAL, CHANNEL_1, POWER_MAX);

   // Setup serial for debug printing.
  Serial.begin(9600);
  
  txData[0] = ADDRESS_LOCAL;//set zer byte as our address
}
uint8_t length = 0;

void loop()
{
  
  switch (fsm){
    case IDLE:
      length = Radio.receiverOn(rxData, sizeof(rxData), 1000);
      if (length > 0){
        if (rxData[1] == ACTIVE){
          //change state stage
          fsm = ACTIVE;
          txData[1] = ACTIVE;//Set command
          txData[2] = 0x00;
          Radio.transmit(ADDRESS_REMOTE, (unsigned char*)&txData, 2); 
          //send 500ms inpuls to actuator
          digitalWrite(releclose, LOW);
          digitalWrite(relecloseled, HIGH);
          delay(500);
          digitalWrite(releclose, HIGH);
          digitalWrite(relecloseled, LOW);
        }
        else{
          fsm = IDLE;
        }
      }
      else{
      }
    break;
    
    case ACTIVE:
      length = Radio.receiverOn(rxData, sizeof(rxData), 100);
      if (length > 0){
        if (rxData[1] == IDLE){
          //change state stage
          fsm = IDLE;
          txData[1] = IDLE;//Set command
          txData[2] = 0x00;
          Radio.transmit(ADDRESS_REMOTE, (unsigned char*)&txData, 2); 
          //send 500ms inpuls to actuator
          digitalWrite(releopen, LOW);
          digitalWrite(releopenled, HIGH);
          delay(500);
          digitalWrite(releopen, HIGH);
          digitalWrite(releopenled, LOW);
        }
        else{
          fsm = ACTIVE;
        }
      }
      else{
      }
         checkperimeter();   
    break;
    
    case ALERT:
      length = Radio.receiverOn(rxData, sizeof(rxData), 1000);
      if (length > 0){
        if (rxData[1] == IDLE){
          //change state stage
          fsm = IDLE;
          txData[1] = IDLE;//Set command
          txData[2] = 0x00;
          Radio.transmit(ADDRESS_REMOTE, (unsigned char*)&txData, 2); 
          //send 500ms inpuls to actuator
          digitalWrite(releopen, LOW);
          digitalWrite(releopenled, HIGH);
          delay(500);
          digitalWrite(releopen, HIGH);
          digitalWrite(releopenled, LOW);
        }
        else{
          fsm = ALERT;
        }
      }
      else{
      }   
    break;
    
    default:
    break;
  }

}

void checkperimeter(){
    uint8_t sensorstate = digitalRead(sensor);
    if (sensorstate == LOW){
      Serial.println("Alert!");
          //alert!!
        fsm = ALERT;
        txData[1] = ALERT;//Set command
        txData[2] = 0x00;
        Radio.transmit(ADDRESS_REMOTE, (unsigned char*)&txData, 2);     
    }
}


Шлюз

Задача шлюза не сложнее — дублировать светодиодами состояние системы (для теста) и в случае тревоги отправить сообщение на телефон.

Рисунок 15: шлюз в сборе
Temboo+NEXMO

Но для начала подготовим API-почву. Для этого регистрируемся на сервисах Temboo[18] и Nexmo[19]. В задачи Nexmo входит подключение к любому мобильному телефону в любой точке мира. При регистрации дают стартовые 2 Евро, которых вполне достаточно, чтобы опробовать этот сервис.

В задачи Temboo будет входить организация связи между нашим устройством и сервисом Nexmo. Здесь для старта дается 250 запросов, которые можно бесплатно расширить на добрый десяток тысяч, приглашая друзей. Что до тарифов — смски мне обошлись в 2 евроцента за штуку.

В списке возможных API выбираем Nexmoo.SMS.TextMessage.

Выбираем нашу плату — CC3200 и указываем параметры Wi-Fi подключения


Рисунок 16: Настройка Wi-Fi

Указываем параметры подключения. От нас требуют указать API ключи от нашего аккаунта Nexmoo, номер телефона отправителя, который привязан к нашему аккаунту, номер телефона получателя и текстовое сообщение.


Рисунок 17: Выбор получателя и настройка сообщения

Нажатием на кнопку Run можно проверить что все работает.
Копипастим код из блоков и «докопипасчиваем» ему поддержку режимов работы:

Листинг кода Wi-Fi шлюза
#include <SPI.h>
#include <AIR430BoostETSI.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <Temboo.h>
#include "TembooAccount.h" // Contains Temboo account information

WiFiClient client;

#define ADDRESS_LOCAL    0x01

unsigned char rxData[60] = {
  "\0" };

unsigned char txData[60] = {  
  "\0" };
/*
Finite state machine:
 1. IDLE mode
 2. Action Mode
 3. Alert mode
 1 -> 2 Received command 0x01
 2 -> 1 received command 0x02
 2 -> 3 sensor triggered. Send alert
 */
enum {
  IDLE=0x01, ACTIVE, ALERT};
unsigned int fsm = IDLE;

// -----------------------------------------------------------------------------
// Main example

void setup()
{
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  digitalWrite(YELLOW_LED, LOW);
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, LOW);

  Radio.begin(ADDRESS_LOCAL, CHANNEL_1, POWER_MAX);

  // Setup serial for debug printing.
  txData[0] = ADDRESS_LOCAL;//set zer byte as our address

  Serial.begin(9600);

  int wifiStatus = WL_IDLE_STATUS;

  // Determine if the WiFi Shield is present
  Serial.print("\n\nShield:");
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("FAIL");

    // If there's no WiFi shield, stop here
    while(true);
  }

  Serial.println("OK");

  // Try to connect to the local WiFi network
  while(wifiStatus != WL_CONNECTED) {
    Serial.print("WiFi:");
    wifiStatus = WiFi.begin(WIFI_SSID, WPA_PASSWORD);

    if (wifiStatus == WL_CONNECTED) {
      Serial.println("OK");
    } 
    else {
      Serial.println("FAIL");
    }
    delay(5000);
  }
  digitalWrite(YELLOW_LED, HIGH);
  Serial.println("Setup complete.\n");
}
uint8_t length = 0;

void loop()
{
  length = Radio.receiverOn(rxData, sizeof(rxData), 1000);
  if (length > 0){
    Serial.print("Get state: ");
    Serial.println(rxData[1], DEC);

    switch (fsm){
    case IDLE:
      if (rxData[1] == ACTIVE){
        fsm = ACTIVE;
        digitalWrite(GREEN_LED, HIGH);
      }
      break;

    case ACTIVE:
      if (rxData[1] == IDLE){
        fsm = IDLE;
        digitalWrite(GREEN_LED, LOW);
        digitalWrite(RED_LED, LOW);
      }
      if (rxData[1] == ALERT){
        fsm = ALERT;
        digitalWrite(RED_LED, HIGH);
        sendmessage();
      }    
      break;

    case ALERT:
      if (rxData[1] == IDLE){
        fsm = IDLE;
        digitalWrite(GREEN_LED, LOW);
        digitalWrite(RED_LED, LOW);
      }     
      break;
    }
  }
}

void sendmessage(){
  Serial.println("Running SendMessage - Run #" + String(numRuns++));

    TembooChoreo SendMessageChoreo(client);

    // Invoke the Temboo client
    SendMessageChoreo.begin();

    // Set Temboo account credentials
    SendMessageChoreo.setAccountName(TEMBOO_ACCOUNT);
    SendMessageChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
    SendMessageChoreo.setAppKey(TEMBOO_APP_KEY);

    // Set Choreo inputs
    String TextValue = "Testing! Testing! 1, 2, 3";
    SendMessageChoreo.addInput("Text", TextValue);
    String APIKeyValue = "000";
    SendMessageChoreo.addInput("APIKey", APIKeyValue);
    String ToValue = "000";
    SendMessageChoreo.addInput("To", ToValue);
    String APISecretValue = "000";
    SendMessageChoreo.addInput("APISecret", APISecretValue);
    String FromValue = "000";
    SendMessageChoreo.addInput("From", FromValue);

    // Identify the Choreo to run
    SendMessageChoreo.setChoreo("/Library/Nexmo/SMS/SendMessage");

    // Run the Choreo; when results are available, print them to serial
    SendMessageChoreo.run();

    while(SendMessageChoreo.available()) {
      char c = SendMessageChoreo.read();
      Serial.print(c);
    }
    SendMessageChoreo.close();
}


Компилируем, тыкаем кнопочки и убеждаемся, что все работает.

Демонстрация

Наглядная демонстрация с большими релюшками:



Подведу итоги — отладочная плата CC3200 — весьма приятная железка имеющая свою нишу для применений. Показанное здесь демо сделано по принципу «слепила из того что было» и призвано показать часть возможностей плат Energia lauchpad. В планах — в подробностях рассказать об особенностях подключения датчиков и исполнительных механизмов с учетом надежности и устойчивости к электромагнитным помехам.

Исходный код проекта доступен в репозитории[20].

Полезные ссылки:


1. CC3200 Product Brief http://www.ti.com/product/cc3200
2. CC3200 Datasheet http://www.ti.com/lit/ds/symlink/cc3200.pdf
3. CC3200-LAUNCHXL User Guide http://www.ti.com/lit/ug/swru372b/swru372b.pdf
4. BMA222 Accelerometer Datasheet https://ae-bst.resource.bosch.com/media/products/dokumente/bma222/bst-bma222-ds002-05.pdf
5. TMP006 IR Thermopile Sensor Datasheet http://www.ti.com/lit/ds/sbos518e/sbos518e.pdf
6. CC3200 SDK http://www.ti.com/tool/cc3200sdk
7. CCS UniFlash http://www.ti.com/tool/uniflash
8. Code Composer Studio 6 IDE http://www.ti.com/tool/ccstudio
9. TI-RTOS http://www.ti.com/tool/TI-RTOS
10. CC3200 HTTP server User Guide http://processors.wiki.ti.com/index.php/CC32xx_HTTP_Server
11. Wi-Fi Starter App for Android https://play.google.com/store/apps/details?id=com.pandaos.smartconfig
12. Wi-Fi Starter App for iOS https://itunes.apple.com/us/app/texas-instruments-simplelink/id884122493?ls=1&mt=8
13. TIVA-C launchpad http://www.ti.com/tool/ek-tm4c123gxl
14. MSP430F5529 launchpad http://www.ti.com/tool/msp-exp430f5529lp
15. CC110L Air Module Boosterpack https://www.anaren.com/air/cc110l-air-module-boosterpack-embedded-antenna-module-anaren
16, Реле РП-12. Описание: http://www.cheaz.ru/ru/production/ustroystva-releynoy-zashchity/rele-promezhutochnye-dvukhpozitsionnye-rp-8-9-11-12
17. Energia IDE http://energia.nu/
18. Temboo https://temboo.com/
19. Nexmo https://www.nexmo.com/
20. Electronic Lock GitHub repo https://github.com/radiolok/electronic_lock_energia
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 12: ↑11 and ↓1+10
Comments8

Articles