Делал так:
Сч=начала считаем сколько надо счетчику насчитать чтоб получить заданный период импульса.
Получаем количество "тиков". Потом умножаем количество тиков на заданную скважность. Получаем - длительности высокого и низкого состояния.
Счетчик считает рассчитанное количество полных циклов плюс рассчитанный "остаток" пока не насчитает заданный импульс (высокое состояние). Вывод "out" переключается. Затем счетчик считает период "низкого состояния"
Сейчас попробую накидать скетч.
Добавлено спустя 2 часа 46 минут 51 секунду:Быстро подправил один из скетчей.
loop() можно чистить вообще.
Код:
/*
Генератор частоты-скаважности
*/
// ISR interrupt service routine
//#include < interrupt.h >
#define TOGGLE_IO 6 //вывод Arduino для переключения по таймеру ISR
#define TOGGLE_IO_GND 5 //земля светодиода
#define ClockHZ 1 //Частота в герцах
#define Skvaz 0.9 //Скважность
unsigned int latency;
unsigned int latencySum;
unsigned int sampleCount;
unsigned int CountPer;
long timerLoadValue; //Количество тиков
long Tick1; //Тиков для "1" ЦЕЛЫХ
long Tick0; //Тиков для "0" ЦЕЛЫХ
long TickCount; //Тиков для обработки в прерывании
void setup() {
// initialize the digital pin as an output.
// Pin 13 has an LED connected on most Arduino boards:
pinMode(13, OUTPUT);
//Устанавливает порт, который нам нужно переключать в ISR, выходным.
pinMode(TOGGLE_IO,OUTPUT);
pinMode(TOGGLE_IO_GND,OUTPUT);
digitalWrite(TOGGLE_IO_GND, LOW);
interrupts(); // Разрешить прерывания глобально
//Запускает последовательный порт
Serial.begin(9600);
//Сообщение о запуске программы
Serial.println("Timer Test");
//Запускает таймер Настройка таймера.
timerLoadValue=SetupTimer2(ClockHZ);
//Выводит рассчитанное значение таймера
Serial.print("Timer2 Period=");
Serial.println(timerLoadValue);
Tick1=timerLoadValue*Skvaz;
Tick0=timerLoadValue-Tick1;
Serial.print("Timer2 Tick1=");
Serial.println(Tick1);
Serial.print("Timer2 Tick0=");
Serial.println(Tick0);
TickCount=Tick1;
digitalWrite(TOGGLE_IO, HIGH);
}
void loop() {
// digitalWrite(13, HIGH); // set the LED on
delay(5000); // wait
digitalWrite(13, LOW); // set the LED off
// delay(); // wait for a second
// Serial.println( TCNT2 );
// Serial.print(" ");
// Serial.print( TestPerem );
// Serial.print(" ");
//locateSensor=digitalRead(LOC_INPUT);
delay(5000); // wait
// Serial.print (curstep) ;
// Serial.print (" ") ;
Serial.print ("TickCount=") ;
Serial.println (TickCount) ;
// Serial.println (" ");
//Serial.println( digitalRead(LOC_INPUT) );
// TestPerem=locateStat;
digitalWrite(13, HIGH);
//Собирает текущее значение задержки из ISR и увеличивает счетчик на 1
//the sample counter
latencySum+=latency;
sampleCount++;
//Как только наберется 20 замеров, вычисляет и выводит результат измерений
if(sampleCount>20) {
float latencyAverage;
float loadPercent;
//Вычисляет среднюю задержку
latencyAverage=latencySum/100.0;
//обнуляет значения сумм
sampleCount=0;
latencySum=0;
//Вычисляет ожидаемый процент загрузки процессора
loadPercent=latencyAverage/(float)timerLoadValue;
loadPercent*=100; //Переводит доли в проценты;
//Выводит среднюю задержку
Serial.print("Latency Average:");
Serial.print((int)latencyAverage);
Serial.print(".");
latencyAverage-=(int)latencyAverage;
Serial.print((int)(latencyAverage*100));
//Выводит ожидаемый процент загрузки
Serial.print(" Load:");
Serial.print((int)loadPercent);
Serial.println("%");
}
}
//Timer2 указатель вектора прерывания по переполнению
ISR(TIMER2_OVF_vect) {
//Проверим счетчик TickCount
//Проверим состояние выхода, если 1 - то
if (TickCount==0) {
if (digitalRead(TOGGLE_IO)){ TickCount=Tick0;}
else { TickCount=Tick1;}
digitalWrite(TOGGLE_IO,!digitalRead(TOGGLE_IO)); //Переключение IO-вывода в другое состояние.
}
else{
//проверяем - больше ли счетчик целого чикла (255)
if (TickCount<255) {
TCNT2=255-TickCount+TCNT2;
TickCount=0;} //Компенсация того, что натикало.
else {
TickCount-=255;}
}
// if (curstep> 400 || curstep<0){dir=-dir;}
// curstep+=dir;
// //Переключение IO-вывода в другое состояние.
// digitalWrite(TOGGLE_IO,!digitalRead(TOGGLE_IO));
//Захват текущего значения таймера. Это величина ошибки
//из-за задержки обработки прерывания и работы этой функции
int latency=TCNT2;
//Перезагрузка таймера и коррекция по задержке
//TCNT2=latency+timerLoadValue;
//TCNT2=timerLoadValue;
}
long SetupTimer2(long Frequency){
#define TIMER_CLOCK_FREQ 15625.0
#define TIMER_CLOCK_TICK 2000000.0
//15625 for /1024
//2MHz for /8 prescale from 16MHz
//Установка Таймера2.
//Конфигурирует 8-битный Таймер2 ATMega168 для выработки прерывания
//с заданной частотой.
//Возвращает количество тиков таймера на один период требуемой частоты
//Установки Таймер2: Делитель частоты /8, режим 0
//Частота = 16MHz/1024 = 15625 герц или 64 мкс
//Делитель /1024 дает нам хороший рабочий диапазон
//Но нужен 16MHz/8 = 2Mhz или 0.5 мкс
//так что сейчас мы просто жестко запрограммируем это.
TCCR2A = 0;
TCCR2B = 0<<CS22 | 1<<CS21 | 0<<CS20; //это на 8
// TCCR2B = 7; //Это на 1024
//Подключение прерывания по переполнению Timer2
TIMSK2 = 1<<TOIE2;
//загружает таймер для первого цикла (если меньше 255, или
TCNT2=0;
//Количество тиков:
long CountPer=TIMER_CLOCK_TICK/(long)Frequency;
return(CountPer);
}
Добавлено спустя 2 минуты 47 секунд:Да, если нужна бОльшая точность - то делитель счетчика можно установить =1.