#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 сек для компенсации дребезга
		}
	  }
  }
}

 

Вам может также понравиться...

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

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