Усилитель. Шаг 2. Подключение ЖК дисплея.

Следующим шагом на пути создания усилителя я выбрал подключение жк дисплея и вывод некоторой информации на него. В данной статье в частности будут рассмотрены следующие варианты:

  1. Вывод любой тестовой инфы на дисплей.
  2. Вывод часов на дисплей.
  3. Вывод температуры на дисплей.

С этим этапом разработки у меня есть один небольшой негативный момент. Дело в том, что я сначала купил дисплей фирмы sunlike sc1602. Я на него убил кучу времени. Мне кажется что я уже перепробовал все возможные способы инициализации всех возможных процессоров, и ничего так мне и не удалось увидеть. Потом я плюнул и купил новый дисплей фирмы Winstar, который завелся сразу же по стандартной процедуре инициализации хитачевского проца, которая была рассмотрена ранее.

Дисплей подключен, но в старом коде меня некоторые пункты не устраивали, вот то что внутри lcd.h:


#include <htc.h>
#ifndef _LCD_H_
#define _LCD_H_

#ifndef _XTAL_FREQ
// Unless specified elsewhere, 4MHz system frequency is assumed
#define _XTAL_FREQ 4000000
#endif

#define LCD_RS RD2
#define LCD_EN RD3

#define lcd4b RD4
#define lcd5b RD5
#define lcd6b RD6
#define lcd7b RD7

#define    lcd_cursor(x)    lcd_write(((x)&0x7F)|0x80)
#define    LCD_STROBE()    ((LCD_EN = 1),(LCD_EN=0))
#define testbit(data,bitno) ((data>>bitno)&0x01)

extern void lcd_write(unsigned char c);
extern void lcd_clear(void);
extern void lcd_puts(const char * s);
extern void lcd_putch(char c);
extern void lcd_goto(unsigned char pos);
extern void lcd_init();

#endif

Главное отличие в этом файле – это то что для данных я не использую весь порт, а в прошлой версии хотя и использовалось всего 4 линии, но присваивание шло на весь порт. Раз изменилась система присваивания данных, то изменению должны подвергнуться и две функции: lcd_write и lcd_init

Внутренности lcd.c

#include "lcd.h"

void
lcd_write(unsigned char c)
{
__delay_us(40);
if (testbit(c,4)) lcd4b = 1; else lcd4b = 0;
if (testbit(c,5)) lcd5b = 1; else lcd5b = 0;
if (testbit(c,6)) lcd6b = 1; else lcd6b = 0;
if (testbit(c,7)) lcd7b = 1; else lcd7b = 0;
LCD_STROBE();
if (testbit(c,0)) lcd4b = 1; else lcd4b = 0;
if (testbit(c,1)) lcd5b = 1; else lcd5b = 0;
if (testbit(c,2)) lcd6b = 1; else lcd6b = 0;
if (testbit(c,3)) lcd7b = 1; else lcd7b = 0;
LCD_STROBE();
}

void
lcd_clear(void)
{
LCD_RS = 0;
lcd_write(0x1);
__delay_ms(2);
}

void
lcd_puts(const char * s)
{
LCD_RS = 1;    // write characters
while(*s)
lcd_write(*s++);
}

void
lcd_putch(char c)
{
LCD_RS = 1;    // write characters
lcd_write( c );
}

void
lcd_goto(unsigned char pos)
{
LCD_RS = 0;
lcd_write(0x80+pos);
}

void
lcd_init()
{
LCD_RS = 0;
LCD_EN = 0;

__delay_ms(15);    // wait 15mSec after power applied,
lcd4b = 1;
lcd5b = 1;
lcd6b = 0;
lcd7b = 0;
LCD_STROBE();
__delay_ms(5);
LCD_STROBE();
__delay_us(200);
LCD_STROBE();
__delay_us(200);
lcd4b = 0;
lcd5b = 1;
lcd6b = 0;
lcd7b = 0;          // Four bit mode
LCD_STROBE();

lcd_write(0x28); // Set interface length
lcd_write(0xF); // Display On, Cursor On, Cursor Blink
lcd_clear();    // Clear screen
lcd_write(0x6); // Set entry Mode
}

Для проверки работоспособности используем следующий код:

TRISD = 0x00;
lcd_init();
lcd_goto(0x00);
lcd_puts("LCD 16x2 test");
lcd_goto(0x40);
lcd_puts("Diymicro.ru");

Успех 🙂

Беремся за 2 и 3 пункт.

Прежде всего придется смириться с тем, что придется проворачивать похожие манипуляции как с семисегментными дисплеями, а именно создать массив определений символов. Пока мне нужны только цифры:


const unsigned char digits[10] = {
0b00110000,            //0
0b00110001,            //1
0b00110010,            //2
0b00110011,            //3
0b00110100,            //4
0b00110101,            //5
0b00110110,            //6
0b00110111,            //7
0b00111000,            //8
0b00111001,            //9
};

Все, можно писать функции дежурного отображения:


void display_tt() {                                                 //дежурная функция отображения информации на LCD
unsigned char d;
get_temp();                                                         //берем значение температуры
LCD_RS = 0;
lcd_write(0b00001100);                                              //выключаем курсор
__delay_us(100);
lcd_clear();
d = ReadHour();
lcd_goto(0x05);
lcd_putch(digits[d/10]);                                            //выводим значение часов
d = d - ((d/10)*10);
lcd_putch(digits[d]);
d = 0b00111010;
lcd_putch(d);
d = ReadMin();
lcd_putch(digits[d/10]);                                            //выводим значение минут
d = d - ((d/10)*10);
lcd_putch(digits[d]);
lcd_goto(0x44);
if (!sign) lcd_putch(0b00101011); else lcd_putch(0b10110000);       //знак температуры
d=temperature/10;
lcd_putch(digits[d]);                                               //целое значение температуры
d=temperature-((temperature/10)*10);
lcd_putch(digits[d]);
d = 0b00101110;
lcd_putch(d);                                                       //точка
lcd_putch(digits[temp_drob]);                                       //вывод дробного значения
d = 0b11011111;
lcd_putch(d);                                                       //градус
d = 0b01000011;
lcd_putch(d);                                                       //С

}

Вот что получилось, отладка в разгаре 🙂

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

Допилим прерывания по таймеру, которые служат с целью обновления информации на дисплее. Здесь я решил заюзать таймер TMR2, потому что у меня есть смутные подозрения, что другие два таймера мне еще понадобятся в будущем. Так как нам нужны приличные временные промежутки, то ставим все значения на максимум и получаем импульсы длиной около 16 секунд. Далее, я с помощью переменной флага увеличил этот промежуток в два раза. То есть инфа на дисплея будет обновляться раз в 32 секунды, для меня самое то.


interrupt isr() {

if (TMR2IF) {
update++;

if (update == 255) {
flag++;
update = 0;
}

TMR2 = 0x01;
T2CKPS0 = 1; T2CKPS1 = 1; //1 делитель не делит входную частоту
TOUTPS2 = 1; TOUTPS1 = 1; TOUTPS3 = 1; TOUTPS0 = 1; //2 делитель делит на 5

TMR2IF = 0;  //сброс флага
}

}

Не забываем то, что переменные используемые и в прерываниях и в главной функции должны быть объявлены как volatile.

Закидываю сюда также весь проект, будет и в качестве бэкапа для меня.

Усилитель. Шаг 2. Подключение ЖК дисплея.: 6 комментариев

  1. Вывод цифр можно сделать проще, без масива.

    lcd_clear();
    d = ReadHour();
    lcd_goto(0x05);
    lcd_putch(0x30+d/10);
    С адреса 0x30 знакогенератора расположенны коды цифр от 0 до 9
    последовательно.

    • Не затруднит, например, нам надо вывести число 25 на дисплей, в моей функции отображается только один разряд, то есть:
      1. Выводим цифру 2 = 25/10 (целочисленный тип переменной)
      2. Выводим цифру 5 = 25 – (25/10)*10 (=20)

      • А если в моем случае по UARTу приходит 9 байт данных и я их хочу вывести в 16-ричной форме на экран, то есть по две цифры, например AA FF 1D 3A 55 4D 3E 2E 4A, то как лучше сделать. Cоздать 9 переменных и потом их последовательно в одну строчку выстроить ?

        • Я бы просто переделал свою функцию отображения с помощью струкутры switch(), и последовательно бы все выпихивал на экран.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.