требуется помощь знатоков Си
- Войдите на сайт для отправки комментариев
Втр, 31/10/2017 - 10:53
Начал изучать структуры, решил сделать таймер который работает по заданным интервалам с заданой маской включения или выключения ножки МК. Пока сделал для 1 таймера все работает в протеусе как надо. Помогите правильно собрать всё функцию, то что сейчас находится в основном цикле программы так чтоб второй таймер крутился параллельно первому, но уже со своими интервалами и задержками. Переменная tic инерементируется по прерыванию раз в секунду. Я так понимаю тут без указателей не обойтись?
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define TIMER_TICKS_IN_ONE_SECOND 8 //тики таймера в секунду при делителе 1024. OCRA=122. (1000000/1024/122 = 8)
unsigned char count_to_second; //число тиков TIMER1
unsigned long int tic; //отсчет времени в секундах
//------------------------------------------------------------------
void port_ini (void){
DDRB = (1 << PB0) //выход
|(1 << PB1)//выход
|(1 << PB2)//выход
|(1 << PB3)//выход
|(1 << PB4);//выход
PORTB=0b00000000;
}
//------------------------------------------------------------------
//инициализация таймера1
void timer1_ini (void){
TCCR1 |= (1 << CTC1) //режим CTC
|(0<<COM1A1)|(0<<COM1A0) //отключаем OC1A
|(1 << CS13)|(0 << CS12)|(1 << CS11)|(0 << CS10); //Делитель 512
TCNT1 = 0x00; //сброс счетчика
OCR1A = 125;
OCR1C = 125; //регистр сравнения
TIMSK |=(1<<OCIE1A); //включаем прерывания по сравнению с OCR1A
}
//------------------------------------------------------------------
//обработка прерывания таймера0
ISR (TIMER1_COMPA_vect){
count_to_second++;
if (count_to_second >= TIMER_TICKS_IN_ONE_SECOND) { // Отсчитываем прерывание 8 раз получаем 1 секунду
tic++;
count_to_second=0;
}
}
typedef struct //создаем синоним структуры
{
unsigned char sequence; //последовательность включения светодиода
unsigned char intervals[8]; //время каждого интервала
} Timers;
int main(void)
{
sei();
port_ini(); //Инициализируем порты
timer1_ini(); //Инициализируем таймер1
Timers Timer_1 = {0b01010101, {1, 1, 1, 1, 2, 1, 2, 1}};
//Timers Timer_2 = {0b01010101, {1, 1, 1, 1, 2, 1, 2, 1}};
while(1)
{
for ( unsigned char i=0; i<8;){
static unsigned char time; //сумма интервалов после 0 элемента массива
if (tic<Timer_1.intervals[0]+time){
if (((Timer_1.sequence>>i)&0x01)>0){
PORTB |=(1<<PB0);}
else {PORTB &=~(1<<PB0);}
}
else{ i++; time+=Timer_1.intervals[i];}
}
}
}
посмотри как реализовано
https://github.com/DetSimen/Arduino-
1 аппаратный таймер для нескольких программных
В классах пока не особо разбираюсь, я так понял вы реализуете все уменьшением заданного интервала. У вас на С++ все я на С# делаю :/
Меня интересует как собрать в функцию данный кусочек кода, именно программная реализация, не пойму как объявить элементы массива структуры как переменные в функции. Моя структура Timer_1 со своими параметрами будет работать для PB0, Timer_1 для PB1 и т.д. Я понимаю что там много праллелных таймеров и они будут работать абсолютно асинхронно.
for ( unsigned char i=0; i<8;){ static unsigned char time; //сумма интервалов после 0 элемента массива if (tic<Timer_1.intervals[0]+time){ if (((Timer_1.sequence>>i)&0x01)>0){ PORTB |=(1<<PB0);} else {PORTB &=~(1<<PB0);} } else{ i++; time+=Timer_1.intervals[i];} } }В классах пока не особо разбираюсь, я так понял вы реализуете все уменьшением заданного интервала. У вас на С++ все я на С# делаю :/
Тут я и ауелъ. Вопросов больше не имею.
не все вашего уровня, уж простите.
посмотри как реализовано
https://github.com/DetSimen/Arduino-
1 аппаратный таймер для нескольких программных
Я посмотрел. Слабенько сделано. Чем дергать TTimerList::Step каждую мсек. лучше расчитатьт по данным Items сколько времени нужно до ближайшего требуемого интервала и настроить таймер на требуемую длительность. Так процессор существенно менше нагружается. Определять сколько времени нужно - это поиск минимального значения в массиве.
По изложеному подходу я делал на одном таймере формирование интервалов для одновременного использования сервоприводов и ds18b20, интервалы от 10мксек получаются и погрешность 4мксек. Но то уже совсем жестко, приходится учитывать время отработки самого обработчика. В конце цикла по значению таймера смотрим как долго крутился обработчик и если до следующего интервала мало времени, то считаем что он уже наступил и вызываем его обработчик.
Гдето так вобщем.
void TIMER1::Interrupt(void) { restart_proc: cli(); word dhh=Pause(); TCCR1A = 0; volatile word e; volatile word f; for(e=TCNT1;;){f=TCNT1;if(e!=f) break;} //ждем инкримента таймера для защиты от него следующих операций f=TCNT1; if(f>=dhh) //следующий интервал слишком короткий, он фактически прошел, сразу и стартуем {TCNT1 =f-dhh;sei();goto restart_proc;} TCNT1 =f-dhh; sei(); }; int TIMER1::Pause(void) { start: word t=0xffff; TIMER1_INTERRUPT_LIST_RECORD* p; for(p=TIMER1_INTERRUPT_LIST;p->fn;p++) { /* По логике CurrInterval всегда не более любого p->time */ if(p->time) p->time=p->time-CurrInterval; if(p->time<4) //это допустимая погрешность, если осталось менше 4 тактов, то считаем пора p->time=p->fn(p->ctx); if(p->time) if(p->time<t) t=p->time; //Serial.print(p->time); Serial.print("; "); } CurrInterval=t; return CurrInterval; }В классах пока не особо разбираюсь, я так понял вы реализуете все уменьшением заданного интервала. У вас на С++ все я на С# делаю :/
Тут я и ауелъ. Вопросов больше не имею.
+1