AS7ti6K

Расчет Оборотов. "глюки?" В Протеусе.

65 сообщений в этой теме

AS7ti6K    2

Здравствуйте! Есть такой участок кода (остальное(весь) - ниже):

....
RPM4 = RPM3;
RPM3 = RPM2;
RPM2 = RPM1;
TMR1ON = 0;
RPM1 = (1000 / MsRotate) * 60;
RPM = (RPM1 + RPM2 + RPM3 + RPM4) / 4;
MsRotate = 0;
Rotation = 1;
TMR1ON = 1;
....

В протеусе при пошаговом выполнении бывает так, что переменная RPM3 изменяется(становится красной в отладочном окне), а другие нет. Как такое может быть? Ведь для того, что бы изменилась эта переменная, нужно это значение с начало получить в RPM1 и потом по цепочке....

Это протеус глючит или все таки у меня код не верный?

Вот весь код. Процедура main: (пока "бесполезная")

void main(void) {

InitApp(); /* Initialize I/O and Peripherals for application */

while (1) {
GIE = 0;
GPIO1 = (RPM > 500);
GPIO2 = (RPM > 950);
GPIO4 = (RPM > 3500);
GIE = 1;
}

}

Обработка прерываний:

int CntImpl = 0; //Количество импульсов на 1 оборот
unsigned int MsRotate = 0; //Длительность одного оборота в мс
unsigned char Rotation = 0; //Флаг вращения, если в течении секунды не было импульсов, считать, что вращения нет

void CalcPeriodMS(void) {
MsRotate++; //подсчитываем миллисекунды
if (MsRotate == 1000) { //если насчитали секунду
RPM1 = 0; //все обнулить
RPM2 = 0;
RPM3 = 0;
RPM4 = 0;
RPM = 0;
MsRotate = 0;
Rotation = 0; //сбросить флаг вращения
}
}

void CalcRPM(void) {

if (GPIO0) { //считать только "положительные прерывания"
CntImpl++; //прибавить счетчик импульсов
if (CntImpl == 2) { //2 импульса на один оборот
RPM4 = RPM3; //сдвинуть предыдущие вычисления
RPM3 = RPM2;
RPM2 = RPM1;
TMR1ON = 0; //остановить TMR1
RPM1 = (1000 / MsRotate) * 60; //Высчитать RPM из 1 оборота
RPM = (RPM1 + RPM2 + RPM3 + RPM4) / 4; //высчитать среднее из 4 предыдущих значений
MsRotate = 0; //Сбросить мс для следующего оборота
Rotation = 1; //Установить флаг вращения
TMR1ON = 1; //запустить таймер
CntImpl = 0; //сбросить кол-во импульсов на оборот
}
}

}

void interrupt isr(void) {

if (TMR1IF) {

TMR1 += 64537; // 1000 тиков - 1 мс
if (Rotation) CalcPeriodMS(); //Считать только когда крутится вал
TMR1IF = 0; //Обработали прерывание TMR1
}

if (GPIF) {
CalcRPM(); //расчет RPM
GPIF = 0;
}

}

На сколько оптимально/не оптимально, правильно/неправильно написано?) Спасибо!

Вот весь проект и файл протеуса в папке PROT. TAH2.rar

Я "зажимал" мышкой кнопку в протеусе пошаговое выполнение (стрелочка с палочкой) и в окне переменных видно как меняются эти самые переменные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
COKPOWEHEU    257

Скомпилировано небось с -Os? Попробуйте -O0. Ну и посмотреть ассемблерный файл, как оно на самом деле работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Скомпилировано небось с -Os? Попробуйте -O0.

Спасибо за ответ. Искал в MPLAB'e нечто похожее - не нашел.

Я пользуюсь MPLAB X 2.05 и компилятор XC8. Я так понял это параметры командной строки?

Можно подробнее объяснить, что нужно сделать для проверки?

Ну и посмотреть ассемблерный файл, как оно на самом деле работает.

Может кто разбирается в ассемблере - посмотрит. Я в ассемблере - как козел в ананасах :(

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

"Глюки" начинаются где-то примерно с частоты 45гц

Например на 32гц все переменные имеют одно значение(правильное) и не меняются.

Но если выставить 60гц или 113гц - то начинается свистопляска переменных.

С чем связано - не пойму. :( Но думаю, что это в моем коде что-то не так. Но что - не знаю.

Пробовал и в 8 протеусе. То же самое.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251
С чем связано - не пойму. :( Но думаю, что это в моем коде что-то не так. Но что - не знаю.

Пробовал и в 8 протеусе. То же самое.

есть подозрение что связано с функцией
CalcRPM(); //расчет RPM

в ней есть операции деления и умножения

RPM1 = (1000 / MsRotate) * 60; //Высчитать RPM из 1 оборота
RPM = (RPM1 + RPM2 + RPM3 + RPM4) / 4; //высчитать среднее из 4 предыдущих значений

что разворачивается в немалый машинный код ( по второй строке вообще надо см. как компилятор реализовал деление на 4)

скорее всего при их выполнении происходит пропуск событий прерывания при увеличении частоты...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251
Может кто разбирается в ассемблере - посмотрит. Я в ассемблере - как козел в ананасах :(

Спасибо!

сдается мне компилятор работает в режиме лайт

 663						 ;interrupts.c: 43: RPM4 = RPM3;
664 0029 0841			 movf _RPM3+1,w ;volatile
665 002A 01C3			 clrf _RPM4+1 ;volatile
666 002B 07C3			 addwf _RPM4+1,f ;volatile
667 002C 0840			 movf _RPM3,w ;volatile
668 002D 01C2			 clrf _RPM4 ;volatile
669 002E 07C2			 addwf _RPM4,f ;volatile
670 

в нормальном виде должен быть как :

		  663						   ;interrupts.c: 43: RPM4 = RPM3;
  664  0029  0841				   movf	_RPM3+1,w	;volatile
  665  002A  01C3				  movwf   _RPM4+1	;volatile
  667  002C  0840				   movf	_RPM3,w	;volatile
  669  002E  07C2				  movwf	_RPM4   ;volatile
  670

на самой элементарной операции идет увеличение на 2 маш.цикла...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

сдается мне компилятор работает в режиме лайт

Т.е. это из-за того что я пользуюсь бесплатной версией компилятора, он генерирует такой "не оптимальный" вариант, так я понимаю?

есть подозрение что связано с функцией

CalcRPM(); //расчет RPM

в ней есть операции деления и умножения

RPM1 = (1000 / MsRotate) * 60; //Высчитать RPM из 1 оборота
RPM = (RPM1 + RPM2 + RPM3 + RPM4) / 4; //высчитать среднее из 4 предыдущих значений

что разворачивается в немалый машинный код

А можно это как-то оптимизировать для XC8 компилятора?

Или мой код пойдет, но нужно сменить компилятор?

А может нужно код, где рассчитывается RPM1 и RPM, вынести из обработки прерывания и сделать в основном цикле?

Спасибо за помощь!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Вынес из обработчика прерываний:


void interrupt isr(void) {

if (TMR1IF) {
TMR1 += 64537; // 1000 тиков - 1 мс
if (Rotation) CalcTurnMS(); //Считать только когда крутится вал
TMR1IF = 0; //Обработали прерывание TMR1
}

if (GPIF) {
if (GPIO0) { //считать только положительные прерывания
CntImpl++; //прибавить счетчик импульсов
if (CntImpl == 2) { //2 импульса на один оборот
if (!ReadyData) {
MsRotate = TurnMs;
ReadyData = 1;
}
TurnMs = 0;
CntImpl = 0;
Rotation = 1;
}
}
GPIF = 0;
}

}

while (1) {
if (ReadyData) RPM = CalcRPM();
GPIO1 = (RPM > 500);
GPIO2 = (RPM > 950);
GPIO4 = (RPM > 3500);
}

unsigned int CalcRPM(void) {
unsigned int ARPM;
RPM4 = RPM3; //сдвинуть предыдущие вычисления
RPM3 = RPM2;
RPM2 = RPM1;
RPM1 = (1000 / MsRotate) * 60; //Высчитать RPM из 1 оборота
ARPM = (RPM1 + RPM2 + RPM3 + RPM4) / 4; //высчитать среднее из 4 предыдущих значений
ReadyData = 0;
return ARPM;
}

Стало по моему еще хуже...(

ЗЫЖ Почему-то форматирование кода тут рушится :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251
А можно это как-то оптимизировать для XC8 компилятора?

Или мой код пойдет, но нужно сменить компилятор?

RPM1 = (1000 / MsRotate) * 60; //Высчитать RPM из 1 оборота

преобразуется как

RPM1 = 1000 / MsRotate; //Высчитать RPM из 1 оборота
RPM1 = RPM1<<6 - RPM1<<2;

RPM = (RPM1 + RPM2 + RPM3 + RPM4) / 4; //высчитать среднее из 4 предыдущих значений

можно заменить на :

RPM = (RPM1 + RPM2 + RPM3 + RPM4)>>2; //высчитать среднее из 4 предыдущих значений

или заменить на

RPM = (RPM<<1+RPM)>>2 + RPM1>>2; RPM = 0,75*RPM + 0,25*RPM1//высчитать среднее из 4 предыдущих значений

тогда не нужно сохранять промежуточные данные RPM2, RPM3, RPM4

а вообще не понятно зачем вы вычисляете частоту вращения вала... у вас же есть значение периода

как по мне

GPIO1 = (RPM > 500);

тоже самое что и

GPIO1 = (MsRotate< 120);

или нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2
оборота[/code]

преобразуется как

RPM1 = 1000 / MsRotate; //Высчитать RPM из 1 оборота
RPM1 = RPM1<<6 - RPM1<<2;

можно заменить на :

RPM = (RPM1 + RPM2 + RPM3 + RPM4)>>2; //высчитать среднее из 4 предыдущих значений

Спасибо, вечером дома попробую.

а вообще не понятно зачем вы вычисляете частоту вращения вала... у вас же есть значение периода

как по мне

GPIO1 = (RPM > 500);

тоже самое что и

GPIO1 = (MsRotate< 120);

или нет?

Согласен. Можно и миллисекундами (MsRotate) ограничится.... я что-то даже и не подумал об этом. Наверное из-за того, что RPM нагляднее :)

Но тоже наверное нужно их как-то усреднить. ...сгладить скачки.

Тогда мне нужно сложить 4 последних MsRotate:

AverageMsRotate = (MsRotate1 + MsRotate2 + MsRotate3 + MsRotate4) >> 2;

Верно?

Просто я

или заменить на

RPM = (RPM<<1+RPM)>>2 + RPM1>>2; RPM = 0,75*RPM + 0,25*RPM1//высчитать среднее из 4 предыдущих значений

тогда не нужно сохранять промежуточные данные RPM2, RPM3, RPM4

пока не понял как это сделать(сделали) без промежуточных данных....

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251

пока не понял как это сделать(сделали) без промежуточных данных....

это называется аппроксимирующее звено или фильтр НЧ

ну скажем обороты были равны 0 , после стали 100

при первом замере РПМ=25обр

при втором РПМ= 25*0,75 +25= 18+25=43

при третьем РПМ= 43*0,75 +25= 32 + 25=57

при четвертом РПМ=42+25=67

при пятом РПМ=50+25=75

и тд... после достаточного накопления РПМ (первых 20 замеров) значение РПМ будет равно РПМ1

изменяя коэффициенты можно регулировать реакцию выхода на изменение на входе

более подробно здесь: http://we.easyelectronics.ru/Theory/chestno-prostoy-cifrovoy-filtr.html

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Спасибо за ответ. Конечно с аппроксимирующем звеном нужно разбираться отдельно.... Но.

Я убрал все расчеты из проекта, оставив только подсчет миллисекунд между двумя прерываниями. Т.е.:

void interrupt isr(void) {

if (TMR1IF) {
   TMR1 += 64537;    // 1000 тиков - 1 мс
   TurnMs++;             //подсчитываем миллисекунды
   TMR1IF = 0;           //Обработали прерывание TMR1
}

if (GPIF) {
 if (GPIO0) { //считать только положительные прерывания
   if (CntImpl == 1) { //2 импульса на один оборот
     if (!ReadyData) { //Если данные считаны, то
       [b]MsRotate = TurnMs[/b];//подготовить новые
       ReadyData = 1; //и выставить флаг готовности
     }
   TurnMs = 0; //Сбросить счетчик мск
   CntImpl = 0; //Сбросить счетчик импульсов
 } else CntImpl++; //прибавить счетчик импульсов
}
GPIF = 0; //Сбросить флаг прерывания
}

Так вот значение прыгает при постоянной частоте прерываний. Другими словами ничего не изменилось убрав из кода кучу расчетов связанных с делением и умножением.

В протеусе при частоте 32 Гц в пошаговом выполнении кода, значение MsRotate прыгает 62мс- 63мс - Откуда берется эта миллисекунда???

Даже если бы с таймером было не все в порядке, я так думаю, что не должно прыгать, ведь в протеусе все значения фиксированы и постоянны - другое дело в железе. Но раз тут прыгает в железе наверное совсем бардак будет :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251

В протеусе при частоте 32 Гц в пошаговом выполнении кода, значение MsRotate прыгает 62мс- 63мс - Откуда берется эта миллисекунда???

так дак усе просто.... TMR1 считает - считает, TurnMs увеличивается при переполнении TMR1 таки да... TurnMs вы сбрасываете по состоянию порта , а TMR1 продолжает тикать , через какое время произойдет переполнение? может 1мкс, а может через 1мс... или нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Ага, сейчас Вы мне подсказали, что нужно TMR1 также сбросить, примерно как-то так:

if (GPIF) {
if (GPIO0) { //считать только положительные прерывания
if (CntImpl == 1) { //2 импульса на один оборот
if (!ReadyData) { //Если данные считаны, то
MsRotate = TurnMs;//подготовить новые
ReadyData = 1; //и выставить флаг готовности
}

TMR1 = 64535; 

TurnMs = 0; //Сбросить счетчик мск на 1 оборот
CntImpl = 0; //Сбросить счетчик импульсов
} else CntImpl++; //прибавить счетчик импульсов
}
GPIF = 0; //Сбросить флаг прерывания
}

Вроде перестала прыгать.... сейчас буду весь код пробовать. Спасибо большое за подсказки)

Спасибо огромное! Все заработало как надо :)

Единственное только не смог заставить работать эту конструкцию:

RPM1 = (1000 / MsRotate) * 60; //Высчитать RPM из 1 оборота

преобразуется как

RPM1 = 1000 / MsRotate; //Высчитать RPM из 1 оборота
RPM1 = RPM1<<6 - RPM1<<2;

Хотя теперь она и не нужна, ведь мне действительно достаточно знать только мск 1 оборота

Ну и возможно, если не разберусь с аппроксимацией, пригодится:

AverageMsRotate = (MsRotate1 + MsRotate2 + MsRotate3 + MsRotate4) >> 2;

Еще раз спасибо за помощь!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

С позволения, я продолжу в этой теме.

Ответ в общем я как бы получил в этом топике. Но столкнулся с "неточностью расчетов".

Ну т.е. в данном контексте все считается правильно, но мне захотелось повысить точность расчетов.

Я переделал немного, но как-то мне не очень понравился результат моего кодинга.

Считает-то верно, но как-то расточительно. Хотя иногда вроде сбивается на мгновение. Я все так же зажимаю мышкой кнопку пошагового выполнения и смотрю как меняются переменные :)

Вот примерно как сделал (ниже весь проект с файлом протеуса)

volatile long MksTurns = 0L, TurnsTime = 0L;
volatile unsigned int Freq;

unsigned char CntImpl = 0; //Количество импульсов на 1 оборот

void interrupt isr(void) {

if (TMR1IF) { // Таймер переполнился
MksTurns += 65535; // Считаем микросекунды
TMR1IF=0; // Сбрасываем флаг таймера
}


if (GPIF) {
if (GPIO0) { //считать только положительные прерывания
if (CntImpl == 6) { //2 импульса на один оборот, считаем по 3 оборота
TMR1ON = 0; // Останавливаем таймер для атомарного доступа
TurnsTime = MksTurns + TMR1; //Собираем микросекунды
MksTurns = 0; // Сбросили микросекунды
TMR1 = 0; // Обнуляем таймер
TMR1ON = 1; // Запускаем таймер дальше
CntImpl = 1; // Сбросили счетчик импульсов
} else CntImpl++; //прибавить счетчик импульсов
}
GPIF = 0; //Сбросить флаг прерывания
}

}

while (1) {
if(TurnsTime!=0){
Freq=(unsigned int)(10000000L/(TurnsTime/3)); // считаем частоту из периода
RPM = (Freq * 60)/10;
} else RPM = 0;

}

Прошу прощение за форматирование - это оно тут рушится при вставке из буфера. :(

Весь - TAH5.rar

Вопрос собсно можно ли это как-то сделать по другому? Более оптимальнее что ли.

Дело в том, что этот код будет внедрен в другой проект и боюсь, что там уже не хватит места для двух long переменных.

Нужно, имея мк с частотой 4 мгц у которого в распоряжении TMR1 с 1:1 и одна свободная нога контроллера, на которую приходят импульсы тахометра. Хотелось бы как можно точнее считать обороты от 0 до 10 000 (т.е. кратность как можно меньше) но и в туже очередь, что бы код был максимально экономным. Реально переделать? :) Спасибо!

Может быть вообще другой алгоритм использовать?

Изменено пользователем AS7ti6K

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    561

Всё сделано достаточно оптимально и правильно, за исключением неатомарного доступа к переменной TurnsTime в основном цикле. А так, алгоритм выбран верный, обороты именно так и подсчитываются - измерением периода.

Точнее Вы уже никак не сделаете, да и нужно ли это Вам... Точность определяется частотой квантования периода (в Вашем случае - частота тактирования таймера) и временем выхода программы на обработку прихода импульса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Спасибо. Ясно... :) А по поводу:

за исключением неатомарного доступа к переменной TurnsTime в основном цикле.

Я думал об этом. Так же думаю, что иногда в RPM "неверное" значение именно из-за этого.

Вечером попробую читать эту переменную с помощью:

unsigned long GetTimerVar (volatile unsigned long * pTmv){
unsigned long RetTmv;
GIE=0;
RetTmv = * pTmv;
GIE=1;
return RetTmv;
}

Лишь бы еще код этого проекта вместился в проект, который Вы мне помогали делать полгода назад :) По некоторым причинам пришлось отложить хобби на этот долгий срок...

Вот практически с нуля всё вспоминал. Спасибо форуму и его жителям :)

Изменено пользователем AS7ti6K

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Хм... переделал на вот так:

unsigned long GetTimerVar (volatile unsigned long * pTmv){
unsigned long RetTmv;
GIE=0;
RetTmv = * pTmv;
GIE=1;
return RetTmv;
}

int RPM;
void main(void) {
unsigned long tmpTT;

InitApp(); /* Initialize I/O and Peripherals for application */

while (1) {
if(TurnsTime!=0){
tmpTT = GetTimerVar(&TurnsTime);
Freq=(unsigned int)(10000000L/(tmpTT/3)); // считаем частоту из периода
RPM = (Freq * 60)/10;
} else RPM = 0;

// GPIO1 = (RPM > 500);
// GPIO2 = (RPM > 950);
// GPIO4 = (RPM > 3500);
}

}

Все равно переменная RPM иногда принимает другое(на мгновение) значение - это видно, если в окне PIC CPU Variables поставить галочку что бы отображались предыдущие значения переменных.

Но что интересно, переменная Freq не меняется при этом. Т.е. получается что RPM = (Freq * 60)/10; при одинаковых значениях Freq, может получать разный результат? Бред какой-то :(

Может в данном случае протеус глючит?, во что я конечно не верю...

Сидел минуты три "мышкой держал" кнопку пошагового выполнения. При Freq = 250 RPM равнялся 1500, но иногда он становился даже 220....

Есть какие соображения?

Изменено пользователем AS7ti6K

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

В общем не знаю с чем связано, но вот этот код:

unsigned long GetTimerVar (volatile unsigned long *pTmv){
unsigned long RetTmv;
GIE=0;
RetTmv = *pTmv;
GIE=1;
return RetTmv;
}

unsigned int CalcRPM(void) {
unsigned long tmpTT;

if(TurnsTime != 0){
tmpTT = GetTimerVar(&TurnsTime);
Freq = (unsigned int)(10000000L / (tmpTT/2)); // считаем частоту из периода
return (Freq * 60) / 10;

} else return 0;

}

unsigned int RPM;
void main(void) {

InitApp(); /* Initialize I/O and Peripherals for application */

while (1) {
RPM = CalcRPM();
GPIO1 = (RPM > 500);
GPIO2 = (RPM > 1490);
GPIO4 = (RPM > 3500);
}

}

дает разные выходные результаты с постоянно одинаковыми входными данными.

Я обратил внимание, что при входной частоте 50гц - RPM на мгновение принимает только два значения - 1280 и 220 в остальное время стабильно 1500 - как и должно.

Кстати и Freq тоже меняется, но только на 0, и гораздо реже чем RPM. Это если совсем долго(относительно) держать зажатой кнопку пошагового выполнения... минут 5) Но это очень мало(или быстро) для вообще работы программы, которая будет работать часами...

Может это действительно какая-то фича протеуса?

В железе нет возможности проверить. Тут наверное нужно осциллограф, генератор.... у меня этого ничего нет :(

Вот исправленный, но с данным "глюком" проект TAH5 - _TAH5.zip

Если кому не сложно попробуйте запустить на своем протеусе.

Сделать нужно будет так. Открыть файл протеуса из папки PROT нажать зеленую стрелку дождаться начала выполнения программы (появились виртуальные приборы) и зажать кнопку треугольник с палкой (пошаговое выполнение) и держать ее минут 5 :)

Сотреть значения RPM и ждать когда в Previous value появится значение... Но при этом в Freq, в это время, ничего не меняется, т.е. в Previous value для Freq - остается пусто. Также если еще дольше держать зажатой кнопку, то и в Freq возможно появится другое значение.

Может я и зря паникую и все это нормально и в железе поведет себя по другому, но не вылезет ли это в еще какой сюрприз из-за неправильного моего кода??? отсюда паника :) Ибо я только начал(правда был промежуток "безделья" в полгода от начала осваивания) осваивать МК.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Выставив входную частоту 2 гц

я словил момент "изменения на мгновение" переменных.

RPM с 60 поменялся на 54, а Freq с 10 на 9 и держались эти значения в течении подсчета импульсов, когда CntIpml++.

Просто при низких значения входной частоты - это оказалось возможным. (отследить)

В данном случае я могу это объяснить что не хватило нескольких микросекунд вот Freq и "не добрал до нужного".

Но как тогда при частоте 50 гц и RPM 220???? Тут получается много нужно недобрать :(.... Не понимаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251

MksTurns += 65535;			 // Считаем микросекунды

почему 65535 а не 2^16=65536?

зачем функция GetTimerVar???

так не проще?

unsigned int CalcRPM(void) {
unsigned long tmpTT;

if(TurnsTime != 0){
 GIE=0;
 tmpTT = TurnsTime;
	 GIE=1;
 Freq = (unsigned int)(10000000L / (tmpTT/2)); // считаем частоту из периода
 return (Freq * 60) / 10;

} else return 0;

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Эх... подозревал я о 65536, но проверить так и не удосужился :( Двоечник(

А с функцией... с начало хотел без временной переменной, но что-то не получилось.... а функция так и осталась.

С Вашими поправками пока нормально... стабильно :) Спасибо огромное в очередной раз.

...Но я еще пока тестирую :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Я наверное больно быстро отвечаю, а в итоге "поспешишь - людей насмешишь" :(

В общем стало чуть стабильнее, но ошибка не исчезла.

Уже все с самого начала сделал, убирал функцию CalcRPM - делал все в основном цикле....

Так и прыгают периодически Freq и RPM....

Вроде все правильно, нигде ничего лишнего..... кода по минимуму.... Но все равно не получается...

Может и правда протеус глючит?

Кто скачивал последний проект, запускали? Есть глюк? Может это у меня только так, а я тут всех замучил :(

TAH5_1.zip

Изменено пользователем AS7ti6K

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
IMXO    1 251
Кто скачивал последний проект, запускали? Есть глюк?

ну я скачивал... нормально просмотреть возможности нет... пере соберите весь проект в 8-м мплабе , так чтобы весь код был в одном сишнике , весь проект в одной папке, в нее добавьте проект протеза 7.10 , в код добавьте задержку при инициализации на 1-2сек , это позволит сделать останов в протезе и будет доступен код сишника , в нем добавьте точки останова после расчета RPM.... (имя файла сишника и файла протеза сделать одинаковыми....)

и еще вопрос почему для регистрации импульсов пользуете GPIE, а не INTE по пину GP2 ????

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Ясно. Хм.... я об этом не подумал. Получается у каждого свои версии программ установлены. И если каждый будет просить ставить ихи версии, будет накладно :)

Ну это беда вопрошающих.... т.е. в данном случае моя.

А почему 8 мплаб? Он же старее... И протеус у меня 7,7 SP2.... Новое - не значит хорошее, но всеж, есть какие-то серьезные аргументы в пользу старых версий?

Я начал изучать действия протеуса на точках останова.... поставил точку на строку

if (TMR1IF) {

MksTurns += 65536;

>>>>TMR1IF = 0;

}

Но в окне переменных в этой самой переменной(MksTurns) всегда 0.

Но и считает в это время верно. (если не принимать во внимание, когда происходит глюк).

Просто переполнения таймера не было.... Я скоро с ума сойду с этими числами, секундами-микросекундами... :)

Возможно нужно как Вы и говорите, собрать проект в одном файле. Хотя там в протеусе можно выбрать любой сишный файл и в нем ставить точки....

Я тут вот еще что подумал, а не может это быть из-за входных данных?

Может это внутренний генератор (вирт прибор в протеусе) глючит?

IMXO, Спасибо, Вам огромное. Но если я вообще не разберусь, тогда сделаю, как Вы просите.

А пока может кто еще что подскажет. Не хочется ставить еще версии программ, я только, и то не совсем, привык(разобрался) с имеющимися...

и еще вопрос почему для регистрации импульсов пользуете GPIE, а не INTE по пину GP2 ????

Я где-то в начале говорил, что код этого проекта будет совмещен с другим, а вот в том, другом INTE уже занят.

Изменено пользователем AS7ti6K

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас