Кафедра АИиСУ уже более 35 лет готовит профессионалов в области разработки и эксплуатации электронных, микропроцессорных, компьютерных, робототехнических, мехатронных и информационных систем управления для автомобильной и аэрокосмической техники, машиностроения и бизнеса. Научно-исследовательская работа сотрудников кафедры ведется в областях, связанных с разработкой систем поддержки принятия решений на основе технологий искусственного интеллекта, анализа и синтеза процессов управления сложными системами, контроля и интеллектуального выявления сбоев аппаратуры. Важным направлением научной деятельности кафедры является проведение исследований в области автоматических и электронных систем транспортных средств.
Для создания управляющей программы воспользуемся средой программирования RAD Studio Delphi.
Создадим новый проект, откроется окно для моделирования вида и содержания приложения, с надписью в поле заголовка Form1. Добавим в это окно несколько элементов. Из панели Standard добавим элемент TComboBox – для выбора номера COM-порта, элемент TButton – по нажатию кнопки будет происходить подключение к COM-порту, 4 элемента TRadioButton – для включения/выключения привода вентилятора и выбора режимов, 2 элемента TPanel – для группировки элементов TRadioButton, элемент TImage – для добавления логотипа или любой другой картинки. Перейдем к вкладке элементов Additional и добавим элемент TApplicationEvents – для осуществления реакции приложения на действия пользователя. Теперь выберем вкладку элементов Win32 и выберем элемент TTrackBar – для управления поворотом сервопривода.
В результате добавление вышеописанных элементов и изменения надписей к ним получится окно пользовательского приложения, представленное на рис. 13.
Займёмся написанием кода программы.
При переходе на страницу с кодом нажатием кнопки «Toggle Form/Unit» – , можно увидеть код следующего содержания (рис. 14).
Рис. 14. Начало программы
Словом var начинается секция описания переменных. В этой секции опишем переменные необходимые для работы COM-порта и поворота сервопривода, как показано в листинге №5.
Листинг №5
var
Form1: TForm1;
CommHandle: THandle;
{номер созданного элемента для подключения и использования COM-порта}
DCB: TDCB;
{DCB - управляющая структура Вашего порта, в которой определяются настройки порта}
Ovr: TOverlapped;
{
overlapped-структура, необходимая для асинхронных операций (чтения/записи данных)}
Transmit: array [0..10] of integer; {
переменная для записи в нее данных, необходимых для передачи по COM-порту}
KolByte: DWord;
// для определения количества передаваемых байт
H1, H2, a: integer;
{целочисленные, для осуществления поворота сервопривода и перемещения бегунка на TrackBar}
Вернёмся к окну с видом пользовательского приложения (кнопка «Toggle Form/Unit» или клавиша F12 на клавиатуре) и дважды кликнув на кнопке Button1 автоматически создадим процедуру Button1Click, тем самым вернемся к тексту программы и опишем вновь созданную процедуру (листинг №6).
В программе по нажатию кнопки Button1 будет происходить подключение устройства по COM-порту для дальнейшего управления им.
Опишем переменную CommHandle, которой присваивается указатель на открытое (созданное) устройство, определяемый при срабатывании функции CreateFile. При успешном открытии порта функция возвращает его описатель, а в случае ошибки возвращает INVALID_HANDLE_VALUE. Первый параметр этой функции – имя создаваемого файла, в нашем случае это будет номер порта. А так как мы выбираем номер COM-порта из элемента ComboBox, то в параметре «имя создаваемого файла» пропишем PChar(ComboBox1.Text).
Листинг №6
procedure
TForm1.Button1Click(Sender: TObject);
begin
KolByte:=0; //очитка KolByte
{переменная CommHandle, ей будет присвоен номер элемента, который определяется при срабатывании функции CreateFile}
CommHandle:=CreateFile(PChar(ComboBox1.Text), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0);
// получаем исходное состояние структуры DCB с помощью функции GetCommState()
GetCommState(CommHandle, DCB);
//установка параметров порта
DCB.BaudRate:=9600;
//скорость передачи данных
DCB.Parity:=NoParity;
//отсутствие проверки на четность
DCB.ByteSize:=8;
//количество бит в байте
DCB.StopBits:=OneStopBit;
//одиночный стоп-бит
//устанавливаем измененные параметры в DCB-структуре
SetCommState(CommHandle, DCB);
Сделаем проверку создания подключения (листинг №7): если не получилось подключиться к COM-порту, выведем на экран сообщение «Ошибочка вышла!» или что-нибудь похожее, в противном случае сделаем недоступным выбор номера COM-порта.
Листинг №7
if (CommHandle=invalid_handle_value) then ShowMessage('Ошибочка вышла!') else
ComboBox1.enabled:=false;
end;
Перейдём к описанию четырех процедур RadioButtonClick. При выборе RadioButton1 по нашему замыслу должен включаться двигатель вентилятора. Для этого необходимо по COM-порту передать 1 байт со значением $31 (листинг №8). $31 - зарезервированное нами значение под код команды, принимаемое микроконтроллером и понимаемое им как значение для включения двигателя вентилятора. Для передачи данных по COM-порту используется функция WriteFile() со своими определенными параметрами:
hFile: THandle; // Указатель на открытый файл;
const Buffer; // Указатель на данные для записи;
nNumberOfBytesToWrite: DWORD; // Количество записанных байт;
var lpNumberOfBytesWritten: DWORD; // Указатель на количество записанных байт;
lpOverlapped: POverlapped // Указатель на структуру OVERLAPPED.
Так для нашего случая указатель на открытый файл – CommHandle; указатель на данные для записи – Transmit; количество записанных байт – KolByte; указатель на количество записанных байт – KolByte; указатель на структуру OVERLAPPED – @Ovr.
Также при выборе RadioButton1 сделаем доступными RadioButton3 и RadioButton4, которые будут использоваться для выбора режима работы вентилятора (автоматический и ручной режимы).
Аналогично опишем процедуру выключения двигателя вентилятора (листинг №9) с некоторыми изменениями: пересылаемое значение – $20, сделать недоступными для выбора RadioButton3 и RadioButton4 и отменить выбор включения вентилятора.
Теперь займёмся описанием режимов работы вентилятора автоматического и ручного. Начнём с автоматического режима (листинг №10), в котором приложение будет непрерывно передавать значения на микроконтроллер для поворота сервопривода на небольшой угол.
Листинг №10
procedure
TForm1.RadioButton3Click(Sender: TObject);
var i: integer;
begin
TrackBar1.Enabled:= false; {сделаем недоступным для пользователя ползунок}
RadioButton3.Checked:=true;
//отметим выбор автоматического режима
RadioButton4.Checked:=false;
//и отменим выбор ручного
a:=1455;
{зададим минимальное условленное значение соответствующее нулевому положению сервопривода}
repeat
{внешний цикл repeat..until для непрерывного вращения сервопривода влево-вправо}
repeat
{внутренний цикл repeat..until для поворота сервопривода вправо}
Чтобы заставить сервопривод постепенно поворачиваться надо послать контроллеру значение крайнего положения сервопривода $05AF (1455 в десятичной системе счисления) и прибавлять к нему желаемое значение угла поворота (в нашем случае в качестве такого значения мы выбрали 50 –варьированием этого минимального угла можно регулировать скорость вращения сервопривода).
Если сделать так, как мы только что описали, то бегунок TrackBar1 и сервопривод будут двигаться в противоположных направлениях (это вызвано расположением сервопривода на подставке). Для того чтобы бегунок TrackBar1 и сервопривод двигались в одном направлении проведем несложные арифметические операции: сложим максимальное – 5455 ($154F) и минимальное – 1455 ($05AF) значения и постепенно из этой суммы будем вычитать значение 1455 + минимальный угол поворота, равный 50 (листинг №11).
Листинг №11
a:=6910-(a+50);
TrackBar1.Position:=a;
{вычисленное значение присвоим положению бегунка на TrackBar}
Так как полученное значение занимает больше одного байта, необходимо его разделить на 2 байта (листинг №12), сделаем это с помощью команды логического умножения «and» и команды сдвига числа на 8 разрядов «shr».
Листинг №12
h1:=a and $ff;
//младший байт числа
h2:=(a shr 8) and $ff;
//старший байт
Чтобы сервопривод отрабатывал четко и без сбоев сделаем повторяющуюся 5 раз передачу данных. Отправляем 3 байта за 1 цикл: 1 байт – зарезервированное значение «A1», по которому микроконтроллер понимает, что следующие 2 байта предназначены для сервопривода, и будет работать только с ним (листинг №13); 2 байт – младший байт числа «h1»; 3 байт – старший байт числа «h2». Между функциями WriteFile() специально добавлены задержки на 5 мс - Sleep(5) – чтобы микроконтроллер успевал обрабатывать пришедшие к нему команды.
Листинг №14 аналогичен описанному выше внутреннему циклу с поворотом вправо (листинг №11-13). Разница здесь в том, что в этом цикле описывается поворот влево, и, соответственно изменится только процесс вычисления значения положении бегунка и поворота сервопривода: a:=6910-(a-50).
Листинг №14
repeat
{внутренний цикл repeat..until для поворота сервопривода влево}
Все циклы repeat..until будут выполняться до тех пор, пока будет выбран RadioButton3, отвечающий за автоматический режим или пока переменная a не достигнет максимального или минимального значения (зависит от направления поворота). Также в текст программы добавлены строки «application.ProcessMessages;» необходимые для того чтобы приложение не «зависало» и отвечало на действия пользователя.
Процедура RadioButton4Click отвечающая за включение ручного режима (листинг №15), делает доступным для пользователя TrackBar1 и отменяет выбор включения автоматического режима.
Листинг №15
procedure
TForm1.RadioButton4Click(Sender: TObject);
begin
RadioButton3.Checked:=false;
TrackBar1.Enabled:=true;
end;
Процедура TrackBar1Change (листинг №16) осуществляет передачу значения положения бегунка TrackBar на микроконтроллер для поворота сервопривода в нужное пользователю положение. Здесь переменной a присваивается значение вычисляемое исходя из суммы максимального и минимального значения минус текущее положение бегунка TrackBar1.
Авторы:
Крюков А.И., Шубникова И.С., Тройков С.М.
e-mail: mr.krukov@mail.ru
кафедра «Автоматика, Информатика и Системы Управления» Московкого Государственного Индустриального Университета (ГОУ МГИУ), http://www.msiu.ru