I2c CoDeSys
Содержание
Задача
Для использования периферийных устройств, через i2c. Например у меня на контроллере 16 (однобитовых/ключей)входов и 16 выходов. В тестовой плате Beck DB54 таких входов и выходов по восемь. Ну чтож расширим, для этого выполним следующие шаги:
Создание платформы
Отрываем ближайшую подходящую платформу
Откроем в CoDeSys@CHIP IEC Platform Builder тестовую платформу для платы BECK DB54 C:\Program Files\Beck IPC GmbH\CoDeSys@CHIP SDK\samples\Full\DK55\SC23\DK55_FP_CM.xml. Мы делаем так как наша плата почти полностью соответствует этой платформе, иначе придется все создавать с нуля.
Вносим изменения:
General
В оригинале:
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-orig1.jpg
Меняем:
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-my1.jpg
Имя (Name) может быть на ваше усмотрение, а вот с ID не все так просто, он должен быть либо из диапазона для тестирования 20300 - 20309 как я и выбрал, либо попросить у компании Beck выделить личный ID.
Теперь переходим на вкладку Device.
Оригинал:
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-orig2.jpg
Меняем:
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-my2.jpg
Так как на плате с которой сейчас проводится эксперимент есть три порта RS-232 и все они будут заняты внешними устройствами то убираем галочку с RS232, тем самым отключаем управление контроллером через RS-232 порт и оставляем управление только через ethernet.
IO Configuration
Оригинал:
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-orig3.jpg
Меняем:
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-my3.jpg
Здесь мы создаем две переменные по 8 бит каждая (и того 16 бит) для входных и выходных данных подключенных через i2c. D0_in, D1_in и D0_out, D1_out - это байтовые (8bit)переменные которые будут доступны из программ CoDeSys, как? об этом ниже.
Сохраняем и создаем новую платформу:
Сохраняем платформу в новое место
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-my-save.jpg
Создаем файлы новой платформы
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-my-make.jpg
Переходим в папку с вновь созданной платформой
http://rrv.nsk.ru/wiki/images/i2c-PlatfBuil-my-go.jpg
Теперь вносим изменения в myrts.c будущий exe-файл платформы
В RTOS запускается файл myrts.exe читаем тут. Для того что бы заработали все требуемые COM-порты и i2c-устройства были привязаны к определенными нами переменными напишем соответствующие драйверы изменив файл myrts.c он расположен в папке rts которая лежит в папке в которую мы сохранили, а потом создали платформу с помощью CoDeSys@CHIP IEC Platform Builder (см. выше)
Включение трех COM-портов
У меня три COM-порта, активируем их изменив в myrts.c следующие строки:
RHISerPortTypes s_SerialPortTypes = /* See for a detailed description the RHI Documentation !!! */ { RHI_MAXCOMPORTS, /* NumComPorts */ { /* ComPortUse[RHI_MAXCOMPORTS] */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_COM, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ }, RHI_SERPORT_SPI, /* SPIPortUse: RHI_SERPORT_NAV or RHI_SERPORT_SPI */ RHI_SERPORT_I2C, /* I2CPortUse: RHI_SERPORT_NAV or RHI_SERPORT_I2C */ };
на:
RHISerPortTypes s_SerialPortTypes = /* See for a detailed description the RHI Documentation !!! */ { RHI_MAXCOMPORTS, /* NumComPorts */ { /* ComPortUse[RHI_MAXCOMPORTS] */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_COM, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_COM, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_COM, /* ComPortUse: RHI_SERPORT_NAV or RHI_SERPORT_COM */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ RHI_SERPORT_NAV, /* ComPortUse: RHI_SERPORT_NAV */ }, RHI_SERPORT_NAV, /* SPIPortUse: RHI_SERPORT_NAV or RHI_SERPORT_SPI ОБЯЗАТЕЛЬНО ОТКЛЮЧИТЬ если используются три COM порта иначе система будет выдавать ошибку при загрузке*/ RHI_SERPORT_I2C, /* I2CPortUse: RHI_SERPORT_NAV or RHI_SERPORT_I2C */ };
Описание здесь.
Драйвер I2C
Правим секцию
/* IO Access */
В отличии от платы BECK DB54 у меня устройства I2C имеют следующие адреса:
0x40 - младший байт выхода D0_out
0x48 - старший байт выхода D1_out
0x42 - младший байт входа D0_in
0x44 - старший байт входа D1_in
Меняем:
/*****************************************************************************/ /* IO Access */ /*****************************************************************************/ void RHIIOInit (void) { /* TO-DO: add here code to initialize your hardware */ } #pragma argsused int RHIIOReadAllInputs (unsigned char *pInputArea) { /* TO-DO: add here code to copy the hardware values into the IEC input area. Example: RHIInputArea *theInputArea = (RHIInputArea *)pInputArea; theInputArea->myByteInput = inportb(0xC00); theInputArea->myWordInput = inport(0xC02); */ return 1; } #pragma argsused int RHIIOReadInput (unsigned char *pInputArea, int iFieldOffset) { /* TO-DO: add here code to copy the hardware values into the IEC input area. Example: RHIInputArea *theInputArea = (RHIInputArea *)pInputArea; switch (iFieldOffset) { case IFID_myByteInput: theInputArea->myByteInput = inportb(0xc00); return 1; case IFID_myWordInput: theInputArea->myWordInput = inport(0xc02); return 1; default: return 1; } */ return 1; } #pragma argsused int RHIIOWriteAllOutputs (unsigned char *pOutputArea) { /* TO-DO: add here code to copy the IEC output area values to the hardware. Example: RHIOutputArea *theOutputArea = (RHIOutputArea *)pOutputArea; outportb(0xC00, theOutputArea->myByteOutput); outport (0xC02, theOutputArea->myWordOutput); */ return 1; } #pragma argsused int RHIIOWriteOutput (unsigned char *pOutputArea, int iFieldOffset) { /* TO-DO: add here code to copy the IEC output area values to the hardware. Example: RHIOutputArea *theOutputArea = (RHIOutputArea *)pOutputArea; switch (iFieldOffset) { case OFID_myByteOutput: outportb(0xC00, theOutputArea->myByteOutput); return 1; case OFID_myWordOutput: outport (0xC02, theOutputArea->myWordOutput); return 1; default: return 1; } */ return 1; }
На:
/*****************************************************************************/ /* IO Access */ /*****************************************************************************/ void RHIIOInit (void) { /* Example for DK55 Board, see also DK55 Dokumentation */ /* Init I2C-Port */ I2C_select_data_pin (0); /* Use HW_I2C Interface */ I2C_select_clock_pin (0); I2C_init (); I2C_transmit_char (0x40, 0xFF); /* Preset Out register 0-7 D0_out */ I2C_release (); I2C_transmit_char (0x48, 0xFF); /* Preset Out register 8-15 D1-out*/ I2C_release (); } #pragma argsused int RHIIOReadAllInputs (unsigned char *pInputArea) { unsigned char B; unsigned char C; /* Example for DK55 Board, see also DK55 Dokumentation */ RHIInputArea *theInputArea = (RHIInputArea *)pInputArea; I2C_receive_char (0x42, &((char)B), 0); /* Read one Byte */ I2C_release (); theInputArea->D0_in = ~(B); I2C_receive_char (0x44, &((char)C), 0); /* Read one Byte */ I2C_release (); theInputArea->D1_in = ~(C); return 1; } #pragma argsused int RHIIOReadInput (unsigned char *pInputArea, int iFieldOffset) { unsigned char B; unsigned char C; RHIInputArea *theInputArea = (RHIInputArea *)pInputArea; switch (iFieldOffset) { case IFID_D0_in: I2C_receive_char (0x42, &((char)B), 0); /* Read one Byte */ I2C_release (); theInputArea->D0_in = ~(B); return 1; case IFID_D1_in: I2C_receive_char (0x44, &((char)C), 0); /* Read one Byte */ I2C_release (); theInputArea->D1_in = ~(C); return 1; default: return 1; } } #pragma argsused int RHIIOWriteAllOutputs (unsigned char *pOutputArea) { RHIOutputArea *theOutputArea = (RHIOutputArea *)pOutputArea; I2C_transmit_char(0x40, ~(theOutputArea->D0_out)); /* Write one Byte */ I2C_transmit_char(0x48, ~(theOutputArea->D1_out)); /* Write one Byte */ I2C_release (); return 1; } #pragma argsused int RHIIOWriteOutput (unsigned char *pOutputArea, int iFieldOffset) { RHIOutputArea *theOutputArea = (RHIOutputArea *)pOutputArea; switch (iFieldOffset) { case OFID_D0_out: I2C_transmit_char(0x40, ~(theOutputArea->D0_out)); /* Write one Byte */ return 1; case OFID_D1_out: I2C_transmit_char(0x48, ~(theOutputArea->D1_out)); /* Write one Byte */ return 1; default: return 1; } }
Все по аналогии из примера.
Компиляция
Теперь откомпилируем, открыв файл myRts.pdl (находится в той же папке что и myrts.c) в Paradigm C++ Beck IPC Edition.
Если не было ошибок то в папке rts (в которой лежит файл myrts.c) появляется папка bin, а в ней файл myrts.exe. Этот файл надо скопировать в контроллер (в корень диска a или куда нибудь еще, главное что бы потом указать правильный путь AUTOEXEC.BAT)и запускать при старте через a:\AUTOEXEC.BAT (диск a находится в контроллере, о записи в контроллер читать тут).
Таким образом в a:\AUTOEXEC.BAT последней строчкой должно быть:
myrts.exe
Создание платформы в CoDeSys
Для того что бы CoDeSys видел нашу платформу требуется выполнить:
tsp\install.bst /f
ключ f заменит платформу если она уже существует.
Папка tsp лежит там же где и папка rts.
Использование
Открываем CoDeSys V2.3 (C:\Program Files\3S Software\CoDeSys V2.3\Codesys.exe) создаем новый проект и выбираем созданную ранее платформу.
И создаем следующую программу:
http://rrv.nsk.ru/wiki/images/i2c-test-program-codesys.jpg
Здесь %IB0 и %IB1 это входные байты соответствуют D0_in D1_in, а %QB0, %QB1 соответствуют D0_out и D1_out. Так же можно обратится к конкретному биту например нулевой бит IB0 соответствует переменная IX0.0. В общем смотрим "Конфигурация ПЛК".
Эта простая программа считывает все входы и выводит эти значения на выход один раз в секунду.