Программа модуля цифровых вводов на языке С
Входы RA0-RA2 я оставил для выхода, к ним подключены индикаторы.
Файл заголовка
Void putch(unsigned char); unsigned char getch(void); int init_coimns (); int sim_num_adr(); int cmd(); int din_stat();
Основной файл
#include <picl6f62xa. h> #include <stdio. h> #include "digin. h"
Unsigned char input; регистра.
// Для считывания приемного // Первый символ адреса модуля. // Второй символ адреса модуля. |
Unsigned char M0D_SIM1; unsigned char M0D_SIM2;
Unsigned char command_recіev [6]; // Массив для полученной команды.
Int MOD_ADDR; // Заданный адрес модуля, как число,
Int sim_end_num = 0; // Полный символьный номер
Модуля.
Int MOD_NUM; // Полученный адрес модуля, как число,
Unsigned char DINSTAT = 0xF8; // Статус позиционно: 1 - вкл, 0 - выкл.
Unsigned char DINSIM1; // Символы состояния для передачи,
Unsigned char DINSIM2; unsigned char DINSIM3; int і;
// Получение байта.
Unsigned char getchO {
While(!RCIF) // Когда регистр не пуст.
Continue; return RCREG;
}
// Вывод одного байта.
Void putch (unsigned char byte) {
While (1TXIF) J/ Когда регистр пуст.
Continue; TXREG = byte;
}
// Преобразуем символьный адрес в число.
Int sim_num_adr() {
Sim_end_num = 0;
M0D_SIM1 = coinmand_reciev [1]; // Первый символ номера.
MOD_SIM2 = command_rec і ev [2]; // Второй символ номера.
MOD_SIMl = M0D_SIM1 - 0x30;
MOD_SIM2 = MOD_SIM2 - 0x30;
Sim_end_num = MOD_SIMl*OxOA + MOD_SIM2;
Return sim_end_num;
}
// Получение и выполнение команды.
Int cmd() {
Swi t ch (command_recі ev [5 3) {
Case "S": din__stat();
Break; }
// Выполнение команды передачи состояния.
Int din_stat() {
Int din; int dinl; int din2; int din3;
Din = DINSTAT; // Преобразуем состояние в символы.
Dinl = din/0x64;
DINSIM1 = dinl + 0x30;
Din2 = (din - dinl*0x64) /OxA;
DINSIM2 = din2 + 0x30;
Din3 = (din - dinl*0x64 - din2*0xA) ;
DINSIM3 = din3 + 0x30;
Coinmand_reciev[0] = "D"; command_reciev[l] = MOD_SIMl+0x30; command_rec і e v [ 2 ] = MOD_SIM2+0x30; command__reciev[3] = DINSIM1; command_reciev[4] = DINSIM2; command_reciev[5] = DINSIM3;
CREN =0; // Запрещаем прием.
RB0 = 1; //Переключим драйвер RS485 на передачу.
TXEN =1; // Разрешаем передачу.
For (i=0; i<6; ++i) putch(command_reciev[i]) ;
For (i=0;i<1000;i++); // Задержка для вывода.
For (i=0; i<6; ++i) coiranand_reciev [i] = " ";
RB0 = 0; // Выключаем драйвер RS485 на передачу.
TXEN = 0; // Запрещаем передачу.
CREN =1; // Разрешаем прием.
RA1 = 0;
// Инициализация модуля. |
DINSTAT = 0xF8; // Сбросим состояние.
Int init_comms () {
// Настройка портов А и В. |
PORTA = 0xF8; CMCON = 0x7; TRISA = 0xF8; TRISB = OxFE;
; // Настройка приемника.
; // Настройка передатчика.
RCSTA = 0Ы0010000; TXSTA = ObOOOOOllO; |
SPBRG = 0x68; RB0 = 0; |
// Настройка режима приема-передачи. // Выключаем драйвер RS485 на передачу.
RAO = 1;
Void main(void)
// Инициализация модуля. init_comms () ;
For (i=0; i<6; ++i) coinmand_reciev [i] = " "; coinmand_reciev [0] = "D"; //Прочитаем и преобразуем номер модуля.
MOD_ADDR = PORTB; // Номер модуля в старших битах. MOD_ADDR = MOD_ADDR»4; // Сдвинем на четыре бита.
// Начинаем работать, start: CREN =1;
If ((PORTA&OXF8) != 0xF8) {
DINSTAT = DINSTAT& PORTA; RAl = 1;
}
If (RCIF) // Если пришел запрос по сети,
Input = getch(); switch (input)
Case "D": // Если обращение к модулю.
For (i=l; i<6; ++i) // Запишем команду в массив. {
Input = getch();
Coinmand_reciev [і] = input; }
MOD_NUM = sim_num_adr (); // Чтение из сети.
If (MOD_NUM!= MOD_ADDR) break; // Если не наш адрес, else
If (command_reciev [3] = "$") cmd(); //Если команда, default: goto start;
}
Goto start;
}
Выводы порта A RA0-RA2 на время работы с макетом я программирую так, чтобы индикатор на выводе RA0 включался при включении модуля, а индикатор на выводе RA1 отображал наличие изменений состояния входов модуля
При настройке программы в MPLAB я использую данные, показанные на рис. 2.1.
SO. ' orRbook* {Untitled}
Pn I RegKtw Actions Advanced FW Relief Clock Stmukis Regret Injection. Regrict Tiace, TineUntaj w jJ □ Repeal fde^nalj
CSck here to Add Signals |
Time (dec) 5 10000 20000 100000 ШМ |
1 |
RA7 RAS RA5 RA4 RB? RBG RBS RB4 (bin) (br>) (bin) {bin) (bn) (bn) (bn)I (br>)^
Lis
( fienwate sg Fiom Workbook ] [jbeteteRow ] feaveWockbook} | Egt [ | Цф
Рис. 2.1. Отладочные данные
В этом файле многие переменные и функции я оставил в обозначениях, близких к исходным. Я уже говорил, что собираюсь переделать программу из программы релейного модуля. Часть текста, подправив, я взял из текста программы модуля приемника системных ИК-команд. Правка была минимальной.
Здесь мне хотелось бы еще раз вернуться к вопросу о написании текста программы. Многие переменные в представленном выше тексте обозначены так, что трудно понять, для каких целей они служат. Функции не облегчают понимание их назначения. Вернувшись к тексту после нескольких недель
перерыва, начинаешь понимать, что лучше было бы все сделать иначе. Удобно обозначать переменные, чтобы легко было понять их назначение. То же касается и функций. Для этого есть много правил, которые лучше поискать в руководствах по программированию. Но есть один момент в работе над текстом. Переменную удобно обозначить, например, int digital_input_close. Однако, используя эту переменную десятки раз, переделывая программу столько же раз, ты понимаешь, что каждый раз вписывать это многословное название переменной - утомительное занятие. Можно, конечно, копировать название из текста программы. Но для этого приходится возвращаться к началу, затем искать место, где ты работал. Можно поступить иначе, и это будет полезно во всех отношениях - использовать файл todo. txt. В нем перечислить все переменные и функции, попутно описав их. Переключение между файлами быстрое, а копирование не сложное, поскольку перечень переменных и функций можно сделать коротким.
При проверке макета (а для его проверки я использую тестовую часть основной программы, исправив обращение к одному из модулей на обращение к модулю цифровых входов - D14$0S), первое, что мне не нравится, но не является неожиданностью, - это поведение входов. Думаю, причина в отсутствии «подтягивающих» резисторов.
Я впаиваю на макет подтягивающие резисторы (резисторы между плюсом питающего напряжения и выводом) на входы, и картина действительно меняется - макет полностью перестает реагировать на тестовые команды!
Создается впечатление, что или конвертер RS232-RS485, или интерфейс RS485 макета вышли из строя. В моем распоряжении только мультиметр. Не самый удачный вариант. Первое, что приходит в голову после нескольких неудачных попыток оживить модуль, - внести в программу изменение: при инициализации переключить драйвер RS485 на передачу (бит RB0).
Бит переключается, что уже хорошо. Затем, манипулируя индикаторами на выводах RA0-RA2, я начинаю проверять, в чем дело? И проблема оказывается в простой халатности - при переделке программы релейного модуля я, хотя и намеревался, не изменил основную часть программы, которую собирался позаимствовать от программы фотоприемника. После изменения программы модуль цифровых входов стал работать вполне убедительно.
В тексте выше приведена уже исправленная версия программы.
Теперь осталось проверить работу модуля в основной программе в режиме Работа. В этом режиме программа не реагирует ни на что, кроме сетевых событий. Ранее для выхода из режима Работа я использовал ИК-команду. Сейчас я хочу использовать изменение входа RA3, внеся для этой цели изменения в основную программу:
Sub work() Do
Forml. Key Preview = True Forml. MSComml. Output = "D14$0S"
For і = 0 To 10000000 Next і
StrAnsw = Forml. MSComml. Input и т. д. до строки
Саве "D14$0SD14240"
Ext = True End Select
Таким образом, я поменял обращение к модулю (было обращение к модулю фотоприемника) и условие выхода. Программа работает.