воскресенье, 31 марта 2013 г.

Программирование ATmega328 для работы с LCD 1602 в С

Подключение двухстрокового дисплея 1602 к микроконтроллеру осуществляется по 11 или 7 проводам, в зависимости от того, какой режим работы выбран (8 или 4 бит данных).
Рекомендую к прочтению:
Если информация с дисплея считываться не будет, можно освободить еще один провод. Используя 8 бит шину данных, мы прежде всего экономим машинное время процессора микроконтроллера, а также уменьшаем размер программы, но уменьшаем количество свободных портов.
В этом варианте программы, мы будем использовать шину данных разрядностью 8 бит, а так как мы будем только записывать данные в дисплей, то управление будет осуществляться по 2-м проводам.
Рисунок 1 - Схема подключения дисплея 1602
Для управления дисплеем будут использоваться два младших разряда порта B, а для передачи данных все восемь разрядов порта D. Регулировка контрастности осуществляется резистором R2.
В верхнюю строку будет дисплея будет выведен текст, в нижнюю время, прошедшее с момента запуска микроконтроллера в формате ЧЧ:ММ:СС. Обновляться время будет каждую секунду.
Для упрощения код программы подсчет времени будет осуществляться с использованием стандартной задержки 1000 мс.

Пример кода программы:

#include <avr/io.h> //подключение стандартной библиотеки ввода/вывода
#define F_CPU 8000000UL //определение тактовой частоты микроконтроллера для корректной работы функций задержки
#include <util/delay.h> //подключение библиотеки для генерации задержек

void LCDcom(char b) //функция управления
{
PORTB=0b00000010; //строб начала записи
PORTD=b; //команда
_delay_us(5); //поддержание высокого уровня строба начала записи
PORTB=0x00; //окончание строба начала записи
}
void LCDdat(char b) //функция вывода символов
{
PORTB=0b00000011; //строб начала записи, вывод символа
PORTD=b; //символ
_delay_us(5); //поддержание высокого уровня строба начала записи
PORTB=0x01; //окончание строба начала записи
}
void setTime(int h, int m, int s) //функция вывода времени
{
//вычисление каждого символа часов ЧЧ:ММ:СС
int h1=h/10; 
int h2=h%10;
int m1=m/10;
int m2=m%10;
int s1=s/10;
int s2=s%10;
LCDcom(0b11000000); //установка курсора на вторую строку
//вывод символов времени поочереди
_delay_us(50);
LCDdat(48+h1);
_delay_us(50);
LCDdat(48+h2);
_delay_us(50);
LCDdat(58); //вывод двоеточия
_delay_us(50);
LCDdat(48+m1);
_delay_us(50);
LCDdat(48+m2);
_delay_us(50);
LCDdat(58); //вывод двоеточия
_delay_us(50);
LCDdat(48+s1);
_delay_us(50);
LCDdat(48+s2);
}
void LCDinit() //функция инициализации дисплея
{
_delay_ms(40); //задержка для полного включения дисплея
LCDcom(0b00110000); //команда инициализации
//повтор предыдущей команды
_delay_ms(5);
LCDcom(0b00110000);
//повтор предыдущей команды
_delay_us(120);
LCDcom(0b00110000);
//выбор режима работы
_delay_ms(1);
LCDcom(0b00111000); //выбор шины данных 8 бит, 2 строки
_delay_ms(5);
LCDcom(0b00001100); //включение дисплея, курсор выключен, не мигает
_delay_ms(5);
LCDcom(0b00000001); //очистка дисплея
_delay_ms(5);
LCDcom(0b00000110); //сдвиг курсора вправо после вывода
}
int main(void)
{
//SETUP
DDRB=0xFF; //порт B как выход
DDRD=0xFF; //порт D как выход
LCDinit(); //инициализация дисплея
    while(1)
    {
//вывод текста
char t[16]="Time from start"; //текстовая строка
for (int i=0;i<15;i++) //в цикле поочереди выводим каждый символ
{
 _delay_ms(1);
 LCDdat(t[i]); //вывод символа на дисплей
}
_delay_us(50);
//программа подсчета времени
for (int h=0;h<24;h++) //подсчет часов
{
for (int m=0;m<60;m++) //подсчет минут
{
for (int s=0;s<60;s++) //подсчет секунд
{
setTime(h,m,s); //вывод времени на дисплей
_delay_ms(1000); //задержка 1000 мс
}
}
}  
    }
}

В связи с тем, что в программе используется подсчет времени с помощью функции delay, погрешность очень велика. Лучше использовать подсчет времени по прерыванию от таймера/счетчика T2 в асинхронном режиме с внешним кварцевым резонатором.