Внешнее преравание и запуск по нему таймера
- Войдите на сайт для отправки комментариев
Втр, 03/03/2015 - 14:52
проблемка выходит с таймером
#include <CyberLib.h>
volatile boolean i = 0;
void setup() {
D3_In;
D9_Out;
attachInterrupt(1,impuls,FALLING); //прерывание по 3 пину
}
void loop() {
if(i==1){StartTimer1(obrobotchik, 1000);i = 0;};} //запуск таймера о обнуление флага
void obrobotchik() {D9_High;delay_ms(1);D9_Low;StopTimer1();} //после отсчета таймера
void impuls() {
i=1;} //установка флага
пробовал запускать таймер в interrup, но ничего не дает
желтый - вход D3, синий - выход D9

dmitriykisliy, а что вы хотели получить?
по описанию таймера понял, что по истечении времени (1000 мкс)
программа переходит к
т.е. после LOW на D2, на D9 возникнет HIGH через 1000 мкс, но или я туплю, или ATmega328 меня не понимает.
Голову ломаю 2 недели, delay не подходит, частота входа меняется (датчик Холла автомобиля) и void loop сбивается
Если есть варианты, подскажите)
dmitriykisliy, т.е. вам нужно, что б ежели кто-то дёрнет ногу порта d2 на ноль, то через 1мс поднять ногу d9, а ещё через 1мс её опустить, так?
да, верно.
кто-то - это датчик Холла трамблера авто, 1 мс - это пробная величина, далее она будет функцией оборотов мотора
http://arduino.ru/forum/programmirovanie/takhometr-0#comment-35202
http://arduino.ru/forum/programmirovanie/takhometr-0#comment-35142
подсчет внешних прерываний это не сложнл, а как по внешнему прерыванию запустить таймер и с выдержкой времени выполнить действие?
вы что делаете - электронный регулятор угла опережения зажигания от оборотов движка ?
верно, со своим алгоритмом работы, выложу когда заработает. сейчас езжу на ардуине, лучше, чем было на штатном трамблере, но угол опережения нестабилен (из за delaymicroseconds думаю)
http://arduino.ru/forum/proekty/fuoz-takhometr
реализация через счётчики МК и таблицу пересчёта - быстрее и точнее, чем производить матрассёты
верно, со своим алгоритмом работы, выложу когда заработает. сейчас езжу на ардуине, лучше, чем было на штатном трамблере, но угол опережения нестабилен (из за delaymicroseconds думаю)
алгоритм у всех ФУОЗов одинаков - разные только кривые зависимости "обороты-времяОпережения" :)
про счетчик МК можно поподробнее?
ATmega48PA/88PA/168PA/328P
14. 8-bit Timer/Counter0 with PWM
15. 16-bit Timer/Counter1 with PWM
16. Timer/Counter0 and Timer/Counter1 Prescalers
17. 8-bit Timer/Counter2 with PWM and Asynchronous Operation
это видел,
а как ПРАВИЛЬНО запустить таймер 1 после прерывания? в этом и есть проблема (рис 1 пост)
в Ассемблере я 0, с библиотекой проще, но не работает(
dmitriykisliy, тут не много тех, кто в ассемблере !=0 ;-) У меня был похожий шаблончик, подкорректировал под ваши данные. Вроде всё как надо, снял осциллограмку -одна клетка пол миллисекунды. Синий график -кнопка, подтянута к HIGH, при нажатии соответссно ноль. Жёлтый график -выход с D9 ардуины.
Управление сделал через ещё одно прерывание от таймера, иначе не знаю как.. Сам скетч:
void setup() { pinMode (3,INPUT_PULLUP); //вход pinMode (9,OUTPUT); //выход EICRA=(1<<ISC11)|(0<<ISC10); //настройка внешнего прерывания (falling ) EIMSK|=1<<INT1; //разрешение внешнего прерывания TCCR1B=0; //настройка таймера1 TCCR1A=0; //настройка таймера1 TIMSK1=(1<<TOIE1); //разрешить прерываение для таймера 1 } ISR(INT1_vect) { //вектор внешнего прерывания TCCR1B= _BV(WGM13)|_BV(CS10); //запуск таймера 1 TCCR1A=0; ICR1=8000;//установка частоты прерывания } ISR (TIMER1_OVF_vect) { //вектор прерывания таймера 1 static byte msec=0; // переменная счёта входов в прерывание if (msec==1) PORTB |= 1<<1; //если второй вход включаем d9 if (msec==2){ // если третий вход PORTB &= ~(1<<1); //отключаем d9 TCCR1B = _BV(WGM13); //отключаем таймер msec=0; //сбрасываем счёт } msec++; } void loop() { }RESPECT! спасибо, попробую на работе,
как я понял выдержки времени можно менять строкой 15 (это предделитель?), ну и строками 21 и 22. Верно?
dmitriykisliy, да в 15 строке задаёте период вызова прерывания (8000 попугаев = 1мс учитывая и прочие настройки таймера) но не более 65535, а в прерывании таймера делаете что нужно..
12 строка (вектор внешнего прерывания) значит, что если на d3 falling, то запускается таймер?
не совсем так - посмотрите все биты управляющих регистров одного счётчика
всяко нужно два счётчика - один постоянно измеряет t оборота коленвала, второй создаёт задержку искрообразования в зависимости от t оборота коленвала ( или из таблицы(быстрее и проще - но кривая зависимости ступенчатая) , или по формуле пересчёта(помедленне - но кривая зависимости непрерывная)
счётчик rpm -
1) прерывание по ризинг ( или фаллинг ) от сигнала с датчика Холла
2) обработчик прерывания - захват значения счётчика в глобальную волатильную переменную, обнуление счётчика
итого: система на каждом обороте КВ знает период или частоту, или rpm ( что по сути меры одного и того же )
......здесь рассчёт/формирование значения установки для второго счётчика, который формирует задержку искрообразования
счётчик задержки - ...........
volatile unsigned int NclkTCNT1; volatile unsigned int RPM = 0; // обороты для Сериала volatile byte RPM100 = 0; // сотни оборотов для индекса таблицы "обороты-УОЗ" - 60 значений ( на выбор ) byte AngleDelayChargeBabin [] PROGMEM = // таблица "обороты-задержка накопления бабины" - числа пока не рассчитаны { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }; byte AngleChargeBabin [] PROGMEM = // таблица 10 х Тзаряда - числа пока не рассчитаны { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }; byte AngleIgnition [] PROGMEM = // таблица "обороты-УОЗ" - числа пока не рассчитаны { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF }; //============================================================================================================================== void setup( ) { //************************** // Счётчик_0 DDRD = DDRD | B01000000; // pinMode( 6 , OUTPUT ); // OC0A - выход на коммутатор // PORTD = PORTD | B00000000; TCNT0 = 0; // TIMSK0 >>> OCIE0B - 2 OCIE0A - 1 TOIE0 - 0 TIMSK0 = ( 1 << OCIE0A ); // TCCR0A >>> COM0A1 - 7 COM0A0 - 6 COM0B1 - 5 COM0B0 - 4 WGM01 - 1 WGM00 - 0 // OC0A - 00=disconnected , 01=Toggle , 10=Clear , 11=Set TCCR0A = ( 1 << COM0A1 ) | ( 0 << COM0A0 ) | ( 1 << WGM01 ) | ( 0 << WGM00 ); // TCCR0B >>> FOC0A - 7 FOC0B - 6 WGM02 - 3 CS02 - 2 CS01 - 1 CS00 - 0 TCCR0B = ( 1 << FOC0A ) | ( 0 << FOC0B ) | ( 0 << WGM02 ) | ( 0 << CS02 ) | ( 0 << CS01 ) | ( 0 << CS00 ) ; // CS >>> 0-stop, 1-/1, 2-/8, 3-/64, 4-/256, 5-/1024, 6-externalT0falling, 7-externalT0rising //************************** // Счётчик_1 DDRB = DDRB | B00000000; // pinMode( 8 , INPUT ); // вход от датчика Холла PORTB = PORTB | B00000001; // digitalWrite( 8 , HIGH ); // резистор к VCC TCNT1 = 0; // TIMSK1 >>> ICIE1 - 5 OCIE1B - 2 OCIE1A - 1 TOIE1 - 0 TIMSK1 = ( 1 << ICIE1 ); // TCCR1A >>> COM1A1 - 7 COM1A0 - 6 COM1B1 - 5 COM1B0 - 4 WGM11 - 1 WGM10 - 0 TCCR1A = ( 0 << WGM11 ) | ( 0 << WGM10 ); // TCCR1B >>> ICNC1 - 7 ICES1 - 6 WGM13 - 4 WGM12 - 3 CS12 - 2 CS11 - 1 CS10 - 0 // CS >>> 0-stop , 1-/1 , 2-/8 , 3-/64 , 4-/256 , 5-/1024, 6-externalT1falling, 7-externalT1rising TCCR1B = ( 0 << ICNC1 ) | ( 1 << ICES1 ) | ( 0 << WGM13 ) | ( 0 << WGM12 ) | ( 0 << CS12 ) | ( 0 << CS11 ) | ( 0 << CS10 ) ; // TCCR1C >>> FOC1A - 7 FOC1B - 6 //************************** NclkTCNT1 = 0; // Serial.begin( 9600 ); } //============================================================================================================================== ISR( TIMER1_CAPT_vect ) { TCNT1 = 0; NclkTCNT1 = ICR1 + 34; // 34 такта - задержка от времени фронта до выполнения этой строки ДЛЯ сохранение RG-ов в стэк RPM = int( 96 / NclkTCNT1 * 10 ^ 7 ); // X=60/(N*16000000)=60*16000000/N=96/N*10^7 // RPM50 = RPM % 50; // 120 значений ( на выбор ) // RPM100 = RPM % 100; // 60 значений ( на выбор ) // загрузить Счётчик_2 = AngleDelayChargeBabin [ RPM100 ]; // разрешить прерывания Счётчик_2 // загрузить Счётчик_2 = AngleIgnition [ RPM100 ]; // разрешить прерывания Счётчик_2 } //============================================================================================================================== ISR( TIMER0_COMPA_vect ) { } //============================================================================================================================== void loop( ) { // Serial.println( RPM ); delay( 500 ); } //=============================================================================================================================примерно так...
машина времени ещё не создана, поэтому говорить об опережении зажигания на Х гр от ВМТ можно как о задержке на 360-Х гр от ВМТ ( или на 180-Х гр от НМТ ) , НО в следующем обороте КВ
счётчик задержки - ...........
....должен сформировать временные значения и сами фронты сигнала на коммутатор бабины
апгрейд системы будет заключаться в изменении таблицы соответствия "обороты-УОЗ" ( все зависимости в авто построены на этом ) , или изменением коэффициентов в формуле пересчёта "обороты-УОЗ"
построение системы хардварное или софтовое - вопрос философский и вкуса.... моя за хардвар - хватит и Attyni85 :)
если на d3 falling, то запускается таймер?
тут два варианта
1 - ст обнулён, счёт запрещён коэффициентом деления = 0 ( STOP ) , по прерыванию устанавливаем коэффициентом деления = 1, 64, ...... нужный
2 - по прерыванию обнуляем ст
......результат одинаков - запускается таймер на отсчёт чего-либо от момента начала прерывания
уважаемые dmitriykisliy и dimax, есть у вас время и желание вступить в симбиоз ?
....и создать адаптированную систему под вкус-цвет и потребности любого пользователя ?
кто-то логику, кто-то коды, кто-то свою машинку для испытаний :)
....моя корысть - модуль управления УОЗ старенького ( но очень распространённого ) дизелька :)
SU-27-16, увы, я в автомобильной тематике полный ноль. Да и с таймерами буквально две недели как начал разбираться :)
SU-27-16, увы, я в автомобильной тематике полный ноль. Да и с таймерами буквально две недели как начал разбираться :)
на то и симбиоз :)-
понял.... вы согласен ! :)
сорри, до нета только добрался
с расчетом прерываний проблем 0, на работе делали датчики тока и напряжения с цифровой опторазвязкой (преобразование ток-частота и напряжение-частота)
по поводу машины времени +1, это приближенный расчет, но факт то, что он лучше штатного трамблеровского с грузами и вакуумом, да и проблемы с запуском пропали...
по поводу функции или массива (таблицы) - по быстродействию, да и ступенчатости массив рулит (составлял на 100 элементов - 50 об/мин +на вакууме висит датчик холла (корректор))
скетч не опробовал, планирую на завтра
su-27-16 спс за рекомендации
в чем вопрос по дизельку? есть наработки
Ну заработало)
Готовый скетч
unsigned long t = 0; volatile boolean i = 0; volatile int zaderg, delit = 0; volatile unsigned int Ch = 0; unsigned int Zaderg[] = {250, 230, 223, 211, 201, 191, 183, 175, 167, 160, 154, 149, 143, 138, 133, 128, 124, 120, 238, 231, 224, 217, 211, 205, 199, 194, 188, 183, 178, 173, 169, 164, 160, 155, 151, 147, 144, 140, 137, 134, 131, 129, 126, 124, 122, 119, 117, 116, 114, 112, 110, 108, 106, 214, 211, 208, 204, 202, 199, 196, 193, 190, 188, 185, 183, 180, 178, 176, 173, 171, 169, 167, 165, 163, 161, 160, 158, 156, 155, 153, 151, 150, 148, 147, 145, 144, 142, 141, 139, 138, 137, 135, 134, 133, 132}; unsigned int Delit[] = {1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256}; void setup() { pinMode (3,INPUT_PULLUP); //вход pinMode (9,OUTPUT); //выход EICRA=(1<<ISC11)|(0<<ISC10); //настройка внешнего прерывания (falling ) EIMSK|=1<<INT1; //разрешение внешнего прерывания TCCR1B=0; //настройка таймера1 TCCR1A=0; //настройка таймера1 TIMSK1=(1<<TOIE1); //разрешить прерываение для таймера 1 } ISR(INT1_vect) { //вектор внешнего прерывания TCCR1B= _BV(WGM13)|_BV(CS10); //запуск таймера 1 TCCR1A=0; ICR1=delit;//установка частоты прерывания i = 1; } ISR (TIMER1_OVF_vect) {//900 - холостой ход, УОЗ = 0, т.е. повторитель заднего фронта if (Ch < 900) {TCCR1B = _BV(WGM13); //отключаем таймер PORTB &= ~(1<<1); delay(1); //отключаем d9 и чуток ждем PORTB |= 1<<1;} //включаем d9 else if (Ch > 900) { //вектор прерывания таймера 1 static byte msec=0; // переменная счёта входов в прерывание if (msec==30) PORTB |= 1<<1; //если 30 вход включаем d9 if (msec==zaderg){ // если (из массива) вход PORTB &= ~(1<<1); //отключаем d9 TCCR1B = _BV(WGM13); //отключаем таймер msec=0; //сбрасываем счёт } msec++; };} void loop() {if (i == 1) { i = 0; Ch = 30000000/(micros() - t); t = micros(); delit = Delit[map(Ch, 900, 5600, 0, 94)]; zaderg = Zaderg[map(Ch, 900, 5600, 0, 94)]; }; }Строки 28 - 30 переделаю на многоискровой запуск
на холостых оборотах
чуть больше 3000 об/мин
частота около 5500 об/мин, уоз 36 градусов
очень хорошо, что заработало :)
критика
- неоптимальное использование коммутатора и "бабины", т.е. - лишний расход ЭлЭн....
накопление энергии в "бабине" - const по времени.... и не должно зависеть от оборотов движка.....
- процессы в лупе и прерываниях "относительно" синхронны
есть предложения - позже обосную
за дизелёк - спасибо, всё решено - тока код надо допилить без рассчётов в коде, только через таблицы ( желание заказчика :( )
по коду - волатильными переменные стоит ( нужно ) объявлять только те, которые изменяются в прерываниях - может кто поправит ?
т.е. - 01, 03, 04 - могут быть неволатильными
Чтобы не плодить новую ветку вопрос задам тут.
Меня интересует, что происходит при повторном запуске таймера 1 по команде TCCR1B=(1<<CS10)|(1<<WGM12) ? Один запуск делаю сначала в "void loop()", а повторный в int 0. Таймер считает количество тактов генератора в течении 1 секунды по внешнему прерыванию. Вроде по теории не должно быть разницы. Поскольку сбрасываю регистр таймера по прерыванию.
Если запускаю таймер только в "void loop()" - то количество тактов 16000000 +/- 3 такта
Если запускаю таймер в "void loop()" и затем по "int 0" - то количество тактов 16000000 +/- 1 такта
вот 1 вариант:
void loop()
{TCCR1B=(1<<CS10)|(1<<WGM12);} //Запускаем Таймер 1
ISR (INT0_vect)
{if (start_timer_1==1 && flag_LED==0){TCNT1=0;} }
вот 2 вариант:
void loop()
{TCCR1B=(1<<CS10)|(1<<WGM12);} //Запускаем Таймер 1
ISR (INT0_vect)
{if (start_timer_1==1 && flag_LED==0){TCNT1=0;TCCR1B=(1<<CS10)|(1<<WGM12);} }
интересно. кто вам сказал. что строчка
"запускает таймер" ?
Эта строчка у вас в loop(). если бы она действительно ЗАПУСКАЛА таймер - он бы у вас перестартовывался тысячи раз в секунду.
Эта строка ВСЕГО ЛИШЬ устанавливает значение регистра TCCR1B. А если регистр уже установлен - строка не меняет состояние таймера. Помещать ее в ЛУП или в обработчик - бессмысленно, ей место в setup()
Вот от таких Булдаковых и непонятно какие дети рождаются.(
Поместил эту строчку в setup все перестало работать. Работает только первый раз. А потом ничего не меняется. Код рабочий. У меня был только вопрос почему добавление строчки TCCR1B=(1<<CS10)|(1<<WGM12); в прерывание улучшает стабильность счета таймера?
специально нашел описание регистра TCCR1B. Если TCCR1B=0 - то таймер не считает. Если TCCR1B=(1<<CS10)|(1<<WGM12) - то таймер считает без деления частоты.
Было так:
void setup() { //---Настройка прерывания int 0 EIMSK = (1<<INT0); EICRA = (1<<ISC01) | (1<<ISC00); //---Настройка таймера 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 15999; TIMSK1 |= (1 << OCIE1A); } //---Прерывание по int 0 ISR (INT0_vect) { if (start_timer_1==1 && flag_LED==0){TCNT1=0;ovf_tik_timer_1=0;ovf_tik_int_0=0;start_timer_1=0;} if ( stop_timer_1==1 && flag_LED==0){TCCR1B=0;flag_LED=1;} if (flag_LED==0 ){ovf_tik_int_0=ovf_tik_int_0+1;} } //---Прерывание по таймеру 1 ISR(TIMER1_COMPA_vect) {ovf_tik_timer_1=ovf_tik_timer_1+1;} void loop() { //---Условия окончания измерения if (ovf_tik_timer_1>=interval_izm && flag_LED==0)stop_timer_1=1; if (ovf_tik_timer_1>=1.5*interval_izm) {flag_LED=1;TCCR1B=0;} //---Условия индикации if (flag_LED==1) { tik_timer_1=(unsigned long)ovf_tik_timer_1*16000+TCNT1; } //---Условия вывода if (flag_LED==1) { ovf_tik_timer_1=0;ovf_tik_int_0=0;start_timer_1=1;stop_timer_1=0; TCCR1B=(1<<CS10)|(1<<WGM12); flag_LED=0; }дел
давайте код целиком, с описанием переменных
специально нашел описание регистра TCCR1B. Если TCCR1B=0 - то таймер не считает. Если TCCR1B=(1<<CS10)|(1<<WGM12) - то таймер считает без деления частоты.
и как из этого следует, что ваша строчка "запускает таймер"? Она запускает, только если до того TCCR1B=0. А если TCCR1B у вас уже настроен - последующее "добление" этой строкой в лупе НЕ МЕНЯЕТ НИЧЕГО.
А если TCCR1B у вас уже настроен - последующее "дробление" этой строкой в лупе НЕ МЕНЯЕТ НИЧЕГО.
Правильно. И я так думал. А оказывается - ошибался. Поэтому я и спросил почему такое может быть.
Скорее всего все упирается в длительность исполнения участков кода.