Міністерство освіти і науки, молоді та спорту України
Національний університет «Львівська політехніка»
ЗВІТ
про виконання лабораторної роботи №4
з курсу «Програмування мікроконтролерів СА»
Тема: «Вивід інформації на LCD-дисплей»
Варіант № 1
Мета роботи:
Зібрати у пакеті симуляції Proteus схему на основі МК ATmega32A та написати програму мовою Ci для реалізації вказазаного алгоритму (таблиця 2).
Завдання:
Таблиця 1.
Завдання
Непарні номери варіантів реалізують 8-ми розрядний інтерфейс LCD для обміну даними, Парні номери варіантів – 4-ри розрядний.
У завданні вказується таймер за допомогою якого потрібно реалізувати відлік інтервалів часу для зазначеного пристрою.
При використанні таймера 2 в асинхронному режимі передбачається, що він тактується від годинникового кварца 32768 Гц.
Тривалість звукових сигналів вибирається студентом самостійно, дотримуючись вказаних меж.
Натиск кожної кнопки супроводжується коротким одинарним сигналом, успішне підтвердження введення даних за допомогою клавіші # супроводжується коротким подвійним сигналом, введення невірних даних за допомогою клавіші # та відміна усієї операції за допомогою клавіші * супроводжується довгим сигналом.
№
п/п
Таймер
відліку часу
Частота тактування, МГц
Клаві-атура
Сиг-нал
Порт даних LCD.
Виводи керування
Алго-ритм
1
T0
7.3728
PORTС
PD7
PORTA
PB(1-3)
1
Таблиця 2. Варіанти пристроїв
№
п/п
Опис алгоритму роботи пристрою
1
Годинник.
Відображає години, хвилини, секунди. Запускається одразу ж при подачі живлення на МК. При співпадінні значень будильника та годинника запускається звуковий сигнал (короткими гудками) тривалістю 0,5-2 хв.
Кнопка A – переводить у режим виставлення годин та хвилин годинника.
Кнопка B – переводить у режим виставлення годин та хвилин будильника.
* Значення годин та хвилин вводиться за допомогою клавіш 0-9. Підтвердження введення за допомогою #, при цьому здійснюється перевірка коректності значень годин та хвилин (від 0 до 59).
Кнопка C – відображає значення поточного будильника.
Кнопка D – активізує/відключає будильник (літера А) після натиснення кнопки С.
Кнопка * – відміна операції, перехід у режим ходу годинника.
/
Рис.1. Схема підключення в пакеті Proteus
Остаточна версія програми:
LCDinit.h (файл ініціалізації дисплей в 8-біт режимі):
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#define RS PB0
#define RW PB1
#define E PB2
void LCDinit (void) {
_delay_ms(40);
//Ініцалізація портів(на вихід) на дисплей
DDRA = 0xFF; //Data
PORTA = 0x00;
DDRB = 0xFF; //Control
PORTB = 0x00;
//Функція установки: шина 8 біт, 2 стрічки, 5х8 точок
PORTB &= ~((1 << RW)|(1 << RS));
PORTA = 0x38;
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
_delay_us(50);
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
_delay_us(50);
//Функція установки: включити дисплей (курсор)
PORTB &= ~((1 << RW)|(1 << RS));
PORTA = 0x0C;
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
_delay_us(50);
//Функція установки: зсуви екрану та курсору
PORTB &= ~((1 << RW)|(1 << RS));
PORTA = 0x04;
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
_delay_us(50);
//Функція установки: очистити дисплей
PORTB &= ~((1 << RW)|(1 << RS));
PORTA = 0x01;
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
}
//Опитування прапорця зайнятості BF (busy flag)
void BF (void) {
DDRA = 0x00; //Data
PORTA = 0xFF;
PORTB &= ~(1 << RS);
PORTB |=(1 << RW);
do {
PORTB &= ~(1 << E);
PORTB |= (1 << E);
_delay_us(0.15);
} while(PINA & (1 << 7));
PORTB &= ~(1 << E);
}
//Запис команди в LCD
void LCD_WriteCommand(unsigned char Command) {
BF(); //Опитування прапорця БФ
PORTB &= ~((1 << RW)|(1 << RS));
//Порт data налаштовуємо на вихід
DDRA = 0xFF; //Data
PORTA = 0x00;
// Bиводимо команду в порт даних
PORTA = Command;
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
}
//Вивід символу на LCD
void LCD_WriteLetter(unsigned char Letter) {
BF(); //Опитування прапорця БФ
PORTB |= (1 << RS);
PORTB &= ~(1 << RW);
//Порт data налаштовуємо на вихід
DDRA = 0xFF; //Data
PORTA = 0x00;
// Bиводимо символ в порт даних
PORTA = Letter;
PORTB |= (1 << E);
_delay_us(0.15);
PORTB &= ~(1 << E);
}
// Функція виводу стрічки на екран LCD
void LCD_WriteStr(volatile char *str) {
for(int i=0;i<255;i++)
if (str[i]=='\0') return;
else LCD_WriteLetter(str[i]);
}
// Функція виводу стрічки, записаної у Flash, на екран LCD.
void LCD_WriteStrPROGMEM(unsigned char *str, unsigned char n) {
for(int i=0;i<255;i++)
if (pgm_read_byte(& (str[i]) )=='\0') return;
else LCD_WriteLetter(pgm_read_byte( &(str[i]) ));
}
// Перехід курсору на нову позицію на екрані LCD.
void LCD_GotoYX(unsigned char Y, unsigned char X) {
if(Y==1) LCD_WriteCommand(((1<<7)|(X-1)));
else LCD_WriteCommand(((1<<7)|(0x40+X-1)));
}
LCD.c (основний файл):
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "LCDinit.h"
#define RS PB0
#define RW PB1
#define E PB2
#define Key_1 0b11101110
#define Key_2 0b11011110
#define Key_3 0b10111110
#define Key_A 0b01111110
#define Key_4 0b11101101
#define Key_5 0b11011101
#define Key_6 0b10111101
#define Key_B 0b01111101
#define Key_7 0b11101011
#define Key_8 0b11011011
#define Key_9 0b10111011
#define Key_C 0b01111011
#define Key_F 0b11100111
#define Key_0 0b11010111
#define Key_E 0b10110111
#define Key_D 0b01110111
PROGMEM unsigned char sixty[60][3] ={
{"00"},{"01"},{"02"},{"03"},{"04"},{"05"},{"06"},{"07"},{"08"},{"09"},
{"10"},{"11"},{"12"},{"13"},{"14"},{"15"},{"16"},{"17"},{"18"},{"19"},
{"20"},{"21"},{"22"},{"23"},{"24"},{"25"},{"26"},{"27"},{"28"},{"29"},
{"30"},{"31"},{"32"},{"33"},{"34"},{"35"},{"36"},{"37"},{"38"},{"39"},
{"40"},{"41"},{"42"},{"43"},{"44"},{"45"},{"46"},{"47"},{"48"},{"49"},
{"50"},{"51"},{"52"},{"53"},{"54"},{"55"},{"56"},{"57"},{"58"},{"59"}
};
unsigned char counter = 0;
volatile unsigned char symbol_pos = 0;
volatile char symbol = -1, type = 0, pinc = 0, E_press = 0, alarm_info = 0, alarm_status = 0, buzzer = 0, buzflag = 0;
volatile unsigned char display = 0;
typedef struct
{
unsigned char second, minute, hour;
} Time;
Time T1 = {10,10,10};
Time T2 = {0,0,0};
Time TA = {0,0,0};
ISR(TIMER0_COMP_vect) { // Таймер Т0 по співпадінню, кожні 10 мсек.
counter++;
buzzer=(buzzer+1)%10;
if (counter == 100) {
if(++T2.second == 60) {
T2.second = 0;
if(++T2.minute == 60)
{
T2.minute = 0;
if(++T2.hour == 24)
T2.hour = 0;
}
}
counter = 0;
}
if(display==0)
{
LCD_GotoYX(2,5);
LCD_WriteStrPROGMEM(sixty[T2.hour],2);
LCD_WriteLetter(':');
LCD_WriteStrPROGMEM(sixty[T2.minute],2);
LCD_WriteLetter(':');
LCD_WriteStrPROGMEM(sixty[T2.second],2);
if (alarm_status == 1) {
LCD_GotoYX(2,16);
LCD_WriteLetter('A');
if (TA.hour == T2.hour && TA.minute == T2.minute) {
if ((buzzer == 0) && (buzflag == 0) && (T2.second < 59)) {
PORTD = 0xFF;
buzflag = 1;
} else if ((buzzer == 0) && (buzflag == 1)) {
buzflag = 0;
PORTD = 0x00;
}
}
} else {
LCD_GotoYX(2,16);
LCD_WriteLetter(' ');
}
}
}
void main()
{
initialization();
sei();
unsigned char freePIN=1, key=1;
while (1) // основний робочий цикл
{
if(freePIN == 1) // перевірка чи була натиснута кнопка
{ // якщо =1, тоді ще не натисалася
if(PINC != 0xF0)
{
PORTD |= 1<<7; // включаємо бузер
_delay_ms(100);
freePIN = 0;
// Визначення натиснутої клавіші
// почергова подача 0V на рядки клавіатури A,B,C,D
PORTC = 0b11111110; // A-рядок
if(PORTC == PINC)
{
PORTC = 0b11111101; // B-рядок
if(PORTC == PINC)
{
PORTC = 0b11111011; // C-рядок
if(PORTC == PINC)
{
PORTC = 0b11110111; // D-рядок
if(PORTC == PINC)
key=0; // жодна клавіша не натиснута
}
}
}
if(key==1) // визначення натиснутої клавіші
{
LCD_WriteCommand(0X01); // очистити LCD
display = 1; // вимкнення відображення годинника
if(PINC == Key_1) {
symbol = 1;
setup('1');
}
if(PINC == Key_2) {
symbol = 2;
setup('2');
}
if(PINC == Key_3) {
symbol = 3;
setup('3');
}
if(PINC == Key_4) {
symbol = 4;
setup('4');
}
if(PINC == Key_5) {
symbol = 5;
setup('5');
}
if(PINC == Key_6) {
symbol = 6;
setup('6');
}
if(PINC == Key_7) {
symbol = 7;
setup('7');
}
if(PINC == Key_8) {
symbol = 8;
setup('8');
}
if(PINC == Key_9) {
symbol = 9;
setup('9');
}
if(PINC == Key_0) {
symbol = 0;
setup('0');
}
if(PINC == Key_A) {
type = 1;
symbol = -1;
symbol_pos = 0;
setup('A');
}
if(PINC == Key_B) {
type = 2;
symbol_pos = 0;
symbol = -1;
setup('B');
}
if(PINC == Key_C) {
if (pinc == 1) {
pinc = 0;
LCD_WriteCommand(0X01);
display = 0;
E_press = 0;
type = 0;
symbol_pos = 0;
T1.hour = 10;
T1.minute = 10;
} else {
pinc = 1;
}
symbol = -1;
setup('C');
}
if(PINC == Key_D) {
symbol = -1;
symbol_pos = 0;
if (pinc == 1)
alarm_info = 1;
setup('D');
}
if(PINC == Key_E) {
if (type != 0)
E_press = 1;
symbol = -1;
symbol_pos = 0;
setup('E');
}
if(PINC == Key_F) {
display = 0; // вкл. відобр. годинника
E_press = 0;
type = 0;
pinc =0;
symbol_pos = 0;
T1.hour = 10;
T1.minute = 10;
LCD_WriteCommand(0X01);
}
}
key=1;
_delay_ms(300);
PORTC = 0xF0; // відновлюємо порт
PORTD &= ~(1<<7); // виключаємо бузер
}
}
else
if(PINC == 0xF0) // перевіряємо чи кнопка відпущена
{
_delay_ms(100);
freePIN=1;
}
}
}
void setup (unsigned char value) {
//Якшо натиснута кнопка Е
if (E_press == 1) {
if (type == 1) {
if (T1.hour < 24 && T1.minute < 60) {
T2.hour = T1.hour;
T2.minute = T1.minute;
symbol_pos = 0;
type = 0;
T1.hour = 10;
T1.minute = 10;
LCD_WriteCommand(0X01);
E_press = 0;
display = 0;
PORTD |= 1<<7;
_delay_ms(100);
PORTD &= ~(1<<7);
_delay_ms(100);
PORTD |= 1<<7;
_delay_ms(100);
PORTD &= ~(1<<7);
} else {
LCD_GotoYX(1,2);
LCD_WriteStr("Incorrect time");
_delay_ms(1000);
LCD_WriteCommand(0X01);
E_press = 0;
symbol_pos = 0;
T1.hour = 10;
T1.minute = 10;
}
}
if (type == 2) {
if (T1.hour < 24 && T1.minute < 60) {
TA.hour = T1.hour;
TA.minute = T1.minute;
symbol_pos = 0;
type = 0;
T1.hour = 10;
T1.minute = 10;
LCD_WriteCommand(0X01);
E_press = 0;
display = 0;
PORTD |= 1<<7;
_delay_ms(100);
PORTD &= ~(1<<7);
_delay_ms(100);
PORTD |= 1<<7;
_delay_ms(100);
PORTD &= ~(1<<7);
} else {
LCD_GotoYX(1,2);
LCD_WriteStr("Incorrect time");
_delay_ms(1000);
LCD_WriteCommand(0X01);
E_press = 0;
symbol_pos = 0;
T1.hour = 10;
T1.minute = 10;
}
}
}
//Якшо натиснута кнопка С
if (pinc == 1) {
LCD_GotoYX(1,4);
LCD_WriteStr("Alarm Time");
LCD_GotoYX(2,7);
LCD_WriteStrPROGMEM(sixty[TA.hour],2);
LCD_WriteLetter(':');
LCD_WriteStrPROGMEM(sixty[TA.minute],2);
if (alarm_info == 1 && alarm_status == 0) {
alarm_status = 1;
alarm_info = 0;
} else if (alarm_info == 1 && alarm_status == 1) {
alarm_status = 0;
alarm_info = 0;
}
if (alarm_status == 1) {
LCD_GotoYX(2,16);
LCD_WriteLetter('A');
}
if (alarm_status == 0) {
LCD_GotoYX(2,16);
LCD_WriteLetter(' ');
}
return;
}
//Якшо уст. годинника і натиснута кнопка цифрова
if (type == 1 && symbol != -1) {
if (symbol_pos == 5) {
symbol_pos = 0;
T1.hour = 10;
T1.minute = 10;
}
if (symbol_pos == 1) {
T1.hour *= symbol;
LCD_GotoYX(2,7);
LCD_WriteLetter(value);
}
if (symbol_pos == 2) {
T1.hour += symbol;
LCD_GotoYX(2,8);
LCD_WriteLetter(value);
}
if (symbol_pos == 3) {
T1.minute *= symbol;
LCD_GotoYX(2,10);
LCD_WriteLetter(value);
}
if (symbol_pos == 4) {
T1.minute += symbol;
LCD_GotoYX(2,11);
LCD_WriteLetter(value);
}
LCD_GotoYX(1,4);
LCD_WriteStr("Clock Setup");
LCD_GotoYX(2,9);
//LCD_WriteStrPROGMEM(sixty[T1.hour],2);
LCD_WriteLetter(':');
//LCD_WriteStrPROGMEM(sixty[T1.minute],2);
symbol_pos++;
return;
}
//Якшо уст. будильника і натиснута кнопка цифрова
if (type == 2 && symbol != -1) {
if (symbol_pos == 5) {
symbol_pos = 0;
T1.hour = 10;
T1.minute = 10;
}
if (symbol_pos == 1) {
T1.hour *= symbol;
LCD_GotoYX(2,7);
LCD_WriteLetter(value);
}
if (symbol_pos == 2) {
T1.hour += symbol;
LCD_GotoYX(2,8);
LCD_WriteLetter(value);
}
if (symbol_pos == 3) {
T1.minute *= symbol;
LCD_GotoYX(2,10);
LCD_WriteLetter(value);
}
if (symbol_pos == 4) {
T1.minute += symbol;
LCD_GotoYX(2,11);
LCD_WriteLetter(value);
}
LCD_GotoYX(1,4);
LCD_WriteStr("Alarm Setup");
LCD_GotoYX(2,9);
//LCD_WriteStrPROGMEM(sixty[TA.hour],2);
LCD_WriteLetter(':');
//LCD_WriteStrPROGMEM(sixty[TA.minute],2);
symbol_pos++;
return;
}
display = 0;
}
// Ініціалізація заліза
void initialization (void) {
// Ініціалізація портів з підт. резистр.
// Порт A на вхід
DDRA = 0x00;
PORTA = 0xFF;
// Порт B на вихід
DDRB = 0xFF;
PORTB = 0x00;
// Порт С клавіатура: рядки на вихід, стовпці на вхід
DDRC = 0x0F;
PORTC = 0xF0;
// Порт D на вихід
DDRD = 0xFF;
PORTD = 0x00;
LCDinit(); //Ініціалізація ЛСД
// Ініціалізація таймера
TIMSK|=(1<<OCIE0); // Дозволити переривання по співпаданню.
OCR0=0x48; // Частота 7,3728 МГц, 10ms - 72 такта.
TCCR0|=(1<<WGM01)|(1<<CS00)|(1<<CS02); // Ділити частоту на 1024.
}
/
Рис.2. Результати роботи програми
Висновок:
На даній лабораторній роботі ми освоїли принципи ініціалізації LCD дисплею RC1602A-GGN-CSX (Raystar) (сумісний з HD44780), навчилися працювати з клавіатурою 4×4. Результатом лабораторної роботи стала програма мовою Сі для реалізації годинника з виводом даних на LCD дисплей.