Ключевое ?лово

vk

Существует несколько способов подключения исполнительных механизмов ( освещение и другие электроприборы) для управления через компьютер в системе умного дома или в других электронных поделках.Это и отдельные микроконтроллеры,подключенные через ethernet или через последовательный порт и используя различные беспроводные протоколы.Но существует вариант и простой и очень дешевый - всего в 200 рублей можно уложится в примере,который ниже будет описан.Хотя данный вариант это не полноценный GPIO ,но как минимум управление портами и чтение их состояния возможно.Так же существует ещё вариант GPIO на основе USBasp с возможностью подключения ,например датчиков влажности

Для этого нам необходимо всего два основных радиокомпонента:

1. I2C-USB переходник,который можно получить,перепрограммируя USBasp программатор.Его стоимость на ebay.com всего чуть больше 3$.Можно собрать и самому,но врят ли цена будет ниже..

2.Микросхема MCP23017 - это I2C расширитель портов.Имеет 16 вводов-выводов.Может как читать состояние контактов,так и управлять на них нагрузкой.Примерная цена 1.5$.

Управление MCP23017 возможно как из Linux так и из Windows.

Подключение микросхемы MCP23017 к I2C осуществляется согласно распиновке микросхемы:
MCP23o17Vdd подключаем к плюсу питания,к Vss подключаем минус питания.Для адреса 0х20 замыкаем А0,А1 и А2 на минус.SCL и SDA подключем на соотвествущие выводы GPIO Raspberry PI или переходника I2C-USB.Так же необходимо подключить вывод Reset к плюсу против случайной наводки на вывод и ненамеренного сброса микросхемы в исходное состояние.Согласно стандарту шины I2C выводы SCL и SDA необходимо "подтянуть" на плюс через резисторы 4.7кОм (У Raspberry они уже запаяны на плате).

 

 

Пример работы с MCP23017 из Linux

 Данный способ подключения и исходный код программы подходит для подключения MCP23017 и к одноплатному компьютеру Raspberry PI и к другим , имеющим на борту Linux.

 
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <string.h>
// Строки ниже необходимы для rasbian/debian.В Suse должны быть закаментированы.
//#include <linux/i2c.h>
//#include "smbus.h" 

#define mcp_I2C_ADDRESS 0x20 // адрес устройства в сети i2c,задается перемычками A0,A1,A2 на микросхеме.


// ниже 2 строки задают направление порта ,1 - на ввод,0 - на вывод.
#define mcp_bank_a 0b00000000  //байты 7 по 0 порт
#define mcp_bank_b 0b00000000 //байты 8 по 15 порт
// следущие 2 строки-подтяжка резистором 100 кОм на +, 1 - включен.Актуально для режима на ввод.
#define gppu_bank_a 0b00000000 //байты 7 по 0 порт
#define gppu_bank_b 0b00000000 //байты 8 по 15 порт





int fd;
unsigned int  utv;
int l=1;
int x=0;

// Open a connection to the mcp
// Returns a file id
int mcp_i2c_Begin()
{
 
   char *fileName = "/dev/i2c-7"; // указать Ваш адрес
   
   // Open port for reading and writing
   if ((fd = open(fileName, O_RDWR)) < 0){
     printf("i2c device not found \n");
      exit(1);
   } 
   // Set the port options and set the address of the device
   if (ioctl(fd, I2C_SLAVE, mcp_I2C_ADDRESS) < 0) {               
      close(fd);
      printf("on i2c mcp device not found \n");
      exit(1);
   }

   return fd;
}

// Read a byte to mcp
__s32 mcp_i2c_Read_byte(int fd, __u8 address)
{
   __s32 res = i2c_smbus_read_byte_data(fd, address);
   if (res < 0) {
      printf("error \n");
      close(fd);
      exit(1);
   }

   return res;
}

//Write a byte to mcp
void mcp_i2c_Write_Byte(int fd, __u8 address, __u8 value)
{
   if (i2c_smbus_write_byte_data(fd, address, value) < 0) {
      close(fd);
      exit(1);
   }
}
// чтение состояния порта
int mcp_read (int mcppin)
{
 if (mcppin < 0 || mcppin >15) {
       printf("Please select a valid GPIO pin \n");
        exit(1);
 }

 int fd =  mcp_i2c_Begin();
 int regbank;

if (mcppin < 8){
  
 mcp_i2c_Write_Byte(fd,0x00,mcp_bank_a);
 mcp_i2c_Write_Byte(fd,0x0c,gppu_bank_a);
 
    regbank=0x12;

//printf("bank A\n");
} else {
  
    mcp_i2c_Write_Byte(fd,0x01,mcp_bank_b);
    mcp_i2c_Write_Byte(fd,0x0d,gppu_bank_b);
      
   regbank=0x13;
   mcppin=mcppin-8;

 //  printf("bank B\n");
}

    utv = mcp_i2c_Read_byte(fd,regbank);

      while(x <  mcppin)
    {
      x = x+ 1;
      l=l*2;
}


if (utv & l) return 1;
else return 0;

close(fd);

}


// запрос таблицы статусов портов
void mcp_state_in () {   
      int fd =  mcp_i2c_Begin();
     utv = mcp_i2c_Read_byte(fd,0x12);
 //    printf ("--%d--\n",utv);
             while(x <  8)
    {
      
 if ((mcp_bank_a & l)) {
      if ((utv & l)) printf ("%d 1\n",x);
     else printf ("%d 0\n",x);

} else printf ("%d -\n",x);
      l=l*2;
     x = x+ 1;
     
}

      x=0;
      l=1;

          utv = mcp_i2c_Read_byte(fd,0x13);
//	      printf ("--%d--\n",utv);
             while(x <  8)
    {
       if ((mcp_bank_b & l)) {
      if ((utv & l)) printf ("%d 1\n",x+8);
     else printf ("%d 0\n",x+8);

     } else printf ("%d -\n",x+8);
           l=l*2;
     x = x+ 1;
}
  	      
close(fd);

}
// установка состояния порта
void mcp_write (int mcppin,int mcpst)
{
 if (mcppin < 0 || mcppin >15) {
       printf("Please select a valid GPIO pin \n");
        exit(1);
 }
   if (mcpst != 0 && mcpst != 1) {
      printf("Не верно задан статус порта 0 или 1\n");
        exit(1);
 }
  
 int fd =  mcp_i2c_Begin();
 int regbank;

if (mcppin < 8){
  
 mcp_i2c_Write_Byte(fd,0x00,mcp_bank_a);
 mcp_i2c_Write_Byte(fd,0x0c,gppu_bank_a);
 
    regbank=0x14;

//printf("bank A\n");
} else {
  
    mcp_i2c_Write_Byte(fd,0x01,mcp_bank_b);
    mcp_i2c_Write_Byte(fd,0x0d,gppu_bank_b);
      
   regbank=0x15;
   mcppin=mcppin-8;

 //  printf("bank B\n");
}

    utv = mcp_i2c_Read_byte(fd,regbank);

      while(x <  mcppin)
    {
      x = x+ 1;
      l=l*2;
}


if (!(utv & l) && mcpst==1) mcp_i2c_Write_Byte(fd,regbank,utv+l);
if (utv & l && mcpst==0) mcp_i2c_Write_Byte(fd,regbank,utv-l);

close(fd);

}


// запрос таблицы статусов портов
void mcp_state_out () {   
      int fd =  mcp_i2c_Begin();
     utv = mcp_i2c_Read_byte(fd,0x14);
 //    printf ("--%d--\n",utv);
             while(x <  8)
    {
      
 if (!(mcp_bank_a & l)) {
      if ((utv & l)) printf ("%d 1\n",x);
     else printf ("%d 0\n",x);

} else printf ("%d -\n",x);
      l=l*2;
     x = x+ 1;
     
}

      x=0;
      l=1;

          utv = mcp_i2c_Read_byte(fd,0x15);
//	      printf ("--%d--\n",utv);
             while(x <  8)
    {
       if (!(mcp_bank_b & l)) {
      if ((utv & l)) printf ("%d 1\n",x+8);
     else printf ("%d 0\n",x+8);

     } else printf ("%d -\n",x+8);
           l=l*2;
     x = x+ 1;
}
  	      
close(fd);

}
// основное тело программы

int main(int argc, char **argv)

{
   if (argc == 1) {
     printf("%s <команда>\nin -чтение данных из порта,установленых на ввод\nout-установка состояния порта,установленного на вывод.\n", argv[0]);
     return 1;
   } 
   else if (argc == 2) {
  if(strcmp(argv[1], "out") == 0) mcp_state_out();
  else if(strcmp(argv[1], "in") == 0) mcp_state_in();
  else printf("Нет такой команды\n");
  return 1;
   }
   
   if(strcmp(argv[1], "out") == 0) {
   
        if (argc != 4) {
             printf("Настройка порта: %s <порт> <состояние>\n", argv[0]);

return 1;
}
int mcppin = atoi(argv[2]);
int mcpst = atoi(argv[3]);

mcp_write (mcppin,mcpst);
     
     
   }
   else if(strcmp(argv[1], "in")== 0) {
   if (argc != 3) {
             printf("Чтение одного порта: %s <порт>\n", argv[0]);
     mcp_state_in();
     return 1;
   }
   int mcppin = atoi(argv[2]);

   printf ("%d\n",mcp_read (mcppin));
   
   }





   return 0;
}

 
Для компиляции данного примера необходимо ввести команду в консоли gcc -Wall -o mcp_rw ./mcp_rw.c ,находясь в той же папке где и сохранен исходный код.Пример mcp_rw работает только с одной микросхемой MCP23017 ,но ничего не мешает переписать программу или скомпилировать несколько вариантов с разными адресами.

Не забываем поправить номер i2c устройства в исходном коде,у Вас оно может быть другим.

Возможности примера программы mcp_rw:

1.Вывод состояния портов,сконфигурированные на вывод.Команда  ./mcp_rw out . Прочерк состояния порта означает,что порт сконфигурирован на ввод.

2.Управление состоянием порта,сконфигурированный на вывод  ./mcp_rw out номер_пина состояние_пина(0 или 1).

3.Вывод состояния портов,сконфигурированные на ввод.Команда ./mcp_rw in . Прочерк состояния порта означает,что порт сконфигурирован на вывод.

4.Чтение состояния порта,сконфигурированный на ввод .Команда ./mcp_rw in номер_пина.

 В текущем виде программку mcp_rw in можно использовать , вызвав её из других языков,например из php или использовать подпрограммы в своих более полноценных программах на Си.

Схема на макетной плате:

shema mcp

Видео демонстрация работы:

На видео показано  как из консоли можно управлять устойствами.Подключено 2 светодиода и блок из 2-х реле.

Обратите внимание,что блок реле управляется нулем,а не единицей.

shotsНа скриншоте видим как вводились команды в видеоролике.А так же  можно увидеть результат сканирования i2c устройств командой i2cdetect -y 7 ,где находит устройство по адресу 0х20 - это как раз подключеная микросхема MCP23017.В данном случае все выводы,кроме 2, назначены на вывод.

Запуск утилиты требует права суперпользователя,если на устройство /dev/i2c не назначены полные права.

 

 

 

 

 

 

Пример работы с MCP23017 из Windows

Программа написана на Си используя cygwin,основана на примерах из i2c_tiny_usb.Управление пинами MCP23017 через данную утилиту осуществляется аналогично примеру из Linux.

 

Качаем программу тут ,перед запуском не забываем про драйвер для переходника I2C-USB.Работа программы проверена только через переходник i2c_tiny_usb.

Программа создает файл pinsmode.cfg ,где указывается режим работы выводов в виде 16 единиц и нулей -нумерация справа налево ! Состояние 0 - вывод назначен как вывод.Состояние 1 - вывод назначен как ввод.По умолчанию все выводы назначены на вывод -т.е. в файле все нули.Обратите внимание,что pinsmode.cfg должен находится там,откуда идет вызов программы:

mcp winНапример в данном случае файл pinsmode.cfg должен находится в папке C:\mcp_win\ .Этот пример ярлыка включает единичку на 1 порте.

 

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

Home`s Smart © 2013-2016. г.Киров.
Цитирование материалов возможно только со ссылкой на сайт. Использование фотоматериалов только с разрешения авторов.