Перейти к содержанию

Язык СИ для микроконтроллеров


Рекомендуемые сообщения

Если Вам не сложно, набросайте основные моменты кода. А то мне уже кажется, что я делаю тоже самое, но не так как надо :)

//Fmax = 10 000 îá/ìèí = 166.7 Ãö, Tmaxf = 0.006C
//Fclk = 4 000 000/4 = 1 0000 000Hz Tclk = 0.000 001C
//Nt = Tmax / Tclk  = 0.006 / 0.000 001 = 6 000 âûáèðàåì ïðåääåëèòåëü 16
//òîãäà FclkTimer = 1 000 000 / 8 = 125000Hz, Tclk = 0.000 008C, Nt = Tmax / Tclk  = 0.006 * 125000 = 750
//Ntmax = 65535, Ttmax = 65535 * 0.000 008 = 0.52C, Ftmax = 0.43Hz = 114 îá/ìèí
//Äàííûå ïàðàìåòðû íàñ óñòðàèâàþò.

unsigned int  Time;
unsigned char Flag;
const Time_is_Rady = 0;
const SecondInt = 1;
void interrupt(){
//static unsigned int i=0,j=0;
static unsigned char n=0, TMR1_OverFlow = 0;
  if   (INTCON.GPIF == 1){
    if (Flag & 1<<SecondInt){
	  Flag |= 1<<Time_is_Rady;
	  Flag &= ~(1<<SecondInt);
	  if (TMR1_OverFlow < 4){
		 Time = TMR1H<<8 + TMR1L;
	  }else{
		 Time = 0xFFFF;
	  }
	  TMR1_OverFlow = 0;
    }else Flag |= 1<<SecondInt;
  }
  if   (PIR1 & 0x01 == 1){
    TMR1_OverFlow++;
  }
}

void main() {
unsigned int RealTime,LastTime = 0;
unsigned int EngineSpeedTime; //Íóæíîå íàì çíà÷åíèå (ïåðåìåííàÿ äëÿ äàëüíåéøåãî ðàñ÷åòà)
   asm{
	  bsf STATUS, RP0
	  call 0x3FF
	  movwf OSCCAL
	  bcf STATUS, RP0
 }
 OPTION_REG = 0b10000000;		  //
 WPU = 0;
 IOCB = 0b00000001;
 CMCON	  = 0b00000111;
 VRCON = 0;
 TRISIO	 = 0b00000001;
 GPIO	   = 0b00000000;		  // initialize gpio
 INTCON	 = 1<<GIE | 1<<PEIE | 0<<T0IE | 0<<INTE | 1<<GPIE | 0<<GPIF; //
 T1CON = 0b00110101;
 PIR1 = 0b00000000;
 PIE1 = 0b00000001;
 do{
 if (Flag & 1<<Time_is_Rady){
	  Flag &= ~(1<<Time_is_Rady);
	  RealTime = Time;
	  EngineSpeedTime = RealTime - LastTime;
	  LastTime = RealTime;
   }

 } while(1);
}//~

Проверить не было возможности потому что мой микроси почему-то не хочет генерить cof файл.

Если че не так то знатоки, я думаю, подправят..

post-139865-0-84212700-1382330832_thumb.png

Изменено пользователем korsaj
Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Спасибо за пример. Но я что-то не смог его откомпилировать... Мой компилятор кучу ошибок нашел, некоторые я исправил, но когда остановился на строке

if (Flag & 1<<SecondInt){

тут я уже не понял чего он хочет... :(

и по поводу вот этих:

if (Flag & 1<<SecondInt){
Flag |= 1<<Time_is_Rady;
Flag &= ~(1<<SecondInt);

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

я пока вот так еще понимаю

Flag = Flag | 1<<Time_is_Ready

- это должно быть вроде одно и тоже, но тут еще стрелки "<<" в общем пока мой мозг это плохо переваривает.

:)

Пример оказался сложным, даже для разбора, но это уже моя проблема.

Сам-то я пока продолжил развивать свой код:

// PIC12F675 Configuration Bit Settings
#include <xc.h>

#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)

#define IN_TAH GPIObits.GP0
//#define LED_BLUE GPIObits.GP4
//#define LED_GREEN GPIObits.GP5

#define COUNT_IMP 3 //2 фронта импульса на 1 об/мин

volatile char ReadyDATA;
volatile int impcnt, tmrmsk, msk_in_turn, mskLight, PauseMs;
volatile unsigned long int RotatePerMin, fcnt, d_tmp;

void interrupt isr(void) {
// на 1 оборот с тахометра приходят два импульса
// нам нужно посчитать сколько миллисекунд длится один оборот
// на 2 импульса приходит 4 прерывания (1 - фронт, 2 - спад, 3 - фронт, 4 спад)
// считаем оборот - это между 1 и 3 импульсом, т.е. замеряем время между ними
// Хотя на приведенном выше рисунке замеры идут между 2 и 4 импульсами... но думаю разницы нет.
if (GPIF) {
if (!ReadyDATA) { //Считаем только когда данные неготовы
 if (impcnt <= COUNT_IMP) if (IN_TAH) impcnt++;	//считаем только Фронты
 else {
	impcnt = 0;
	msk_in_turn = tmrmsk; //в msk_in_turn время в миллисекундах на один оборот
	tmrmsk = 0;
	ReadyDATA = 1;
 }
}
GPIF = 0;
}

if(T0IF) {
tmrmsk++;
T0IF=0; //Обработали прерывание TMR0
}

}

void main(void) {

CMCON = 0x07;
ANSEL = 0;
GPIO = 0;
TRISIO = 0b00000001;

T0CS = 0;
PSA = 0;
PS0 = 1;
PS1 = 0;
PS2 = 0;

INTCON = 0;
T0IE = 1;
GPIE = 1;
IOCbits.IOC0=1;
GIE = 1;

while (1){
if (ReadyDATA) {
 RotatePerMin = 60000 / msk_in_turn; // RotatePerMin - Тут у нас обороты в минуту

 ReadyDATA = 0;
}
}

}

Так вот я нахожу обороты в минуту. В протеусе на ногу GPIObits.GP0 подаю сигнал с частотой 166 гц и в RotatePerMin вижу 10000 об/мин

при 83 гц - 5000. Теперь нужна пауза. Так-то все верно вроде, но подозреваю, что опять делаю как-то не так.

Потому как в примере из #726 вообще не вижу, что бы там пауза рассчитывалась...

Если честно, то там я вообще не понял как выход (на светодиод) организован. Спасибо.

Прокомментируйте "моё творение"....

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

//Fmax = 10 000 îá/ìèí = 166.7 Ãö, Tmaxf = 0.006C

//Fclk = 4 000 000/4 = 1 0000 000Hz Tclk = 0.000 001C

//Nt = Tmax / Tclk = 0.006 / 0.000 001 = 6 000 âûáèðàåì ïðåääåëèòåëü 16

//òîãäà FclkTimer = 1 000 000 / 8 = 125000Hz, Tclk = 0.000 008C, Nt = Tmax / Tclk = 0.006 * 125000 = 750

//Ntmax = 65535, Ttmax = 65535 * 0.000 008 = 0.52C, Ftmax = 0.43Hz = 114 îá/ìèí

//Äàííûå ïàðàìåòðû íàñ óñòðàèâàþò.

//Fmax = 10 000 об/мин = 166.7 Гц, Tmaxf = 0.006C

//Fclk = 4 000 000/4 = 1 0000 000Hz Tclk = 0.000 001C

//Nt = Tmax / Tclk = 0.006 / 0.000 001 = 6 000 выбираем предделитель 16

//тогда FclkTimer = 1 000 000 / 8 = 125000Hz, Tclk = 0.000 008C, Nt = Tmax / Tclk = 0.006 * 125000 = 750

//Ntmax = 65535, Ttmax = 65535 * 0.000 008 = 0.52C, Ftmax = 0.43Hz = 114 об/мин

//Данные параметры нас устраивают.

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

Особенности хранения литиевых аккумуляторов и батареек

Потеря емкости аккумулятора напрямую зависит от условий хранения и эксплуатации. При неправильном хранении даже самый лучший литиевый источник тока с превосходными характеристиками может не оправдать ожиданий. Технология, основанная на рекомендациях таких известных производителей литиевых источников тока, как компании FANSO и EVE Energy, поможет организовать правильный процесс хранения батареек и аккумуляторов. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

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

Теперь ваши трудности:

if (Flag & 1<<SecondInt) - здесь в условии сделано наложение маски на регистр флага Flag, а именно Flag & 0b00000010. Т.е. 1<<SecondInt (где SecondInt = 1) означает сдвинуть влево число 1 на SecondInt знаков (на один). Аналог 0b00000001 << 1 = 0b00000010

Теперь о условии: if (Flag & 1<<SecondInt) выполнится если проверяемый параметр не равен 0. Т.е. 0 = false, все что больше либо равно 1 = true

Flag |= 1<<Time_is_Rady с этим вы справились Flag = Flag | 1<<Time_is_Rady, где 1<<Time_is_Rady = 1<<0 = 0b00000001

Flag &= ~(1<<SecondInt) это инверсная операция Flag = Flag & ~(1<<SecondInt) = Flag & ~(1<<1) = Flag & ~(0b00000010) = Flag & 0b11111101, знак "~" - это инверсия (not).

И не забывайте перед int ставить unsigned

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

Ага, разобрался как вы сделали подсчет кол-ва тиков. Зря только заняли два регистра памяти. В мк уже есть регистр счетчика и он уже считает, его нужно только считывать вовремя.

Изменено пользователем korsaj
Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

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

Теперь ваши трудности:

if (Flag & 1<<SecondInt) ...

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

if (Flag & 1<<SecondInt) - здесь в условии сделано наложение маски на регистр флага Flag, а именно Flag & 0b00000010. Т.е. 1<<SecondInt (где SecondInt = 1) означает сдвинуть влево число 1 на SecondInt знаков (на один). Аналог 0b00000001 << 1 = 0b00000010

Теперь о условии: if (Flag & 1<<SecondInt) выполнится если проверяемый параметр не равен 0. Т.е. 0 = false, все что больше либо равно 1 = true

Если честно, то никак не могу понять смысл этого и этого тоже:

if (Flag & 1<<SecondInt){
Flag |= 1<<Time_is_Rady;
Flag &= ~(1<<SecondInt);
if (TMR1_OverFlow < 4){
Time = TMR1H<<8 + TMR1L;
}else{
Time = 0xFFFF;

Т.е. вроде понимаю, что << сдвигает бит влево, но для чего это не понимаю :(

И если SecondInt всегда равно 1 Const же , то тогда зачем все эти хитрые действия с Flag

может проще написать так сразу "if (Flag & 0b00000010) {..." ?

В обще, конечно, сложно для восприятия все эти конструкции...

И не забывайте перед int ставить unsigned

Действительно.... Тут я все прекрасно понимаю.... Мое личное упущение, другими словами - косяк. :) ...но на данном этапе жить можно.)

Зря только заняли два регистра памяти. В мк уже есть регистр счетчика и он уже считает, его нужно только считывать вовремя.

Не спорю, конечно зря.... но я уже двигаюсь в правильном направлении.... изначально памяти мк на три строчки моего кода хватило :).... теперь лучше.

Тут я так понимаю про TMR0 говорится? Если да, то в таком случае придется дополнительно делать пересчет в нужные нам цифры, ведь TMR0 тикает по своему и когда происходит его переполнение тут мы свою переменную меняем извлекая из этого нужную нам миллисекунду, иначе нам нужно как-то TMR0 подогнать под нужное нам значение, т.е. не саму TMR0 а извлечь из нее нужную нам информацию...

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

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

Т.е. вроде понимаю, что << сдвигает бит влево, но для чего это не понимаю :(

Знаете в чем парадокс? Это все для того чтобы читабельно было.
И если SecondInt всегда равно 1 Const же , то тогда зачем все эти хитрые действия с Flag

может проще написать так сразу "if (Flag & 0b00000010) {..." ?

Да можно. Просто при объявлении константы в таком виде const Time_is_Rady = 0; легко понять что Time_is_Rady - это нулевой бит регистра флагов. Вообще это у меня после программирования на ассемблере для AVR. У него есть две команды - одной как аргумент нужен номер бита, другой - маска. Вот и привык я рисовать такие загогулины, а компилятору все равно, он все что нужно сделает. Применение маски иногда очень удобно...

Тут я так понимаю про TMR0 говорится? Если да, то в таком случае придется дополнительно делать пересчет в нужные нам цифры, ведь TMR0 тикает по своему и когда происходит его переполнение тут мы свою переменную меняем извлекая из этого нужную нам миллисекунду, иначе нам нужно как-то TMR0 подогнать под нужное нам значение, т.е. не саму TMR0 а извлечь из нее нужную нам информацию...

При правильной настройке он будет тикать именно так как вам надо. И для замеров (в моем варианте) удобнее использовать TMR1 - он 16-ти битный и перекрывает весь диапазон.

Ну ладно.. все придет со временем. Я вообще начинал с линейного кода и о прерываниях даже думать было страшно.

PS Я тоже из Делфи приперся )))

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

Если измерять входные импульсы тахометра с интевалом 0,3сек. То получите результат 10имп/1000об. без математики. Точность получается 100 об/мин. Если для авто, то вполне достаточно.

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

Знаете в чем парадокс? Это все для того чтобы читабельно было.

Вот это уж точно парадокс :)

Скажите, что не так тут:

volatile unsigned int ImpCnt, tmrmsk, msk_in_turn, mskLight;
volatile unsigned long int PauseMs, RPM;
..........
while (1){
if (ReadyDATA) {
RPM = 60000 / msk_in_turn;
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
ReadyDATA = 0;
}

Вроде сообразил как целыми числами рассчитать, но почему-то в протеусе PauseMs показывается не верно.... совсем не верно.

Например для 2000 RPM пауза отображается = 6, а должна 400 быть...

Вот этот же код в делфи все правильно показывает:

procedure TForm1.Button2Click(Sender: TObject);
var RotatePerMin, msLight, PauseMs: Integer;
begin
RotatePerMin :=3476;
msLight := (RotatePerMin div 1000) * 100;
PauseMs := (((1000 - msLight) * 1000) div RotatePerMin);
ListBox1.Items.Add(Format('RotatePerMin = [%d] PauseMs = %d', [RotatePerMin, PauseMs]));
end;

?

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

Не пойму, как можно мереть импульсы с интервалом? Я понимаю, что наоборот между импульсами можно интервал времени замерить...

И по поводу атомарного доступа к ReadyDATA в бесконечном цикле нужно это или в данном случае не обязательно

Я попробовал вот так:

while (1){

GIE = 0;

if (ReadyDATA) {

RPM = 60000 / msk_in_turn;

mskLight = (RPM / 1000) * 100;

PauseMs = (((1000 - mskLight) * 1000) / RPM);

ReadyDATA = 0;

}

GIE = 1;

...

}

Результат такой же...

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

volatile unsigned int ImpCnt, tmrmsk, msk_in_turn, mskLight;
volatile unsigned long int PauseMs, RPM;
..........
while (1){
if (ReadyDATA) {
RPM = 60000 / msk_in_turn;
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
ReadyDATA = 0;
}

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

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

Не пойму, как можно мереть импульсы с интервалом? Я понимаю, что наоборот между импульсами можно интервал времени замерить...

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

Атомарный доступ как у вас приведет к плачевным последствиям. В протеусе можно ставить точки останова, поставьте их на запрет и разрешение прерываний и посмотрите на время прошедшее между этими точками, а затем сравните со временем между прерываниями от таймера.

ЗЫ Зачем вам такие монстра unsigned long int PauseMs, RPM? Вы собираетесь "вечность" ждать переключения светодиода?

Изменено пользователем korsaj
Ссылка на комментарий
Поделиться на другие сайты

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

Как это? :) Не соображу, я вроде и так по минимуму все сделал.... остальные цифры меняются.... как их заранее на бумажке рассчитать?

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

Ну так изначально в самом начале я именно так и сделал...

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

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

Как мерять не важно, главное правильно пересчитать.

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

Как это? :) Не соображу, я вроде и так по минимуму все сделал.... остальные цифры меняются.... как их заранее на бумажке рассчитать?

У вам изменяется только одна цифра - это измеренное кол-во импульсов. А вы умудрились сделать 5 сложных арифметических действия. Должно быть максимум два, а идеально одно, остальное операции сдвига.

Вернитесь к посту #698 и попробуйте сделать тоже со своей формулой. С учетом того что вы описали 2000 на входе и должны получить 400 получаем коэф 300.

Изменено пользователем korsaj
Ссылка на комментарий
Поделиться на другие сайты

У вам изменяется только одна цифра - это измеренное кол-во импульсов.

я же сейчас время на один оборот меряю.... не знаю важное это замечание или нет...

Вернитесь к посту #698 и попробуйте сделать тоже со своей формулой. С учетом того что вы описали 2000 на входе и должны получить 400 получаем коэф 300.

16Х + 2Х/3

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

Да, чувствую, я вообще дуб.... :(

по поводу атомарного доступа сделал так:

unsigned int GetAtomVar (volatile char * pTmv){
char RetTmv;
GIE=0;
RetTmv = * pTmv;
GIE=1;
return RetTmv;
}

void SetAtomVar(volatile char * TmVar, char Value){
GIE=0;
* TmVar = Value;
GIE=1;
}
while (1){
if (GetAtomVar(&ReadyDATA)) {
RPM = 60000 / msk_in_turn;
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
SetAtomVar(&ReadyDATA, 0);
}

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

Опять чего-намудрили с атомарным доступом.

У вас есть глобальная переменная которая меняется в прерывании. Все что нужно - это в основном цикле считать ее в локальную переменную и все. Самое страшное что случится - это запрет прерывания на 6 цикла мк. Дальше вы имеете дело с локальной переменной, которая может изменится только от вашего вмешательства.

300 получилось исходя из ваших рассуждений:

Вроде сообразил как целыми числами рассчитать, но почему-то в протеусе PauseMs показывается не верно.... совсем не верно.

Например для 2000 RPM пауза отображается = 6, а должна 400 быть...

Если 2000 RPM = 2000 об/мин, то 2000*60/400 = 300.

Изменено пользователем korsaj
Ссылка на комментарий
Поделиться на другие сайты

Хм... ну да. т.е. в основном цикле я использую все-таки 2 переменные, которые меняются в прерывании... Это ReadyDATA и msk_in_turn

while (1){
if (GetAtomVar(&ReadyDATA)) {
RPM = 60000 / GetAtomVar(&msk_in_turn);
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
SetAtomVar(&ReadyDATA, 0);
}
...
}

300 получилось исходя из ваших рассуждений:

Вроде сообразил как целыми числами рассчитать, но почему-то в протеусе PauseMs показывается не верно.... совсем не верно.

Например для 2000 RPM пауза отображается = 6, а должна 400 быть...

Если 2000 RPM = 2000 об/мин, то 2000*60/400 = 300.

Должно быть так

при 1000 оборотах пауза должна быть 900

при 2000 - 400

при 3000 - 233

при 1500 - 600

итого возьмем 1000 оборотов

1000*60/900 = 66,66666666666667

что-то не пойму я как этот коэф использовать... я так понимаю, что коэффициент должен быть одинаков для любого RPM....

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

Ну да две.. Про ReadyDATA я забыл. Но дело в том что вы его считываете и в какой момент сбросите не имеет значение. Так как если вы пропустите одно, два вычисление ничего страшного не будет.

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

Должно быть так

при 1000 оборотах пауза должна быть 900

при 2000 - 400

при 3000 - 233

при 1500 - 600

итого возьмем 1000 оборотов

1000*60/900 = 66,66666666666667

что-то не пойму я как этот коэф использовать... я так понимаю, что коэффициент должен быть одинаков для любого RPM....

У нас преподавал в школе хороший физик и всегда нам говорил что перед тем как что либо считать нужно все привести к нужной размерности.

Переведите все в секунды и считайте коэф.

Изменено пользователем korsaj
Ссылка на комментарий
Поделиться на другие сайты

Но дело в том что вы его считываете и в какой момент сбросите не имеет значение. Так как если вы пропустите одно, два вычисление ничего страшного не будет.

Ну т.е. можно вот так сделать:

while (1){
if (GetAtomCharVar(&ReadyDATA)) {
RPM = 60000 / GetAtomIntVar(&msk_in_turn);
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
ReadyDATA = 0;
}
...
}

?

У нас преподавал в школе хороший физик и всегда нам говорил что перед тем как что либо считать нужно все привести к нужной размерности.

Переведите все в секунды и считайте коэф.

Ну что Вы меня мучаете :)

В секундах:

при 1000 оборотах/мин пауза должна быть 0,9 сек

при 2000 - 0,4

при 3000 - 0,2(33)

при 1500 - 0,6

2000*60/0.4 = 300000

1000*60/0.9 = 66666,66666666667

1500*60/0.6 = 150000

Что я не так делаю? :( Не пойму про какой коэф говорится, и как его потом применить...

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

Почитал 2 последние страницы, и никак въехать не могу в проблему AS7ti6K :)

Я так понял, Вы уже сумели измерить обороты ? Тогда вычисляйте паузу по обычной пропорции. Чёт никак не пойму, в чём проблема... Может просто потому что уже сонный :vava:

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

#733 Почему-то код на си выполняет не верные расчеты, хотя тот же самый код в делфи выводит правильные результаты.... :unknw:

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

Ещё раз покажите этот кусок кода и скажите значения переменных на входе этого кода и на выходе. Так же покажите объявления всех переменных, учавствующих в этом коде.

ЗЫ: Вам обороты же не нужно выводить куда-нибудь ? Значит меряйте частоту и от неё уже пляшите. Лишние цифры и преобразования Вас только путают.

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

Вот весь код:

// PIC12F675 Configuration Bit Settings
#include <xc.h>
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)

#define IN_TAH GPIObits.GP0
#define LED_BLUE GPIObits.GP4
#define LED_GREEN GPIObits.GP5

#define COUNT_IMP 3 //2 фронта импульса на 1 об/мин

volatile unsigned char ReadyDATA;
volatile unsigned int ImpCnt, tmrmsk, msk_in_turn, mskLight;
volatile unsigned long int PauseMs, RPM;

unsigned int GetAtomIntVar (volatile unsigned int * pTmv){
unsigned int RetTmv;
GIE=0;
RetTmv = * pTmv;
GIE=1;
return RetTmv;
}

void SetAtomIntVar(volatile unsigned int * TmVar, unsigned int Value){
GIE=0;
* TmVar = Value;
GIE=1;
}

unsigned char GetAtomCharVar (volatile unsigned char * pTmv){
unsigned char RetTmv;
GIE=0;
RetTmv = * pTmv;
GIE=1;
return RetTmv;
}

void SetAtomCharVar(volatile unsigned char * TmVar, unsigned char Value){
GIE=0;
* TmVar = Value;
GIE=1;
}

void interrupt isr(void) {

if (GPIF) {
if (!ReadyDATA) {
if (ImpCnt <= COUNT_IMP) if (IN_TAH) ImpCnt++;
else {
ImpCnt = 0;
msk_in_turn = tmrmsk;
tmrmsk = 0;
ReadyDATA = 1;
}
}
GPIF = 0;
}

if(T0IF) {
tmrmsk++;
T0IF=0;
}

}

void main(void) {

CMCON = 0x07;
ANSEL = 0;
GPIO = 0;
TRISIO = 0b00000001;

T0CS = 0;
PSA = 0;
PS0 = 1;
PS1 = 0;
PS2 = 0;

INTCON = 0;
T0IE = 1;
GPIE = 1;
IOCbits.IOC0=1;
GIE = 1;

while (1){
if (GetAtomCharVar(&ReadyDATA)) {
RPM = 60000 / GetAtomIntVar(&msk_in_turn);
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
SetAtomCharVar(&ReadyDATA, 0);
}

LED_BLUE = 1;
//pause 100
//LED_BLUE = 0;
//pause pausems
}
}

по поводу переменных на входе и выходе не понял.

Ок, попробую:

while (1){
if (GetAtomCharVar(&ReadyDATA)) {
RPM = 60000 / GetAtomIntVar(&msk_in_turn);
mskLight = (RPM / 1000) * 100;
PauseMs = (((1000 - mskLight) * 1000) / RPM);
SetAtomCharVar(&ReadyDATA, 0);
}

RPM к примеру получаем 2000 - т.е. в протеусе я использую генератор на порту и ставлю 32 гц

при таких данных должно быть PauseMs = 400, а впротеусе показывает, что RPM = 2000, а PauseMs = 6

???

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

Ну вот, сразу-же видна ошибка :

mskLight = (RPM / 1000) * 100;

Вы делите на 1000, а потом умножаете на 100, при этом теряя точность счёта в 10 раз. Переменные то целые и после деления они не имеют дробной части, она тупо отбрасывается :)

mskLight = (RPM* 100) / 1000 ;

что эквивалентно

mskLight = RPM / 10;

:)

ЗЫ: Всё, пора баи. Утро вечера мудренее...

ЗыЗы: Для ReadyDATA , в Вашем случае, не нужен атомарный доступ.

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

ЗЫ: Вам обороты же не нужно выводить куда-нибудь ? Значит меряйте частоту и от неё уже пляшите. Лишние цифры и преобразования Вас только путают.

Не нужно, обороты нужны только для расчета паузы

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

Вы все говорите, что я лишнего чего-то считаю.... я вот этого не понимаю, может из-за того, что я совсем не знаю МК.

Для меня непонятно, как можно что-то узнать не сделав определенные расчеты....

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

Есть обороты. Пусть сигнал тахометра выдает 2 импульса на один оборот.

Далее условие такое. Нужно моргать светодиодом по такому алгоритму на 1000 об/мин нужен один мырг в секунду. Т.е. 100 мск горит и 900 не горит.

На 2000 оборотах получается светодиод должен моргнуть два раза: 100 горит + 400 не горит + 100 горит + 400 не горит.

Но смысл хотел не совсем так.

на самом деле светик моргает один раз и пауза(которую нужно рассчитать)

Затем идет новое получение оборотов и новое значение паузы.

Т.е. предположим, что обороты держатся 2000 в течении 5 секунд. Отсюда первый раз получили 2000 оборотов посчитали паузу получилась 400

зажгли светик на 100, потом погасили, выждали 400. К этому времени получили новые обороты(но у нас все теже 2000) и посчитали новую паузу получилось 400

снова зажгли на 100 потом потушили и опять все по новому.

Так вот если обороты будут держаться 2000 в в течении 5 сек, то нам будет казаться, что светодиод моргает 2 раза в секунду.

А он делает один цикл горит+не горит (100+400) затем новый расчет. Обороты сменились на очень высокие, соответственно зажгли светик на 100 мск, потом подождали например 10 мск и новую паузу рассчитали.... Понятно, что на высоких оборотах он будет практически гореть...

mskLight = (RPM* 100) / 1000 ;

что эквивалентно

mskLight = RPM / 10;

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

2500 / 1000 = 2 целых мырга за секунду, а умножаю их на 100 и получаю общее время горения 200...

ЗыЗы: Для ReadyDATA , в Вашем случае, не нужен атомарный доступ.

Я догадывался об этом)

ЗЫ: Всё, пора баи. Утро вечера мудренее...

Золотые слова :)

Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

Мерять частоту импульсов? Т.е. снова переключится на "посчитать кол-во импульсов за определенный интервал времени"?
Не нужно никуда переключаться :) Обороты - это же частота, только умноженная на 60. Так вот, для чего вычислять обороты, делав лишние действия, если можно просто отталкиваться от измеренной частоты.

Например. 166 Гц - 1 сек, 332 Гц - 0.5 сек, соответственно, и т.д... Обычная пропорция.

2500 / 1000 = 2 целых мырга за секунду, а умножаю их на 100 и получаю общее время горения 200...
А должно быть, как я понимаю, 250 Ms. :)
Ссылка на комментарий
Поделиться на другие сайты

Ребята, вы "утопите" МК в расчетах. Это же не ПК. Расчитывать линейную паузу между постоянными вспышками - это так принципиально? Или прихоть? Что мешает выводить информацию на светодиоды с постоянными интервалами, но в количественном виде? Для визуального восприятия это даже лучше, глазу не нужно будет подстраиваться под изменяющуюся длительность. И расчетов никаких, практически. Может я и не прав, и автору нужно просто по-упражняться в математике.

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

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...