ATmega. Счетчик импульсов ШИМ

В статье ATmega. Формирование ШИМ сигнала реализовывал сигнал ШИМ 25 кГц. Осциллографом не обладаю, но проверить результат хочется. Делаем счетчик импульсов, проверяем работу.

Задача

На базе ATmega 328P реализовать счетчик импульсов для проверки ШИМ 25 кГц, точность измерений до импульса не нужна, но порядок нужно знать.

Решение

Логика решения проста, отслеживаем импульсы, по которым инкрементируем глобальную переменную в течении секунды. Накопленное значение и будет частотой входящего сигнала.

Для считывания импульсов воспользуемся внешними прерываниями, они описаны на страницах 87-96 документации от производителя. В Atmega 328P есть два входа, которыми мы можем отслеживать внешние прерывания INT0(PD2) и INT1(PD3), для решения задачи воспользуемся INT0.

Настройка внешних прерываний

Первым делом необходимо настроить порт D как вход, а для избежания наводок подключу подтягивающий резистор.

Для определения по каким событиям будет вызываться обработчик прерывания нужно настроить регистр  ERICA. Биты ISC00 и ISC01 отвечают за INT0, а ISC10 и ISC11 за INT1. Настройка отслеживаемых событий идентична, за разницей в битах:

00 — Низкий уровень сигнала;
01 — Любое логическое изменение сигнала;
10 — Нисходящий фронт сигнала;
11 — Восходящий фронт сигнала.

Для непосредственного включения входов прерываний служит регистр EIMSK, биты INT0 и INT1 отвечают за одноименные выходы. По вышеизложенному пишем код

void int0_initial( void ) {

  DDRD  = 0x00;     // Порт D как вход
  PORTD = (1 << 2); // Включение подтягивающего регистра
  
  EICRA = (1 << ISC00) | (1 << ISC01); // Восходящий фронт сигнала
  EIMSK = (1 << INT0);                 // Включение входа прерывания
  
  sei();  // Разрешаем прерывания
  
}

Обработка внешних прерываний

Прерывания настроил, теперь надо их обработать. Для этого существует функция обработки прерывания ISR(), которой  необходимо указать тип прерывания, в моем случае INT0_vect. В функции будем делать инкремент переменной Tic_Count:

ISR( INT0_vect ) {
  Tic_Count ++;
}

Вывод результата

Для облегчения вывода результата, дабы не прикручивать дисплей воспользовался не чистой ATmega 328P, а Arduino UNO и Arduino NANO, на борту которых тот же МК.

Как писал выше точность измерений не столь важна, потому таймеров настраивать не буду, а просто в основном цикле один раз в секунду выведу накопленное значение переменной Tic_Count и обнулю ее. На время этих действий прекращаю обработку прерываний.

Ниже полный код решения задачи с комментариями:

#define F_CPU 1600000UL
#include <avr/io.h>
#include <util/delay.h>

volatile unsigned int Tic_Count = 0;
 
// Обработчик внешнего прерывания INT0
ISR( INT0_vect ) {
  Tic_Count ++;
}

void setup() {
  
  int0_initial();
  Serial.begin(9600);
  
}

void loop() {

    cli(); // Запрещаем прерывания
  
    Serial.println(Tic_Count);
    Tic_Count = 0;

    sei(); // Разрешаем прерывания

    delay(1000);
 
}

void int0_initial( void ) {

  DDRD  = 0x00;      // Порт D как вход
  PORTD = (1 << 2);  // Включение подтягивающего регистра
  
  EICRA = (1 << ISC00) | (1 << ISC01); // Восходящий фронт сигнала
  EIMSK = (1 << INT0);                 // Включение входа прерывания
  
  sei();  // Разрешаем прерывания
  
}

Теперь остается подключить сигнал ШИМ к ножке PD2, и открыть монитор последовательного порта. Так же можно сформировать и проверить сигнал на одном МК.

ATmega. Счетчик импульсов ШИМ
Выводимые показания примерно равны ранее рассчитанной частоте, небольшие отличия ожидаемы из-за реализации. Для точного измерения наверное правильнее считать время между импульсами и от этого вычислять частоту.

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *