Задача: Управление графическим дисплеем
Исходный материал: PIC16f628a, LCD 2×16, breadboard
Схема подключения дисплея (кварц не подключен, но предполагается, что он есть):
Следующий шаг – написание функций управления дисплеем. Я просто взял файлы из директории samples папки компилятора и переделал под себя.
Файл lcd.c
/* *&nbsp;&nbsp;&nbsp; LCD interface example *&nbsp;&nbsp;&nbsp; Uses routines from delay.c *&nbsp;&nbsp;&nbsp; This code will interface to a standard LCD controller *&nbsp;&nbsp;&nbsp; like the Hitachi HD44780. It uses it in 4 bit mode, with *&nbsp;&nbsp;&nbsp; the hardware connected as follows (the standard 14 pin *&nbsp;&nbsp;&nbsp; LCD connector is used): * *&nbsp;&nbsp;&nbsp; PORTD bits 0-3 are connected to the LCD data bits 4-7 (high nibble) *&nbsp;&nbsp;&nbsp; PORTA bit 3 is connected to the LCD RS input (register select) *&nbsp;&nbsp;&nbsp; PORTA bit 1 is connected to the LCD EN bit (enable) * *&nbsp;&nbsp;&nbsp; To use these routines, set up the port I/O (TRISA, TRISD) then *&nbsp;&nbsp;&nbsp; call lcd_init(), then other routines as required. * */ #ifndef _XTAL_FREQ // Unless specified elsewhere, 4MHz system frequency is assumed #define _XTAL_FREQ 4000000 #endif #include&nbsp;&nbsp;&nbsp; <htc.h> #include&nbsp;&nbsp;&nbsp; "lcd.h"</htc.h> #define&nbsp;&nbsp;&nbsp; LCD_RS RA1 #define&nbsp;&nbsp;&nbsp; LCD_RW RA2 #define LCD_EN RA3 #define LCD_DATA&nbsp;&nbsp;&nbsp; PORTB #define&nbsp;&nbsp;&nbsp; LCD_STROBE()&nbsp;&nbsp;&nbsp; ((LCD_EN = 1),(LCD_EN=0)) /* write a byte to the LCD in 4 bit mode */ void lcd_write(unsigned char c) { __delay_us(40); LCD_DATA = ( ( c &gt;&gt; 4 ) &amp; 0x0F ); LCD_STROBE(); LCD_DATA = ( c &amp; 0x0F ); LCD_STROBE(); } /* * &nbsp;&nbsp;&nbsp; Clear and home the LCD */ void lcd_clear(void) { LCD_RS = 0; lcd_write(0x1); __delay_ms(2); } /* write a string of chars to the LCD */ void lcd_puts(const char * s) { LCD_RS = 1;&nbsp;&nbsp;&nbsp; // write characters while(*s) lcd_write(*s++); } /* write one character to the LCD */ void lcd_putch(char c) { LCD_RS = 1;&nbsp;&nbsp;&nbsp; // write characters lcd_write( c ); } /* * Go to the specified position */ void lcd_goto(unsigned char pos) { LCD_RS = 0; lcd_write(0x80+pos); } /* initialise the LCD - put into 4 bit mode */ void lcd_init() { char init_value; CMCON&nbsp; = 0x07;&nbsp;&nbsp;&nbsp; // Disable analog pins on PORTA init_value = 0x3; TRISA=0; TRISB=0; LCD_RS = 0; LCD_EN = 0; LCD_RW = 0; __delay_ms(15);&nbsp;&nbsp;&nbsp; // wait 15mSec after power applied, LCD_DATA&nbsp;&nbsp;&nbsp; &nbsp;= init_value; LCD_STROBE(); __delay_ms(5); LCD_STROBE(); __delay_us(200); LCD_STROBE(); __delay_us(200); LCD_DATA = 2;&nbsp;&nbsp;&nbsp; // Four bit mode LCD_STROBE(); lcd_write(0x28); // Set interface length lcd_write(0xF); // Display On, Cursor On, Cursor Blink lcd_clear();&nbsp;&nbsp;&nbsp; // Clear screen lcd_write(0x6); // Set entry Mode }и файл lcd.h
/* *&nbsp;&nbsp;&nbsp; LCD interface header file *&nbsp;&nbsp;&nbsp; See lcd.c for more info */ /* write a byte to the LCD in 4 bit mode */ extern void lcd_write(unsigned char); /* Clear and home the LCD */ extern void lcd_clear(void); /* write a string of characters to the LCD */ extern void lcd_puts(const char * s); /* Go to the specified position */ extern void lcd_goto(unsigned char pos); /* intialize the LCD - call before anything else */ extern void lcd_init(void); extern void lcd_putch(char); /*&nbsp;&nbsp;&nbsp; Set the cursor position */ #define&nbsp;&nbsp;&nbsp; lcd_cursor(x)&nbsp;&nbsp;&nbsp; lcd_write(((x)&amp;0x7F)|0x80)Ну и, наконец, тестовая программа
#include <htc.h> #include "lcd.h" #define _XTAL_FREQ 4000000</htc.h> __CONFIG(WDTDIS &amp; UNPROTECT &amp; MCLREN &amp; LVPDIS &amp; HS); void main() { lcd_init(); lcd_goto(0);&nbsp;&nbsp;&nbsp; // select first line lcd_puts("PIC manual"); lcd_goto(0x40);&nbsp;&nbsp;&nbsp; // Select second line lcd_puts("SARGE.PP.UA"); for(;;); }Исходники здесь
UPD: Новую версию кода, адаптированную под любой пин порта можно посмотреть здесь.
Уважаемый sarge
Материалы Ваших статей использую для освоения C, многое уже проянилось, за что Вам большое спасибо! В целом разобрался с работой LCD-панели – в Proteus и на макетке все работает! Но появились вопросы.
1. Помогите разобраться с работой функции lcd_puts(const char * s), она у Вас выводит в LCD строку прямо из PIC. И действительно выводит! А по описанию дисплея (использую MT-16S2R), как я понял, можно отправлять лишь адреса символов по внутренней кодовой таблице. Написал код на ASM-е – все работает, но это же неудобно. А тут сразу выводится строка. Пожалуйста, поясните как понимать выражение с параметрами функции, в частности, фрагмент “*s” (т.е. как это все работает)? В т.ч. и цикл while(*s), ведь в скобках д.б. условие?
2. Большую помощь в понимании процессов оказывает режим пошаговой отладки. Но вот с чем я никак не могу справиться. Содержимое регистров PIC прекрасно отображается в окне Watch. А вот значения глобальных и локальных переменных посмотреть никак не удается. В окне Watch они не отображаются (и не должны). Есть окно Locals (полагаю, как раз для этих целей), но оно пустое. И добавить в него информацию никак не получается. В контекстном меню окна почти все опции “серые”, кроме Properties. Все листинги брал с Вашего сайта “Эксперимент №6”, но и в других проектах все аналогично. Подумал, у меня MPLAB “кривая” (v8.85.00), но и в Proteus окно PIC CPU Variables также пустое и ничего в него не вводится.
Прошу извинить, если вопросы “детские”, но я полный новичок в C, пока в стадии обучения.
1. Для отправки символа используется функция lcd_write(c), которая как раз таки также расположена внутри lcd_puts(), отправляющей всю строку.
*s – читайте про работу с указателями в C, while(*s) пока не закончится вся строка, выдираем по одному символу.
2. Показывайте пример конкретный, кидайте архив на мыло мне (sargein@gmail.com) и попробуем разобраться. Но предупреждаю, мплаба у меня сейчас даже нету, поэтому под протеус давайте все.
Большое спасибо за ответ. Указатели… Читал про это, но на практике не признал. Звезду пытался интерпретировать, как умножение. Теперь идея начинает проясняться в деталях, но надо еще поработать.
К вопросу 2 – Проект отправил Вам на почту, там все вместе: и Proteus, и MPLAB. Собственно, это код из текущего Эксперимента, немного измененный под PIC16F873A. Зачем такой большой PIC? Во-первых, я уже убедился: на шину данных нужно вешать порт целиком. Иначе можно долго ошибки выкорчевывать. А к порту B планировал на перспективу подключить кнопки для переключения режимов. Так вот, в файле lcd.c собраны функции проекта. К примеру, я хочу наблюдать значение параметра “с” в теле функции lcd_write, либо текущее значение указателя “*s” в lcd_puts, либо значение переменной “init_value” в lcd_init(). Судя по документации, окно PIC CPU Variables как раз для этого и должно служить. Но не получается.
Уведомление: Pic Lab, PIC16, Experiment #6, LCD display | diymicro.org