Jump to content
    

Изменение выхода в дампе pic18

On 6/14/2025 at 8:33 AM, Snowmen10 said:

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

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

как это делаеца написано в 4м сообщении темы.

Share this post


Link to post
Share on other sites

2 часа назад, siargy сказал:

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

Вы даёте слишком умные советы. Автор ведь писал уже, что ему не нужны умные советы. Давайте глупые.  :mosking:

Share this post


Link to post
Share on other sites

20 hours ago, jcxz said:

Давайте глупые.

скорее примитивные, как уроки для начинающих - скопировать код и поморгать светодиодом.

Share this post


Link to post
Share on other sites

В 15.06.2025 в 06:32, girts сказал:

Скорее в другом.
Это особенности всех тех чудаков, которые заходят в конференцию и бьют копытом об клаву что ему все тут должны.

копытом. да.

вам бы научиться читать а не умничать.

вопрос-то был простой

"вопрос такой. если стандартно mplab не дает настроить корректно нужную скорость, не дает вручную ввести отличные от предложенных параметров фазы кванты и т.д., чем добиваться работоспособности? сторонними библиотеками? "

т.е. никто конкретно не просил ничего.

и копытом не стучал.

но тут ворвплись прожженые кодеры и начали умничать про "дело плевое".

даже не удосужившись прочитать вопрос и ответить на вопоос, а не умничать на тему как проще с их высоты полета...

Share this post


Link to post
Share on other sites

Добрый день. Чтоб не плодить темы на 5 ответов.

 

Назрел новый вопрос.

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

гуглил, сам пытался не идет.

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

 

В общем на пике моем pic18 бегает в цикле программа.

Шлет некие сообщения в шину CAN. иногда между сериями сообщений вставлена пауза 100мс.

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

 

 

Есть еще ряд функций, в которых проверяются промежутки времени для обработки событий(получение и отправка сообщений).

Промежутки организованы по аналогии с ардуиной - функция millis(), которую я сочинил. работает это проверкой как if (millis - last_send > 2500)

организована millis через tmr0 - в теле цикла программы есть функция, которая проверяет переполнение таймера с периодом 1мс и плюсует один к millis.

   if(TMR0_HasOverflowOccured())           // таймер переполнен?
        {
            TMR0IF = 0;         // menyaem flag
            TMR0_Reload();      // sbros taymera
            ++millis; // uvelichivayem millis na +1
        }

И вроде оно все работает но millis неточные получаются. из-за тех самых вставок паузы между отправками сообщений, которые в некоторых случаях(крайне редко) доходят до 100мс.

Но точно постоянно в цикле есть паузы в 3мс между сообщениями в шину. и таких пауз один два десятка в зависимости от набора отсылаемых сообщений. Итого за цикл программы набегает 20*3=60мс задержек кода, во время которых таймер естественно может 60 раз переполниться но функция эмулирующая ардуиновскую millis увидит это только один раз. а значит отставание millis каждый цикл доходит до 60мс. И тут уже начинаются сбои редкие из-за невовремя отправленных сообщений.

 

как я пытался это побороть.

не ждать переполнение таймера для millis++, а сделать  период таймера значительно больше(4 секунды) и считывать каждый цикл показания таймера(TMR0_ReadTimer(void)) , плюсуя к millis  считанное значение. естественно с учетом того, что иногда tmr0 переполняется и отсчет начинается с нуля.

/* if (TMR0_ReadTimer() >= 3500000) {  // не ждем переполнение таймера, а сбрасываем его немного ранее
    TMR0_Reload();      // sbros taymera
    }*/

  /*  if (TMR0_ReadTimer() > old_tmr_val) {  // если таймер не перевалил за максимальное за время цикла программы и не сбросили его выше
    millis = millis + (TmrMS-old_tmr_val);
    old_tmr_val = TMR0_ReadTimer();
    }
    else {    // иначе - таймер обнулился
    millis = millis + (TMR0_ReadTimer() +(3500-old_tmr_val));
    old_tmr_val = TMR0_ReadTimer();
    }*/

и тогда в каждом цикле к millis будет прибавляться реальное время без всяких задержек. если и будут незначительные отклонения, то только из-за переполнения и начала с нуля. но точно не десятки а иногда и сотни миллисекунд. и расхождение будет появляться раз в 4 секунды ,что для меня уже не критично.

Прав я тут?

Но что-то не работает это у меня.

И тут пара простых вопросов, которые я не нашел в поисковиках и описании tmr0 в mplab.

1. при выставлении в MCC в MPLAB в таймере периода, в окне есть значения от минимального до максимального периода, между которыми и нужно выставить свой требуемый. Является ли этот минимальный период той самой величиной времени, которую можно принять за единицу отсчета таймера?

т.е. если там для выбранных прескаллеров стоит минимальное значение периода 16us, значит ли это что если таймер свой счетчик между запросами изменит на 50 единиц, то равняется это 50*16us(мкрС)?

2. если нет, где взять чему равна единица отсчета таймера.

3. если не так то что такое единица отсчета таймера? величина высчитываемая из тактовой и делителей? или она фиксированная при любых делителях?

Это вот главный вопрос. Что такое единица отсчета таймера и как ее посчитать?

Спасибо.

 

Share this post


Link to post
Share on other sites

44 минуты назад, Snowmen10 сказал:

Но что-то не работает это у меня.

  1. Выкинуть все задержки.
  2. Раз программа построена в стиле суперцикла, то так и работать: В начале каждой итерации цикла читать время из таймера и находить разницу между ним и запланированным временем какого-то действия (запланированным на будущее).
  3. Если получившаяся разница >= 0 - выполнить действие и установить новое время для следующего выполнения этого действия.

Примерно так:

#define ms2tkt(x) ... //макрос пересчитывающий миллисекунды в такты таймера
enum {ACT0_PERIOD = 100, ACT1_PERIOD = 120, ...}; //[ms] периодичность выполнения соответствующих Action...()
int timAct0, timAct1, ...;
for (timAct0 = timAct1 = ... = ReadSysTimer(); ; ) {
  int i = ReadSysTimer();
  if (i - timAct0 >= 0) {
    timAct0 = i + ms2tkt(ACT0_PERIOD); //планируем момент следующего выполнения
    Action0();
  }
  if (i - timAct1 >= 0) {
    timAct1 = i + ms2tkt(ACT1_PERIOD); //планируем момент следующего выполнения
    Action1();
  }
  ...
}

Это для таймера считающего в +. Необязательно рабочие переменные должны быть типа int. Их разрядности подобрать подходящими для вашего CPU и разрядности таймера (скорее всего они должны быть == основной разрядности вашего CPU).

Можно сюда ещё добавить вычисление минимального времени до ближайшего планируемого события и, если оно > 0, то отдавать это время ОС или ложиться спать.

Продвинутый вариант со сном (изучать только после освоения и закрепления предыдущего материала!):

Спойлер
...
enum {MAX_SLEEP_TIME = ...}; //[ms] макс. возможный интервал сна
for (timAct0 = timAct1 = ... = ReadSysTimer(); ; ) {
  int j, i = ReadSysTimer(), t = ms2tkt(MAX_SLEEP_TIME);
  if ((j = timAct0 - i) <= 0) {
    timAct0 = i + ms2tkt(ACT0_PERIOD); //планируем момент следующего выполнения
    Action0();
    t = 0;
  } else if (t > j) t = j;
  if ((j = timAct1 - i) <= 0) {
    timAct1 = i + ms2tkt(ACT1_PERIOD); //планируем момент следующего выполнения
    Action1();
    t = 0;
  } else if (t > j) t = j;
  ...
  if (t) Sleep(t); //отдадимся сну на t тактов таймера; чтобы не жрать впустую миллиамперы и не перегревать ещё более Землю
}

 

44 минуты назад, Snowmen10 сказал:

2. если нет, где взять чему равна единица отсчета таймера.

3. если не так то что такое единица отсчета таймера? величина высчитываемая из тактовой и делителей? или она фиксированная при любых делителях?

Это вот главный вопрос. Что такое единица отсчета таймера и как ее посчитать?

Чтобы это узнать, нужно скачать reference manual + datasheet на ваш контроллер; открыть их на разделах "clocking" (или подобных) и прочитать про устройство системы тактирования контроллера: ядра, периферии, шин, ... А также изучить принципиальную схему вашего устройства.

Share this post


Link to post
Share on other sites

8 минут назад, jcxz сказал:
  1. .
  2. Раз программа построена в стиле суперцикла, то так и работать: В начале каждой итерации цикла читать время из таймера и находить разницу между ним и запланированным временем какого-то действия (запланированным на будущее).
  3.  

Вот это весьма интересно. Попробую.  Хотя отдельной функцией организовать millis из показаний таймера выглядит для меня значительно легче. Код перерабатывать не нужно. Главное все же с таймером и его единицами измерения разобраться.

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

3 часа назад, siargy сказал:

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

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

настроен период таймера в 1мс и включено прерывание. 

void main{

TMR0_SetInterruptHandler(TMR0_millisInterrupt);

...

}

 

// функция вызываемая по прерыванию. при переполнении добавляет +1 к millis

void TMR0_millisInterrupt(void) { 
    TMR0IF = 0;         // menyaem flag
    TMR0_Reload();      // sbros taymera
    ++millis; // uvelichivayem millis na +1
    
    if (millis > 4294000000) millis = 0;        // контроль переполнения millis
}

 

компиляция прошла. В железо пока не заливал.

 

немного больше понял теперь про прерывания и их работу.

 

 

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

Share this post


Link to post
Share on other sites

12 hours ago, Snowmen10 said:

не часто ли?

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

 

12 hours ago, Snowmen10 said:

if (millis > 4294000000) millis = 0;        // контроль переполнения millis

надо еще и время срабатывания сбрасывать, если предполагаеца беспрерывная работа мк 7/24

Share this post


Link to post
Share on other sites

9 часов назад, siargy сказал:

 

 

надо еще и время срабатывания сбрасывать, если предполагаеца беспрерывная работа мк 7/24

время срабатывания чего? контроллер да, всегда включен в авто. но при глушении засыпает. там одновременно со сбросом millis еще и сброс всех переменных для контроля периодов прописан. словно его выкл вкл.

Share this post


Link to post
Share on other sites

В 26.08.2025 в 18:22, Snowmen10 сказал:

if (millis > 4294000000) millis = 0;        // контроль переполнения millis

И зачем нужны эти странные манипуляции?

В 27.08.2025 в 07:21, siargy сказал:

надо еще и время срабатывания сбрасывать, если предполагаеца беспрерывная работа мк 7/24

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

 

PS: И судя по всему - переменная millis имеет разрядность больше разрядности МК. А значит, раз она модифицируется в ISR, то просто так читать её (как в коде автора выше) - нельзя. Нужно обеспечивать атомарное чтение. Чего в коде автора опять же - не наблюдается.

Также большие сомнения вызывает необходимость этого в ISR:

В 26.08.2025 в 18:22, Snowmen10 сказал:

TMR0_Reload();      // sbros taymera

Share this post


Link to post
Share on other sites

5 часов назад, jcxz сказал:

И зачем нужны эти странные манипуляции?

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

 

PS: И судя по всему - переменная millis имеет разрядность больше разрядности МК. А значит, раз она модифицируется в ISR, то просто так читать её (как в коде автора выше) - нельзя. Нужно обеспечивать атомарное чтение. Чего в коде автора опять же - не наблюдается.

Также большие сомнения вызывает необходимость этого в ISR:

железо приедет уже на нем будет допиливаться все что нужно и не нужно. но где-то на форуме находил заготовку такого счета по прерыванию. и там вопрошающему отвечали, что таймер 0 сам не сбрасывается, нужно сбрасывать командами и это занимает столько-то машинных циклов или шагов. а таймер2 сам сбрасывается и он для таких целей предпочтительнее. из этого и вынес, что нужно таймер0 сбрасывать при переполнении. плюсом к этому. в mplab mmc генерирует болванки функций. так вот если в нем настроить таймер без прерывания, то там один набор функций генерируется в фале. если указать что нужно прерывание, то немного иной набор. И void TMR0_Reload(void) там есть и в том и в том варианте генерируемого набора. да, данная команда сброса есть в отдельной функции

void TMR0_ISR(void)
{

    // clear the TMR0 interrupt flag
    INTCONbits.TMR0IF = 0;

    // reload TMR0
    TMR0L = timer0ReloadVal;

    // ticker function call;
    // ticker is 1 -> Callback function gets called every time this ISR executes
    TMR0_CallBack();

    // add your TMR0 interrupt custom code
}

но я ее не вызываю. у меня своя TMR0_millisInterrupt.

 

я-то пока на таком уровне в этом всем плаваю...

вообще я там немного запутался в этих всех прерываниях и сгенерированных MССфункциях . словно несколько дублирующихся.

 

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

 

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

Share this post


Link to post
Share on other sites

29 минут назад, Snowmen10 сказал:

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

Не это плохо, а то что читаете вы её неатомарно. А значит - будете периодически читать из неё мусор. Со всеми вытекающими.

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

29 минут назад, Snowmen10 сказал:

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

Зачем? Если "насчитает больше чем позволяет тип данных", то она сама обнулится.

29 минут назад, Snowmen10 сказал:

таймер 0 сам не сбрасывается, нужно сбрасывать командами

Если это так, то это весьма странно. Так как будет приводить к накоплению ошибки счёта.

В периферии PIC18 не разбираюсь, судить реально ли так - не могу.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...