Db54 COM порты
Спасибо Михаилу Швецову!
В общем много было попыток настроить работу эволюционной платы DB54 фирмы BECK (дальше просто плата) с устройствами подключенными к COM портам платы по следующему описанию. Иногда что то получалось иногда нет. Рекомендовалось обновить прошивку контроллера. Эти эксперименты проводятся после обновления RTOS до версии SC23/SC24 V1.30 FULL.
Итак вчитываемся в форум, скачиваем систему исполнения рекомендуемую на форуме файл и пытаемся повторить опыт.
М... да... облом, автор выложил только часть, полного пакета, а именно RTS. Тарджет используется стандартный из ChipSDK версии DK55_FP_CM. По умолчанию он устанавливается сюда: C:\Program Files\Beck IPC GmbH\CoDeSys@CHIP SDK\samples\Full\DK55\SC23\DK55_FP_CM
На всякий случай вкратце расскажу структуру (коряво и без терминов, возможно позже опишу в нормальной статье):
- в папке RTS хранятся исходные коды, а так же собранные exe файлы выполняемые под RTOS в контроллере (исходники написаны на C++ и кое что можно править, об этом потом)
- в папке tsp (ничего нельзя править) в этой папке описание нашей платформы для CoDeSys, что бы инсталлировать новую платформу в CODeSys необходимо выполнить скрипт tsp\install.bst
Обе папки создаются с помощью генератора платформы IEC Platform Builder где описываем особенности платформы (нам пока это не надо, пригодится, когда создадим собственную плату на микроконтроллере BECK например SC23)
И так, копируем папку C:\Program Files\Beck IPC GmbH\CoDeSys@CHIP SDK\samples\Full\DK55\SC23\DK55_FP_CM куда нибудь, например в G:\rrv-test\COM-порты\ и переходим в эту папку. Теперь переименуем rts в rts.orig и копируем на ее место RTS_DK55 папку из скаченного архива переименовав ее в rts. Внимание! тут описано более корректно и делать как описано тут.
Теперь запустим tsp\install.bst /f как говорилось выше (ключ f заменит платформу если она уже существует).
Теперь любимым ftp клиентом копируем rts\bin\myrts.exe на диск a: нашего микроконтроллера ip, логин и пароль можно задать и посмотреть здесь. И a:\AUTOEXEC.BAT приводим к виду:
myrts.exe
Теперь перезапускаем плату, новый myrts.exe запустится на контроллере автоматически.
Читаем форум и смотрим отличия главного си-шного файла платформы myrts.c (находится в папке RTS) в оригинальном примере со скаченым с форума (с верху кусок оригинального файла, с низу кусок примера с форума):
http://rrv.nsk.ru/wiki/images/myrts.c_com.jpg
как видим, что строки структуры s_SerialPortTypes:
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_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 */ }
Отвечают за восемь COM портов начиная с нулевого, для того чтобы включить порт необходимо поменять в соответствующей строке название с RHI_SERPORT_NAV на RHI_SERPORT_COM, для отключения наоборот.
Причем как видно, на примере с форума автор отключил SPI и I2C (аналогично):
RHI_SERPORT_NAV, /* SPIPortUse: RHI_SERPORT_NAV or RHI_SERPORT_SPI */ RHI_SERPORT_NAV, /* I2CPortUse: RHI_SERPORT_NAV or RHI_SERPORT_I2C */
Для создания изначально правильно платформы, выполним следующее:
- Скопируем из папки C:\Program Files\Beck IPC GmbH\CoDeSys@CHIP SDK\samples\Full\DK55\SC23 файл DK55_FP_CM.xml в папку G:\rrv-test\COM-порты
- Откроем этот файл в IEC Platform Builder
- На вкладке Device снимем галочку RS232, она отвечает за связь CoDeSys c платой по первому COM-порту, но так как нам понадобятся оба COM-порта, то оставим подключение к плате только через TCP порт 1200.
- Теперь сохраним проект, кнопка Save
- Затем создадим проект нажав кнопку Make, если возникнут ошибки с нахождением библиотек, то укажите их правильный путь на вкладке Library (в моем случае не нашлась библиотека LCD_Demo.lib посмотрев исходный проект я указал C:\Program Files\Beck IPC GmbH\CoDeSys@CHIP SDK\samples\Full\DK55\LCD_Demo.lib, хотя можно было и скопировать ее в G:\rrv-test\COM-порты). Аналогично поступим с ошибкой не нахождения картинки DK55.bmp, на вкладке General изменяем путь до картинки в поле Device Bitmap). Нажимаем кнопку Make после исправления каждой ошибки до тех пор пока не устраним все ошибки и не создадим проект.
- Открываем проект G:\rrv-test\COM-порты\DK55_FP_CM\rts\myRts.pdl в Paradigm C++ Beck IPC Edition и правим myrts.c это файл G:\rrv-test\COM-порты\DK55_FP_CM\rts\myrts.c и меняем строку RHI_SERPORT_NAV, на RHI_SERPORT_COM, как это объяснено выше, строки RHI_SERPORT_SPI, и RHI_SERPORT_I2C, оставляем как есть, пригодится.
- Собираем проект C++ выбрав в меню Project -> Build All если ошибок нет и файл myrts.exe создан, то остается воспользоваться любимым FTP-клиентом и залить этот файл в контроллер читаем как. И если мы еще не правили a:\AUTOEXEC.BAT то добавляем в него строчку myrts.exe. Перезапускаем плату. Все теперь можно запускать CoDeSys, все готово.
Можно запускать CoDeSys и создавать пример из форума (Я уже выложил туда свою рабочую версию).
Программа:
http://rrv.nsk.ru/wiki/images/rs-232_COM2_pic1.jpg
И в процессе исполнения:
http://rrv.nsk.ru/wiki/images/rs-232_COM2_pic2.jpg
http://rrv.nsk.ru/wiki/images/rs-232_COM2_pic3.jpg
Приведу код программы PLC_PRG с пояснениями, дабы не набивать в последствии.
PLC_PRG:
PROGRAM PLC_PRG VAR dwHandle:DWORD:=INVALID_HANDLE; (*В эту переменную помещаем результат функции открытия порта в которой указывается адрес привязки для конкретной реализации, если результат 16#FFFFFFFF значит произошла ошибка, в этой демонстрационной программе этот вариант не проверяется, в рабочей программе проверять обязательно! *) Settings:COMSETTINGSEX; (* Структура в которой хранятся параметры открываемого порта. Подробности смотри на вкладке Ресурсы, в пункте Менеджер библиотек, выбрав библиотеку, в нашем случае SysLibCom*) bSt:BOOL; (* Переменная в которую мы будем записывать результат функций: задания параметров порта и закрытия порта. Затем будем использовать эту переменную в качестве перехода к следующему блоку в случае удачного исполнения функций SysComSetSettingsEx и SysComClose *) byBuffer:ARRAY[0..20] OF BYTE:=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0; (* Массив в который будем сохранять принятые байты данных в моем случае мне требуется всего 9 байт, но я взял с запасом, т.к. логика работы внешнего устройства такова, что одновременно могут быть посланы одновременно 2 набора данных то есть 18 байт, но мне нравится число 21 :) иначе бы массив был бы byBuffer:ARRAY[0..17] OF BYTE:=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0; в целом, в место массива можно использовать строку: byBuffer:STRING:="000000000000000000000";*) dwRxBytes:DWORD; (* Важная переменная, в нее мы будем записывать количество принятых байт, учтите, что если массив byBuffe переполнится, то он циклически перезапишется с начала тем самым часть данных будет затерта, в реальном проекте добавьте проверку, что бы размер byBuffer всегда был больше, чем число принятых байт (wRxByte) *) END_VAR
Init:
(* Здесь указанны следующие параметры RS-232: Порт:COM2, Скорость:9600бит/с, Кол-во бит данных в посылке:8, без паритета, 1 стоп-бит. Где взять описание см. выше структура Settings *) Settings.Port:= COM3; (*Обратите внимание! для этих плат, для того что бы указать порт COM1 используем запись COM2 для COM2 указываем COM3, имеется подобное смещение, оно описано на форуме (ссылку см. выше) *) Settings.dwBaudRate:= 9600; Settings.cByteSize:= 8; Settings.byParity:= 0; Settings.byStopBits:= 0; Settings.Size:= SIZEOF(Settings);
OpenPort:
dwHandle:= SysComOpen(Settings.Port); (*Открываем порт*) bSt:=SysComSetSettingsEx(dwHandle, ADR(Settings)); (*Задаем параметры*)
Read:
dwTxBytes:= SysComRead(dwHandle, ADR(byBuffer), 21, 0); (*Читаем из порта, адрес передается через dwHandle, куда записывать, через функцию ADR вычисляющую адрес массива в который будем принимать, сколько максимально байт считывать (размер буфера, что бы не переполнить, при переполнении начинает циклическую запись с начала, то есть в нашем случае 22 байт запишется в нулевую ячейку массива byBuffer) 0 последним означает задержку таймаута, возможно Вам потребуется другое например 250 (что означает, таймаут 250 миллисекунд)*)
Затем идет ветвление. Если что то было считанно, то закрываем порт. В рабочей программе возможно мы захотим как то обработать принятые данные :) И вообще не будем закрывать порт, а начнем читать дальше, в общем это на ваш вкус. Если же мы ничего не считали, то выдерживаем паузу (если требуется) и снова читаем. У меня реально считывание требуется раз в 1 сек, так что я выбрал задержку 0.1 сек, у вас возможно она будет другой. Внимание! Если вы у блока ставите минимальное время исполнения, то если блок выполнился раньше, этого временного интервала, то выполнение начинается сначала (требуется проверка этого постулата). Будте осторожней, например если в таком блоке будет например функция открытия порта, то программа будет остановлена системой Watchdog.
ClosePort:
bSt:=SysComClose(dwHandle);