
#define     DC_pin       PORTC.4
#define     CS_pin       PORTC.5
#define     MOSI_pin     PORTC.2   //D1
#define     SCK_pin      PORTC.1   //D0
#define     RESET_pin    PORTC.3
#define     SPI_delay    4

void LCD_init(void);  //начальная инициализация дисплея
void LCD_Goto(unsigned char x, unsigned char y);    //установить координаты
void LCD_Goto2X(unsigned char x, unsigned char y); //установить координаты умноженые на 2
void LCD_Clear(void);  //очистка всего дисплея
void LCD_Contrast(char set_contrast); //настройка контраста от 0 до 255
void LCD_BigNum(unsigned char num);  //вывод больших цифр
void LCD_Char(unsigned int c);  //вывод символа
void LCD_CharBig(unsigned int c); // вывод крупных символов
void LCD_Printf(unsigned char* buf, unsigned char size); //печатает строку с размерами - 0 самый мелкий 2 - увеличиный - 3 самый большой(только для цифр)
void LCD_DrawImage(unsigned char num_image); //выводит картинку из флеш
void LCD_Bat(unsigned char y,unsigned char x, unsigned char z);   //рисует батарейку по координатам z - от 0 до 10 делений
void LCD_Mode(char set_mode); //1 - inverted / 0 - normal
void LCD_Sleep(char set);   //1 - on sleep / 0 - off sleep

#define SSD1306_LCDWIDTH                      128
#define SSD1306_LCDHEIGHT                     64
#define SSD1306_DEFAULT_SPACE                 5
// Commands
#define SSD1306_SETCONTRAST                  0x81
#define SSD1306_DISPLAYALLON_RESUME          0xA4
#define SSD1306_DISPLAYALLON                 0xA5
#define SSD1306_NORMALDISPLAY                0xA6
#define SSD1306_INVERTDISPLAY                0xA7
#define SSD1306_DISPLAYOFF                   0xAE
#define SSD1306_DISPLAYON                    0xAF
#define SSD1306_SETDISPLAYOFFSET             0xD3
#define SSD1306_SETCOMPINS                   0xDA
#define SSD1306_SETVCOMDETECT                0xDB
#define SSD1306_SETDISPLAYCLOCKDIV           0xD5
#define SSD1306_SETPRECHARGE                 0xD9
#define SSD1306_SETMULTIPLEX                 0xA8
#define SSD1306_SETLOWCOLUMN                 0x00
#define SSD1306_SETHIGHCOLUMN                0x10
#define SSD1306_SETSTARTLINE                 0x40
#define SSD1306_MEMORYMODE                   0x20
#define SSD1306_COLUMNADDR                   0x21
#define SSD1306_PAGEADDR                     0x22
#define SSD1306_COMSCANINC                   0xC0
#define SSD1306_COMSCANDEC                   0xC8
#define SSD1306_SEGREMAP                     0xA0
#define SSD1306_CHARGEPUMP                   0x8D
#define SSD1306_EXTERNALVCC                   0x1
#define SSD1306_SWITCHCAPVCC                  0x2
// Scrolling #defines
#define SSD1306_ACTIVATE_SCROLL               0x2F
#define SSD1306_DEACTIVATE_SCROLL             0x2E
#define SSD1306_SET_VERTICAL_SCROLL_AREA      0xA3
#define SSD1306_RIGHT_HORIZONTAL_SCROLL       0x26
#define SSD1306_LEFT_HORIZONTAL_SCROLL        0x27
#define SSD1306_VERT_AND_RIGHT_HORIZ_SCROLL   0x29
#define SSD1306_VERT_AND_LEFT_HORIZ_SCROLL    0x2A

unsigned char LCD_X,LCD_Y;
char buff[];  //буфер дисплея
unsigned char DATA;
unsigned int out=0;



void SPI_SSD_byte (unsigned char byte){
    unsigned char i;
    RESET_pin = 1;
    CS_pin = 0;    
    for (i=0;i<8;i++) { 
    delay_us(SPI_delay/2);
    if (byte & 0x80) MOSI_pin = 1; else MOSI_pin = 0;
    byte<<=1;  
    delay_us(SPI_delay/2);
    SCK_pin = 1;
    delay_us(SPI_delay); 
    SCK_pin = 0;    
};
}

void spi_go() {
  delay_us(SPI_delay);  
  SCK_pin = 0;
  CS_pin = 0; 
  delay_us(SPI_delay);  
}
// заканчиваем общение
void spi_end() {
  delay_us(SPI_delay);
  CS_pin = 1;
  delay_us(SPI_delay);
}


void SSD_command (unsigned char command){
spi_go();
    DC_pin = 0;
    CS_pin = 0;
    SPI_SSD_byte(command);
    CS_pin = 0;
    spi_end();
};

void SSD_data (unsigned char data){
spi_go();
    DC_pin = 1;
    CS_pin = 0;
    SPI_SSD_byte(data);
    CS_pin = 0;
    spi_end();
}

void SSD_clear (){
unsigned int t;
SSD_command(0x21); //установка столбца
SSD_command(0); //Начальный столбец.
SSD_command(127); //Конечный столбец.
SSD_command(0x22); //установка страницы
SSD_command(0); //Начальная страница.
SSD_command(7); //конечная страница.
for ( t = 0; t < 1024; t++) { 
   SSD_command(0x00);//Передаем данные через функцию 
    }
}

void LCD_init (void){
SSD_command(0xAE);//выключение дисплея
SSD_command(0xD5);
SSD_command(0x80);
SSD_command(0xD3);
SSD_command(0x00);
SSD_command(0x40);
SSD_command(0x8D);//включение емкостного умножителя
SSD_command(0x14);
SSD_command(0x20);//настройка адресации
SSD_command(0x00);// 0х00 для горизонтальной, 0х01 для вертикальной, 0х02 для постраничной адресации
SSD_command(0xA1);//отражение по горизонтали, для отображения справа налево необходимо использовать команду 0xA0
SSD_command(0xC8);//отражение по вертикали, 0xC0 для переворота изображения по вертикали.
 
//Одновременное использование команд 0xC8 и 0xA1 или 0xA0 и 0xC0 позволяет повернуть изображение на 180 градусов.
 
SSD_command(0xDA);
SSD_command(0x12);
SSD_command(0x81);//установка контрастности дисплея
SSD_command(0xCF);
SSD_command(0xD9);
SSD_command(0xF1);
SSD_command(0xDB);
SSD_command(0x40);
SSD_command(0xA4);
SSD_command(0xA6);//инверсия дисплея, 0xA6 для отключения инверсии, 0xA7 для включения инверсии цвета.
SSD_command(0xAF);//включение дисплея
SSD_clear();//Используем функцию очистки дисплея.
 }
 









void SSD_Contrast(char set_contrast)
{
  SSD_command(SSD1306_DISPLAYOFF);
  delay_ms(10);
  SSD_command(SSD1306_SETCONTRAST);
  SSD_command(set_contrast);
  SSD_command(SSD1306_DISPLAYON);
}

void LCD_Mode(char set_mode)
{
 if(set_mode==0){ SSD_command(SSD1306_NORMALDISPLAY); }
 if(set_mode==1){ SSD_command(SSD1306_INVERTDISPLAY); }
}

void LCD_Sleep(char set)
{
  if(set==0){SSD_command(SSD1306_DISPLAYOFF);}
  if(set==1){SSD_command(SSD1306_DISPLAYON);}
}

void LCD_Goto(unsigned char x, unsigned char y)
{
    LCD_X = x;
    LCD_Y = y;

    // установка  и настройка
    SSD_command(0xB0 + y);//установить адрес начала координат
    SSD_command(x & 0xf);//установить нижний адрес столбца
    SSD_command(0x10 | (x >> 4));//установить верхний адрес столбца
}


void LCD_Goto2X(unsigned char x, unsigned char y)
{
    LCD_X = x;
    LCD_Y = y;

    // установка  и настройка
    SSD_command(0xB0 + y);//установить адрес начала координат
    SSD_command(2*x & 0xf);//установить нижний адрес столбца
    SSD_command(0x10 | (2*x >> 4));//установить верхний адрес столбца
}

void LCD_Clear(void)
{
  SSD_command(0x21); //установка столбца
SSD_command(0); //Начальный столбец.
SSD_command(127); //Конечный столбец.
SSD_command(0x22); //установка страницы
SSD_command(0); //Начальная страница.
SSD_command(7); //конечная страница.
 for (l = 0; l < 1024; l++){
 
   SSD_data(0x00);//передаем данные, которые необходимо вывести на дисплей. В данном случае 1024 раза передается значение 0x0 и весь дисплей меняет цвет на белый.
 
 };
}

void LCD_Char(unsigned int c)
{
  unsigned char x = 0;    
  SSD_data(DATA);//data mode
  for (x=0; x<5; x++)
	{
     SSD_data(LCD_Buffer[c*5+x]);
     }
  SSD_command(0x00);  //пробел в одну точку между символами
  

	LCD_X = LCD_X + 8;
	if(LCD_X>SSD1306_LCDWIDTH)
	{
		LCD_X = SSD1306_DEFAULT_SPACE;
	}
}

void LCD_BigNum(unsigned char num)
{
  unsigned char x = 0;
  unsigned char z = 0;

  unsigned char y_s = LCD_Y;

  if(num!=46&&num!=32&&num!=32&&num!=67){num = num - 48;}
  else
   {
   if(num==46){ num = 11; }  // .
   if(num==32){ num = 12; }  // space
   if(num==67){ num = 13; }  // градусы
   }

  
  //SSD_data(DATA);//data mode
  for (x=0; x<96; x++)
	{
     SSD_data(BigNum[num][x]);
     if(z>=23)
     {
       LCD_Goto(LCD_X,LCD_Y+1);  
       z=0;
       //SSD_data(DATA);//data mode
     }else{z++;}

     }

	LCD_X = LCD_X + 23;// тут подправил
    LCD_Goto(LCD_X,y_s);
    if(LCD_X>SSD1306_LCDWIDTH)
	{
		LCD_X = SSD1306_DEFAULT_SPACE;
	}
}

void LCD_CharBig(unsigned int c)
{
  unsigned char x = 0;
  unsigned int m = 0;

    //SSD_data(DATA);//data mode
  for (x=0; x<5; x++)
	{
     m = LCD_Buffer[c*5+x];
     SSD_data(m);               ///////////////////////////////////////////////////////
    // SSD_data(m);
     }
  SSD_command(0x00);  //пробел в одну точку между символами
  	LCD_X = LCD_X + 11;// тут подправил
	if(LCD_X>SSD1306_LCDWIDTH)
	{
		LCD_X = SSD1306_DEFAULT_SPACE;
	}
}

void LCD_Printf(unsigned char* buf, unsigned char size) { //выводим строку из буфера

	while (*buf!=0)
	{
       if(size==0)
       {
		if((LCD_X>SSD1306_LCDWIDTH)||(LCD_X<5)){LCD_X=SSD1306_DEFAULT_SPACE;}
		LCD_Char(*buf++);
        }
       if(size==1)
       {
        if((LCD_X>SSD1306_LCDWIDTH)||(LCD_X<5)){LCD_X=SSD1306_DEFAULT_SPACE;}
        LCD_CharBig(*buf++);
       }
       if(size==2)
       {
        if((LCD_X>SSD1306_LCDWIDTH)||(LCD_X<24)){LCD_X=SSD1306_DEFAULT_SPACE;}
        LCD_BigNum(*buf++);
       }
	}
}

void LCD_DrawImage(unsigned char num_image){
	unsigned int i;
	unsigned char x=0;
	unsigned char y=0;
	LCD_Goto(0,0);

	for (i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++)
	{
        if(num_image==0)
        {
		SSD_data(image0[i]);
        }
        if(num_image==1)
        {
		SSD_data(image1[i]);
        }
        if(num_image==2)
        {
		SSD_data(image2[i]);
        }

		x++;
		if(x>=SSD1306_LCDWIDTH)
		{
			x=0;
			y++;
			LCD_Goto(0,y);
		}
	}
}

void LCD_Bat(unsigned char y,unsigned char x, unsigned char z)
{
 unsigned char i=0;

 LCD_Goto2X(x-1,y);
 SSD_data(0xFF); SSD_data(0xFF);
 LCD_Goto2X(x+2,y);
for (i=0; i<14; i++)
	{
       if(i<11)
       {
         if(z>=i){ SSD_data(0xBD); }
         else    { SSD_data(0x81); SSD_data(0x81); }
       }
       if(i==11)      {SSD_data(0xFF); SSD_data(0xFF);}
       if(i==12)      {SSD_data(0x3C); SSD_data(0x3C);}
       if(i==13)      {SSD_data(0x3C); SSD_data(0x3C);}
       LCD_Goto2X(x+i,y);
	}

}

void LCD_Contrast(char set_contrast)
{
  SSD_command(SSD1306_DISPLAYOFF);
  delay_ms(10);
  SSD_command(SSD1306_SETCONTRAST);
  SSD_command(set_contrast);
  SSD_command(SSD1306_DISPLAYON);
}
