Язык программирования C-51 позволяет писать многомодульные программы.
Оттранслированный программный модуль сохраняется в виде отдельного файла в объектном формате, где кроме машинных команд сохраняется информация о именах переменных, адресах команд, требующих модификации при объединении модулей в единую программу и отладочная информация.
Раздельная трансляция программы возможна при использовании двух программ: транслятора исходного текста программы c-51 и редактора связей bl-51.
При программировании на языке С раздельная трансляция не вызывает каких либо проблем. Однако если при компиляции исходного текста программы транслятор обнаружит переменную, которая не была заранее объявлена, то будет сформировано сообщение об ошибке и объектный модуль будет стёрт с диска компьютера.
Для того, чтобы транслятор вместо формирования сообщения об ошибке записал в объектный модуль информацию, необходимую для редактора связей, нужно осуществить объявление внешних переменных подпрограмм и меток. Для объявления внешних переменных после обычного объявления добавляется слово extern. При таком объявлении при трансляции исходного текста программы для переменной память данных для переменных не распределяется, а создаются соответствующие записи для редактора связей, позволяющие осуществить соответствующие вызовы подпрограмм и переходы между модулями, а также обращение к переменным другого модуля. Пример объявления внешних переменных на языке программирования C-51:
extern char RejRab; extern char UrovGr; extern int NomKan; extern bit Sost; extern bit Soob;
В этом объявлении перечисляются переменные, точное значение которых редактор связей должен получить из другого модуля и модифицировать все команды микроконтроллера, в которых эти переменные используются.
Все используемые в модуле подпрограммы должны быть предварительно объявлены или определены. Это же относится и к подпрограммам из других модулей. При объявлении подпрограммы должны быть полностью объявлены все ее параметры. Пример объявления внешних подпрограмм на языке программирования С-51:
char TestOZU(void); char Rd558(char AdrRAM,char NachAdr,char Nbyte); char Wr558(char AdrRAM,char NachAdr,char Nbyte);
В языке программирования С все подпрограммы и глобальные переменные доступны из любого модуля по умолчанию, поэтому никаких особых действий при написании подпрограммы, используемой в других модулях, не требуется.
Программа bl-51 объединяет несколько объектных файлов (модулей) в один. Для объединения нескольких модулей в исполняемую программу имена всех модулей передаются в редактор связей в качестве параметров при запуске этой программы. Пример вызова редактора связей из командной строки DOS для объединения трёх модулей:
bl51.exe progr.obj, modul1.obj, modul2.obj
В результате работы редактора связей (компоновщика) в этом примере будет создан исполняемый модуль с именем progr.
Как уже указывалось ранее, намного удобнее пользоваться готовой средой программирования, где для объединения модулей в единую программу достаточно просто включить все необходимые модули в программный проект, пользуясь окном менеджера проекта.
Необходимость предварительного объявления внешних переменных и подпрограмм приводит к тому, что исходный текст программы загромождается этими объявлениями и найти собственно программу становится сложно. Кроме того при таких объявлениях возможно возникновение ошибок. Поэтому лучше вынести объявления подпрограмм и переменных в отдельные файлы, которые затем могут быть подключены в исходный текст программы директивой #include.
Наименьшая вероятность ошибиться при описании переменных и подпрограмм у программиста, который писал исходный текст модуля, к подпрограммам и переменным которого нужно обращаться из других модулей. Поэтому правила хорошего тона предполагают, что этот программист будет поставлять не только объектный модуль, но и файл описания своих переменных с атрибутом EXTERN. Такие файлы называются файлами заголовками и обычно записываются с расширением *.h. Пример исходного текста модуля приведён ниже:
/*Исходный текст модуля comm.с*/ char NomPult extern; Bufer(7) byte external, RejRab byte public, NomKan word public, PrmSoob: procedure using 2; declare i byte; for i=0 to KolBytes; do while not RI;end; BufInd(i)=SBuf; RI=0; end; Soob=true; end PrmSoob; PriemKom: procedure interrupt 4 using 2; KodKom=(SBuf and 0f0h)/16; KolBytes=SBuf and 0fh; RI=0; If KodKom=KomSoob then call PrmSoob; If KodKom=KomSost then call PrmSost; end PriemKom; /*------- Конец модуля ---------*/
Исходный текст файла-заголовка этого модуля:
/*Начало файла заголовка comm.h*/ declare RejRab byte external, NomKan word external, PriemKom:procedure external;end PriemKom; /*------- Конец файла заголовка---------*/
Теперь для того, чтобы воспользоваться приведённым выше модулем достаточно записать строку:
#include
Естественно, так как процесс трансляции разбит на два этапа, то ошибки могут возникать не только на этапе трансляции модулей, но и при связывании модулей в исполняемую программу. Наиболее распространённые ошибки - это забыть включить имя объектного модуля в строку вызова редактора связей, забыть объявить переменную или подпрограмму как PUBLIC или использовать одни и те же адреса для переменных или констант в различных модулях. Сообщения об этих ошибках выводятся в файл с расширением *.m51.
Полный путь написания программ на языке программирования с-51 показан на рисунке 1 файла описания языка программирования c-51.