Логотип

Если Вы хотите обучаться программированию микроконтроллеров, но попали, сюда не прочитав предыдущих уроков, то советую начать изучение материала с самого начала.

Программирование микроконтроллеров. Урок 18
Передача символов на дисплей Nokia 5110 и подключение энкодера к МК.

Урок 18 (Передача символов на дисплей Nokia 5110 и подключение энкодера к МК.)

На прошлом занятии мы с вами научились передавать данные по SPI, а сегодня попробуем отобразить на нашем дисплее полезную информацию и за одно подключим к нашему МК самый универсальный и удобный управляющий элемент – энкодер.

Итак, из-за того, что в нашем дисплее нет встроенной библиотеки символов, то ее приходится делать самостоятельно и хранить в памяти МК. Это с одной стороны загружает flash память микроконтроллера, а с другой стороны открывает большое поле деятельности в плане отображаемых элементов. В нашем случае мы ограничены только пикселями экрана и своей фантазией.

Помимо отсутствия встроенной библиотеки у этого дисплея есть еще пара особенностей, которые осложняют модификацию графических изображений. Первая связана с организацией памяти. Дело в том, что согласно описания память дисплея состоит из 6 банков (строк), в каждом из которых находится 84 однобайтных ячейки. Поэтому мы просто так не можем обратиться к конкретному пикселю (биту), а вынуждены иметь дело сразу с байтом. Вторая связана с отсутствием обратной связи, и невозможностью посмотреть то, что находится в памяти дисплея.

Самый универсальный способ управлять изображением это выделить в памяти МК необходимую область, равную по объему графической памяти дисплея и модифицировать ее. А после каждой модификации переписывать в дисплей. У этой модели есть положительные и отрицательные стороны. Положительные заключаются в том, что мы полностью контролируем изображение и можем модифицировать его целиком, например, сдвигать, накладывать маски и т.д. Отрицательная сторона в том, что для этого надо угробить 504 байта оперативки. А это, на минуточку, половина SRAM памяти ATmega8. Ну и обсчет этой матрицы, а также пересылка данных будет отнимать какое-то время. На мой взгляд этот метод подходит тогда, когда надо сделать красиво и необходимо организовать вывод на экран динамических изображений. Например, плавное (по пиксельное) движение массива текста при его пролистывании.

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

Так как дисплей содержит 6 банков (строк), это также накладывает некоторые условия на организацию вывода информации. Конечно, представить текст так чтобы часть буквы располагались на одной, а часть на другой строчке можно, но для этого придется написать специальный обработчик. Поэтому я для себя решил, что лучше всего шрифты для этого дисплея делать по высоте кратными одной, двум или трем строкам.

Не могу сказать, что шрифтов для этого дисплея великое множество. Особо не разбежишься, используя знакоместо 5х8 пикселей. Но я нашел одну библиотеку для этого дисплея и дополнил ее своими подпрограммами. Кто делал эту библиотеку не знаю, но однозначное спасибо ему, или ей, или коллективу разработчиков. В ней есть цифры, знаки, латиница и кириллица. Если ее полностью запихать в контроллер, то она будет весить чуть больше восьмисот байт. Я не сторонник того, чтобы забивать память контроллера ненужными для конкретной программы вещами и поэтому считаю, что для каждого устройства необходимо подбирать минимальное количество символов, которые должны войти в его библиотеку.

Итак, каждый символ шрифта 5х8 пикселей записывается в массив, который располагается во flash памяти. Выглядит это вот так:

//массив чисел
	flash const unsigned  char ft_numer [] [5] = {	//   индекс
		{ 0x3E, 0x51, 0x49, 0x45, 0x3E },   	//	0
		{ 0x00, 0x42, 0x7F, 0x40, 0x00 }, 	//	1
		{ 0x42, 0x61, 0x51, 0x49, 0x46 }, 	//	2
		{ 0x21, 0x41, 0x45, 0x4B, 0x31 }, 	//	3
		{ 0x18, 0x14, 0x12, 0x7F, 0x10 }, 	//	4
		{ 0x27, 0x45, 0x45, 0x45, 0x39 }, 	//	5
		{ 0x3C, 0x4A, 0x49, 0x49, 0x30 }, 	//	6
		{ 0x01, 0x71, 0x09, 0x05, 0x03 }, 	//	7
		{ 0x36, 0x49, 0x49, 0x49, 0x36 }, 	//	8
		{ 0x06, 0x49, 0x49, 0x29, 0x1E }  	//	9
	};

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

void nokia_out_5x1 (unsigned char index) 

в которую помещается индекс необходимого нам числа. Индекс — это не что иное как номер строки нашего двумерного массива. Сама подпрограмма состоит из цикла, который повторяется пять раз и за каждую итерацию в дисплей передается один байт данных из нашего массива. После того как строка массива полностью передана, в дисплей передается еще один пустой байт. Этот байт является разделителем между знаками. Все подпрограммы есть в файлах, прилагаемых к уроку. Подпрограмма находится в файле (Lib_Nokia_number.c).

Теперь давайте напишем программу, которая будет выводить весь наш массив на экран по одному в его центре (См. файл - Leson_18\leson_18_1.c). Здесь я для ознакомления разместил только основную часть программы с сокращениями.

	#define MAX_NUMER 18 //максимальное количество данных в массиве для отображения
	#define MAX_DELAY 150000 //максимальная задержка
	#define LCD_POZ 38,2   //Позиция отображения знака на экране

void main(void){
//переменные
    unsigned char temp = ZERO;
    unsigned long int delay = ZERO;

while (1) {
     lcd_position (LCD_POZ); 		//устанавливаем курсор в необходимую позицию на экране дисплея
     nokia_out_5x1 (temp);		//передаем в дисплей необходимую информацию 
     if (temp < MAX_NUMER) temp++;	//инкримируем указатель
     else temp = CLEAN;			//проверяем указатель и обнуляем его если он максимален
     for (delay=ZERO; delay < MAX_DELAY; delay++); //делаем паузу
    }
}

Если вы воспользовались файлом leson_18_1.c и сделали все правильно, то после прошивки у вас на экране должна появиться вот такая картинка.

Т.к. в процессе подготовки урока я слегка менял данные массива, то символы могут слегка отличаться. Для того чтобы отобразить символы в другой части экрана, стоит лишь поменять передаваемые данные в подпрограмму (lcd_position(LCD_POZ)). В нее передаются два числа первое из которых координата по Х (0...83) а вторая по Y (0…5). Попробуйте поиграться этими координатами.

Теперь давайте отобразим на экране трехзначное число. У меня для этого есть небольшая подпрограмма

void nokia_out_3_number (unsigned int data, unsigned char point)

размещенная в файле (Lib_Nokia_number.c) в нее передаются два числа. Первое число для отображения (0…999), а второе место точки (0…3). Если данные выходят за рамки своих диапазонов, то на экране отображается сообщение об ошибке либо (Err> - число больше 999, либо Err. – ошибка отображения точки).

Пример ее использования можно посмотреть в файле (Leson_18\leson_18_2.c). Если вы правильно все сделали, то у вас будет отображаться вот такая картинка.

С выводом изображений вроде разобрались. Если что-то осталось не понятно, то еще можно почитать еще здесь и здесь. И еще у меня есть два самодельных шрифта для цифр здесь и здесь.

Теперь предлагаю перейти к подключению энкодера.

Схема подключения энкодера

Схема подключения энкодера

Энкодер можно подключать по-разному, но поэкспериментировав в этом направлении я понял, что это самая надежная, безопасная и помехозащищенная схема подключения. Для удобства я подключил энкодер к порту (D) использовав для этого выводы PD0, PD1 и PD2, но не стал ставить емкости. Без них устройство тоже очень хорошо работает. Для обработчика энкодера который я буду использовать по большому счету все равно к каким выводам он подключен. Разбор работы подпрограммы обработчика можно посмотреть здесь. Я же буду использовать ее более позднюю версию. Также для полноценной работы энкодера необходимо иметь подпрограмму обработчика одной кнопки. Мы уже подключали кнопку на предыдущих уроках. Также о подключении кнопки можно почитать здесь.

Из-за того, что мой энкодер имеет толстые выводы и не влезает в макетную панель, то мне пришлось припаять к нему небольшие проводки. После чего я быстро собрал схему.

доработка энкодера Подключение энкодера

доработка энкодера

Подключение энкодера

Теперь все готово к написанию тестовой программы. В ней мы на энкодер «повесим» увеличение и уменьшение выводимого на экран значение, а на кнопку «повесим» изменение положение точки. Ниже приведена тестовая программа с сокращениями. Ее полную версию можно посмотреть в прилагаемых файлах (Leson_18\leson_18.c)

    #define LCD_POZ 27,2  //Позиция отображения знака на экране

    #include "Lib_Nokia_5110_ATmega.c"  //Подпрограммы работы с дисплеем
    #include "lib_encoder.c"            //Подпрограмма обработчик энкодера
    #include "lib_batt_one_fix.c"       //Подпрограмма обработчик кнопки по отпусканию
    #include "Lib_Nokia_number.c"       //Библиотека символов и подпрограмма их вывода

void main(void)
{
    unsigned int temp = 999;
    unsigned char d_encoder = ZERO;
    unsigned char d_point = ZERO;

    lcd_init();    //инициализация дисплея
    LED_ON;        //Включаем подсветку

while (1) {
     //опрос энкодера
     d_encoder = encoder();
     if (d_encoder==2) if (temp < 1001) temp ++;
     if (d_encoder==1) if (temp >0 ) temp --;
     //опрос кнопки
     if (bat_pusch_one()){
        if (!(d_point)) d_point = 4;
        else d_point--;
     };

     //отображение информации
     lcd_position (LCD_POZ);
     nokia_out_3_number (temp, d_point) ;
    }
}

Если вы все правильно сделали у вас должно получиться вот так.

Ну и всё. Надеюсь у вас все получилось и можно начать готовиться к следующему занятию. На нем мы с вами сделаем настоящие часы. Для этого вам необходимо будет обзавестись часовым кварцем на 32768 Гц и двумя одинаковыми конденсаторами на 10…20 pf. А также еще раз освежить память и почитать про таймеры/счетчики Т0 и Т2. В особенности про работу таймера/счетчика Т2 в асинхронном режиме.

   Евстифеев А.В. «Микроконтроллеры AVR семейства Tiny и Mega фирмы Atmel» 2008г. Страницы 264…279.


В качестве домашнего задания я предлагаю сделать вот такую простую полоску, которая будет управляться энкодером.


А на сегодня всё. Удачи.


08.07.19



Если вдруг найдете в статье неточности или заблуждения. Напишите мне об этом. Я подправлю.



Приложение:
Файлы к уроку 18