§ 2.1. Настройка направлений линий ввода/вывода
|
Дмитрий Иванов, 22 марта 2008
|
|
Файлы к статье скачать
|
Имя: KA002_01.zip (ZIP архив) |
Размер: 130 КБ |
|
После того как мы познакомились с возможностями модуля по управлению внешними нагрузками, давайте рассмотрим, а как можно считывать информацию из "внешнего мира", например, с кнопок или ключей. Для начала нам необходимо настроить выводы модуля на вход, поскольку по умолчанию они все настроены на выход. Именно этим мы и займемся в этой статье - напишем собственну программу для установки и чтения направлений линий ввода/вывода.
|
Для установки направления ввода/вывода линии необходимо использовать KE-команду $KE,IO,SET. В
качестве параметров необходимо указать номер линии, направление линии (0 – выход, 1 - вход) и
необязательный флаг (S) – сохранение настройки. Если флаг задан, то произведенная настройка
линии будет сохранена в энергонезависимой памяти модуля, т.е. при следующем подключении
модуля линия будет автоматически сконфигурирована в соответствии с сохраненным направле-
нием. Например, чтобы настроить линию под номером 18 на вход и сохранить эту настройку в памяти модуля, необходимо подать следующую команду:
$KE,IO,SET,18,1,S
Изменение направлений линий рекомендуется производить в таком состоянии схемы, когда к
линиям ввода-вывода не подключена нагрузка, т.е. желательно извлечь модуль из схемы. Поясним
с чем связана подобная рекомендация. Предположим, линия была сконфигурирована на вход и на
нее подан низкий уровень напряжения (фактически, подключена к земле схемы). Теперь подается
команда настройки этой линии на выход, а затем (по ошибке или случайности) команда записи данных, а именно высокого
логического уровня. В результате мы получаем короткое замыкание между землей и шиной
питания. Соответственно, нужно все делать либо очень аккуратно, исключая возможность подачи "опасной" команды, либо все же извлечь модуль из схемы.
Для того чтобы узнать в какое направление сейчас установлена та или иная линия служит команда $KE,IO,GET. Команда имеет две модификации. Одна из них позволяет за одно обращение к модулю получить информацию по всем линиям, другая предназначена для одной конкретной линии (подробнее см. команды управления модулем). Мы будем использовать в нашей программе именно последнюю. Еще необходимо сказать, что в синтаксисе команды необходимо указать откуда собственно необходимо прочесть информацию о направлении линии. Для этого в команде используется специальное поле Location. Информация будет соответствовать текущему состоянию, если поле Location равно ‘CUR’ или будет взята из энергонезависимой памяти (‘MEM’), т.к. в общем случае значения могут отличаться (если подавалась команда $KE,IO,SET без указания сохранять в энергонезависимой памяти).
Приступим к программному обеспечению. Готовый проект вы можете найти в файлах к этой статье. Пример написан на С++ с использованием MFC в среде Microsoft Visual Studio C++ 6.0. Окно программы имеет вот такой вид:

Рисунок 1. Пример программы настройки направления линий ввода-вывода модуля Ke-USB24A
Начнем рассмотрение кода. Сначала идет процедура открытия порта - нам она не интересна, так она была уже рассмотрена несколько раз (если интересна - прошу к рассмотрению функцию void CSetupDirectionDlg::OnOpen()).
Мы же сейчас поговорим о функции установки направления линии, отрабатывающей по нажатию кнопки "SET". Сначала идет группа проверок адекватности введенных данных. Если все Ok то формируем куманду установки линии в заданное направление и проверяем был ли взведен флажок сохранения настройки в память. Если да, то к строке команды в конец подписываем ,S. Далее сформированный буфер отправляем в порт.
//******************************************************************************
void CSetupDirectionDlg::OnSet()
{
// TODO: Add your control notification handler code here
UpdateData(true);
if(this->m_hFile == NULL)
{
MessageBox("You should open\nport first", "Info", MB_ICONINFORMATION);
return;
}
int direction = this->m_SetDir;
if(direction < 0)
{
MessageBox("Please, select\ndirection", "Info", MB_ICONINFORMATION);
return;
}
if(this->m_LineSet <= 0 || this->m_LineSet > 24)
{
MessageBox("Please, select\ncorrect line number", "Info", MB_ICONINFORMATION);
return;
}
DWORD lpdwBytesWritten;
char buf[32];
int len = 0;
if(this->m_save.GetCheck() == BST_CHECKED)
len = sprintf(buf, "$KE,IO,SET,%d,%d,S\r\n", this->m_LineSet, direction);
else
len = sprintf(buf, "$KE,IO,SET,%d,%d\r\n", this->m_LineSet, direction);
WriteFile(m_hFile, buf, len, &lpdwBytesWritten, NULL);
MessageBox("Data has been\nsenе to module", "Info", MB_ICONINFORMATION);
}
А вот болле интересный участок кода - обработчик нажатия кнопки "GET", по которой мы должны получить информацию о том, в какое направление сейчас настроена заданная нами линия. Сначала следует последовательность проверок на корректность данных. Далее, с учетом заданных параметров формируется команда на чтение линии. Затем буфер со строкой команды отправляется в порт. Теперь нам необходимо как-то получить ответ от модуля. Для этого можно поступить так как сделано здесь: непосредственно в обработчике нажатия кнопки сделать небольшую задержку, например на 100 мс. За это время модуль гарантированно отработает отправленную ему команду и выдаст обратно в порт ответ (другой вариант, более правильный так сказать - использовать дополнительный поток, который будет постоянно читать данные из порта и разбирать ответы). Затем пытаемся прочесть данные из порта. Если данные есть - начинаем их разбирать. Зная, в каком формате мы должны получить ответ нехитрыми операциями проверяем его на валидность и "вытаскиваем" значение направления запрошенной линии. Из полученной информации формируем ответ в виде сообщения.
//*********************************************************************************
void CSetupDirectionDlg::OnGet()
{
// TODO: Add your control notification handler code here
UpdateData(true);
if(this->m_hFile == NULL)
{
MessageBox("You should open\nport first", "Info", MB_ICONINFORMATION);
return;
}
int source = this->m_GetSource;
if(source < 0)
{
MessageBox("Please, select\nsource", "Info", MB_ICONINFORMATION);
return;
}
if(this->m_LineGet <= 0 || this->m_LineGet > 24)
{
MessageBox("Please, select\ncorrect line number", "Info", MB_ICONINFORMATION);
return;
}
DWORD lpdwBytesWritten;
char buf[32];
int len = 0;
if(source == 0) // CUR
len = sprintf(buf, "$KE,IO,GET,CUR,%d\r\n", this->m_LineGet);
else // MEM
len = sprintf(buf, "$KE,IO,GET,MEM,%d\r\n", this->m_LineGet);
WriteFile(m_hFile, buf, len, &lpdwBytesWritten, NULL);
// Make littele pause for wait module anser
Sleep(100); // Wait 100 ms
DWORD dwBytesRead;
unsigned char pBuff[128];
ReadFile(m_hFile, &pBuff, sizeof(pBuff), &dwBytesRead, NULL);
if(dwBytesRead > 0)
{
// We must get anser like this: #IO,<value>
if( memcmp(pBuff, "#IO,", 4) == 0)
{
int direction = atoi( (char*)(&pBuff[4]) );
if(direction < 0 || direction > 1)
{
MessageBox("Get Line fail1", "Info", MB_ICONERROR);
return;
}
CString s1;
s1.Format("Direction Info:\nLine: %d\nSource: ", this->m_LineGet);
if(source == 0) // CUR
s1 += "CUR\n";
else // MEM
s1 += "MEM\n";
if(direction == 0)
s1 += "Direction: OUT";
else
s1 += "Direction: IN";
MessageBox(s1, "Info", MB_ICONINFORMATION);
}
else
{
MessageBox("Get Line fail2", "Info", MB_ICONERROR);
}
}
else
{
MessageBox("Get Line fail3", "Info", MB_ICONERROR);
}
}
Если софт вам показался сложным и заумным - всегда можно просто набрать команду в виде текста и отправляеть ее в каком-либо терминале, например HyperTerminal или KeTerm:

Рисунок 2. Настройка направления линий ввода-вывода с помощью терминала
Ну а мы переходим к следуюущей статье, в которой мы будем считывать информацию с внешних датчиков через модуль Ke-USB24A в нашей собственной программе.
© Дмитрий Иванов
22 марта 2008 года
http://www.kernelchip.ru