//ATmega_8A + max7219
//16MHz

#define F_CPU 16000000UL                                     //тактовая частота мк (unsigned long)
#include <avr/io.h>                                          //подключение библиотеки "ввод/вывод" мк
#include <util/delay.h>                                      //подключение библиотеки "пауза" мк
#include <avr/interrupt.h>                                   //подключение библиотеки "прерывание" мк

#define CLK_0 PORTC &= ~(1<<PORTC0)                          //отправить 0 на вывод Clk микросхемы MAX7219
#define CLK_1 PORTC |=1<<PORTC0                              //отправить 1 на вывод Clk микросхемы MAX7219
#define CS_0 PORTC &= ~(1<<PORTC1)                           //отправить 0 на вывод Cs микросхемы MAX7219
#define CS_1 PORTC |=1<<PORTC1                               //отправить 1 на вывод Cs микросхемы MAX7219
#define DIN_0 PORTC &= ~(1<<PORTC2)                          //отправить 0 на вывод Din микросхемы MAX7219
#define DIN_1 PORTC |= 1<<PORTC2                             //отправить 1 на вывод Din микросхемы MAX7219
#define measure 64                 // по результатам 64 измерений вычислить среднее значение measure/64

unsigned int Digit[8]; //массив беззнаковых целочисленных переменных Digit из 8 переменных
unsigned char Data_In[8]; //массив беззнаковых обнобайтных символьных переменных Data_In из 8 переменных (адреса и команды для конфигурирования драйвера)
unsigned int Display1_ADC; //беззнаковая целочисленная переменная Display1_ADC
unsigned int Display2_ADC; //беззнаковая целочисленная переменная Display2_ADC
unsigned char X; //беззнаковая однобайтная символьная переменная X (значение регистра ацп с результатом оцифровки напряжения)
unsigned char I; //беззнаковая однобайтная символьная переменная I (значение регистра ацп с результатом оцифровки тока)

//--- инициализация PB1 ---
void PB1_ini(void) //функция инициализации порта PB1 (выход запуска генератора -Vsup = -5v0)
{
	DDRB |= (1<<1); //PB1 на вывод (OC1A)
	PORTB &= ~(1<<1); //PB1 сброс
}
//--- инициализация таймера OC1A ---
void inverter_ini(void) //функция таймера
{
	ASSR=0x00; //сбрасываем полностью регистр assr
    TCCR1A |= ((1<<COM1A1)|(1<<WGM10)); //Fast PWM oc1a, Clear OC1A on Compare Match, clkT2S/1 (no prescalling)
	TCCR1B |= ((1<<WGM12)|(1<<CS10)); 
	TCNT1H=0x00; // Timer Value = 0 сброс счётного регистра таймера 1
	TCNT1L=0x00;
	OCR1AH=0x00; //Output Compare Register = dec85 - заполнение шим DC~68%
	OCR1AL=0x55;
	TIMSK=0x00; //сброс регистра timsk
}
//--- инициализация шины SPI ---
void SPI_ini(void)
{
	DDRC = 0x07; //биты PC0-PC2 порта PC на вывод
	PORTC &= ~((1<<2)|(1<<1)|(1<<0)); //PC0-PC2 сброс
}

//--- функция отправки данных в драйвер max7219 ---
void Send_max7219(unsigned char Adres_Reg,unsigned char Data_In_Write)
{
  unsigned char Adres_Reg_Copy;
  
  Data_In[Adres_Reg] = Data_In_Write; 
  Adres_Reg_Copy = Adres_Reg;	            //создадим копию значения переменной Adres_Reg
				
  CS_0;                                     //отправим «0» на вывод CS микросхемы MAX7219, чтобы начать процесс передачи адреса и данных	
  asm("nop");                               //пауза в 1 такт
	
  for(I=0;I<8;I++)                          //цикл от 0 до 7 с шагом 1, для побитной отправки байта адреса в микросхему MAX7219	
  {
    if((Adres_Reg & 0x80)==0x80)            //если 7 бит переменной Adres_reg=1 
	{
	  DIN_1;                                //отправим 1 на вывод Din микросхемы MAX7219
	}
	else                                    //если 7 бит переменной Adres_reg=0
	{
	  DIN_0;                                //отправим 0 на вывод Din микросхемы MAX7219
	}
	
	//создадим тактовый импульс на выводе CLK микросхемы MAX7219
	asm("nop");                             //пауза в 1 такт                        
	CLK_1;                                  //отправим 1 на вывод Clk микросхемы MAX7219
	asm("nop");                             //пауза в 1 такт
	CLK_0;                                  //отправим 0 на вывод Clk микросхемы MAX7219
	Adres_Reg <<= 1;                        //сдвинем значение переменной Adres_reg на 1 бит влево
  }                                         //выйдем из цикла когда i станет равной 7, т.е. когда отправка байта адреса в микросхему MAX7219 будет окончена
	
  for(I=0;I<8;I++)                          //цикл от 0 до 7 с шагом 1, для побитной отправки байта данных в микросхему MAX7219
  {                                               
    if((Data_In[Adres_Reg_Copy] & 0x80)==0x80) //если 7 бит переменной Data_in=1
	{
	  DIN_1;                                //отправим 1 на вывод Din микросхемы MAX7219
	}
	else                                    //если 7 бит переменной Data_in=0
	{
	  DIN_0;                                //отправим 0 на вывод Din микросхемы MAX7219
	}
	
	//создадим тактовый импульс на выводе CLK микросхемы MAX7219
	asm("nop");                             //пауза в 1 такт
	CLK_1;                                  //отправим 1 на вывод Clk микросхемы MAX7219
	asm("nop");                             //пауза в 1 такт
	CLK_0;                                  //отправим 0 на вывод Clk микросхемы MAX7219
	Data_In[Adres_Reg_Copy] <<= 1;          //сдвинем значение переменной Data_in на 1 бит влево
  }
                                            //выйдем из цикла когда i станет равной 7, т.е. когда отправка байта данных в микросхему MAX7219 будет окончена
  CS_1;                                     //отправим «1» на вывод CS микросхемы MAX7219, чтобы завершить процесс передачи адреса и данных
}                                             

//********************* Инициализация MAX7219 *****************                       
void MAX7219_ini()                      
{                                             
  Send_max7219(0x09,0x7F);                 //включаем режим BCD code B, для 7 разрядов
  Send_max7219(0x0A,0x0A);                 //яркость свечения сегментов 10 (от 0 до 15)
  Send_max7219(0x0B,0x07);                 //число используемых разрядов (7 разрядов)
  Send_max7219(0x0C,0x01);                 //отключаем режим энергосбережения (Shutdown)
} 

//******** Функция вывода значений на 7 сегм.индикатор №1 ******                       
void ledprint_1(unsigned int number)                      
{ 
 Digit[7]=number/100;                                   //сотни
 Digit[6]=number%100/10;                                //десятки
 Digit[6]=Digit[6]|128;                                 //вкл децимальную точку в разряде Digit_6
 Digit[5]=number%10;                                    //единицы 
 
  
 for(X=5;X<8;X++)
 {
   Data_In[X] = Digit[X];
   Send_max7219(X,Data_In[X]);
 }
}

//******** Функция вывода значений на 7 сегм.индикатор №2 ******                       
void ledprint_2(unsigned int number)                      
{ 
 Digit[4]=15;                                           //Отключим не используемую цифру старшего разряда индикатора №2
 Digit[3]=number/100;                                   //сотни
 Digit[2]=number%100/10;                                //десятки
 Digit[2]=Digit[2]|128;                                 //вкл децимальную точку в разряде Digit_2
 Digit[1]=number%10;                                    //единицы
  
 for(X=1;X<5;X++)
 {
   Data_In[X] = Digit[X];
   Send_max7219(X,Data_In[X]);
 }
}

//--- инициализация ацп ---
void ADC_ini(void)
{
   ADCSRA |= ((1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)); //разрешение использования АЦП, предделитель 16M/128 = 125 кГц
   ADMUX &= ~((1<<REFS0)|(1<<REFS1)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0)); //внешний источник опорного напряжения Aref, сброс канала АЦП на 0 
}

//*************************** Функция измерения напряжения на входах АЦП ***************************
unsigned long ADC_Convert (unsigned char ch_ADC) 
{
  unsigned char set_admux = ADMUX; //переменная для выбора канала АЦП
  set_admux &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0)); //сброс канала АЦП на 0
  switch(ch_ADC)
  {
	  case 3: set_admux |= ((0<<MUX3)|(0<<MUX2)|(1<<MUX1)|(1<<MUX0)); //выберем MUX3
	  break; 
	  case 4: set_admux |= ((0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(0<<MUX0)); //выберем MUX4 
	  break;
	  default: break; //сброс кана АЦП на 0 
  }
  ADMUX = set_admux; //присвоим регистру ADMUX значение переменной set_admux
  _delay_us(10);
  unsigned int adc_value = 0; //сброс переменной для хранения результата усреднения n-замеров АЦП
  for(unsigned char i=0;i<64;i++)
  {
	  ADCSRA |= (1<<ADSC); //запуск АЦП
	  while((ADCSRA &(1<<ADSC))); //ожидание окончания преобразования
	  adc_value += ADCW; //adc_value = adc_value+ADCW прибавим к сумме значений предыдущих измерений значение очередного измерения
  }
	  return(unsigned int)adc_value/measure; //выйдем из функции и вернём среднее значение (из регистров результата ADCL и ADCH)
 }                                           //в переменную типа (unsigned int)
  
 //************************** Основная функция с бесконечным циклом *******************************
int main(void)
{
  PB1_ini(); //инициализация порта PB1
  inverter_ini(); //инициализация инвертора +5v >> -5v
  OCR1AH = 0x00; //запись в регистр сравнения...
  OCR1AL = 0x55; //...числа dec85
  SPI_ini(); //инициализация шины SPI  
  MAX7219_ini(); //инициализация MAX7219
  ADC_ini(); //инициализация АЦП
//-------------------------------------------
  while(1)
  {  	  	  
	Display1_ADC = ADC_Convert(3); //Считаем значение с 3 канала АЦП
    ledprint_1(Display1_ADC); //Отправим считанное значение в функцию вывода на индикатор №1
	_delay_ms(200); 
  
    Display2_ADC = ADC_Convert(4); //Считаем значение с 4 канала АЦП
    ledprint_2(Display2_ADC); //Отправим считанное значение в функцию вывода на индикатор №2
	_delay_ms(200);
  }
}








