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. В общем смотрим "Конфигурация ПЛК".
Эта простая программа считывает все входы и выводит эти значения на выход один раз в секунду.