Введите текст заголовка

// Использование таймера в режиме захвата. Измерение ширины, 
// скважности импульса и частоты сигнала
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
unsigned char OVF_counter, zamer_1, zamer_T, zamer_t, duty;
unsigned long t, T, f;
unsigned int rising_1, rising_2, falling;
// Прерывание по переполнению Таймера/счетчика 1
ISR(TIMER1_OVF_vect)
{
OVF_counter++; // Увеличиваем счетчик переполнений
}
// Прерывание по захвату Таймера/счетчика 1
ISR(TIMER1_CAPT_vect)
{
switch(zamer_1)
  {
    case 0: // Вычисляем ширину импульса
      switch(zamer_t)
	  {
      case 0:
	  rising_1 = ICR1; // Запоминаем значениие счётчика 
      TCCR1B &= ~(1 << ICES1); // Устанавливаем прерывание по спадающему фронту импульса
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_t = 1; // Переходим к следующему вычислению
	  break;
	  
	  case 1:	  
      falling = ICR1;           // Запоминаем значение счётчика
      TCCR1B |= (1 << ICES1);   // Устанавливаем прерывание по нарастающему фронту импульса
// Приводим все переменные к одному типу и вычисляем длительность импульса
      t = (unsigned long)falling - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_t = 0;
	  zamer_1 = 1; // Переходим к следующему вычислению
	  break;      
	  }
    break;
    case 1: // Вычисляем период импульса
      switch(zamer_T)  
      {
      case 0:
      rising_1 = ICR1; // Запоминаем значение счётчика
      OVF_counter = 0; // Обнуляем количество переполнений счётчика
      zamer_T = 1; // Переходим к следующему вычислению
      break;
  
      case 1: 
      rising_2 = ICR1; // Запоминаем значение счётчика
// Приводим все переменные к одному типу и вычисляем период импульса
      T = (unsigned long)rising_2 - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536);
      zamer_T = 0;
      zamer_1 = 2; // Переходим к следующему вычислению
      break;
      }
    break;
  case 2:                   
  f = 1000000/T; // Вычисляем частоту сигнала в Гц
  duty = (t*100)/T; // Вычисляем скважность импульса в процентах
  zamer_1 = 0; // Переходим к следующему вычислению
  break;
  }
}
// Функции работы с LCD 
#define RS PD0 
#define EN PD2
// Функция установки курсора в указанную точку
#define lcd_gotoxy(x, y) lcd_com(0x80|(x)+((y)*0x40))
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция вывода строки на LCD
void lcd_string(char *string)
{
lcd_com(0x0C);
while(*string != '\0')
{  lcd_data(*string);
string++;
}
}
// Функция вывода переменной
void lcd_num_to_str(unsigned long value, char nDigit)
{
 switch(nDigit)
 {
  case 6: lcd_data(((value/100000)%10)+'0');
  case 5: lcd_data(((value/10000)%10)+'0');
  case 4: lcd_data(((value/1000)%10)+'0');
  case 3: lcd_data(((value/100)%10)+'0');
  case 2: lcd_data(((value/10)%10)+'0');
  case 1: lcd_data((value%10)+'0');
 }
}
// Функция инициализации LCD
void lcd_init(void){
/* PD0 - RS PD2 - E
PD4-PD7 - D4-D7

PB0 - input
*/
PORTD = 0x00;
DDRD = 0xFF;
_delay_ms(50); // Ожидание готовности ЖК-модуля
// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);
// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5); 
lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}
int main(void)
{
TCCR1B |= (1 << ICNC1)|(1 << CS11); // Активируем входной подавитель шума, предделитель на 8
TIMSK |= (1 << TICIE1)|(1 << TOIE1); // Разрешаем прерывание по захвату и переполнению
lcd_init(); // Инициализация дисплея
_delay_ms(50);
lcd_gotoxy(0, 0);
lcd_string("F=      Hz  DUTY");
lcd_gotoxy(0, 1);
lcd_string("t=      us     %");
sei(); // Глобально разрешаем прерывания
while (1)
{
lcd_gotoxy(2, 0);
lcd_num_to_str(f, 6); // Выводим частоту сигнала на экран
lcd_gotoxy(2, 1);
lcd_num_to_str(t, 6); // Выводим ширину импульса на экран
lcd_gotoxy(12, 1);
lcd_num_to_str(duty, 3); // Выводим скважность импульса на экран
_delay_ms(250);
}
}