Было дело. Управлял инверторами для электродвигателей.
Программа для Win32. Писал на WF32
Вот собственно код. Выбрал наиболее важные участки.
Для работы мне нужно было только 2 функции. С остальными думаю разберётесь.
Код:
-- ----------------------------------------------------------------------------
: +Field: Over Field + ; \ base n --> base+n
: ?FalseExit 0= If RDrop Then ;
-- ----------------------------------------------------------------------------
\ Преобразование строки C-ADDR U в число в текущей стстеме счисления.
\ Аналогично VAL в SMAL32 только для S" строки.
\ удачно - D. true
\ неудача - c-addr u false.
\ : SVal \ c-addr u --> c-addr u 0 | D. true
\ ;
-- ----------------------------------------------------------------------------
\ Структура пакетов передачи-приема ModBus в ASCII режиме.
0
1 +Field: +MBA.StartByte \ +00 стартовый байт ":"
2 +Field: +MBA.id \ +01 Адрес подчиненного устройства.
2 +Field: +MBA.fn \ +03 Функция запроса (ответа).
0 +Field: +MBA.addr \ +05 Адрес регистра (при записи).
2 +Field: +MBA.cnr \ +05 Количество байт регистров в ответе.
2 +Field: +MBA.rdata \ +07 Начало данных в ответе.
0 +Field: +MBA.cnt \ +09 Количество регистров чтения или
4 +Field: +MBA.srg \ +09 значение одного регистра при записи.
0 +Field: +MBA.data \ +13 Начало данных.
Constant /MBA.BEG \ 13 Длина начальной обязательной части.
\ ......... Сдесь могуть идти данные переменной длины.
\ окончание пакета.
4 Dup Constant /MBA.END \ 4 байта в конце.
Negate \ -4
2 +Field: -MBA.LRC \ -4 Контрольная сумма.
2 +Field: -MBA.CRLF \ -2 Символы окончания строки.
Drop
/MBA.END /MBA.BEG + Constant /MBA \ Минимальная длина пакета (13+4=17байт).
-- ----------------------------------------------------------------------------
$3130 Constant FN_OUT_READ \ Команда чтения статуса выходов. "01"
$3230 Constant FN_IN_READ \ Команда чтения статуса входов. "02"
$3330 Constant FN_HRG_READ \ Команда чтения регистров. "03"
$3430 Constant FN_IRG_READ \ Команда чтения регистров. "04"
$3530 Constant FN_FSC \ Установка еденичного выхода. "05"
$3630 Constant FN_WR_RG \ Запись еденичного регистра. "06"
-- ----------------------------------------------------------------------------
/MBA User-Array BufTx \ Буфер для передачи (минимальный).
/MBA User-Array BufRx \ Буфер для приема (минимальный).
User ResultRead \ Результат операции чтения.
User BytesRead \ Указатель принятых байт.
User FlagACK \ Флаг завершения операции.
-- ----------------------------------------------------------------------------
: PatStrModBus \ --> c-addr u \ Шаблон для формирования пакета .
S" :00000000000000\r\n"
;
-- ----------------------------------------------------------------------------
: CalcLRC \ c-addr u --> c
\ c-addr u - адрес длина буфера приема-передачи.
\ Подсчет КС блока.
1 0 -MBA.LRC 1- D+ \ c-addr+1 u-5 Пропустить служебные.
0 >R \ c-addr u Начальная КС=0
Begin
Dup \ c-addr u u Все?
While
Over C@ RP@ +! \ c-addr u Нарастить LRC.
1 -1 D+ \ c-addr+1 u-1 След. символ.
Repeat
2Drop 0 R> - $FF And \ Дополнение до 0.
;
-- ----------------------------------------------------------------------------
\ Преобразовывает число в строку с записью в память по адресу ADDR.
\ U - беззнаковое число.
\ n - количество символов.
: U>ASCII \ u addr n -->
Base @ >R Hex \ addr c-addr
>R Swap 0 R@ ZStr 1+ \ addr c-addr
Swap R> CMove \
R> Base ! \
;
-- ----------------------------------------------------------------------------
: CheckRxBuf \ c-addr u --> c-addr u
\ Процедура проверки буфера приема. Вызывается при приеме символа LF (10).
\ В Win32 эта процедура основная. Сом-порт настроен на вызов события при приеме
\ этого символа.
2Dup Type \ для отладки.
Over C@ [Char] : = ?FalseExit \ c-addr u Первый символ ":"?
2Dup + -MBA.CRLF C@ 13 = ?FalseExit \ c-addr u Предпоследний CR?
2Dup CalcLRC \ c-addr u b Подсчет LRC
Base @ >R Hex \ c-addr u Начало данных.
0 2 ZStr 1+ W@ \ c-addr u N
R> Base ! >R \ c-addr u w ASCII код.
2Dup + -MBA.LRC W@ R> = ?FalseExit \ c-addr u Совпадает?.
Over +MBA.fn W@ FN_HRG_READ = \ c-addr u f Чтение?
If
\ Ответ на чтение регмстра.
Base @ >R Hex \ c-addr u Начало данных.
Over +MBA.rdata 4 \ c-addr u c-addr' 4
SVal 2Drop ResultRead ! \ c-addr u В число.
R> Base ! \ c-addr u
Then
True FlagACK !
;
-- ----------------------------------------------------------------------------
: ReadCharFromCom \ char -->
\ Процедура записи в буфер приема. Должна вызываться при приеме каждого символа
\ из последовательного порта.
Dup [Char] : = \ c f Начало пакета?
If
0 BytesRead ! \ c Обнулить указатель приема.
Then
BytesRead @ /MBA = \ c f Буфер под завязку?
If
BufRx 1+ BufRx /MBA 1- CMove \ c Сместить данные на 1 байт.
Dup BufRx /MBA + 1- C! \ c Записать символ в конец.
Else
Dup BufRx BytesRead @ + C! \ c Записать символ по указателю.
BytesRead 1+! \ c Нарастить указатель приема.
Then
10 = \ f Конец пакета?
If
BufRx BytesRead @
CheckRxBuf 2Drop
Then
;
-- ----------------------------------------------------------------------------
: SendAndWait \ c-addr u --> f
\ Процедура передачи и приема информации черех последовательный интерфейс.
\ Сильно зависит от аппаратных средств и операционной системы.
\ Вход:
\ c-addr - адрес передачи.
\ u - размер буфера.
\ Выход:
\ f - флаг успешности.
\ Передать_данные --> Принять_данные --> Проверить_правильность_принятого_пакета --> f
False FlagACK ! \ Обнулить флаг завершения операции.
2Dup CR Type \ для отладки - вывести на печать.
0 Do Count ReadCharFromCom Loop Drop \ для отладки - вызвать процедуру чтения.
FlagACK @ \
;
-- ----------------------------------------------------------------------------
: ReadRG \ Addr Id --> U True | False
\ Чтение регистра в протоколе MODBUS.
\ Addr - адрес регистра.
\ Id - номер устройства.
\ U - прочитаное значение.
PatStrModBus BufTx Swap CMove \ Переписать шаблон.
FN_HRG_READ BufTx +MBA.fn W! \ Addr Id Функция.
BufTx +MBA.id 2 U>ASCII \ Addr Номер устройства.
BufTx +MBA.addr 4 U>ASCII \ Адрес регистра.
1 BufTx +MBA.cnt 4 U>ASCII \ Количество регистров.
BufTx /MBA CalcLRC \ u Подсчет LRC
BufTx /MBA + -MBA.LRC 2 U>ASCII \ Сохранить в буфере.
BufTx /MBA SendAndWait \ f Передать-Принять_ответ.
If
ResultRead @ True
Else
False
Then
;
-- ----------------------------------------------------------------------------
: WriteRG \ Val Addr Id --> F
\ Запись в регистр в протоколе MODBUS.
\ Addr - адрес регистра.
\ Id - номер устройства.
\ Val - значение регистра.
PatStrModBus BufTx Swap CMove \ Val Addr Id Переписать шаблон.
FN_WR_RG BufTx +MBA.fn W! \ Val Addr Id Функция.
BufTx +MBA.id 2 U>ASCII \ Val Addr Номер устройства.
BufTx +MBA.addr 4 U>ASCII \ Val Адрес регистра.
BufTx +MBA.srg 4 U>ASCII \ Значение регистра.
BufTx /MBA CalcLRC \ u Подсчет LRC
BufTx /MBA + -MBA.LRC 2 U>ASCII \ Сохранить в буфере.
BufTx /MBA SendAndWait \ f Передать-Принять_ответ.
;
-- ----------------------------------------------------------------------------
: Test $3210 $7654 $98 WriteRG CR .h
$7654 $98 ReadRG If CR .h Then
; test