logo
HCS12 с применением языка С - royallib

Измерение частоты и периода логического сигнала

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

• Бит разрешения работы модуля таймера TEN (регистр управления модулем таймера TSCR);

• Бит разрешения прерывания по переполнению счетчика временной базы TOI и биты выбора коэффициента деления программируемого делителя частоты на входе счетчика временной базы PR2:PR1:PR0 (регистр масок таймера TMSK2);

• Бит выбора режима работы канала IOSn (регистр режимов каналов захвата/сравнения TIOS). Если бит IOSn установлен в 1, то канал работает в режиме выходного сравнения. Если бит IOSn равен 0, то канал настроен на режим входного захвата;

• Биты выбора режима работы детектора события канала входного захвата EDGnB:EDGnA (регистры управления таймером TCTL3 и TCTL4);

• Бит события в канале CnF (регистр флагов таймера TFLG1);

• Бит разрешения прерывания по событию в канале CnI (регистр масок таймера TMSK1);

• Регистр данных канала TCn, в который автоматически записывается код счетчика временной базы в момент события входного захвата.

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

1. Разрешить работу модуля таймера;

2. Выбрать частоту тактирования счетчика временной базы, для чего установить желаемый коэффициент деления программируемого делителя частоты на входе счетчика временной базы;

3. Установить один из каналов в режим входного захвата по нарастающему фронту импульса;

4. Сохранить в памяти МК код счетчика временной базы в момент появления первого фронта импульса;

5. Сохранить в памяти МК код счетчика временной базы в момент появления второго фронта импульса;

6. Взять разность полученных кодов, которая будет равна периоду исследуемого сигнала. Воспользовавшись операцией деления, вычислить частоту исследуемого сигнала. На рис. 4.43 приведена блок схема рассмотренного алгоритма. Ниже приведен программный фрагмент (timer1.c), который реализует этот алгоритм. В программе применен метод программного опроса триггера события входного захвата C2F. Когда программа «обнаруживает» установленный в 1 триггер события первый раз, она копирует регистр данных канала в переменную rising_1, сбрасывает триггер и ожидает следующей установки триггера события. Когда триггер события установится второй раз, программа копирует регистр данных канала в переменную rising_2. Разность двух зафиксированных в регистре данных канала входного захвата значений позволит вычислить период, а затем и частоту исследуемого импульсного сигнала.

Рис. 4.43.  Блок схема алгоритма измерения периода и частоты исследуемого сигнала

Отметим три момента в стиле написания исходного текста представленного программного фрагмента для измерения периода и частоты импульсного сигнала:

• Основная программа «main» содержит вызовы трех функций, каждая из которых выполняет отдельную смысловую задачу;

• Имена функций и переменных выбраны в соответствии с их смысловым назначением;

• Представленный исходный текст программы достаточно полно документирован посредством комментариев перед записью каждой функции.

/*-------------------------------------------------------------------*/

/* filename: timer1.c                                                */

/* МAIN PROGRAМ: Эта программа измеряет период и частоту импульсного */

/* сигнала. Сигнал подключается на вход 2 подсистемы таймера (IC2).  */

/*-------------------------------------------------------------------*/

/*подключаемые файлы*/

#include <912b32.h>

#include <stdio.h>

#include <math.h>

/*используемые функции*/

void timer_init(void);

void measure_wave(void);

void period_freq(void);

/*глобальные переменные*/

unsigned long int rising_1;

unsigned long int rising_2;

void main(void) {

 timer_init(); /*инициализация таймера*/

 measure_wave(); /*определение времени двух фронтов сигнала*/

 period_freq(); /*вычисление периода и частоты*/

}

/*----------------------------------------------------------------------*/

/* Функция timer_init производит инициализацию модуля таймера           */

/* Канал 2 таймера настраивается на режим входного захвата по переднему */

/* фронту сигнала                                                       */

/* Частота тактирования счетчика временной базы устанавливается 2 МГц.  */

/*----------------------------------------------------------------------*/

void timer_init(void) {

 TMSK1 = 0x00; /*запретить прерывания от каналов таймера*/

 TMSK2 = 0x02; /*назначить коэффициент деления 4*/

 TIOS = 0х00; /*установить канал 2 в режим входного захвата*/

 TSCR = 0х80; /*разрешить работу таймера*/

 TCTL4 = 0х10; /*назначить режим детектора событий по*/

               /*положительному фронту*/

 TFLG1 = 0xFF; /*очистить флаги событий*/

}

/*-------------------------------------------------------------------*/

/* Функция measure_wave запоминает два последовательных момента      */

/* нарастающего фронта исследуемого сигнала. Значения запоминаются с */

/* использованием глобальных переменных                              */

/*-------------------------------------------------------------------*/

void measure_wave(void) {

 while((TFLG1 & 0х04) == 0) {

  /*ожидать нарастающего фронта*/

  ;

 }

 rising_1 = TCNT; /*запомнить код счетчика временной базы*/

                  /*в переменной rising_1*/

 TFLG1 = 0х04; /*сброс триггера события канала 2*/

 while((TFLG1 & 0х04) == 0) {

  /*ожидать нарастающего фронта*/

  ;

 }

 rising_2 = TCNT; /*запомнить код счетчика временной базы*/

                  /*в переменной rising_2*/

 TFLG1 = 0х04; /*сброс триггера события канала 2*/

}

/*------------------------------------------------------------------------*/

/* Функция period_freq вычисляет период и частоту исследуемого импульсного*/

/* сигнала и отображает полученные значения на экране                     */

/*------------------------------------------------------------------------*/

void period_freq(void) {

 unsigned long int new_rising;

 unsigned long int new_falling;

 float frequency;

 float period;

 unsigned int int_period;

 unsigned int int_freq, freq_tenths;

 if(rising_2 < rising_1) /*вычисление периода*/

 {

  new_rising = rising_2 + 0xFFFF;

  period = ((float)new_rising (float)rising_l)*0.0000005;

 } else {

  period = ((float)rising_2 (float)rising_l)*0.0000005;

 }

 frequency = 1.0/period; /*вычисление частоты*/

 int_freq = (int)(frequency/l000.0);

 freq_tenths = (int)((frequency –(float) int_freq*1000)/100.0);

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

 printf("Frequency = %d.%d kHz \n\n" int_freq, freq_tenths);

 int_period = (int) (1000000*period);

 printf("Period = %d μs\n\n", int_period);

 printf{"Period = %f ms\n\n", (period*1000))};

}

/*------------------------------------------------------------------------*/

Приведенная программа выдаст ошибочный результат для сигналов, период которых превышает период переполнения счетчика внешних событий. В одном из домашних заданий в конце данной главы мы попросим Вас изменить исходный текст программы так, чтобы измерение более «медленных» сигналов также стало возможным. Какие изменения в программу следует внести? Вы должны будете контролировать, сколько раз переполнился счетчик временной базы между двумя соседними событиями в канале входного захвата. Для этого следует организовать программный счетчик, который будет инкрементироваться каждый раз, когда счетчик переполнится. Переполнение счетчика Вы будете фиксировать по установленному флагу TOF. Этот флаг может программно считываться с последующим сбросом, или по флагу могут быть разрешены прерывания. В подпрограмме прерывания будет инкрементироваться программный счетчик. После того, как второй нарастающий фронт зафиксирован, программа должна выполнить вычисления, используя формулу:

Period  = 216×n + (rising_2  – rising_1 )

Рассматриваемая программа имеет также ограничение по измерению сигналов с достаточно высокой частотой. Как узнать максимальную частоту, которая может быть измерена? Для этого следует вспомнить, что в нашем учебном примере частота внутренней шины МК составляет 8 МГц. Вы должны просмотреть ассемблерный код функции измерения частоты measure_wave и определить, сколько машинных тактов необходимо для распознавания установленного в 1 флага события и считывания кода первого события из регистра данных канала. Именно этот интервал является минимальным периодом сигнала, который может быть измерен.