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

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


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

Что-то ничего не получается.... :) как-то туго в си у меня с этим :(

Вот что нужно. Код в Делфи:

procedure TForm1.Button1Click(Sender: TObject);
var RotatePerMin, fcnt: Double;
     msLight, PauseMs: Integer;
begin
   RotatePerMin := Random(5600)+400;
   fcnt := RotatePerMin / 1000;
   msLight := Trunc(fcnt) * 100;
   PauseMs := Round((1000 - msLight) / fcnt);
   ShowMessage(Format('RotatePerMin=%f PauseMs=%d', [RotatePerMin,PauseMs]));
end;

Мне нужно получить PauseMs

Как такое сделать в си?

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

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

volatile double RotatePerMin, fcnt, d_tmp;
volatile int	 msLight, PauseMs;
//----------------------------------------------------------------------------------//
RotatePerMin = rand(5600)+400;
fcnt = RotatePerMin / 1000;
modf(fcnt, &d_tmp);
msLight=(int)(d_tmp*100);
PauseMs = round((1000 - msLight) / fcnt);

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

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

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

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

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

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

Спасибо за помощь. Но почему-то у меня все равно не хочет это работать. Вот такое теперь:

COMPILS\XC8\sources\common\frndint.c:27: error: no space for ___ftadd parameters

Может это быть как-то связано с указанным МК в свойствах проекта? Данный код "выполняется" на МК PIC12F675

В общем открыл другой, рабочий, проект с другим МК - который компилится без ошибок. вставил туда код:


volatile double RotatePerMin, fcnt, d_tmp;
volatile int msLight, PauseMs;
//----------------------------------------------------------------------------------//
RotatePerMin = rand(5600)+400;
fcnt = RotatePerMin / 1000;
modf(fcnt, &d_tmp);
msLight=(int)(d_tmp*100);
PauseMs = round((1000 - msLight) / fcnt);

не компилится - ошибка. :(

Получается тогда что-то связанное с МПЛАБом или компилятором ХС8

Как же это все дело победить-то? :)

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

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

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

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

Да памяти не хватает в МК :)

Какие рандомы со всякими флоатами в 12ф675 ... :crazy:

Я же написал, что пробовал менять мк на другой pic16f630 тажа ошибка

\COMPILS\XC8\sources\common\frndint.c:27: error: no space for ___ftadd parameters

По поводу рандома - я его в си не использую - это в делфи для примера просто, а у меня вот как было выше:

....
volatile int PauseMs;
...........
RotatePerMin = ((COUNT_IMP * 2) / mskin32) * 60;
....

А на счет флоатов... не совсем понятно. Их вообще нельзя использовать на 12F675? В ДашБоарде показывает, что место-то есть....

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

Ну почему нельзя, можно. Только операции с ними очень требовательны к объёму памяти, особенно всяческие библиотечные функции неизвестного содержания.

Я же написал, что пробовал менять мк на другой pic16f630 тажа ошибка
Значит, скорее всего, там тоже места не хватает :)
Ссылка на комментарий
Поделиться на другие сайты

Эт сколько же нужно памяти для этого:

volatile double RotatePerMin, fcnt, d_tmp;
volatile int msLight, PauseMs;
//----------------------------------------------------------------------------------//
RotatePerMin = rand(5600)+400;
fcnt = RotatePerMin / 1000;
modf(fcnt, &d_tmp);
msLight=(int)(d_tmp*100);
PauseMs = round((1000 - msLight) / fcnt);

ведь кроме этого в проекте практически больше ничего нет :)

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

Значит, скорее всего, там тоже места не хватает :)

Если закомментировать последние три строчки:

volatile double RotatePerMin, fcnt, d_tmp;
volatile int msLight, PauseMs;
//----------------------------------------------------------------------------------//
RotatePerMin = rand(5600)+400;
fcnt = RotatePerMin / 1000;
//modf(fcnt, &d_tmp);
//msLight=(int)(d_tmp*100);
//PauseMs = round((1000 - msLight) / fcnt);

то компиляция проходит. И в дашбоарде в этот момент 50% свободно

Неужели и в самом деле места сжирают эти три строчки??? :) Ужас какой-то.... И как быть? Выкинуть нафик эти МК?

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

Вот ведь, не ожидал такой засады от МК с нехваткой памяти :)

компилятор выдает:

Running this compiler in PRO mode, with Omniscient Code Generation enabled,

produces code which is typically 40% smaller than in Free mode.

The MPLAB XC8 PRO compiler output for this code could be 277 words smaller.

Специально наверное так сделали работу с вещественными числами не оптимально во фри...

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

Писать более осмысленный код.

Можно поподробнее?

Тут три строчки кода как их можно более осмысленно сделать?

Я не придираюсь.... учусь. полмесяца всего в этом деле)

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

Не подскажите, может есть хитрые способы сделать round и trunc без использования math?

Я так понял память у меня переполняется при использовании именно этих функций....

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

Вы лучше опишите задачу целиком...

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

Собственно на данном МК PIC12F675 хочу сделать так: на одну ногу будет подаваться сигнал с тахометра, а с другой будет выход на светодиод.

Светодиод должен моргать пропорционально оборотам. Примерно 1 мырг в секунду на 1000 оборотов.

Вот мне и нужно рассчитать задержку между мыргами в зависимости от оборотов.

Вот этот проект:

// PIC12F675 Configuration Bit Settings
#include <xc.h>
//#include <math.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 33 // ~16.5 * 2 в сек = 1000 об/мин

volatile char ReadyDATA;
volatile int impcnt, tmrmsk, mskin32, msLight, PauseMs;
volatile float RotatePerMin, fcnt, d_tmp;

void interrupt isr(void) {

if (GPIF) {
if (impcnt <= COUNT_IMP) impcnt++;
else {
if (!ReadyDATA) {
impcnt = 0;
mskin32 = tmrmsk;
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; // Включаем прерывание TMR0
GPIE = 1; // Включаем прерывание по изменению порта
IOCbits.IOC0=1; // Порт по изменению - прерывание
GIE = 1; // Разрешаем прерывания

while (1){
if (ReadyDATA) {
// RotatePerMin = ((COUNT_IMP / 2) / mskin32) * 60000;
// fcnt = RotatePerMin / 1000;
// modf(fcnt, &d_tmp);
// msLight=(int)(d_tmp*100);
// PauseMs = (int)round((1000 - msLight) / fcnt);
ReadyDATA = 0;
}

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

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

Наверное стоит пояснить что я там наделал:

В прерывании по изменению порта считает количество изменений 33 шт. (2 тика на 1 оборот) примерно 16,6 в сек на 1000 об/мин

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

далее математически подсчитали сколько оборотов в мин.

ну и затем идет вычисление соб-но самой паузы....

Возможно там не 2 прерывания на оборот нужно считать, а 4 так как 2 импульса с тахометра дадут 4 прерывания 1-й импульс (появился сигнал - 1, пропал сигнал - 2) 2-й импульс (появился сигнал - 3, пропал сигнал - 4) (это пока только догадки и на данном этапе не важно)

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

какой-то немного странный способ Вы предпочли. Для измерения оборотов есть 2 способа.

1. Измерение кол-ва импульсов за период (как правило = 1 сек), умноженное на 60. Такой способ неочень эффективен. Т.к. нужно ждать целую секунду + теряем точность при умножении на 60.

2. Измерение периода частотой дискретизации (как правило - таймер МК). Из периода уже расчитываем обороты. Еффективный способ. Обороты мы знаем уже после очередного периода, причём с приличной точностью (зависит от частоты дискретизации).

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

какой-то немного странный способ Вы предпочли. Для измерения оборотов есть 2 способа.

1. ....

2. ....

Первый способ мне тоже не понравился, там еще может случится что за секунду может оказаться, что еще только полимпульса, потом нужно будет это как-то учитывать....

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

Причем способ я "придумал" после того как прочитал инфу по одной из сылок или пример для гуглопоиска, который Вы мне давали раньше :)

А если честно, то "Измерение периода частотой дискретизации" - это для меня Вы матом ругнулись :)

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

А если честно, то "Измерение периода частотой дискретизации" - это для меня Вы матом ругнулись :)

бывает...есть неизвестный период Тх , есть известная частота (или период То) , по началу периода запускаем счетчик с известной частотой, по окончании периода останавливаем счетчик , тогда Тх=N*То , где N - показания счетчика...

пример известная частота=1МГц, те То=1мкс , счетчик насчитал N=890235 имп.

Тх=N*То= 890235* 10-6 = 0,890235 с или 1,123298904222Гц или 67,40 обр/мин

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

А это поможет решению проблемы? Мне кажется, что все равно нужно будет подключать math и всё так же не хватит памяти :(

Числа-то теже.... вещественные...

(МК PIC12F675)

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

Числа-то теже.... с плавающей точкой...
да вы шо!? чо правда?... а если думалку включить? те же да ни те....если результат нужен в обр/мин, топри Fо=1МГц формула примет вид:Fx=60000000/N , где N - беззнаковое длинное целое, Fx- беззнаковое целое

volatile	   unsigned long int  N_reg @ 0x30;
volatile	   unsigned  int  Rezalt_reg @ 0x3A;
void main(void)
{
N_reg= 6000;
if (N_reg>5999)
  {
Rezalt_reg=60000000/N_reg ;
  }

плавающей точки нет, и код алгоритма деления меньше.... этот код съедает 17% памяти программ и 20% памяти данных, время исполнения около 870мкс

можно деление заменить вычитанием

volatile	   unsigned long int  N_reg @ 0x30;
volatile	   unsigned  long int  Fec_reg @ 0x35;
volatile	   unsigned  int  Rezalt_reg @ 0x3A;
void main(void)
{
	  N_reg= 6000;
if (N_reg>5999)
 {
   Rezalt_reg=0;
   Fec_reg=60000000;
while(Fec_reg>0)
  {  
  Fec_reg=Fec_reg-N_reg;
  Rezalt_reg++;
  if(Rezalt_reg==0xFFFF)Fec_reg--;
  }
  } 

while(1)
   {
NOP();
} // end while(1)

код съедает 8% памяти программ и 6,3% памяти данных, время исполнения около 0,29с

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

Мне кажется, что все равно нужно будет подключать math и всё так же не хватит памяти :(

Числа-то теже.... вещественные...

(МК PIC12F675)

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

ЗЫ. Надо было вам начинать с ассемблера тогда бы и вопросов не возникло.

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

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

Вход 1000 об/мин = 1000/60 = 16 целых 2/3 Гц, выход 1Гц.

Следовательно, используя таймеры с одинаковой дискретизацией (одинаковые делители) для реализации задержки на выходе, вам нужно число полученное от измеряющего таймера Х умножить на коэффициент 16 целых 2/3 и запихнуть это число во второй таймер (пока о реализации таймера речь не идет).

Получаем Х * 16 целых 2/3 = Х * (16*3+2)/3 = (Х*16*3)/3 + 2Х/3 = Х*16 + 2Х/3. Теперь обратимся к организации таймера: мы видим в формуле множитель 16 следовательно можно установить разницу в предделителях равную 16 (в данном случае предделитель должен быть больше у выходного таймера) и сразу получим аппаратное умножение на 16. Следовательно (Х*16 + 2Х/3)/16 = Х + Х/24

Ну а если вам не хочется терять точность - используйте одну дискретизацию в обоих таймерах. Формула имеет вид 16Х + 2Х/3.

Умножение на число кратно 2 в степени равно сдвигу влево на соответствующее кол-во знаков.

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

Спасибо ответившим большое!

Сижу, читаю ваши сообщения уже час.... понимаю, что разжевали уже куда уж лучше. Но чувствую себя полным бараном :(

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

Запутался я уже что нужно, где и как считать, на что умножать.... да еще в формуле 16Х + 2Х/3 есть "/", а это деление - результат вещественный?

Просто Вы всё говорите, что никаких вещественных чисел, можно без них и тем не менее приводите формулы с дробями.... Или я совсем уже ничего не понимаю...

ЗЫ. Надо было вам начинать с ассемблера тогда бы и вопросов не возникло.

Я три недели как изучаю Си .... точнее переучиваюсь с паскаля. Голова трещит :) На ассемблер, я думаю, уже не потяну(

Таймер нужно затактировать от внешнего сигнала.

Таймер - это имеется в виду что-то "наше" или то, что имеется в МК в даташитах?

Т.е. это нужно в схеме внешний кварц использовать? Или Таймер тактировать сигналом тахометра? ...т.е. используя прерывание на изменении порта...

Извините за глупые вопросы.... каша какая-то в голове

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

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

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

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

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

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

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

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

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

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

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

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