Пятница, 29.03.2024, 00:44
Микроконтроллерная техника AVR
Главная Регистрация Вход
Приветствую Вас, Гость · RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Микроконтроллеры » Вопросы по МК » как одним таймером отсчитать разные промежутки времени?
как одним таймером отсчитать разные промежутки времени?
belazovДата: Понедельник, 22.11.2010, 19:49 | Сообщение # 1
Рядовой
Группа: Пользователи
Сообщений: 16
Репутация: 0
Статус: Offline
никак не въеду:
таймер Т1 на тини2313. прерывание при совпадении дает мне счетчик времени.
использую флаг от прерывания для отсчета необходимых пауз. на паузе зависает.
unsigned char x=0;
unsigned char y=0;
unsigned char z=0;
unsigned char N=0;

//***вариант первый
//флаг1 инвертируется каждое прерывание от таймера
//число N задаю по ходу программы дл отработки пауз
//разной длительности
void wait(void)
{
z=N; //назначаю кол-во прерываний N для отсчета
x=flag1; //начальное значение х
y=0; //вспомагательная переменная
if (y<z) //если y<z
{
while (x==flag1){}; //проверяю когда изменится flag1, т.е. произойдет прерывание
//пока флаг не изм. крутится пустой цикл
y=y+1; //как только flag1 изм., то инкремент y
}
else
{
N=0; //если y=z, то переход к следующей функции
};
}

//******** или вариант второй

void wait(void)
{
x=flag1;
y=0;
z=N;
m1:
if (y<z)
{ if (x==~flag1) {y=y+1;x=flag1;}
else {goto m1;};

};
}

//********третий вариант
void wait(void)
{
z=N; //назначаю кол-во прерываний N для отсчета
x=flag1; //начальное значение х
y=0;
if (y<z) //если y<z
{
while (x==flag1){}; //проверяю когда изменится flag1, т.е. произойдет прерывание
//пока флаг не изм. крутится пустой цикл
y=y+1; //как только flag1 изм., то инкремент y
}
else
{
// N=0; //если y=z, то переход к следующей функции
};
}

Добавлено (22.11.2010, 19:49)
---------------------------------------------

Code
/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.9a Evaluation
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :   
Version :   
Date    : 16.11.2010
Author  : Freeware, for evaluation and non-commercial use only
Company :   
Comments:   

Chip type               : ATtiny2313
AVR Core Clock frequency: 8,000000 MHz
Memory model            : Tiny
External RAM size       : 0
Data Stack size         : 32
*****************************************************/

#include <stdio.h>
#include <TINY4313_BITS.h>   
#include <tiny2313.h>    // объявляем библиотека ввода/вывода
#include <delay.h>        // объявляем библиотеку для задержки

#define digit1 PORTD.6      //анод первой цифры - единицы
#define digit2 PORTD.5      //анод второй цифры - десятки
#define digit3 PORTA.0      //анод вспомагателного индикатора
#define buzer  PORTD.4          //пищалка
#define out0volt PORTD.3        //отключения напряжения от электродов
#define rele_napravlen PORTD.1  //реле направления напряжения на электродах
                       
flash char digits[] = {      //создаём массив с цифрами
0x60,                   //0
0xF9,                   //1
0xA4,                   //2
0xB0,                   //3
0x39,                   //4
0x32,                   //5
0x22,                   //6
0xF8,                   //7
0x20,                   //8
0x30,                   //9
0b11111101,                   //знак минуса
0b11111111                    //пустота
};                   

char digit_out[3], cur_dig;   //переменные для работы с LED
unsigned int indication;     //переменная для хранения выводимого на LED числа
unsigned char tmp=0;        //переменная для счета числа прерываний Т1
bit flag0=0;                    //переменные для контроля счета событий таймера Т0
                    // инвертируется 122 раза в сек
bit flag1=0;                    //переменные для контроля счета событий таймера Т1
unsigned char x=0;        //перем вспомогательная
unsigned char time=0;    //перем для счета минут
unsigned char y=0;        //перем вспомогательная
unsigned int z=0;        //перем вспомогательная
unsigned int N=0;       //перем вспомогательная
bit x5=0;                   //перем вспомогательная
//*****************************************************
void wait(void)
{
x=flag0;      
y=0;
z=N;
//m1:
if (y<z)                            //если y<z
      {   if (x==~flag0)       //если флаг поменялся
          {y=y+1;x=flag0;}   //инкремент y, х готовим к смене флага
          else    {};
      };
}

void stop(void)
{
TCCR1B=0x00;           //остановка таймера Т1
time=30;                  // показания индикатора после остановки Т1
out0volt=0;                   //откл напряжения выхода
buzer=0;                      //сигнал вкл
N=61;                         //количество циклов для паузы в 0,5сек
wait();                       //отработка паузы
buzer=1;                     //сигнал откл
}

void recoding(void)                     //функция для перекодировки из hex в dec
{ if (indication<1000)                  //начинаем преобразование если число < 1000 так как
      {                    //3-разрядный LED
      digit_out[0]=indication%10;   //Делим на 10 остаток в масив 1-разряд
      indication=indication/10;       //Оставляем 2 разряда
      digit_out[1]=indication%10;   //Делим на 10 остаток в масив 2-разряд
      digit_out[2]=indication/10;     //Делим на 10 целое число в масив 3-разряд
      }                     
}                     

void counter(void)      //ф-ция счетчика для числа, выводимого на индикатор  
{
if (tmp>=2)              //если счет прерываний достиг 240(для отладки 2 вместо 240)
     {time=tmp/2;       // то это 1 минута (для отладки 2 вместо 240)
      x5=time/5;          //выделяю периоды по 5 минут
      if (time==30)       //если время достигло 30мин
      {stop();}             //то выполн ф-цию СТОП
      else                    //если время еще не 30мин
          {if (x5==1)      //проверка - если прошло 5мин то вкл бузер   
             {buzer=0;
              x5=0;
              N=30;
              wait();                   //вот здесь нужна пауза в 0,25сек[/color][/b]
              buzer=1;}   
           else  {};                  //и обнуляю х5
          };
     }
else    
     {      
     };
}

void start(void)      //описываю ф-цию start
{
indication=0;       //число минут в индикаторе обнулить
TCCR1B=0x00;     //остановка таймера Т1
TCCR1B=0x0D;    //запуск Т1 делитель 7813Гц и режим прерыв при совпадении с OCR1А
}

//таймер 0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
flag0=~flag0;   //инвертирую каждое прерывание флаг0
PORTB=0xFF;       //чтобы предотвратить эффект “тени” на соседних индикаторах
      switch (cur_dig){
      case 0:{digit3=1; digit1=0; break;};  //подаём питание на разряд 3
      case 1:{digit1=1; digit2=0; break;};  //подаём питание на разряд 2
      case 2:{digit2=1; digit3=0; break;};  //подаём питание на разряд 1
                  }                         //ОА на digit->0, OK->1
PORTB=digits[digit_out[cur_dig]];  //выводим с каждым срабатыванием таймера число с
                     //мaссива в порт В, но не для всех разрядов сразу
cur_dig++;                     //с каждым срабатыванием таймера, увеличиваем
                     //переменную cur_dig на 1
if(cur_dig==3) cur_dig=0;           //если cur_dig = 3 обнуляем
}

// Timer1 output compare A interrupt service routine
//прерывание каждые 0,2с.
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
      tmp=tmp+1;
      flag1=~flag1;   //инвертирую каждое прерывание флаг
//    buzer=flag1;     //вывожу на вывод бузера для контроля срабатывания прерывания
      counter();
      indication=time;  //посчитанное отправл на индикацию
      recoding();          //декодирую ед и десятки
}
void main(void)
{
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

PORTA=0x00;
DDRA=0x00;
PORTB=0xFF;
DDRB=0xFF;
PORTD=0x7B;
DDRD=0x7A;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 31,250 kHz
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x04;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x08;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x06;    //период прерываний 200мс
OCR1AL=0x59;
OCR1BH=0x00;
OCR1BL=0x00;

// INT0: On
// INT0 Mode: Low level
GIMSK=0x40;
MCUCR=0x00;
EIFR=0x40;

TIMSK=0x42;
USICR=0x00;
ACSR=0x80;
// Global enable interrupts
#asm("sei")

    start();
}


Сообщение отредактировал belazov - Вторник, 23.11.2010, 19:47
 
HiSERДата: Вторник, 23.11.2010, 18:46 | Сообщение # 2
Продвинутый автор!
Группа: Проверенные
Сообщений: 254
Репутация: 11
Статус: Offline
Напиши задачу что должно выполнять устройство, из кода я ни чего понять не могу.
while (x=flag1); условие равенства пишется двойным "=="
 
belazovДата: Вторник, 23.11.2010, 19:38 | Сообщение # 3
Рядовой
Группа: Пользователи
Сообщений: 16
Репутация: 0
Статус: Offline
задача стоит такая:
Т0 прерывание по переполнению - используется для динамической индикации времени процедуры.
Т1 - прерывание по совпадению с OCR1A - для отсчета времени процедуры.
1) через 5 минут включить реле0-пауза 0,5с-отключить реле0, включить реле1, включить-2сек-выключить реле2
2) через 5 минут включить реле0-пауза 0,5с-отключить реле0, выключить реле1, включить-2сек-выключить реле2
3) т.е. п.1 и п.2 повторяются до окончания времени процедуры каждые 5 минут.
4) после окончания процедуры (дохожу до установленного времени) таймер Т1 стоп, на индикаторе конечное время

нужны паузы 0,2с; 0,5с; 2с без запрета прерываний чтоб не прерывался общий счет времени и не тухла индикация.
может сделать на мега8 с 3мя таймерами или добавить типа тини15 к тини2313?
условие равенства уже увидел, исправил

 
HiSERДата: Вторник, 23.11.2010, 22:00 | Сообщение # 4
Продвинутый автор!
Группа: Проверенные
Сообщений: 254
Репутация: 11
Статус: Offline
Чем такой вариант не подходит?

Code

#include <tiny2313.h>
#include <delay.h>

#define ACTION_TIME 300
#define RELAY0 PORTD.0
#define RELAY1 PORTD.1
#define RELAY2 PORTD.2

typedef unsigned char byte;
typedef unsigned int word;

flash byte led_table[12]={0x60,0xF9,0xA4,0xB0,0x39,0x32,0x22,0xF8,0x20,0x30,0xFD,0xFF};         

word time=ACTION_TIME;
word led_num;
byte led_dig=0;
bit action=0;

interrupt [TIM0_OVF] void tmr0_ovf() {
PORTB=0xff;
switch (led_dig) {
case 1:
PORTD.6=0;
PORTD.5=1;
break;
case 2:
PORTD.5=0;
PORTA.0=1;
break;
default:
led_num=time-1;
PORTA.0=0;
PORTD.6=1;
led_dig=0;
}
led_dig++;
PORTB=led_table[led_num%10];
led_num/=10;
}

interrupt [TIM1_COMPA] void tmr1_compa() {
time--;
if (time==0) {
time=ACTION_TIME;
action=1;
}
}

void main() {
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

PORTA=0;
DDRA=1;
PORTB=0;
DDRB=0xff;
PORTD=0;
DDRD=0x67;

TCCR0A=0;
TCCR0B=0;
TCNT0=0;

TCCR1A=0;
TCCR1B=0;
TCNT1H=0;
TCNT1L=0;
OCR1AH=0x1e;
OCR1AL=0x85;

TIMSK=0x42;

ACSR=0x80;

#asm("sei")

delay_ms(200);

TCCR0B=4;
TCCR1B=0x0d;

while (1) {
if (action==0) continue;
action=0;
RELAY0=1;
delay_ms(500);
RELAY0=0;
RELAY1^=1;
RELAY2=1;
delay_ms(2000);
RELAY2=0;
}
}  


Сообщение отредактировал HiSER - Вторник, 23.11.2010, 22:05
 
belazovДата: Среда, 29.12.2010, 09:48 | Сообщение # 5
Рядовой
Группа: Пользователи
Сообщений: 16
Репутация: 0
Статус: Offline
когда вставлял delay_ms(N) то гасла индикация динамическая. я вроде как понимаю что прерывание от таймера имеет бОльший приоритет и во время delay_ms(N) при прерывании должна произойти обработка прерывания а потом продолжится delay_ms(N). но как только начинается delay_ms(N) - сразу гаснет индикация.
попробую еще как у тебя- напишу

Добавлено (29.12.2010, 09:28)
---------------------------------------------
Не получилось с Tiny2313 и перешел на Mega8. для задержек использую отдельно таймер Т2 в такой подпрограмме. НО! пока не пойму почему эта подпрограмма когда прошиваю только ее одну - работает как надо, а когда она в составе общей программы вызывается в нужных местах - не работает. причем (вывел индикацию работы Т2 на LED)не включается Т2.

void prog5min(void)
{TCCR2=0x07; //старт таймера Т2
// чтобы при обнулении счетчика тактов отработка не началась опять
//пропускаю case0 и работаю с case1
switch (tmp2)
{
case 1: buzer = 0;PC817=0; break; //звук вкл.,PC817 вкл
case 3: buzer = 1;break; //через 2 такта звук выкл
case 4: buzer = 0; break; //через 1 такт звук вкл
case 5: buzer = 1; break; //через 1 такт звук выкл
case 39: buzer =0;rele=~rele; //на 1 такт звук вкл,реле
break; //переключить
case 40:PC817=1; buzer = 1; //РС817 откл, звук откл
TCCR2 = 0x00; //останавливаем timer2
tmp2 = 0; //обнулить счетчик тактов
break;
}
}

Добавлено (29.12.2010, 09:41)
---------------------------------------------

Code
#include <mega8.h>
#include <delay.h>

#define DP2    PORTC.0      //точка на индикаторе
#define digit1 PORTC.2      //анод первой цифры - единицы
#define digit2 PORTC.1      //анод второй цифры - десятки
#define digit3 PORTC.3      //анод вспомагателного индикатора
#define buzer  PORTC.4      //пищалка
#define ADC_in PORTC.5      //вход АЦП
#define PC817  PORTD.0      //отключение напряжения от электродов
#define rele   PORTD.1      //реле направления напряжения на электродах
                         
flash char digits[] = {      //создаём массив с цифрами
0b01010000,                   //0
0b01111101,                   //1
0b01100010,                   //2
0b01101000,                   //3
0b01001101,                   //4
0b11001000,                   //5
0b11000000,                   //6
0b01111100,                   //7
0b01000000,                   //8
0b01001000,                   //9
0b11101111,                   //знак минуса
0b11111111                    //пустота
};                    

char digit_out[3], cur_dig;   //переменные для работы с LED
unsigned int indication;      //переменная для хранения выводимого на LED числа
unsigned char tmp=0;          //переменная для счета числа прерываний Т1
unsigned char tmp2=0;         //переменная для счета числа прерываний Т2
bit flag0=0;                      //переменные для контроля счета событий таймера Т0
bit flag1=0;                     //переменные для контроля счета событий таймера Т1
bit flag2=0;                    //переменные для контроля счета событий таймера Т2
unsigned char time=0;   //перем для счета минут
//*****************************************************
void recoding(void)                     //функция для перекодировки из hex в dec
{   if (indication<1000)               //начинаем преобразование если число < 1000 так как
       {                    //3-разрядный LED
       digit_out[0]=indication%10;    //Делим на 10 остаток в масив 1-разряд
       indication=indication/10;          //Оставляем 2 разряда
       digit_out[1]=indication%10;    //Делим на 10 остаток в масив 2-разряд
//    digit_out[2]=indication/10;     //Делим на 10 целое число в масив 3-разряд
       digit_out[2]=0b11101111;
       }                      
}                      
//******************************************************
void prog5min(void)
{
TCCR2=0x00;     //таймер остановлен
TCCR2=0x0F;     //старт таймера Т2
// чтобы при обнулении счетчика тактов отработка не началась опять
//пропускаю case0 и работаю с case1           
           switch (tmp2)
           {
           case 1:  buzer = 0;PC817=0; break;  //звук вкл.,PC817 вкл
           case 3:  buzer = 1;break;               //через 2 такта звук выкл
           case 4:  buzer = 0; break;              //через 2 такта звук вкл
           case 5:  buzer = 1; break;              //через 1 такт звук выкл    
           case 39: buzer =0;rele=~rele;        //на 1 такт звук вкл,реле
                    break;                    //переключить
           case 40:PC817=1; buzer = 1;         //РС817 откл, звук откл
           TCCR2 = 0x00;                            //останавливаем timer2
           tmp2 = 0;                    //обнулить счетчик тактов
           break;
           }          
//здесь добавить еще переключение крутилки    
}

void stop(void)
{
TCCR1B=0x00;    //остановка таймера Т1
time=30;           // показания индикатора после остановки Т1
PC817=0;          //откл напряжения выхода      
prog5min();
}

void counter(void)
{time=tmp;
switch (time)
           {
           case 5:  [color=red]prog5min()[/color]; break;            
           case 10: prog5min(); break;              
           case 15: prog5min(); break;             
           case 20: prog5min(); break;             
           case 25: prog5min(); break;             
           case 30: stop();     break;
           }
}

void start(void)        //описываю ф-цию start
{
indication=0;         //число минут в индикаторе обнулить
TCCR1B=0x00;      //остановка таймера Т1
TCCR1B=0x0D;      //запуск Т1 делитель 977Гц и режим прерыв при совпадении с А
DP2=flag2;           //мигающая точка во время работы Т2
}

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{TCNT0=0xBF;                    // Reinitialize Timer 0 value, частота прерываний 77Гц
    flag0=~flag0;                    //инвертирую каждое прерывание флаг0
    PORTB=0xFF;                    //чтобы предотвратить эффект “тени” на соседних индикаторах
       switch (cur_dig){
       case 0:{digit3=1; digit1=0; break;};  //подаём питание на разряд 3
       case 1:{digit1=1; digit2=0; break;};  //подаём питание на разряд 2
       case 2:{digit2=1; digit3=0; break;};  //подаём питание на разряд 1
                   }                    //ОА на digit->0, OK->1
    PORTB=digits[digit_out[cur_dig]];   //выводим с каждым срабатыванием таймера число с
                      //мaссива в порт В, но не для всех разрядов сразу
cur_dig++;                    //с каждым срабатыванием таймера, увеличиваем
                      //переменную cur_dig на 1
if(cur_dig==3) cur_dig=0;           //если cur_dig = 3 обнуляем
     }

// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{    tmp=tmp+1;
       flag1=~flag1;      //инвертирую каждое прерывание флаг
       counter();
       indication=time; //посчитанное отправл на индикацию
       recoding();         //декодирую ед и десятки
}

// Timer2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{tmp2=tmp2+1;
    flag2=~flag2;
}

#define ADC_VREF_TYPE 0xE0
// Read the 8 most significant bits of the AD conversion result
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
ADCSRA|=0x40;                     // Start the AD conversion
while ((ADCSRA & 0x10)==0); // Wait for the AD conversion to complete
ADCSRA|=0x10;
return ADCH;
}

void main(void)
{    
PORTB=0xFF; // .7=1 .6=1 .5=1 .4=1 .3=1 .2=1 .1=1 .0=1
DDRB=0xFF;  // .7=Out .6=Out .5=Out .4=Out .3=Out .2=Out .1=Out .0=Out

PORTC=0x1F;// State6=T State5=T State4=1 State3=1 State2=1 State1=1 State0=1
DDRC=0x1F; // Func6=In Func5=In Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out

PORTD=0xFC; // State7=1 State6=1 State5=1 State4=1 State3=1 State2=P State1=0 State0=0    
DDRD=0xFB; // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=In Func1=Out Func0=Out

// Timer/Counter 0 initialization
// Clock source: System Clock; Clock value: 15,625 kHz
TCCR0=0x03;
TCNT0=0xBF; //частота прерываний 77Гц

// Timer/Counter 1 initialization
// Clock source: System Clock; Clock value: 0,977 kHz
// Mode: CTC top=OCR1A; OC1A output: Discon. OC1A output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x01; //1min=E4FC, для отладки ставлю 0.5 сек    
OCR1AL=0xE8;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 0,977 kHz
// Mode: CTC top=OCR2
// OC2 output: Disconnected
ASSR=0x00;
//TCCR2=0x0F;   //так таймер запускается с Clock value: 0,977 kHz
TCCR2=0x00;     //таймер остановлен
TCNT2=0x00;
OCR2=0xC3;

// External Interrupt(s) initialization
GICR|=0x40;
MCUCR=0x00;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x91; // 1001 0001

// Analog Comparator initialization
ACSR=0x80;      //0b1000 0000
SFIOR=0x00;

// ADC initialization
ADMUX=ADC_VREF_TYPE & 0xff; //0b1111 1111
ADCSRA=0x82;                //0b1000 0010

#asm("sei")  // Global enable interrupts
start();
}

Добавлено (29.12.2010, 09:48)
---------------------------------------------
подпрограммы counter и stop вызывают в своем теле подпрограмму prog5min(). но prog5min() не запускается. может я неправильно вызываю prog5min() из других подпрограмм?

Сообщение отредактировал belazov - Четверг, 30.12.2010, 14:09
 
Форум » Микроконтроллеры » Вопросы по МК » как одним таймером отсчитать разные промежутки времени?
  • Страница 1 из 1
  • 1
Поиск:

Хостинг от uCoz