#define F_CPU 16000000UL //Частота в герцах(16МГц)
#include <avr/io.h> //Библиотека для упрощённой работы с вводами/выводами (_BV, и др.)
#include <util/delay.h> //Библиотека с функциями задержек
#include <stdio.h> //Standart Input Output Library (Библиотека Стандартного Ввода Вывода, sprintf, и др...)
#include <stdbool.h> //Библиотека с битовой переменной типа bool(1/0)
//----------------------------------------
#define e1 PORTB|=_BV(PB5) // установка линии E в 1
#define e0 PORTB&=~_BV(PB5) // установка линии E в 0
#define a1 PORTB|=_BV(PB4) // установка линии A в 1 (данные)
#define a0 PORTB&=~_BV(PB4) // установка линии A в 0 (команда)
//----------------------------------------
//Пример функции с описанием
int simp(int num, char c, unsigned char uc, bool logic)
/*
int - тип значенечиния возвращаемого функцией (после оканчание её работы)
simp - имя функции
(int num, char c, unsigned char uc, bool log) - аргументы передоваемые в функцию
int num - аргумент типа int(сокр от integer(целочисленный)
в avr может содержать цифры -32768 до +32767) и занимает 2 байта
с именем num
внутри функции виден как переменная типа int по имени num
char c - аргумент(переменная) типа char(содержит коды символов в диапазоне -128 до +127 и занимает 1 байт)
и именем с
unsigned char uc (unsigned (беззнаковая) переменная типа char (содержит от 0 до +255) также 1 байт)
bool logic битавай переменная может содержать 0 либо 1
*/
{//Начало тела функции
/*что-то делаем*/
return num-logic;
/*return значение;
значение возврощаемое при выходе из функции
можно получит след обр
int var = simp(3, 'd', 34, 1);
var будет содержать возворщённое значение в данном случае 2
*/
}//конец тела функции
unsigned int voltage_ADC ;//переменная результата напряжения
ISR (ADC_vect)//прерывание по завершению преобразования АЦП
{
voltage_ADC = ADCW;//считываем значение АЦ преобразования
ADCSR |= (1<<ADSC);//запускаем очередное преобразование
}
//Объявление прототипов функций для вызова функции из другой функции
// нужно что бы функция вызываемая в новой была либо выше, либо обьявлена тут
void LCD_ini();
void ADC_ini();
void setpos(unsigned char, unsigned char);
void str_lcd (char str1[]);
void sendhalfbyte(unsigned char);
void sendbyte(unsigned char, unsigned char);
void clearlcd();
void port_init();
//----------------------------------------
void sendhalfbyte(unsigned char c) //Передача 4 бит
{
e1; //включаем линию Е
PORTC=0b00000000; //стираем информацию на входах DB4-DB7
_delay_us(250);
PORTC|=c; //Передаём данные из переменной c
_delay_us(50);
e0; //выключаем линию Е
_delay_us(250);
PORTC=0x00; //16 запись, эквивалентно 0b00000000 в двоичном виде
}
//----------------------------------------
void sendbyte(unsigned char c, unsigned char mode) //Передача полных 8 бит
{
if (mode==0) a0;//Если mode = 1 установка режима команд(A=0)
else a1;//в противно случае установка режима передачи данных(A=1)
unsigned char hc=0;//объявление временной переменной для старших 4 бит
hc=c>>4; //Отделение 4 старших бит из переменной с, в переменную hc
sendhalfbyte(hc);//Отправка 4 старших бит
sendhalfbyte(c);//Отправка оставшихся 4 младших бит
}
//----------------------------------------
void setpos(unsigned char x, unsigned char y)//Функция установки позиции курсора
{
char adress;//Временная переменная адреса
/************************************************************************/
/*0b1ХХХХХХХ Установка адреса в память дисплея для последующей записи символов,
где ХХХХХХХ адрес.
0b00000000 (адрес 0 символа, 0 строки на дисплее)
0b01000000 (адрес 0 символа, 1 строки на дисплее)
*/
/************************************************************************/
adress=(0x40*y+x)|0b10000000; //0x40(0b01000000) смещение второй строки
//установка курсора в позицию
// 0x40 *y+ x |0b10000000=adress
//x=0 символ y=0 строки (0x01000000*0+0b00000000)|0b10000000=0b10000000
//x=0 символ y=1 строки (0x01000000*1+0b00000000)|0b10000000=0b11000000
//x=1 символ y=0 строки (0x01000000*0+0b00000001)|0b10000000=0b10000001
//x=1 символ y=1 строки (0x01000000*1+0b00000001)|0b10000000=0b11000001
//x=5 символ y=0 строки (0x01000000*0+0b00000101)|0b10000000=0b10000101
//x=5 символ y=1 строки (0x01000000*1+0b00000101)|0b10000000=0b11000101
sendbyte(adress, 0); //Отправка команды
_delay_us(50);
}
//----------------------------------------
void LCD_ini(void)
{
_delay_ms(20); //Ждем 20 мс (стр 5)
//Начальная инициализация дисплея для работы в 4х битном режими
sendhalfbyte(0b00000011);
_delay_us(40);
sendhalfbyte(0b00000011);
_delay_us(40);
sendhalfbyte(0b00000011);
_delay_us(40);
sendhalfbyte(0b00000010);
_delay_us(40);
//Отправка команд установки параметров дисплея
sendbyte(0b00101000, 0); //0b001(DL)10(P)0, 4 бит-режим DL=0(8бит-зежим DL=1), P - Таблица знакогенератора
_delay_ms(1);
sendbyte(0b00001100, 0); //включаем изображение на дисплее (D=1), курсоры никакие не включаем (C=0, B=0)
_delay_ms(1);
sendbyte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
_delay_ms(1);
}
//----------------------------------------
void clearlcd()
{
sendbyte(0b00000001, 0);//Отправка команды очистки дисплея
_delay_us(1500);
}
//----------------------------------------
void str_lcd (char str1[]) //Функция вывода строки
{
int n; //Временная переменная счётчика
for(n=0;str1[n]!='\0';n++) {//Посимвольный перебор строки до символа '\0'(Конец строки)
sendbyte(str1[n],1);//Вывод 1 символа
}
}
//----------------------------------------
void port_ini(void)//Инициализация портов
{
DDRB|=_BV(PB5)|_BV(PB4); //Установка PB4 - E, PB5 - A, в режим вывода DDRB=0b00110000;
DDRC=0b00001111;//Установка PC0-PC3(DB4-DB7) в режим вывода
DDRD&=~_BV(PD2);
DDRD&=~_BV(PD3); //Установка PD3-PD2 в режим ввода
PORTC=0x00;//Установка PC(0-7) в лог 0(GND)
PORTB=0x00;//Установка PB(0-7) в лог 0(GND)
PORTD|=_BV(PD2)|_BV(PD3); //Включение внутренних подтягивующих PD2-PD3 (к +пит) резисторов //DDRD|=_BV(PD2)|_BV(PD3); //Установка PD3-PD2 в режим ввода
}
//----------------------------------------
void ADC_ini() {
// 7 6 5 4 3 2 1 0
//ADMUX = REFS1 REFS0 ADLAR – MUX3 MUX2 MUX1 MUX0
ADMUX |= (1<<REFS0);//в качестве опорного - напряжение питания, результат выравнивается вправо, 0-й канал АЦП (PC0)
// 7 6 5 4 3 2 1 0
//ADCSRA = ADEN ADSC ADFR ADIF ADIE ADPS2 ADPS1 ADPS0
ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS1) | (1<<ADPS0);//разрешаем преобразование, запускаем его, разрешаем прерывание от АЦП
//тактовую частоту делим на 8 - получаем частоту преобразования 125 кГц
}
//----------------------------------------
int main(void)
{
port_ini(); //Инициализируем порты
LCD_ini(); //Инициализируем дисплей
ADC_ini(); //Инициализируем АЦП
sei(); //разрешение прерываний
clearlcd(); //Очистка индикатора
setpos(0,0); //Установка позиции курсора на 0 строку 0 символ
char tmp[18]; //Временный буфер для строки (количество символов + символ конца строки + 1 на всякий случай)) )
int i = 2017; //Пример переменной (В данном случае год)
//clearlcd();
// sendbyte(0b00101010, 0); //смена таблицы символов из 0 в 1
sprintf(tmp, "#Mac%cepa %d", 0xbf, i); //Заполнение буферной переменной
str_lcd(tmp); //Вывод данных на дисплей
setpos(0,1); //Установка курсора на 1 строку 0 символ
sprintf(tmp, "Bc%c%ca%c xpe%c%c", 0xC7, 0xBA, 0xC7, 0xBD, 0xC4); //Заполнение буферной переменной
str_lcd(tmp); //Вывод данных на дисплей
_delay_ms(3000);
clearlcd();
bool d_upd=0; //Переменная для флага очистки дисплея
while(1)
{
if(d_upd==1) //В случае присутствия флага очистка дисплея
{
clearlcd(); //Очистка дисплея
d_upd=0; //Сброс флага очистки
sprintf(tmp, "ADC0=%d",voltage_ADC);
str_lcd(tmp); //Вывод данных на дисплей
}
if(!(_BV(PD2)& PIND)) //Если на входе PD2 уст лог 0 (Кнопка Menu нажата)
{
setpos(0,1); //Установка курсора на 1 строку 0 символ
str_lcd("MENU BUT PRESSED"); //Вывод данных на дисплей
d_upd=1; //Установка флага очистки
while(!(_BV(PD2)& PIND)) { //Ожидания отпуска кнопки
_delay_ms(500); //Задержка 0.5 сек для компенсации дребезга
}
}
else if(!(_BV(PD3)& PIND)) //Если на входе PD3 уст лог 0 (Кнопка OK нажата)
{
setpos(0,1); //Установка курсора на 1 строку 0 символ
str_lcd("OK BUT PRESSED "); //Вывод данных на дисплей
d_upd=1;; //Установка флага очистки
while(!(_BV(PD3)& PIND)) { //Ожидания отпуска кнопки
_delay_ms(500); //Задержка 0.5 сек для компенсации дребезга
}
}
}
}