[pic12f675] Этап 5. Два сигнала по одной линии

Дмитрий Филатов
Подключив дисплей к МК на предыдущем этапе, мы заняли почти все ножки микроконтроллера. Теперь нужно усовершенствовать схему и программный код, чтобы высвободить некоторые пины чипа.

Информация
Условия сборки и настройки прибора, компиляции исходного кода и прошивки МК аналогичны предыдущему этапу.

Радиокомпоненты и приборы
Аналогичны предыдущему этапу.

Электрическая принципиальная схема
От предыдущей она отличается тем, что линия RS дисплея подключена не к GP4, а к GP0 совместно с сигналом SH_CP, а ST_CP заведена на пин GP5 совместно с линией E дисплея. Таким образом, в этой схеме, в отличие от предыдущей, высвобождены две ножки: GP4 и GP2.
Исходный код прошивки на языке C
Файл pic.c, компилятор SDCC

#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
NOP
NOP
NOP
NOP
__endasm;
}
}

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

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

//Инициализация ЖКИ
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 на выход, остальные - на вход
GPIO = 0b00000000; //На всех GPIO установить логический ноль
CMCON = 0b00000111; //Отключить компаратор
ADCON0 = 0b00000000; //Отключить АЦП
ANSEL = 0b00000000; //Отключить аналоговые входы, все ножки установить как цифровые входы-выходы

lcd_init();

lcd_write('R', 1);
lcd_write('x', 1);
lcd_write('L', 1);
lcd_write('a', 1);
lcd_write('b', 1);
lcd_write('.', 1);
lcd_write('O', 1);
lcd_write('r', 1);
lcd_write('g', 1);

//Входим в бесконечный цикл, чтобы не выйти из подпрограммы и не погасить экран
while(1){
__asm
NOP
__endasm;
}
}

Тонкости
Следует обратить внимание, что сигнал RS теперь передаётся через функцию, а не отдельно. В регистре TRISIO на выход включены уже только 3 ножки, а не 5, как в предыдущем этапе. Также, для примера символы записаны здесь буквами, а не двоичными кодами. В остальном, результат работы этой схемы аналогичен работе предыдущей схемы - на экране высветится заданный текст.
2013-11-29