Форум по микроконтроллерам: Расчет Точных Временных Задержек - Форум по микроконтроллерам

Перейти к содержимому

Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

Расчет Точных Временных Задержек Возможно ли рассчитывать точные временные задержки?

#1 Пользователь офлайн   Digg 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 19
  • Регистрация: 14 Октябрь 09

Отправлено 14 Октябрь 2009 - 13:35

Добрый день.
Подскажите пожалуйста как можно рассчитать точную временную задержку на С для PICов.
IDDQD, IDKFA... и понеслось
0

#2 Пользователь офлайн   Alex 

  • Активный участник
  • PipPipPip
  • Группа: Администратор
  • Сообщений: 320
  • Регистрация: 08 Август 08
  • Пол:Мужчина
  • Город:http://forum.eldigi.ru/

Отправлено 15 Октябрь 2009 - 17:22

Таймером.
По конкретнее задачу изложите.
0

#3 Пользователь офлайн   Digg 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 19
  • Регистрация: 14 Октябрь 09

Отправлено 16 Октябрь 2009 - 12:13

Я с помощью таймера и прерывания сделал задержку в 0.5 секунды, а там через 1.5 секунды появляется 2мкс лишних. Я моделировал в Proteus там это хорошо видно
#include <htc.h>
#include <pic.h>
#include  <pic16f62xa.h>

//config

__CONFIG(WDTDIS & LVPDIS & HS);// wachdogtimer off, low voltage progr off, qartz external


//function
void main(void);
unsigned char eeprom_read(unsigned char adr);
void wait(unsigned int time_ms);
//void second(second);

//EEpROM DATA
__EEPROM_DATA(0x7E,0x0C,0xB6,0x9f,0xcc,0xda,0xfa,0x0e);// 0,1,2,3,4,5,6,7
__EEPROM_DATA(0xfe,0xde,0x00,0x00,0x00,0x00,0x00,0x00);//8,9 №eeprom adress== numbers


//variables
unsigned char Hour=12,HourL=0,HourH=0;
unsigned char Minute=59, MinuteL=0,MinuteH=0;
unsigned char Second=0;
unsigned char count=0, countT1=0, mode_counter=0;


void main(){
//PORTB 1-7 sevenseg data
//RA7,RA6 - oSC
//RB0- button for next
//ra0-ra3 - dinamic indicatin	
//rA4-RA5 - buttons


//PORT init
CMCON=0x07;// compartors off
TRISA=0x10;
PORTA=0x00;
TRISB=0x01;
PORTB=0x00;

//timer 1 use for second account
//timer0 use for inication 
// timer0 init
T0CS=0; // generator internal	
PSA = 0;//prescaler use
PS0=0;
PS1=1; // prescaler 1:8
PS2=0;

//timer1 init
TMR1L=0xf2;
TMR1H=0x0b;//таймер настроен примерно на 1 сек
	#asm
		nop;// надо для точного счета!!!!!!!!!!!!!
		nop
		nop
		nop
		nop
		nop
		nop
	#endasm
T1OSCEN=0;//генератор - внутренний off
T1CKPS1=1;// предделитель 1:8
T1CKPS0=1;
TMR1CS=0;//работа от внутреннего генератора f/4
TMR1ON=1;//вкл						


//Interrupt Enable
TMR1IE=1;//t1 int
PEIE=1;
GIE=1;// all int enable

while(1){//here will be indication
	


	
//button presed

if(!RB0){	//Mode butto press
	wait(2000);
	if(!RB0){
		wait(10000);
		if (!RB0){
			wait(10000);//only for
			while (RB0){
				PORTB=eeprom_read((Hour%0x0a)&0x0f);
				RA2=1;//show HourL
				wait(10);
				RA2=0;
				PORTB=eeprom_read((Hour/0x0a)&0x0f);
				RA3=1;//show HourH
				wait(10);
				RA3=0;
				if(RA4==0){
					wait(2000);
					if (RA4==0){
						Hour++;
						if(Hour==24) Hour=0;
					}// RA$==0 
				}//if(RA4==0) first pres
			}//while
			if(!RB0){
				wait(10000);
				while(RB0){
					PORTB=eeprom_read(((Minute)%0x0a)&0x0f);
					RA0=1;//show MinuteL
					wait(20);
					RA0=0;
					PORTB=eeprom_read(((Minute)/0x0a)&0x0f);
					RA1=1;//show MinuteH
					wait(20);
					RA1=0;
					if(RA4==0){
						wait(2000);
						if (RA4==0){
							Minute++;
							if(Minute==60) Minute=0;
						}// RA$==0 
					}//if(RA4==0) first pres
				}//while
			}//if(!RB0)
		
			
			
				Second=0;
				wait(10000);
				
			
	

		}//if (!RB0) long_press
		else {
			wait(1500);
			while(RB0){
			PORTB=eeprom_read(((Second)%0x0a)&0x0f);
			RA0=1;//show MinuteL
			wait(200);
			RA0=0;
			PORTB=eeprom_read(((Second)/0x0a)&0x0f);
			RA1=1;//show MinuteH
			wait(200);
			RA1=0;
			if(RA4==0){
					wait(2000);
					if (RA4==0){
						Second=0;
					}// RA$==0 
				}//if(RA4==0) first pres
		}
		}

	}//if(!RB0) first short press

}//if(!RB0)start press





//indication
	PORTB=eeprom_read(((Minute)%0x0a)&0x0f);
	RA0=1;//show MinuteL
	wait(200);
	RA0=0;
	PORTB=eeprom_read(((Minute)/0x0a)&0x0f);
	RA1=1;//show MinuteH
	wait(200);
	RA1=0;
	PORTB=eeprom_read((Hour%0x0a)&0x0f);
	RA2=1;//show HourL
	wait(200);
	RA2=0;
	PORTB=eeprom_read((Hour/0x0a)&0x0f);
	RA3=1;//show HourH
	wait(200);
	RA3=0;
}



}//main 

static void interrupt isr(void) {
	if(TMR1IF){
	//	RA4=!RA4;
		TMR1L=0xdd;
		TMR1H=0x0b;
		GIE=0;
	
		TMR1IF=0;
		GIE=1;
		countT1++;
		if (countT1==2) {	
		Second++;//one second is over
		countT1=0;
	}
	if (Second==60){
			Second=0;
			Minute++;
			if (Minute==60){
				Minute=0;
				Hour++;
				if (Hour==24){
					Hour=0x00;
				}//if (Hour==24)
			}//(Minute==60
		}//(Second==60)
	}//tmr1if 

}//isr

unsigned char eeprom_read(unsigned char a) {
	EEADR=a;// адрес ячейки данных -> EEADR
	RD=1;	//добро на чтение
	//while(RD){} //ждем
	return EEDATA;
}//eeprom_data

void wait(unsigned int time_ms){
	
	TMR0=0x05; 
	count=0;
	while(time_ms){
		while(count!=0x10){
			if (T0IF){
				TMR0=0x05; 
				count++;
				T0IF=0;	
				//time count

	
			}//if (T0IF)
		}//while(count)
	time_ms--;
	}//while (time_ms)
}


Может подскажете почему так?
IDDQD, IDKFA... и понеслось
0

#4 Пользователь офлайн   Admin 

  • Администратор
  • PipPipPip
  • Группа: Администратор
  • Сообщений: 585
  • Регистрация: 08 Август 08

Отправлено 17 Октябрь 2009 - 19:05

1. Возможно ошибка протеуса.
2. Неправильно рассчитали временную задержку (нужно считать по формуле из даташита)
0

#5 Пользователь офлайн   Digg 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 19
  • Регистрация: 14 Октябрь 09

Отправлено 27 Октябрь 2009 - 16:05

Спасибо, тему можно закрывать.
IDDQD, IDKFA... и понеслось
0

#6 Пользователь офлайн   Alex 

  • Активный участник
  • PipPipPip
  • Группа: Администратор
  • Сообщений: 320
  • Регистрация: 08 Август 08
  • Пол:Мужчина
  • Город:http://forum.eldigi.ru/

  Отправлено 28 Октябрь 2009 - 01:25

Ну зачем сразу закрывать ? Скажу и я тогда пару слов о таймерах. :(

Реализация точных задержек на таймерах дело не простое, и требует некоторого опыта и много личного времени.
Ускорю Вам немного процесс "самоучения" и приведу пару примеров работы с таймерами. Заодно укажу на ошибки в вашей программе.

Итак, начнём с самого основного, с испольования таймера как 2-х байтной переменной (тип int).
Вовсе не обязательно "разлогать" его на байты, и обращатся к ним по отдельности. Это может сделать сам компиль.
В <b>pic16f62xa.h</b> TMR1 к сожалению не описан, но это не значит что мы сами не сможем сделать это.
Итак, пишем в начале проги (после инклудов и конфигов) такую строку

<b>static volatile near unsigned int TMR1 @ 0x00E;</b>

Тем самым мы объявили переменную TMR1 как 2-х байтную переменную находящуюся по адресу 0x00E.
Теперь мы можем к таймеру обращаться как к переменной.


Получилось у нас вот такое дело
#include <pic.h>
#include  <pic16f62xa.h>   // Это вовсе не обязательно. Всё это есть в pic.h

__CONFIG(WDTDIS & LVPDIS & HS);

static volatile near unsigned int	TMR1		@ 0x00E;

void main()
{
CMCON=0x07;// compartors off







while(1);
}


Едем далее.
Настраиваем таймер и разрешаем прерывания

TMR1IF=0; 
TMR1ON=1;
TMR1= 65535 - 1000;   // Таймер на 1000 циклов
TMR1IE=1;

PEIE=1;
GIE=1;
Думаю тут всё понятно.

Далее, создаём обработчик.

<b>void interrupt isr(void)
{


}</b>
И в нём пишем:

<b>if(TMR1IF)
{
TMR1IF =0;
TMR1= 65535 - 1000; // Таймер на 1000 циклов

NOP(); // Для точки останова

}</b>
Ставим бркпоинт в обработчике таймера (на НОПе) и смотрим в мплабе с каким промежутком у нас он вызывается.
Посмотрели, убедились что далеко не 1000 циклов, а 1012. А нам нужно 1000.
Немного пошаманив, поизменяв число 1000, добились постоянного вызова через каждые 1000 циклов. Получилось 988 (у меня по крайней мере).
И думаем, о как хорошо, сделали таймер на 1 мс. Да ничего подобного, мы просто, тупо, методом тыко подстроили таймер.
И проблемы начинаются когда мы начинаем писать программу дальше, добавлять ещё обработчики, объявлять переменные внутри обработчика и т.д..
Пример. Добавим парочку NOP'ов до обработки флага TMR1IF

NOP();
NOP();

if(TMR1IF)
{
......

И видим что наша 1 мс. уехала на 2 цикла.
И чего, постоянно коректировать наше число, подстраивать под программу ? А если мы добавим ещё какой-нибудь обработчик, например внешнего прерывания, и во время его обработки, произойдёт переполнение таймера. И пока обработчик не закончится, программа не выдет на обработку таймера. И когда она выдет на него, пройдёт некоторое время после установки флага <b>TMR1IF</b>, и это время у нас прибавится к нашему установленному значению. Следующим вызовом таймера у нас будет пересчёт.
И что нам делать ? А всё очень просто, мы скоректируем этот пересчёт, и установим значение таймера больше на столько тактов, сколько он пересчитал.
Пишем :

TMR1= 65535 - 1000 <b>+ TMR1</b>;

И получается, что следующим вызовом он "догонит" отстающее время.
Запускаем отладку, и видим что у нас на каждом вызове проходит одно и тоже время, но оно почемуто не 1000 циклов (хотя должно быть), а 1002.
И тут мы вспоминаем добрый и полезный ДШ. Оказывается, после установки таймера 2 следующих МЦ он не работает :)
Корректируем эти 2 цикла :

TMR1= 6553<b>7</b> - 1000 + TMR1;

Т.е. прибавляем к таймеру 2 еденицы (уменяьшаем время отсчёта).
Собираем всё это дело в кучу
#include <pic.h>
#include  <pic16f62xa.h>   // Это вовсе не обязательно. Всё это есть в pic.h

__CONFIG(WDTDIS & LVPDIS & HS);

static volatile near unsigned int	TMR1		@ 0x00E;

void main()
{
CMCON=0x07;// compartors off





TMR1IF=0; 
TMR1ON=1;
TMR1= 65535 - 1000;   // Таймер на 1000 циклов
TMR1IE=1;

PEIE=1;
GIE=1;

while(1);
}




void interrupt isr(void) 
{


NOP();
NOP();

if(TMR1IF)
{
TMR1IF =0;
TMR1= 65537 - 1000 + TMR1;

NOP();


}


}
И у нас получился таймер на 1 мс. Причём хоть до него, хоть после, пиши что угодно, он всегда будет считать по 1 мс.
На сколько бы программа не отстала до обработки флага <b>TMR1IF</b>, следующим вызовом она догонит своё полюбому.

Ну а теперь можно и секунды считать :)
Добавляем переменную для подсчёта миллисекунд

<b>unsigned int ms=0;</b>

и в обработчике пишем счётчик

ms++;
if(ms>999)
{
ms=0;
NOP();	// 1 секунда
}

Ставим брекпоинт на НОПе, и запускаем отладчик. И что мы видим ? О чудо , у нас получилась 1 сек :) И неважно в каком месте и что будет делать программа, сюда она будет приходить ровно через каждые 1 000 000 машинных циклов.

Теперь о задержках.
В Вашей программе увидел функцию <b>wait</b>. Не трудно было догататься что это такое. :)
Хочу привестисвой пример реализации таких задержек.

Что нам нужно ?
Нам нужно создать свой таймер на основе системного (тот который мы сделали).
Для этого создаём структуру с переменными (свойства таймера) и с именем (назовём tmr1).

struct 
{
	unsigned  enabled : 1;  // таймер вкл./выкл.
	  unsigned int interval;	// текущее значение таймера
} tmr1;


И процедуру его обработки (само тело)

void tmr1_modal()
{
	if(tmr1.enabled)   //  если таймер включен
	{	
	tmr1.interval--;   //   уменьшаем его значение на еденицу
		if(tmr1.interval==0)	tmr1.enabled=0;   //  если таймер дошёл до нуля, выключаем его	
	}
}


И в обработчике системного таймера (TMR1) вызываем эту процедуру.

if(TMR1IF)
{
TMR1IF =0;
TMR1= 65537 - 1000 + TMR1;

tmr1_modal();
.....
.....


И таймер готов.
Теперь остаётся в программе, в любом месте (естественно не в обработчике прерываний) задать ему значение (interval), включить его (enabled)
и ждать когда он выключится.
Выглядет это примерно так

tmr1.interval=500; tmr1.enabled=1;
while(tmr1.enabled);

Всё, задержка в 500 мс. готова :)
Теперь у нас и секунды будут точно щёлкать и задержки можно реализовывать в основном цикле.


Ну вот вроде бы и всё. :)
Прикрепляю проект, который Мы только что сделали.
Прикрепленный файл  123.rar (13,01К)
Количество загрузок:: 313

Удачи и успехов !
0

#7 Пользователь офлайн   Digg 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 19
  • Регистрация: 14 Октябрь 09

Отправлено 28 Октябрь 2009 - 10:39

Спасибо, очень интересно.
Скажите каким кампилятором вы пользуетесь и может посоветуете, что почитать чтобы с С разобраться ?
IDDQD, IDKFA... и понеслось
0

#8 Пользователь офлайн   Alex 

  • Активный участник
  • PipPipPip
  • Группа: Администратор
  • Сообщений: 320
  • Регистрация: 08 Август 08
  • Пол:Мужчина
  • Город:http://forum.eldigi.ru/

Отправлено 28 Октябрь 2009 - 19:37

Таким же, каким и Вы :( HI-TECH PICC
Вместе с компилем устанавливается мануал (правда на англицком), в нём описаны все команды и функции.
0

#9 Пользователь офлайн   shapkin 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 1
  • Регистрация: 12 Октябрь 10
  • Пол:Мужчина

Отправлено 12 Октябрь 2010 - 12:17

Благодарю Вас. Очень полезный ответ!
0

#10 Пользователь офлайн   Oleg_S 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 1
  • Регистрация: 06 Ноябрь 10

Отправлено 06 Ноябрь 2010 - 20:51

Alex, спасибо! Очень хорошее объяснение.
0

#11 Пользователь офлайн   salarm 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 1
  • Регистрация: 26 Декабрь 10

Отправлено 26 Декабрь 2010 - 20:54

исчерпывающий ответ, поучительно!
0

#12 Пользователь офлайн   Ethereal 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 10
  • Регистрация: 18 Январь 11

Отправлено 18 Январь 2011 - 20:29

ДРУГОЙ СТИЛЬ СОЗДАНИЯ ТАЙМЕРОВ

Подготовительная работа :

1.) Выкидываем нафиг Протеус и другие симуляторы. Симулятором будет ваш мозг !
Распечатываем программу на принтере, ползем по листингу с карандашом и
в голове представляем что делает процессор, исполняя ту или иную команду
и что в итоге происходит.
2.) Выкидываем нафиг Си. Си - это попса. Пусть Филипп Киркоров пишет на Си.
Тяжелый рок - это ассемблер. В нем все в тысячу раз легче и в тысячу раз
проще !
3.) Выкидываем нафиг все среды разработки. Они даром не нужны.
Все, что вам надо - пакетный ассемблер, которому на вход подается текст
программы, а на выходе получается или HEX-файл или листинг с ошибками.

Проверено на личном опыте (с 1987-го года пишу на всевозможных
ассемблерах от PDP-11 до Motorola MCORE и симулятор не понадобился ни разу).

Создание таймера :

Пусть наш процессор - самый простой из всех, с самым примитивным 8-битным
таймером - PIC16F84 и пусть нам надо отсчитывать десятки миллисекунд.
В навороченных процессорах с многорежимными таймерами все выглядит, конечно,
гораздо проще, но мы возьмем самый сложный случай.

Первым делом подбираем кварц, чтобы его частота имела достаточно много
двоек среди множителей. Например, берем 4 Mhz, тогда один такт процессора
- 1 мкс. Значит нам надо сделать так, чтобы таймер тикал один раз в 10000
тактов. Делим эту 10000 на два до тех пор, пока можем
10000 /2 = 5000
10000 /2 /2 = 2500
10000 /2 /2 /2 = 1250
10000 /2 /2 /2 /2 = 625
и еще немножко :
10000 /2 /2 /2 /2 /2 = 312.5
10000 /2 /2 /2 /2 /2 /2 = 156.25
Результат деления вписался в диапазон байта : 0..255. Отлично !

Значит будем делать так :
1.) Предделитель таймера сделаем равным 2*2*2*2*2*2 = 64.
В итоге таймер будет тикать каждые 64 такта.
2.) Когда таймер тикнет и переполнится (перекинется из 255-и в 0-ль),
через 5 тактов после этого начнет выполняться обработчик прерывания
от таймера. Мы должны будем обновить счетчик таймера ДО ТОГО как
он тикнет еще раз (иначе возникнет трудноразрешимая проблема
потерянных тиков). Поскольку тикает таймер раз в 64 такта для этого
у нас есть большой запас по времени (64-5 = 59 тактов). Если мы поместим
обновление счетчика таймера в обработчике прерывания САМЫМ ПЕРВЫМ, то
мы заведомо успеем.
3.) Будем в обработчике прерывания подгружать в счетчик таймера
константу 256-156 = 100. Но каждый четвертый раз подгрузим не 100, а 99,
т.е. будем делать поправку на то, что 10000 на 64 делится с дробями.
В итоге три раза таймер будет переполняться через 156 тактов, а
один раз через 157. Что даст в среднем переполнение через 156.25 такта.
Т.е. таймер будет отсчитывать 1MHz / 64 / 156.25 = 100Hz
сотые доли секунды, т.е десятки миллисекунд
4.) В обработчике прерывания будем декрементировать некую переменную
PAUSE до нуля. Если в головной программе надо будет сделать паузу в 1
секунду, то закинем в переменную PAUSE число 100 и подождем пока PAUSE
не скинется в ноль. В процессе ожидания наша головная программа может
заниматься своими делами, например опрашивать кнопки - пауза все равно
отсчитается. Таких переменных для отсчета пауз можно сделать несколько.
5.) Кроме того, можно инкрементирвать в обработчике переменную TIME,
которая будет нашим системным временем в десятках миллисекунд.
А можно это время сделать двухбайтным TIME_H:TIME_L, а можно и
четырехбайтным.

Короче говоря, в головной программе имеем :
		MOVLW   B'xx0x0110';Predivisor RTCC 1:64
		OPTION
		MOVLW   (1 << GIE) | (1 << RTIE)
		MOVWF   INTCON;Разрешение прерываний по переполнению таймера

А в обработчике прерывания имеем :
				ORG	 0004H		 ;Вектор прерывания

INTERRUPT	   MOVWF   TEMP_W		;Сохранение
				SWAPF   STATUS,W	  ; W и
				MOVWF   TEMP_STATUS; STATUS
				INCF	TIME_L,F	  ;Мл.байт системного времени
				BTFSC   STATUS,Z
				INCF	TIME_H,F	;Ст.байт системного времени
				MOVLW   .99		;В одном случае из четырех
				BTFSC   TIME_L,1
				BTFSS   TIME_L,0
				MOVLW   .100		  ;В трех случаях из четырех
				MOVWF   TMR0		  ;Обновление счетчика таймера

				MOVF	PAUSE,F
				BTFSS   STATUS,Z	  ;Надо ли отсчитывать паузу ?
				DECF	PAUSE,F	;Отсчет паузы

				...

				SWAPF   TEMP_STATUS,W ;Восстановление
				MOVWF   STATUS		; W
				SWAPF   TEMP_W,F	  ; и
				SWAPF   TEMP_W,W	  ; STATUS
				BCF	 INTCON,RTIF;Сброс RTCC overflow interrupt flag
				RETFIE				;Возврат из прерывания

И это все ! Причем таймер выходит не плюс минус лапоть, а секунды
отсчитывает, что твой кварцевый метроном.
0

#13 Пользователь офлайн   Alex 

  • Активный участник
  • PipPipPip
  • Группа: Администратор
  • Сообщений: 320
  • Регистрация: 08 Август 08
  • Пол:Мужчина
  • Город:http://forum.eldigi.ru/

Отправлено 19 Январь 2011 - 16:45

И что Вы такого нового нам рассказали ? Я привёл в точности такой-же алгоритм как и Вы. Только в моём случае 16-ти битный таймер, а в Вашем 8-ми. И писал я на Си, а Вы на АСМе.
0

#14 Пользователь офлайн   wws63 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 1
  • Регистрация: 24 Декабрь 10

Отправлено 19 Январь 2011 - 17:13

Просмотр сообщенияAlex (19.1.2011, 19:45) писал:

И что Вы такого нового нам рассказали ?

"Распечатываем программу на принтере, ползем по листингу с карандашом" - А это разве не новшество :unsure:
Только так все радости жизни мимо пройдут, пока будете "ползать с карандашом"
P.S. Можно оспаривать чужое мнение, но не навязывать своё.....
0

#15 Пользователь офлайн   Ethereal 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 10
  • Регистрация: 18 Январь 11

Отправлено 22 Февраль 2011 - 23:14

С помощью карандаша отлаживается куда быстрее чем с помощью эмулятора.
Во всяком случае тех людей, которые пользуются Протеусами, я с помощью карандаша обгоняю.
Т.е. если вы натренируете свой мозг прогонять программу мысленно глядя на ее листинг,
лузеров, которые пользуются эмуляторами в качестве протеза мозга вы по скорости всегда будете делать.
Когда я начинал программировать, за время пока компилируется программа можно было пообедать.
Поверьте, очень способствовало быстрому росту профессионализма.
Приучало, сначала потратить 15 минут на мысленную компиляцию глазами и карандашом, чтобы потом
не терять в пустую много больше времени из-за наляпанных ошибок.
Что в итоге и привело к убежденности, что листинг и карандаш - самый быстрый способ.
Главное соблюдать принцип - чтобы не тратить огромное время на отлавливание ошибок
надо их не делать. А чтобы их не делать нужно хорошо понять работу команд процессора
и если тогда ты, глядя на листинг, видишь, что алгоритм безупречен, то и работать будет
он сразу.

О чем там говорить, если я не раз сейчас наблюдаю как заказчик жалуется, что написанная мною
программа не симулируется. Я его спрашиваю - программа на железе работает ?
Он говорит - работает. Но не симулируется.
Так-что это именно с симулятором только время зря терять, наступая на грабли
невозможности идеальной симуляции реальных процессов.
Пока вы трахаетесь с одной программой в симуляторе, а без него программу давно
напишу и отлажу на конечном железе.
0

#16 Пользователь офлайн   Ethereal 

  • Участник
  • PipPip
  • Группа: Пользователи
  • Сообщений: 10
  • Регистрация: 18 Январь 11

Отправлено 22 Февраль 2011 - 23:22

>И что Вы такого нового нам рассказали ?
Например отсчитывание четверти такта - вот новое.
В моем таймере каждое четвертое прерывание отчитывается на такт больше, что
дает поправку в среднем ровно на четверть такта.
Т.е. как делатся прецизионнаяя поправка к частоте на фиксированную долю такта, если кварц
не дает получить требуемую частоту сразу в чистом виде.

И нового то, как таймер делать минимумом средств (и минимумом команд процессора), сразу и точно.
А в вашем варианте вы попадали пальцем в небо :
>Посмотрели, убедились что далеко не 1000 циклов, а 1012. А нам нужно 1000.
>Немного пошаманив, поизменяв число 1000, добились постоянного вызова через каждые 1000 циклов. Получилось 988 (у меня по крайней мере).
>И думаем, о как хорошо, сделали таймер на 1 мс. Да ничего подобного, мы просто, тупо, методом тыко подстроили таймер.
и все эти подгонки методом тыка - это художественная самодеятельность какая-то.
Поправку надо вводить не по результатам сомнительных замеров, а рассчитать заранее какая она понадобится.
Если взялись делать таймер - делайте сразу образцово, а не подгоняйте алгоритм киянкой по месту.
0

#17 Пользователь офлайн   Alexeyslav 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 7
  • Регистрация: 05 Ноябрь 11

Отправлено 05 Ноябрь 2011 - 19:28

Тут небольшая неточность имеется. а именно в пункте

Цитата

3.) Будем в обработчике прерывания подгружать в счетчик таймера
константу 256-156 = 100

Дело в том что когда мы подгружаем в таймер константу сбрасывается его предделитель и теряются такты 5-10, сколько их пройдет с момента переполнения до загрузки константы в таймер. Поэтому будет иметь систематическую недостачу насчитанных тактов, что выльется в увеличении задержки на 5-10 маш.циклов примерно каждые 156.25*64 маш.цикла. Может это конечно и спишется в погрешность кварцевого генератора... однако имеет место быть. Для часов такой подход возможен только если предусмотрена еще какая-то коррекция хода на более высоком уровне - например пропускать или наоборот начислять по два за раз по 10мс интервалами каждую минуту. В зависимости от того сколько раз прибавим или отнимем от "счетчика времени" интервалов по 10мс за минуту можно регулировать величину коррекции хода часов. Остается найти кварц с нулевым ТКЕ или термостатировать его и можно получить довольно точные часы с точностью хода +-1 минута в год независимо от точности кварца.

Еще один принцип формирования нужных временных интервалов: пусть таймер себе считает непрерывно некоторое время, сравниваем в программе его с предыдущим значением - если оно больше на необходимый интервал(например 1000) - прибавляем к предыдущему значению 1000 - неважно на сколько больше счетчик перебрал в момент проверки, просто следующий момент коррекции произойдет немного раньше. При этом сам таймер не затронут, а значит такты не теряются. Даже если где-то в программе произойдет задержка больше чем необходимый интервал - программа это наверстает за несколько заходов.
0

Поделиться темой:


Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

1 человек читают эту тему
0 пользователей, 1 гостей, 0 скрытых пользователей