Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Для начала пойдем на сайт ST и скачаем Application note AN3114 («How to use the STM8L152x and STM8L162x LCD controllers»). Сходу там идёт овер9000 некоторое количество теории и графиков,



Для начала пойдем на сайт ST и скачаем Application note AN3114How to use the STM8L152x and STM8L162x LCD controllers»).
Сходу там идёт овер9000 некоторое количество теории и графиков, объясняющих основополагающие принципы работы жидких кристаллов и про “ расово верное ” управление дисплеями на их основе. Большинство из этого нам не интересно – такие знания вам потребуются в случае, если надумаете сами писать программный драйвер для управления ЖКИ-дисплеем, как когда-то я.
Всю эту теорию стоит, конечно, просмотреть, но на эту тему информации предостаточно и в более удобоваримом виде. Самое интересное начинается с 18 -й странички, где размещены блок-схемы, иллюстрирующие устройство LCD-контроллера в МК линейки STM8L medium класса и отдельной диаграммой medium+ и high классов, которые включают в себя старших представителей данного семейства и имеют более навороченный LCD -контроллер (8х44).
Наш STM8L152C6T6, который установлен на дискавери, относится к medium классу, поэтому внимательно изучаем соответствующую диаграмму:

Как известно, ЖК требуется для управления переменное напряжение, иначе они быстро деградируют и срок их службы значительно сокращается, более того, даже определённая асимметрия управляющих напряжений приводит к появлению постоянной составляющей, также нежелательной для ЖК. Обычно предельные значения этой составляющей и рекомендуемая частота указываются производителем дисплея. Но в любом случае величина постоянной составляющей не должна превышать 30-50 мВ, а частота выбирается в пределах от 30 Гц до 100 Гц. Очевидно, что при частоте ниже указанной будет появляться визуально наблюдаемое мерцание, но и завышать частоту тоже не стоит, потому что ЖК свойственна существенная инерционность (для переориентирования кристаллов требуется некоторое время).
Если над первым нам можно не заморачиваться, поскольку на то он и драйвер, чтоб формировать «правильные» по форме сигналы, то для получения соответствующей частоты нам придется правильно сконфигурировать блок, именуемый Frequency generator, состоящий из 16-тиразрядного предделителя и делителя.
Но для начала нам надо определиться с источником тактирования. Для этого давайте заглянем в Reference manual RM0031, раздел Clock control на страницу 87, где приведена общая структурная схема системы тактирования контроллера:

Из рисунка видно, что тут у нас есть 4 варианта: HSE, HSI, LSI, LSE.

HSE (high speed external) – внешний источник тактирования высокой частоты (кварц).
HSI (high speed internal) – внутренний RC-генератор высокой частоты.
LSI (low speed internal) – внутренний низкочастотный RC-генератор.
LSE (low speed external) – внешний низкочастотный источник тактирования, например часовой кварц.



Вообще система тактирования у стм-ок устроена достаточно круто, но сейчас мы не будем вдаваться в детали.
Нас интересует тактирование для LCD -драйвера. Если мы посмотрим на приведенный рисунок, то увидим, что “схема сфазирована” таким образом, что цепи тактирования LCD связаны с тактированием RTC (real time counter) и источник тактирования у них должен быть общий. Кроме того, можно заметить, что на приведенной диаграмме формируется два источника тактов, подающихся на LCD -драйвер. Один из них – это RTCCLK/2 и LCDCLK. На основе одного, как можно узреть на первой картинке, формируются управляющие напруги для стекляшки, а второй используется для тактирования самого LCD controller -а, а точнее чтения/записи регистров. Но пока нам это не особо интересно, давайте, наконец, затактируем наш драйвер:


//Подаем тактирование на LCD, RTC:
CLK_PCKENR2 |= (1<<3)|(1<<2);
//Выбираем внешний кварц (LSE) для RTC:
CLK_CRTCR_bit.RTCSEL3 = 1;
//CLK_CRTCR_bit.RTCSEL2 = 0;
//CLK_CRTCR_bit.RTCSEL1 = 0;
//CLK_CRTCR_bit.RTCSEL0 = 0;
//Ожидание стабилизации внешнего кварца:
while(CLK_ECKR_bit.LSERDY==0);

 

все очень элементарно: за тактирование периферии у нас отвечают регистры CLK_PCKENRX, а конкретно за наш LCDCLK_PCKENR2, где мы и устанавливаем соостветствующие биты: 2 — отвечающий за такты RTC и 3 — отвечающий за LCD. Далее, в соответствующем регистре определяем источник тактов для RTC. Думаю из комментариев и так все понятно: источником этих тактов у нас будет внешний низкочастотный кварц.
Выполнив эти операции, рекомендуется дождаться стабильной генерации с кварца. Это конечно не особо критично, но нарушать рекомендации официальной доки рекомендуется лишь любителям решения увлекательных квестов с элементами головоломки (а порою даже триллера), выплывшими в будущем (особенно весело, когда уже в процессе производства).
Итак, тактирование подано, идем дальше:


/*.............Настройка LCD.............*/
//устанавливаем скважность:
LCD_CR1_bit.DUTY1 = 1;/****фактически ****/
LCD_CR1_bit.DUTY0 = 1;/*количество COM-ов*/

LCD_CR2_bit.PON0 = 1;
LCD_CR2_bit.PON1 = 1;
LCD_CR2_bit.PON2 = 1;

//прескаллер n = 2 (коэфициэнт деления будет 2^n, F=(F_RTC/2)/2^n)
//LCD_FRQ_bit.PS3 = 0;/****После прескаллера (32768/2)/4=4096****/
//LCD_FRQ_bit.PS2 = 0;/**и дальше проходит через делитель на 16**/
LCD_FRQ_bit.PS1 = 1;/******что и даст в результате 256 Гц******/
//LCD_FRQ_bit.PS0 = 0;/******частота кадра же равна 256/4 Гц*****/
//включение LCD:
LCD_CR3_bit.LCDEN=1;

//включим 24 ноги для управления сегментами (SEG00 -- SEG23):
LCD_PM0 = (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7);
LCD_PM1 = (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7);
LCD_PM2 = (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7);

 

Здесь мы в регистре LCD_CR1 устанавливаем комбинацию битов DUTY, которая соответствует количеству выводов COM нашего индикатора, что описано в подразделе 17.6.1 на странице 267 Reference manua l. Стекляшка, установленная на дискавери, имеет 4 «общих», соответсвенно — " 11 ".
Биты PON, находящиеся в регистре LCD_CR2, насколько я понял, определяют задержку между изменением уровней на выводах индикатора, как говорит Reference manual " длительность ". Уменьшение этого значения приводит к уменьшению энергопотребления, но для дисплеев с большим внутренним сопротивлением может потребоваться увеличить это значение (видимо время на переориентацию кристаллов?). На практике, с исследуемой стекляшкой лучший результат получился при максимальном значении, уменьшение же этой числа, записываемого в соотв. биты, приводит к появлению незначительной паразитной засветки сегментов.
Дальше мы устанавливаем коэффициенты деления предделителя и делителя, чтобы получить нужное значение частоты для управления дисплеем. Предделитель делит частоту на число, получаемое из двойки, возведенной в степень, которую мы в двоичном виде задаем битами PS[3:0]. На выходе прескаллера, в результате, получим 4096 Гц, которые дальше поступают на основной делитель. По умолчанию биты DIV[3:0], отвечающие за его коэффициент деления равны " 000 ", и это соответствует минимальному коэффициенту деления 16, который равен 16+x, где x= DIV[3:0]. Таким образом получаем 256 Гц. Это будет частота изменения состояний на выводах COM, но так как их у нас 4, то частота кадра (частота, с которой будет происходить полное обновление дисплея) равна 256/4=64 Гц.
Дальше, врубив сам ЖКИ контроллер, установкой бита LCDEN в регистре LCD_CR3, накладываем маску портов для определения задействованных в управлени стекляхой пинов. Те, которые не используются — можно юзать в своих целях. Подробнее про это в том же референс мануале начиная со страницы 270.
Вобщем, я думаю, что никаких сложностей тут не должно возникнуть.
Отдельной функцией было решено написать установку контраста, дабы иметь возможность менять его на лету:

 

void LCD_Contrast(unsigned char cntr)
{
//установка контрастности:
LCD_CR2 |= ((cntr&0x07)<<1);
}


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

В качестве опорного напряжения мы можем выбрать внутренний или внешний источник. Про это, а также многие другие фичи можно подробно прочитать в разделе 17, советую если не полностью, то хотя бы покурить структуру регистров. Там много интересного.
Таким образом, это все, что нам нужно, чтобы завести дисплейчик. Теперь допишем саму библиотеку, чтобы работать с индкатором без напряга, как все нормальные потсоны:

Начнем с определения символьных констант

 

//массив символов цифр
const unsigned int number_mask[] =
{
//0
(1<<A_)|(1<<B_)|(1<<C_)|(1<<D_)|(1<<E_)|(1<<F_)|(0<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(0<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//1
(0<<A_)|(1<<B_)|(1<<C_)|(0<<D_)|(0<<E_)|(0<<F_)|(0<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(0<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//2
(1<<A_)|(1<<B_)|(0<<C_)|(1<<D_)|(1<<E_)|(0<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//3
(1<<A_)|(1<<B_)|(1<<C_)|(1<<D_)|(0<<E_)|(0<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//4
(0<<A_)|(1<<B_)|(1<<C_)|(0<<D_)|(0<<E_)|(1<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//5
(1<<A_)|(0<<B_)|(1<<C_)|(1<<D_)|(0<<E_)|(1<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//6
(1<<A_)|(0<<B_)|(1<<C_)|(1<<D_)|(1<<E_)|(1<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//7
(1<<A_)|(1<<B_)|(1<<C_)|(0<<D_)|(0<<E_)|(0<<F_)|(0<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(0<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//8
(1<<A_)|(1<<B_)|(1<<C_)|(1<<D_)|(1<<E_)|(1<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL),
//9
(1<<A_)|(1<<B_)|(1<<C_)|(1<<D_)|(0<<E_)|(1<<F_)|(1<<G_)|(0<<H_)|(0<<J_)|(0<<K_)|(1<<M_)|(0<<N_)|(0<<P_)|(0<<Q_)|(0<<DP)|(0<<COL)
};


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

 


static unsigned int LCD_Char_Find(unsigned char* symb)
{
unsigned int cur_char;
//если цифра:
if ((*symb <= 0x39) && (*symb >= 0x30))
{
cur_char = number_mask[*symb-'0'];
}
//если буква латинского алфавита:
/* Если символ введён в верхнем регистре*/
else{if ((*symb <= 0x5A) && (*symb >= 0x41))
{
cur_char = char_mask[*symb-'A'];
}
/* Если символ введён в нижнем регистре*/
else{if ((*symb <= 0x7A) && (*symb >= 0x61))
{
cur_char = char_mask[*symb-'a'];
}
//если буква кириллицы:
/* Если символ введён в верхнем регистре*/
else{if ((*symb <= 0xDF) && (*symb >= 0xC0))
{
cur_char = rus_char_mask[*symb-'А'];
}
/* Если символ введён в нижнем регистре*/
else{if (*symb >= 0xE0)
{
cur_char = rus_char_mask[*symb-'а'];
}
else
{
switch (*symb)
{
//если спецсимвол:
case '$':
cur_char = spec_char_mask[0];
break;

case '(':
cur_char = spec_char_mask[1];
break;

case ')':
cur_char = spec_char_mask[2];
break;

case '*':
cur_char = spec_char_mask[3];
break;

case '+':
cur_char = spec_char_mask[4];
break;

case '-':
cur_char = spec_char_mask[5];
break;

case '=':
cur_char = spec_char_mask[6];
break;

default:
cur_char = 0x00;
break;
};
};
};
};
};
};

if(*symb=='m') {cur_char = spec_char_mask[7];}
if(*symb=='u') {cur_char = spec_char_mask[8];}
if(*symb=='n') {cur_char = spec_char_mask[9];}

return(cur_char);
}


и функцию, которая непосредственно выводит полученный символ в соответствующее знакоместо индкатора:

 

void LCD_Write_Char(unsigned char* ch, bool point, bool column, unsigned char position)
{
unsigned int cur_char; /*контейнер для хранения маски символа*/
unsigned char temp[2];

/* Определение соответствующей символу константы*/
cur_char = LCD_Char_Find(ch);
if(position<5)/* В пятом, шестом знакоместе BAR */
{
/* Установка состояния десятичной точки */
if(point){cur_char |= (1<<DP);};
/* Установка состояния двоеточия */
if(column){cur_char |= (1<<COL);};
};

temp[0]=(unsigned char)cur_char;
temp[1]=(unsigned char)(cur_char>>8);

/*Запись маски символа в биты LCD_RAM, соответствующие текущей позиции*/
switch (position)
{
/* Позиция 1 */
case 1:
/*Очистка 1M, 1E*/ /*Запись нового значения 1M, 1E*/
LCD_RAM0 &= ~((1<<1)|(1<<0)); LCD_RAM0 |= temp[0] & ((1<<1)|(1<<0));
/*Очистка 1G, 1B*/ /*Запись нового значения 1G, 1B*/
LCD_RAM2 &= ~((1<<7)|(1<<6)); LCD_RAM2 |= (temp[0]<<4) & ((1<<7)|(1<<6));
/*Очистка 1C, 1D*/ /*Запись нового значения 1C, 1D*/
LCD_RAM3 &= ~((1<<5)|(1<<4)); LCD_RAM3 |= temp[0] & ((1<<5)|(1<<4));
/*Очистка 1F, 1A*/ /*Запись нового значения 1F, 1A*/
LCD_RAM6 &= ~((1<<3)|(1<<2)); LCD_RAM6 |= (temp[0]>>4) & ((1<<3)|(1<<2));
/*Очистка 1COL, 1P*/ /*Запись нового значения 1COL, 1P*/
LCD_RAM7 &= ~((1<<1)|(1<<0)); LCD_RAM7 |= temp[1] & ((1<<1)|(1<<0));
/*Очистка 1Q, 1K*/ /*Запись нового значения 1Q, 1K*/
LCD_RAM9 &= ~((1<<7)|(1<<6)); LCD_RAM9 |= (temp[1]<<4) & ((1<<7)|(1<<6));
/*Очистка 1DP, 1N*/ /*Запись нового значения 1DP, 1N*/
LCD_RAM10 &= ~((1<<5)|(1<<4)); LCD_RAM10 |= temp[1] & ((1<<5)|(1<<4));
/*Очистка 1H, 1J*/ /*Запись нового значения 1H, 1J*/
LCD_RAM13 &= ~((1<<3)|(1<<2)); LCD_RAM13 |= (temp[1]>>4) & ((1<<3)|(1<<2));
break;

/* Позиция 2 */
case 2:
/*Очистка 2M, 2E*/ /*Запись нового значения 2M, 2E*/
LCD_RAM0 &= ~((1<<3)|(1<<2)); LCD_RAM0 |= (temp[0]<<2) & ((1<<3)|(1<<2));
/*Очистка 2G, 2B*/ /*Запись нового значения 2G, 2B*/
LCD_RAM2 &= ~((1<<5)|(1<<4)); LCD_RAM2 |= (temp[0]<<2) & ((1<<5)|(1<<4));
/*Очистка 2C, 2D*/ /*Запись нового значения 2C, 2D*/
LCD_RAM3 &= ~((1<<7)|(1<<6)); LCD_RAM3 |= (temp[0]<<2) & ((1<<7)|(1<<6));
/*Очистка 2F, 2A*/ /*Запись нового значения 2F, 2A*/
LCD_RAM6 &= ~((1<<1)|(1<<0)); LCD_RAM6 |= (temp[0]>>6) & ((1<<1)|(1<<0));
/*Очистка 2COL, 2P*/ /*Запись нового значения 2COL, 2P*/
LCD_RAM7 &= ~((1<<3)|(1<<2)); LCD_RAM7 |= (temp[1]<<2) & ((1<<3)|(1<<2));
/*Очистка 2Q, 2K*/ /*Запись нового значения 2Q, 2K*/
LCD_RAM9 &= ~((1<<5)|(1<<4)); LCD_RAM9 |= (temp[1]<<2) & ((1<<5)|(1<<4));
/*Очистка 2DP, 2N*/ /*Запись нового значения 2DP, 2N*/
LCD_RAM10 &= ~((1<<7)|(1<<6)); LCD_RAM10 |= (temp[1]<<2) & ((1<<7)|(1<<6));
/*Очистка 2H, 2J*/ /*Запись нового значения 2H, 2J*/
LCD_RAM13 &= ~((1<<1)|(1<<0)); LCD_RAM13 |= (temp[1]>>6) & ((1<<1)|(1<<0));
break;

/* Позиция 3 */
case 3:
/*Очистка 3M, 3E*/ /*Запись нового значения 3M, 3E*/
LCD_RAM0 &= ~((1<<5)|(1<<4)); LCD_RAM0 |= (temp[0]<<4) & ((1<<5)|(1<<4));
/*Очистка 3G, 3B*/ /*Запись нового значения 3G, 3B*/
LCD_RAM2 &= ~((1<<3)|(1<<2)); LCD_RAM2 |= temp[0] & ((1<<3)|(1<<2));
/*Очистка 3C, 3D*/ /*Запись нового значения 3C, 3D*/
LCD_RAM4 &= ~((1<<1)|(1<<0)); LCD_RAM4 |= (temp[0]>>4) & ((1<<1)|(1<<0));
/*Очистка 3F, 3A*/ /*Запись нового значения 3F, 3A*/
LCD_RAM5 &= ~((1<<7)|(1<<6)); LCD_RAM5 |= temp[0] & ((1<<7)|(1<<6));
/*Очистка 3COL, 3P*/ /*Запись нового значения 3COL, 3P*/
LCD_RAM7 &= ~((1<<5)|(1<<4)); LCD_RAM7 |= (temp[1]<<4) & ((1<<5)|(1<<4));
/*Очистка 3Q, 3K*/ /*Запись нового значения 3Q, 3K*/
LCD_RAM9 &= ~((1<<3)|(1<<2)); LCD_RAM9 |= temp[1] & ((1<<3)|(1<<2));
/*Очистка 3DP, 3N*/ /*Запись нового значения 3DP, 3N*/
LCD_RAM11 &= ~((1<<1)|(1<<0)); LCD_RAM11 |= (temp[1]>>4) & ((1<<1)|(1<<0));
/*Очистка 3H, 3J*/ /*Запись нового значения 3H, 3J*/
LCD_RAM12 &= ~((1<<7)|(1<<6)); LCD_RAM12 |= temp[1] & ((1<<7)|(1<<6));
break;

/* Позиция 4 */
case 4:
/*Очистка 4M, 4E*/ /*Запись нового значения 4M, 4E*/
LCD_RAM0 &= ~((1<<7)|(1<<6)); LCD_RAM0 |= (temp[0]<<6) & ((1<<7)|(1<<6));
/*Очистка 4G, 4B*/ /*Запись нового значения 4G, 4B*/
LCD_RAM2 &= ~((1<<1)|(1<<0)); LCD_RAM2 |= (temp[0]>>2) & ((1<<1)|(1<<0));
/*Очистка 4C, 4D*/ /*Запись нового значения 4C, 4D*/
LCD_RAM4 &= ~((1<<3)|(1<<2)); LCD_RAM4 |= (temp[0]>>2) & ((1<<3)|(1<<2));
/*Очистка 4F, 4A*/ /*Запись нового значения 4F, 4A*/
LCD_RAM5 &= ~((1<<5)|(1<<4)); LCD_RAM5 |= (temp[0]>>2) & ((1<<5)|(1<<4));
/*Очистка 4COL, 4P*/ /*Запись нового значения 4COL, 4P*/
LCD_RAM7 &= ~((1<<7)|(1<<6)); LCD_RAM7 |= (temp[1]<<6) & ((1<<7)|(1<<6));
/*Очистка 4Q, 4K*/ /*Запись нового значения 4Q, 4K*/
LCD_RAM9 &= ~((1<<1)|(1<<0)); LCD_RAM9 |= (temp[1]>>2) & ((1<<1)|(1<<0));
/*Очистка 4DP, 4N*/ /*Запись нового значения 4DP, 4N*/
LCD_RAM11 &= ~((1<<3)|(1<<2)); LCD_RAM11 |= (temp[1]>>2) & ((1<<3)|(1<<2));
/*Очистка 4H, 4J*/ /*Запись нового значения 4H, 4J*/
LCD_RAM12 &= ~((1<<5)|(1<<4)); LCD_RAM12 |= (temp[1]>>2) & ((1<<5)|(1<<4));
break;

/* позиция 5 */
case 5:
/*Очистка 5M, 5E*/ /*Запись нового значения 5M, 5E*/
LCD_RAM1 &= ~((1<<1)|(1<<0)); LCD_RAM1 |= temp[0] & ((1<<1)|(1<<0));
/*Очистка 5G, 5B*/ /*Запись нового значения 5G, 5B*/
LCD_RAM1 &= ~((1<<7)|(1<<6)); LCD_RAM1 |= (temp[0]<<4) & ((1<<7)|(1<<6));
/*Очистка 5C, 5D*/ /*Запись нового значения 5C, 5D*/
LCD_RAM4 &= ~((1<<5)|(1<<4)); LCD_RAM4 |= temp[0] & ((1<<5)|(1<<4));
/*Очистка 5F, 5A*/ /*Запись нового значения 5F, 5A*/
LCD_RAM5 &= ~((1<<3)|(1<<2)); LCD_RAM5 |= (temp[0]>>4) & ((1<<3)|(1<<2));
/*Очистка 5COL, 5P*/ /*Запись нового значения 5COL, 5P*/
LCD_RAM8 &= ~((1<<1)|(1<<0)); LCD_RAM8 |= temp[1] & ((1<<1)|(1<<0));
/*Очистка 5Q, 5K*/ /*Запись нового значения 5Q, 5K*/
LCD_RAM8 &= ~((1<<7)|(1<<6)); LCD_RAM8 |= (temp[1]<<4) & ((1<<7)|(1<<6));
/*Очистка 5DP, 5N*/ /*Запись нового значения 5DP, 5N*/
LCD_RAM11 &= ~((1<<5)|(1<<4)); LCD_RAM11 |= temp[1] & ((1<<5)|(1<<4));
/*Очистка 5H, 5J*/ /*Запись нового значения 5H, 5J*/
LCD_RAM12 &= ~((1<<3)|(1<<2)); LCD_RAM12 |= (temp[1]>>4) & ((1<<3)|(1<<2));
break;

/* Позиция 6 */
case 6:
/*Очистка 6M, 6E*/ /*Запись нового значения 6M, 6E*/
LCD_RAM1 &= ~((1<<3)|(1<<2)); LCD_RAM1 |= (temp[0]<<2) & ((1<<3)|(1<<2));
/*Очистка 6G, 6B*/ /*Запись нового значения 6G, 6B*/
LCD_RAM1 &= ~((1<<5)|(1<<4)); LCD_RAM1 |= (temp[0]<<2) & ((1<<5)|(1<<4));
/*Очистка 6C, 6D*/ /*Запись нового значения 6C, 6D*/
LCD_RAM4 &= ~((1<<7)|(1<<6)); LCD_RAM4 |= (temp[0]<<2) & ((1<<7)|(1<<6));
/*Очистка 6F, 6A*/ /*Запись нового значения 6F, 6A*/
LCD_RAM5 &= ~((1<<1)|(1<<0)); LCD_RAM5 |= (temp[0]>>6) & ((1<<1)|(1<<0));
/*Очистка 6COL, 6P*/ /*Запись нового значения 6COL, 6P*/
LCD_RAM8 &= ~((1<<3)|(1<<2)); LCD_RAM8 |= (temp[1]<<2) & ((1<<3)|(1<<2));
/*Очистка 6Q, 6K*/ /*Запись нового значения 6Q, 6K*/
LCD_RAM8 &= ~((1<<5)|(1<<4)); LCD_RAM8 |= (temp[1]<<2) & ((1<<5)|(1<<4));
/*Очистка 6DP, 6N*/ /*Запись нового значения 6DP, 6N*/
LCD_RAM11 &= ~((1<<7)|(1<<6)); LCD_RAM11 |= (temp[1]<<2) & ((1<<7)|(1<<6));
/*Очистка 6H, 6J*/ /*Запись нового значения 6H, 6J*/
LCD_RAM12 &= ~((1<<1)|(1<<0)); LCD_RAM12 |= (temp[1]>>6) & ((1<<1)|(1<<0));
break;
/* выходим во всех остальных случаях (некорректный номер позиции)*/
default:
break;
}
}


Вот и все. Осталось только ещё немного облегчить себе жизнь, организовав вывод строки:

 

void LCD_Write_String(unsigned char* str)
{
unsigned char i = 1;

/* Пока не дошли до конца строки
или не вывели 6 символов*/
while ((*str!= 0) && (i < 7))
{
/* Выводим символ в текущее знакоместо */
LCD_Write_Char(str, 0, 0, i);

if(*str == '.')
{
i--;
LCD_Write_Char(str-1, 1, 0, i);
};
if(*str == ':')
{
i--;
LCD_Write_Char(str-1, 0, 1, i);
};

/* перевод указателя на след. символ */
str++;

/* Инкремент номера знакоместа */
i++;
};
}

 

 

Теперь у нас уже совсем все готово. И можно радоваться результатам.

Запилим тестовый проект в IAR е

 


#include "iostm8l152c6.h"
#include "LCD.h"

unsigned long i;
int main(void)
{
CLK_CKDIVR_bit.CKM=0;
LCD_Init();
LCD_Contrast(5);



while(1)
{
LCD_Write_String("Hello ");
for(i=0; i<200000; i++){asm("nop");};
LCD_Write_String(" world");
for(i=0; i<200000; i++){asm("nop");};
};
}

 


Дата добавления: 2015-09-29; просмотров: 22 | Нарушение авторских прав




<== предыдущая лекция | следующая лекция ==>
Этрусские диски из Мальяно | Вставай, страна огромная, Вставай на смертный бой С фашистской силой темною, С проклятою ордой!

mybiblioteka.su - 2015-2024 год. (0.017 сек.)