PDA

Просмотр полной версии : ПР-200 + драйвер шагового двигателя



Владимир Технос М
28.05.2021, 11:05
Добрый день!

Подскажите пожалуйста разрабатываем систему на основе ПР-200 сможет ли данный прибор управлять драйвером
https://electroprivod.ru/smsd-4.2rs.htm

протокол RS-485 не стакдартный, не MOДБАС , похоже ASKII

посмотрите пожалуйста структуру посылки, по зубам ли это ПР-200?

glazastik
28.05.2021, 11:23
Нет, на ПР-200 вы не сформируете отправку таких команд


Для ПР подойдёт драйвер Onitex OSM-42RA

ну или вообще-то надо понимать какая задача ставится, может вы и дискретными выходами обойдётесь, запишите программу в SMSD и будете её вызывать замыкая Пуск, и возвращать в начало командой Поиск 0.

petera
28.05.2021, 11:44
Когда-то на СП300 хотел сделать программатор контроллера ШД https://owen.ru/forum/showthread.php?t=26553&p=244671&viewfull=1#post244671
Некий гибрид гипертерминала и OSM Programmer.
55305

https://www.youtube.com/watch?v=Hw6rPL-osog

glazastik
28.05.2021, 13:04
Не ну в случае если СП300 общается с драйвером через modbus это я ещё понимаю.
Но если надо сформировать ASCII команду и отправить её? СП разве на такое способна? Через макросы только если?

petera
28.05.2021, 14:29
Не ну в случае если СП300 общается с драйвером через modbus это я ещё понимаю.
Но если надо сформировать ASCII команду и отправить её? СП разве на такое способна? Через макросы только если?

Ну да, на Си есть прямой доступ к порту, можно любой протокол написать.
Пример - гипертерминал в СП https://owen.ru/forum/showthread.php?t=26719&p=246881&viewfull=1#post246881

/*
Макрос "ТЕРМИНАЛ"

(с) petera для форума ОВЕН

*/

// Used PSW Adr ---------------------
#define SetupAdr 259
#define KbdStatusAdr 260
#define inAdr 300 // (DWord) !!!
#define bufAdr 500 // buffer uses (lTotal x cTotal) Regs.!!!
//-----------------------------------------------------------------------------------
#define KbdStatus PSW[KbdStatusAdr] /* В битах этого регистра - состояние управляющих кнопок клавиатуры (Shift, Ctrl, Repead),
индикаторов "Прием", "Передача" и бит разрешения работы макроса */
#define Setup PSW[SetupAdr] // Настройки режимов приема и передачи
#define Input PSW[inAdr] // Буфер для приема символов с клавиатуры
#define dwInput *(DWORD*)(PSW + inAdr) // -- // -- в формате DWord
#define buffer PSW[bufAdr] /*Начальный адрес области регистров PSW из которых сделано текстовое окно терминала
для окна терминала будет занято (lTotal x cTotal) регистров PSW */

//---Макро для чтения бит регистра Setup---------------------------------------------------------
#define GetSetupStatus(bitno) ((Setup) & (1 << (bitno)))
//---------------------------- назначение бит регистра Setup
#define CRLFreceive 0 //При вводе с клавиатуры дополнять символ CR символом LF(перевод строки)
#define CRLFsend 1 //Дополнять символ CR, полученный от удаленного терминала, символом LF(перевод строки)
#define BS_BSsend 3 //Передавать символ "backspace"(BS) как комбинацию из "BS"+"пробел"+"BS"
#define Echo 4 /*Включить режим "Эхо". В режиме "Эхо" все денные,принятые от удаленного терминала
тут же отправляются обратно, после чего обрабатываются и выводятся на экран */
#define Visible 5 /*"Показывать введенные символы". Символы, вводимые с клавиатуры, отправляются удаленному
терминалу и также отображаются в окне. Если Visible=FALSE, то символы, вводимые с клавиатуры,
отправляются удаленному терминалу, но на экран не выводятся.*/
//---Макро для инверсии бит -------------------------------------------------------------------
#define ReversPSB(PSB_No) PSB[(PSB_No) / 8] ^= (1 << ((PSB_No) % 8)) /* В дополнение к существующим SetPSB(PSB_No) и ResetPSB(PSB_No)
этот макро выполняет инверсию заданного PSB
Пример:
ReversPSB(256); *

#define ReversBit(reg, bitno) ((reg) ^= (1 << (bitno))) //
//---Макро для работы с битами регистра KbdStatus-----------------------------------------------
#define GetKbdStatus(bitno) ((KbdStatus) & (1 << (bitno)))
#define ResetKbdStatus(bitno) ((KbdStatus) &= ( ~ (1 << ((bitno)))))
#define SetKbdStatus(bitno) ((KbdStatus) |= ( 1 << ((bitno))))
//---------------------------- назначение бит регистра KbdStatus
#define Shift 0 // Нажата кнопка Shift
#define Ctrl 1 // Нажата кнопка Ctrl
#define Repead 2 // Нажата кнопка Rep - повторение символов при вводе
#define RunEnable 3 // Работа приема и передачи разешена
#define receiver 4 // Состояние индикатора "Прием"
#define sender 5 // Состояние индикатора "Передача"
#define ClrScreen 6 // Команда "Очистить экран"

//------------------------------------------------------------------
const int lTotal = 18; // Количество строк в окне терминала
const int cTotal = 80; // Количество символов в одной строке
const int tabs = 8; // Кратность (в символах) позиций табуляции

static int cCount, lCount; // Номер текущей позиции в строке и Номер текущей строки
static char savMark; /* Сохраненный код символа, который скрыт курсором
т.к. курсор может перемещаться на экране не только вперед, но и вверх,
вниз и назад, то перед перемещением курсора в другую позицию необходимо
сохранять код символа в том знакоместе, в котором окажется курсор после перемещения.
И при последующем перемещании курсора возвращать сохраненный символ в знакоместо
ранее занимаемое курсором */
/* Курсор - мигающий символ '_', указывает знакоместо в окне терминала,
в которое будет вводится очередной символ. Координаты курсора однозначно
определяются переменными cCount и lCount */
static BOOL init; // Флаг инициализации(устанавливается после первого вызова макроса)

BYTE byReceive[3] = {0x00}; /* Буфер приема для СОМ порта
буфер приема имеет и второе назначение. Т.к. все, что пришло в буфер приема
от удаленного терминала безусловно должно быть выведено на экран.
Чтобы использовать этот же фрагмент кода вывода на экран и для вывода символов,
вводимых с клавиатуры, буфер приема будет использован и при вводе данных с клавиатуры */
BYTE bySend[3] = {0x00}; // Буфер передачи для СОМ порта
BYTE *pBuff; // Указатель адреса символа в памяти регистров, отображаемых в окне терминала
int i, count, tmp;
BOOL flagSend, flagVisible; // флаги - требуется вывод в СОМ порт, требуется вывод на экран

//--------------------------------------------------------------------
//pBuff = (BYTE *)&buffer + lCount * cTotal + cCount; //Установить указатель в текущую позицию курсора
//--------------------------------

//if ((lCount == 0) && (cCount == 0) && (savMark == 0)) { //Clr Screen.
if (GetKbdStatus(ClrScreen) || !init) { //Clr Screen
ResetKbdStatus(ClrScreen); //Сбросить бит команды
init = TRUE;
memset(&buffer, ' ', cTotal * lTotal); //Во все байты всех регистров отображаемых в окне терминала
savMark = ' '; //будут записаны коды пробела - произойдет "очистка" окна терминала
lCount = cCount = 0; //курсор в правый верхний угол окна терминала
pBuff = (BYTE *)&buffer; //Установить указатель на начало буфера окна

}
else pBuff = (BYTE *)&buffer + lCount * cTotal + cCount; //Установить указатель в текущую позицию курсора

//-------------------------------
if (!GetKbdStatus(RunEnable)) { //Если работа макроса запрещена, то
ResetKbdStatus(Repead); //"отжать" кнопку "rep"
ResetKbdStatus(sender); //Выключить индикатор "Передача"
ResetKbdStatus(receiver); //Выключить индикатор "Прием"
dwInput = 0; //Очистить буфер клавиатуры
*pBuff = savMark; //Восстановить символ, скрытый курсором
return; //Завершить работу макроса
}
//-----------------------------
flagSend = GetSetupStatus(Echo); //Получить состояние настроек "Эхо" и "Показывать введенные символы"
flagVisible = GetSetupStatus(Visible);

Enter(PLC); //Открыть порт PLC
count = Receive(PLC, byReceive, 3, 100, 12);/*Читать 3 байта, TimeOut=100мс, TimeOutBytes=12мс(что это за зверь я не знаю)
значения тайм-аутов подбирал методом "научного тыка" на скорости 57600.
возможно, что при уменьшении скорости до 9600 TimeOut немного увеличить.
Макрос с TimeOut=100 будет работать и на скорости 115200,если в гипертерминале Windows
не зажимать клавиши до автоповтора, т.к. в редких случаях единичные символы
при приеме могут "проглатываться". Передедача из панели на 115200 без нареканий.*/
if (count == NULL) { //Если ничего не пришло, то проверить наличие символов в буфере клавиатуры
if (dwInput == 0) { //Если и в буфере клавиатуры пусто
flagSend = flagVisible = FALSE; //то ничего не отправлять и ничего не выводить на экран
count = 0;
}
else { //А если кто-то нажимал кнопки клавиатуры, то
SetKbdStatus(sender); //Включить индикатор "Передача"
ResetKbdStatus(receiver); //Выключить индикатор "Прием""
memcpy(&byReceive, &Input, 3); /*Копировать три байта из буфера клавиатуры в буфер передачи
последующие манипуляции будем проводить с содержимым буфера передачи
его же в дальнейшем будем отправлять через СОМ порт и выводить на экран */
//Проверить состояние управляющих кнопок
if (GetKbdStatus(Shift)) { //Если нажата кнопка Shift
if (((byReceive[0] >= 0x41) && (byReceive[0] <= 0x5A)) || //и введен код заглавной латинской буквы
((byReceive[0] >= 0x61) && (byReceive[0] <= 0x7A)) || // или строчной латинской буквы
(byReceive[0] >= 0xC0)) ReversBit(byReceive[0], 5); // или любой русской буквы, то поменять заглавную на строчную или наоборот
else if ((byReceive[0] == 0xA8) || // если введен код Ё или ё
(byReceive[0] == 0xB8)) ReversBit(byReceive[0], 4); // то и их поменять местами
}
if (GetKbdStatus(Ctrl)) { //Если нажата кнопка Ctrl, то заменить ЛАТИНСКИЕ БУКВЫ на управляющие коды
if (((byReceive[0] >= 0x41) && (byReceive[0] <= 0x5A)) ||
((byReceive[0] >= 0x61) && (byReceive[0] <= 0x7A))) byReceive[0] = byReceive[0] & 0x1F;
else byReceive[0] = 0; // Если это были не буквы, то ничего не отправлять и не выводить
}
//Возможно нужно изменить способ передачи символов CR(ctrl+M /Enter) или backspace - (ctrl+H /Delete)
if (GetSetupStatus(CRLFsend) && (byReceive[0] == 0x0D)) byReceive[1] = 0x0A; //Если нужно, то к CR добавить LF
else if (GetSetupStatus(BS_BSsend) && (byReceive[0] == 0x08)) { //Если нужно, то к BS
byReceive[1] = 0x20; //добавить ' '
byReceive[2] = 0x08; //и ещё один BS
}
count = strlen(byReceive); //Возможно длина посылки теперь будет другой
memcpy(&bySend, &byReceive, count); //Копировать то, что на вводили с клавиатуры в буфер передачи
flagSend = TRUE; //Разрешить передачу удаленному терминалу
if (! GetKbdStatus(Repead)) { //Если кнопка повтора не нажата, то
dwInput = 0; //очистить буфер клавиатуры
ResetKbdStatus(Ctrl); //"отжать" кнопку Ctrl
ResetKbdStatus(Shift); //"отжать" кнопку Shift
} /*А если кнопка повтора нажата, то код введенного символа и модификаторы Ctrl и Shift
запомнятся и будут заново отправлены в следующем цикле выполнения макроса */
}
}
//Сюда попали, минуя обработку буфера клавиатуры, если буфер чтения СОМ порта не пустой
else {
ResetKbdStatus(sender); //Выключить индикатор "Передача"
SetKbdStatus(receiver); //Включить индикатор "прием"
flagVisible = TRUE; //Выводить на экран содержимое буфера приема
memcpy(&bySend, &byReceive, count); //Копировать в буфер передачи из буфера приема все принятые символы
//в неизменном виде на случай необходимости Эха удаленному терминалу
if (GetSetupStatus(CRLFreceive) && (byReceive[0] == 0x0D)) {//Если нужно, то в буфере приема к полученным CR добавить LF
byReceive[Min(2, count)] = 0x0A;
count = Min(3, count+1);
}
}
//------------------------------------
// В эту точку можем попасть или после приема данных от удаленного терминала или после ввода символов с клавиатуры
// и всегда если буфер приема из СОМ порта был пуст и буфер клавиатуры тоже пуст
if ((count != NULL) && flagSend) { //отправка данных удаленному терминалу необходима если есть, что отправлять и
//если, например включен флаг Эхо
Send(PLC, bySend, count); //отправка даанных удаленному терминалу
}
Leave(PLC); //Закрыть СОМ порт
//------------------------------------
//Эта часть программы - вывод информации на экран
if ((count == 3) && (byReceive[0] == 0x1B) && flagVisible) { //Если в буфере приема три символа и код первого символа 0x1B
// то в буфере Escape последовательность
*pBuff = savMark; //восстановить в текущем знакоместе символ скрытый курсором
tmp = MAKEWORD(byReceive[2], byReceive[1]); //Собрать два оставшихся в буфере символа "в кучку"
switch (tmp) {
case 0x5B41: //Up //Это кнопка стрелка вверх
if (lCount != 0) { //Пока не достигнем верха окна терминала
lCount--; //переместим курсор в ту же позицию вышележащей строки
pBuff = pBuff - cTotal; //пересчитать адрес нового положения курсора
}
break;
case 0x5B42: //Down //Это кнопка стрелка вниз
if (lCount != lTotal -1) { //Пока не достигнем низа окна терминала
lCount++; //переместим курсор в ту же позицию нижележащей строки
pBuff = pBuff + cTotal; //пересчитать адрес нового положения курсора
}
break;
case 0x5B44: //Left //Это кнопка стрелка влево
if (cCount != 0) { //Пока не достигнем левого края окна терминала
cCount--; //переместим курсор на одну позицию влево в той же строке
pBuff --; //пересчитать адрес нового положения курсора
}
break;
case 0x5B43: //Right //Это кнопка стрелка вправо
if (cCount != cTotal - 1) { //Пока не достигнем правого края окна терминала
cCount++; //переместим курсор на одну позицию вправо в той же строке
pBuff++; //пересчитать адрес нового положения курсора
}
break;
case 0x5B48: //Home //Это кнопка Домой, т.е.
lCount = 0; //переместить курсор в левый верхний угол окна терминала
cCount = 0;
pBuff = (BYTE *)&buffer; //пересчитать адрес нового положения курсора (указатель на начало буфера)
break;
case 0x5B4B: //End //Кнопка End
*pBuff = ' '; //В позиции курсора записать пробел
memset(pBuff, ' ', cTotal - cCount); //Удалить все символы от текущего положения курсора до донца строки
break;
}
savMark = *pBuff; //Сохранить символ в знакоместе экрана, на которое теперь будет указывать курсор
}
else if ((count != NULL) && flagVisible) { //А если в буфере не оказалось Escape последовательность, а он не пустой
for (i=0; i<count; i++) { //то будем выводить по очереди все символы, которые обнаружим в буфере
*pBuff = savMark; //восстановить в текущем знакоместе символ скрытый курсором
switch (byReceive[i]) { //кроме печатных символов в буфере могут находится управляющие символы
//некоторые из управляющих символов используются для управления выводом
case 0x07: //Bell - (ctrl+G). Удаленный терминал может прислать звуковой сигнал
Beep(); //и если звук в панели не запрещен (PFW[2] == 0), то услышим короткий Бип
break;
case 0x8: //backspace - (ctrl+H /Delete)
if (cCount != 0) { //если курсор не в начале строки
cCount--; //то прееместить его на одно знакоместо влево
pBuff--; //пересчитать адрес нового положения курсора
}
break;
case 0x9: //Tab - (ctrl+I) Табуляция - перемещение курсора вправо до ближайшей позиции кратной "tabs"
if (cCount < (cTotal - tabs)) { //Если до конца строки осталось болше чем значение "tabs"
tmp = tabs - cCount % tabs; //то подсчитать сколько символов от текущего положения курсора до до ближайшей позиции кратной "tabs"
cCount = cCount + tmp; //переместить курсор в новую позицию
pBuff = pBuff + tmp; //пересчитать адрес нового положения курсора
}
else { //если до конца строки символов осталось меньше чем значение "tabs"
tmp = cTotal -1 - cCount; //то подсчитать сколько их осталось
cCount = cTotal-1; //и новое положение курсора, в этом случае, однозначно д.б. в конце строки
pBuff = pBuff + tmp; //пересчитать адрес нового положения курсора
}
break;
case 0xA: //LF - line feed (ctrl+J). Перевод строки
lCount++; //переместим курсор в ту же позицию нижележащей строки
pBuff = pBuff + cTotal; //пересчитать адрес нового положения курсора
break;
case 0xD: //CR - carriage return (ctrl+M /Enter). Возврат каретки
cCount = 0; //переместим курсор в начало текущей строки
pBuff = (BYTE *)&buffer + lCount * cTotal;//пересчитать адрес нового положения курсора
break;
//следующие три управляющих кода пока не используются
case 0x03: //ETX - end of text (ctrl+C)
case 0x04: //EOT - end of transmission (ctrl+D)
case 0x1A: //ctrl+Z (SUB -substitute)
//А теперь выводим печатные символы
default:
*pBuff = byReceive[i]; //очередной символ из буфера приема поместить по адресу курсора
pBuff++; //декремент указателя адреса
cCount++; //переместить курсор в следующую позицицию строки
break;
}
savMark = *pBuff; //Сохранить символ в знакоместе экрана, на которое теперь будет указывать курсор
}
}
//----------------------------------------------------------------------
if (cCount >= cTotal) { //если текущее(расчетное) положение курсора оказалось больше чем символов в одной строке
cCount =0; //то курсор переместить в начало следующей строки
lCount++;
}
if (lCount >= lTotal) { //если после этого нмер текущей строки стал больше чем есть строк в окне терминала
memmove(&buffer, &buffer+cTotal/2, ((lTotal-1)*cTotal)); //по переписать все содержимое строк начиная со второй и по последнюю в начало буфера окна
lCount=lTotal-1; //теперь номер текущей строки будет на 1 меньше, чем общее количество строк
memset(&buffer+(lTotal-1) * cTotal/2, ' ', cTotal); //освободившуюся последнюю строку очистить (заполнить пробелами)
savMark = ' '; //естественно новый смвол скрытый курсором будет - пробел
}
//---------------------------------------------------------------------
//Мигающий курсор
if (GetPSBStatus(4)) *pBuff = '_'; //0,5 сек показывать курсор '_'
else *pBuff = savMark; //0,5 сек показывать символ, скрытый курсором
//-----------------------------------------

https://www.youtube.com/watch?v=k1K7IP1nV9o
Обмен текстовыми сообщениями(ASCII) между панелью и стандартным гипертерминалом Windows.
Работу терминала можно протестировать если подключить панель к СОМ порту компьютера (можно и через переходник RS232/USB) простым трехпроводным кабелем
2 <------> 3
3 <------> 2
5 <------> 5
И запустить в Widows программу HyperTerminal.

Панель СП300 даже больше чем просто панель.
Тетрис на СП300 - https://owen.ru/forum/showthread.php?t=33784&p=340895&viewfull=1#post340895

https://youtu.be/-0o6NfBF4Ig