Доброго времени суток.
Пытаюсь которую неделю реализовать следующее при помощи таймера1:
(Пытался сделать на обработки прерывания по совпадению, а после на fast pwm. Уже думаю, что невозможно сделать на ардуино и нужно esp32 так как там частоты выше.)
1)Выставляю на D9 и D10 высокий уровень.
2)С D9 посылаю через PORTB низкий уровень, потом опять высокий. (Длина отрицателтного импульса получается около 120нс)
3) Потом жду нужное количество тактов процессора (от 3 до 35 микросекунд где то)
4) Подаю с D10 так же отрицательный импульс длительностью 2 такта процессора.
Основная загвоздка в точности задержки. Так как у меня с частотой в 1гмгц прямо впритык и важен каждый цикл процессора.
Пытался реализовать на прерывании по совпадению. В прерывании ISR(TIMER1_COMPA_vect) останавливал таймер, а так же управлял D10.
Но при использовании прерывания по совпадению точность варьируется в 2-3такта процессора. А иногда больше. То есть например задаю переменную , по которой будет отработка прерывания равной 500. Прерывание сработает на 500. Задаю 501, прерывание все равно на 500. Задаю 502, прерывание сработало на 502.
Пример кода:
#include <Wire.h>
//#include <LiquidCrystal_I2C.h>
//LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line displa
bool flagBtn = false; //high or low for btnStart
int OCR1AmyValue = 30; //time setting value
int currentStep = 1; //current step
uint32_t btnTimer = 0;
void setup() {
Serial.begin(9600);
//lcd.init(); // initialize the lcd
//lcd.backlight();
pinMode(8, OUTPUT); //RESET
pinMode(9, OUTPUT); //START
pinMode(10, OUTPUT); //STOP
//High
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
cli(); //stop interrupts for till we make the settings
TCCR1A = 0; // Reset entire TCCR1A to 0
TCCR1B = 0; // Reset entire TCCR1B to 0
TIMSK1 |= (1 << OCIE1A); //Set OCIE1A to 1 so we enable compare to match OCR1A
TCNT1 = 0; //reset clock value
sei(); //Enable back the interrupts
prepareMethod(); //initialize variables and show on display
}
void loop() {
for (int i = 1; i < 500; i++) {
prepareMethod();
startBtnPressed();
showInfoSerial();
OCR1AmyValue++;
delay(100);
}
delay(1500000);
}
void showInfoSerial() { //SHOW ALL THE INFORMATION ON THE LCD
Serial.print("My/RC:");
Serial.print(OCR1AmyValue + 25);
Serial.print(" ");
Serial.println(TCNT1); //
}
void prepareMethod() {
// lcd.clear();
// lcd.setCursor(0, 0); //Column, Row
// lcd.print("#");
// lcd.print(currentStep);
//
// lcd.print("ET:");
// lcd.print((OCR1AmyValue + 25) * 0.0625);
//
// //number of clocks i set
// lcd.print("MC:");
// lcd.print(OCR1AmyValue + 25); //20 interrupt, 4 H>L>H, 1 stop timer
//OCR1A = OCR1AmyValue; //Finally we set compare register A to this value
OCR1A = OCR1AmyValue;
TCNT1 = 0; //First, set the timer back to 0 so it resets for next interrupt
}
//SEND SIGNALS
void startBtnPressed() {
//Reset L
PORTB = B110; //8 L 687,5ns lenght
//9nop x 0.0625us = 0.5625uS +2 ticks for PORTB
__asm__ __volatile__ (
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
);
//Reset H
PORTB = B111; //8 L
//delay ~20uS before start
delayMicroseconds(20);
//START 9 H>L 4 clocks
PORTB = B101; //8 L; 9 L
PORTB = B111; //8 L; 9 H
TCCR1B = B1; //T1 ON; running at 16 MHz //1такт
}
//COMP A TIMER
ISR(TIMER1_COMPA_vect) { //~20 clock takes interrupt
//STOP 10 H > L
PORTB = B011; //8 H; 9 H; 10 L 2 clocks
PORTB = B111; //8 H; 9 H 10 H 2 clocks
TCCR1B = 0; //Timer-1 OFF 1 clock
}
Второй вариант это мне посоветовали режим Fast pwm.
При COM1A1 =1; COM1A0 = 1 (Set OC1A/OC1B on compare match, clear OC1A/OC1B at BOTTOM (inverting mode))
И OCR1B = 1; OCR1A = 1000; если не останавливать генерацию, то имеется одиночный отрицательный импульс длиной 2 такта процессора, все как и должно работать. Но если пытаться сразу остановить его, что бы получить одиночный импульс то ничего не работает.
Так же пробовал с не инвертированным режимом:
COM1A1 =1 and COM1A0 = 0 (Clear OC1A/OC1B on compare match, set OC1A/OC1B at BOTTOM (non-inverting mode)).
При
OCR1B = 999; //compare match
OCR1A = 1000; //top value
Длина импульса почему то 3uS.
А что бы получить 120нс надо выставить OCR1B =1022. Ничего не понимаю…
void setup() {
pinMode(9, OUTPUT); //START
pinMode(10, OUTPUT); //STOP
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
cli(); //stop interrupts for till we make the settings
TCCR1A = 0; // Reset entire TCCR1A to 0
TCCR1B = 0; // Reset entire TCCR1B to 0
TCNT1 = 0; //reset clock value
//Set OC1B on compare match, clear OC1A/OC1B at BOTTOM (inverting mode)
TCCR1A |= (1 << COM1B1); //
TCCR1A |= (1 << COM1B0); //
////set to fast PWM mode 15 via WGM bits(count from 0 to OCR1A):
////TOP = OCR1A (output compare register timer1 channelA)
TCCR1A |= (1 << WGM10) | (1 << WGM11) ;
TCCR1B |= (1 << WGM12) | (1 << WGM13) ;
////Timer/Counter1 Interrupt Mask Register:
////bit OCIE1B - (COMPARE B)The corresponding interrupt vector is executed when the OCF1B flag, located in TIFR1 register, is set
////bit OCIE1A - (COMPARE A)The corresponding interrupt vector is executed when the OCF1A flag, located in TIFR1 register, is set
////bit TOIE1 - (OVERFLOW) The corresponding interrupt vector is executed when the TOV1 flag, located in TIFR1 register, is set;
//TIMSK1 |= (1 << OCIE1A); //Set OCIE1A to 1 so we enable compare counter to match OCR1A and call vector - ISR(TIMER1_COMPA_vect) {//something}
//TIMSK1 |= (1 << OCIE1B); //Set OCIE1B to 1 so we enable compare counter to match OCR1A and call vector - ISR(TIMER1_COMPB_vect) {//something}
//TIMSK1 |= (1 << TOIE1); //Set TOIE1 to 1 so we call overflow vector when overflow happens - ISR(TIMER1_OVF_vect) {//something}
sei();
////The extreme values for the OCR1x register represents special cases when generating a PWM waveform output in the fast
////PWM mode. If the OCR1x is set equal to BOTTOM (0x0000) the output will be a narrow spike for each TOP+1 timer clock
//////cycle. Setting the OCR1x equal to TOP will result in a constant high or low output (depending on the polarity of the output set
////by the COM1x1:0 bits.)
OCR1B = 1; //compare match
OCR1A = 1000; //top value
TCCR1B = B1; //T1 ON; running at 16 MHz no prescaling; //1 clock
}
void loop() {
TCCR1B = B0; // stop
delay(100000);
}
ISR(TIMER1_OVF_vect) { //OVERFLOW VECTOR
//TCCR1B &= ~_BV(CS10); //turn off timer1 29 clocks
TCCR1B = B0; //turn off timer1 (CS10 = 0) 18 clocks
}