Переход с SDCC на XC8

Дмитрий Филатов
В качестве модельной схемы используем цифровой вольтметр на микроконтроллере pic12f675, предложенный на седьмом этапе. Схемотехника остаётся той же самой, логика программы - тоже, изменится только среда программирования и компилятор. Компания Microchip - производитель микроконтроллеров семейства PIC - предлагает собственную среду разработки MPLAB X IDE, установочный файл можно бесплатно скачать на официальном сайте. Ещё нужно будет скачать и установить компилятор XC8 (для 8-битных микроконтроллеров, к которым относится и pic12f675). Откройте IDE, выберите пункт меню File - New Project, в открывшемся диалоговом окне в разделе Categories выберите Microchip Embedded, а в разделе Projects - Standalone Project. Нажмите Next. На следующей странице выберите Mid-Range 8-bit MCUs, затем МК pic12f675. Нажмите Next. На следующей странице оставьте None, перейдите на следующую страницу и оставьте ICD 3, затем выберите компилятор XC8. На последней странице введите имя проекта и предпочитаемую кодировку. Нажмите Finish. Откроется проект. В дереве проекта щёлкните правой кнопкой мыши на пункте Source Files, выберите New - Empy File, в поле File Name введите main.c, затем вызовите контекстное меню для проекта (щелчок правой кнопкой мыши на названии проекта в дереве проекта), выберите меню Properties, перейдите в раздел Conf - XC8 global options - XC8 compiler, справа в выпадающем списке Option categories выберите Optimizations и в строке Operation mode установите требуемый уровень оптимизации - от Free до PRO (PRO - платный уровень оптимизации). Ниже приведён текст программы.

Файл main.c, среда MPLAB X IDE, компилятор XC8

#include <pic12f675.h>

#define RS_SHCP GPIO0 //Сдвоенные сигналы: тактовый и тип данных
#define DS GPIO1
#define E_STCP GPIO5 //Сдвоенные сигналы: стробирующий и защёлка

//Функция задержки, в мкс. Исходит из того, что один такт этого МК при 4 МГц выполняется за 200 нс, согласно даташиту.
void delay_us(unsigned char t){
while(t--){
//Ассемблерная вставка: 5 холостых тактов
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
}
}

//Функция задержки в мс
void delay_ms(unsigned char m){
while(m--){
delay_us(1000);
}
}

//Функция отправки байта в ЖКИ через сдвиговый регистр
void lcd_write(unsigned char c, unsigned char sig_rs){
E_STCP = 0; //Здесь Е нас не интересует, может быть любым
unsigned char i = 7;
do{
DS = (c >> i) & 1;
RS_SHCP = 0; //Здесь важна SHCP, RS может быть любым
RS_SHCP = 1; //-//-
}while(i--);
E_STCP = 1; //Защёлкнули данные и выставили высокий уровень стробирующего сигнала. Интересуют оба.
RS_SHCP = sig_rs; //Теперь можем пренебрегать SH. Выставили нужный уровень сигнала RS
delay_us(200); //Теперь имеем сигналы DS (DB7-DB0), для создания которых отработали SH и ST, и сигнал RS
E_STCP = 0; //Начинаем выполнять операцию записи в ЖКИ, STCP не интересует
}

//Инициализация ЖКИ
void lcd_init(){
delay_ms(15);

lcd_write(0b00111100, 0); //Шина 8 бит, 2 строки, 5х8 точек - Function Set
delay_ms(40);

lcd_write(0b00000001, 0); //Очистка экрана - Clear Display
delay_ms(2);

lcd_write(0b00000110, 0); //Инкремент - Entry Mode Set
delay_ms(40);

lcd_write(0b00001100, 0); //Включили дисплей и курсор, мигание курсора отключили - Display ON/OFF Control
delay_ms(40);

lcd_write(0b10000000, 0); //Очистили дисплей - Set DDRAM Address
delay_ms(2);
}

main(){
OSCCAL = 0x80; //Установить внутренний осциллятор на среднюю частоту
TRISIO = 0b11011100; //Установить GPIO0, GPIO1, GPIO5 на выход, остальные - на вход. GPIO4/AN3/#3 - вход АЦП
GPIO = 0b00000000; //На всех GPIO установить логический ноль
CMCON = 0b00000111; //Отключить компаратор
ADCON0 = 0b10001100; //Правое выр., опорн. Vdd, канал 3, ожидание, модуль выключен
ANSEL = 0b00011000; //Предделитель /8, AN3

lcd_init();

while(1){
unsigned int x;
delay_ms(2);
ADON = 1; //Включили модуль
delay_ms(15); //Заряжается Chold
GO_DONE = 1; //Начало преобразования
while(GO_DONE); //Конец преобразования
x = (ADRESH<<8) + ADRESL; //Читаем результат
ADON = 0;
x = (x*49)/10; // мВ
lcd_write(0b00000001, 0); //Очистили дисплей
lcd_write((x/1000)+'0', 1);
lcd_write(((x/100)%10)+'0', 1);
lcd_write(((x/10)%10)+'0', 1);
lcd_write((x%10)+'0', 1);
delay_ms(10);
}
}

Этот код несколько отличается от такого же кода для компилятора SDCC. Убраны знаки подчёркивания перед названиями функций delay_... (чтобы не конфликтовать со встроенными функциями - а там такие предусмотрены), по-другому вызываются ассемблерные вставки, а главное - на дисплей выводятся все 4 цифры, а не только первая, потому что компилятор XC8 генерирует более компактный файл прошивки. Названия битов конфигурации в большинстве случаев соответствуют таковым для SDCC. К сожалению, XC8, в отличие от SDCC, не поддерживает рекурсивный вызов, поэтому все функции, содержащие рекурсию, нужно будет переписать с использованием оператора do{}while(); Скомпилированный файл прошивки будет находиться по адресу (ProjectName)\dist\default\production\(ProjectName).production.hex
2014-08-05