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

crazz

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

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

сготовился, и пусть себе лежит в регистре, покуда не пригодится

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

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

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

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

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

Сиречь в прерывания и ДМА.

戦う前に相手のベルトの色に注目

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

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

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

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

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

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

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

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

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

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

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

Ну а прежде всего, ему надо почитать про двоичную арифметику, про то как контроллер считает числа и т.д. без осознания этих фактов он будет постоянно удивляться таким вещам как число 161 в результате вместо ожидаемых 92. п.с. вообще это чудо что число получилось настолько близко к искомому, поэтому может прийти в голову нелепая мысль что это какая-то ошибка округления при умножении/делении. А на самом деле, результат мог быть любым числом в диапазоне 0..65535 из-за ограничения разрядности в промежуточных вычислениях.

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

Учение - изучение правил. Опыт - изучение исключений.

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

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

Он сейчас находится на том этапе когда чем проще программа тем лучше. Прерывания пока еще рано вводить

Прерывания ничего сложного из себя не представляют, тем более, что они УЖЕ ЕСТЬ.

И единственная ошибка ТС состоит лишь в том, что он не сопоставил интервал прерываний и время исполнения обработчика.

Экая сложная наука!

Ничего сакрального в этом нет и объясняется РОВНО ОДНОЙ ФРАЗОЙ.

Не многим больше требуется, чтобы объяснить про типы.

А самое лучшее, если все это он пару-тройку раз сделает БЕЗ КОМПИЛЯТОРА. То есть на АСМе.

Тогда и про биг-литл эндиан будет от зубов отлетать, хоть ночью разбуди....

ДМА?

Да, ДМА, если он имеется. Речь была об ОБЩЕМ подходе.

Естественно, что я в курсе, что в обсуждаемом МК нет ДМА.

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

戦う前に相手のベルトの色に注目

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

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

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

Учение - изучение правил. Опыт - изучение исключений.

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

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

Ну и что? Если не считать РАЗОВОГО непонимания времени исполнения ISR, он в общем с задачей справился.

Разрешения включил все, флаг в ISR загасил, синтаксис прерывания не переврал.

Исправит расположение вычислений и включит ISR от АЦП - вот и вся нЕдолга...

Чего тут такого академически сложного?

Ну даже и сделает еще пару ошибок. Мир от этого не рухнет, а человек научится.

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

:crazy:

戦う前に相手のベルトの色に注目

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

разбирайтесь

Спасибо, есть много вопросов)

1. Почему коды индикаторов записаны каким то другим способом с побитовым сдвигом? #define SEG_A (1<<0) что эта запись вообще означает?

2. Вижу объявление переменной массива volatile unsigned char LEDS[3] но не вижу где описание этого массива? и зачем вообще вот это название volatile? почитал но нифига не понял функциональность =)

3. зачем в инициализации сначала идет запрет всех прерываний? INTCON =0x00; // запрет всех прерываний

4. Зачем два раза обнуляются порты?

5. Почему мне человек писал:

Тактирование АЦП - 500 нс, что В 4 РАЗА меньше допустимого ( 2мкс)...
хотя сейчас гляжу тактирование точно такое же как у меня и стояло ADCON0=0b01000001; //тактирование АЦП Fosc/8,

6.Почему у вас запись OPTION а у меня OPTION_REG? разные библиотеки?

7. Зачем в мэйне вот эта минипауза как я понял. for(i=255;i>0;i--); ?

8. Почему в мэйне цикл while (1) почему в скобочках 1?

9. Если в цикле while в скобочках стоит что то, то это значит что тело цикла работает пока это что то равняется единице? и кстати что такое NOP? не смог нагуглить (GODONE){NOP();};

10. что такое 500L? adc = (adc*500L)/1024;

11. Вот это вообще не понял что такое:

else
   {
   for (j=0;j<3;j++)
	 {
	   DS=volt%10;
	   volt=volt/10;
	  if(j==2)
		 { tempLEDS[j]= digits [DS] + SEG_H;}
	  else
		 { tempLEDS[j]= digits [DS];} 
	 }
   }

Типо если результа ацп отличный от 499 то тогда выполняется это тело,

в теле цикл счетчик от 0 до 3

если счетчик равен 2 то чето загорается.

12. Так же не очень понятный код:

GIE = 0;
  LEDS[2]= tempLEDS[2];
  LEDS[1]= tempLEDS[1];
  LEDS[0]= tempLEDS[0];
   GIE = 1;  

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

Ведь умножив исходный коэффициент на 1024, Вы превысили разрядность int.

вот тут вы меня в ступор вводите. Как я превышаю разрядность int? я в инете гляжу у int разрядность 4 байта -2 147 483 648 / 2 147 483 647

Следующим вопросом ТС будет про прыганье показаний.

это про меня? Просто ТС это же Топик Стартер. А топик стартер это не я.

Про прыганье показаний читал, понимаю что дергаться будет и видел. Но я думал просто сделать задержку между замерами АЦП к примеру 1 секунда. и тогда точно не будет прыгать чаще чем раз в секунду.

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

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

Ну а прежде всего, ему надо почитать про двоичную арифметику, про то как контроллер считает числа и т.д. без осознания этих фактов он будет постоянно удивляться таким вещам как число 161 в результате вместо ожидаемых 92. п.с. вообще это чудо что число получилось настолько близко к искомому, поэтому может прийти в голову нелепая мысль что это какая-то ошибка округления при умножении/делении.

Такие вещи я понимаю и знаю. Знаю что если разрядность у переменной 255 и если я в ней сложу 245 и 20 то получу 10 или где то так. Просто в интернете написано что у int разрядность -2 147 483 648 / 2 147 483 647

и я не понимаю какого хрена у меня получается 161 а не 92

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

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

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

Ага, а ты поинтересовался какой именно это INT, вообще путаница в этом деле очень знатная. Так повелось что размер INT раньше зависел от разрядности системы - INTEGER сейчас можно найти описанный как 16 бит или как 32 бит целое число, а на современных больших процессорах INTEGER и вовсе 64-битный.

в МК INT это 16-битное целое число.

1. кто во что горазд так и записывают... #define SEG_A (1<<0) означает число 1 сдвинутое на 0 разрядов. Или другими словами, это одно и то же что 1 в 0-м разряде. (1<<5) будет означать число с "1" в 5-м бите, а если записать (3<<5)... надеюсь сами догадаетесь. Просто такая форма легче для восприятия и редактирования чем битовое число, особенно когда необходимо будет корректировать сегменты согласно реальной разводке печатки, тогда номера битов заменяются на константы и одной строчкой можно легко поменять все сегменты заданные для всех чисел. В противном случае пришлось бы переписывать минимум 10 строчек двоичных чисел, переставляя биты местами вручную.

2. volatile означает что их нельзя оптимизировать компилятору и использовать в некоторых местах регистр вместо ячейки памяти а то и вовсе компилятор посчитает что эту переменную можно выбросить из кода т.к. нет прямого обращения к ней. такое объявление просто выделяет кусок памяти в сегменте данных, т.е. в адресном пространстве RAM.

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

8. Это особенность контроллеров. Выполнение программы в контроллере безостановочное, у него нет конца и следовательно программа завершиться никогда не должна, поэтому она и зациклена в бесконечном цикле. 1 - это просто цифровое изображение значения true. Впрочем, туда прокатит любое число отличное от нуля так устроен язык - у его FALSE только при значении 0, т.к. на низком уровне контроллер быстро умеет только сравнивать значение с нулём, остальные варианты предполагают выполнение команды вычитания и сравнения результата с нулём.

"что такое NOP" - по нашему, это "нет операции", команда которая ничего не делает лишь прокручивая такты.

Учение - изучение правил. Опыт - изучение исключений.

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

1. имено то что и означает сегменту_А присвоить значение 1 и сдвинуть оную на 0 бит те SEG_A=0b00000001

те установить бит0 в лог1 , на моменте симуляции легче всего сенментам A:H назначить биты от 0 до 7 , но когда дело доходит до реальной платы проводники ну ни как не хотят нормально разводится, поэтому разводим как удобно и в описании сегментов тупо меняем номера битов.... как-то так...

2. что бы компилятор не испортил значения этого массива, кагбы прерывание является внешней программой для основного цикла

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

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

4. изначально все входы и состояние битов порта не определено , принудительно определяем, включаем на выход, подтверждаем тк сушествует ЧМЗ(чтение-модификация-запись)

5. ошибя наверное...

6 да

7 АЦП включили, сделали задержку для заряда емкости холд, можете убрать и протез сразу посыпит варнинги

8 стандартная запись бесконечного цикла

9 цикл выполняется пока условие истенно те не равно 0, NOP() равносильна ассемблерной вставке asm `nop` - пустая команда, ставится для предотвращения действия ЧМЗ тк обращение к порту идет побитно

10 для правильного вычисления результата требуется 32-разрядное вычисление , поэтому константу указываем Long , иначе компилятор приведет все к int (вам уже на это my504 указывал)

11 а че тут не понятного, 5в вычисляем с точность до сотен те 5,00 эквивалентно значению volt=500 требуется только добавить точку на индикаторе в третий разряд что собственно и делаем

12 это называется атомарный доступ , сделано для предотвращения передачи неправильного значения массива в прерывание , если прерывание произойдет в момент изменения значений массива

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

МК INT это 16-битное целое число.

Ну тогда понятно раз оно только до 65535 то конечно в формуле косяк будет =) а я то размахнулся что у меня число аж два миллиарда =)))) и не понимал в чем же проблема.

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

2. вот блин мне уже объясняли а я опять забыл =))) Вообщем под данную переменную выделяется место в памяти на ПМЖ =)

3. Понял это вообщем подготовительные операции по феншую.

Зачем тут прокручиваются такты? и сколько конкретно тактов? Это связано с тем что значения нули?

dig1=0; NOP(); dig2=0;NOP(); dig3=0; LED=~(digits [10]);

Что будет если отсюда убрать NOP? Как я понимаю ничего не будет, но в каких случаях может спасти наш Ноп?

while (GODONE){NOP();};

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

Зачем тут прокручиваются такты? и сколько конкретно тактов? Это связано с тем что значения нули?

dig1=0; NOP(); dig2=0;NOP(); dig3=0; LED=~(digits [10]);

Что будет если отсюда убрать NOP? Как я понимаю ничего не будет, но в каких случаях может спасти наш Ноп?

while (GODONE){NOP();};

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

ничего не будет...

иногда полезная вещь, при отладке точку останова на нее повесить, ну или очень короткую задержку организовать

ЗЫ Вам бы это почитать:

polnyy_spravochnik_po_c_gerbert_shildt.rar

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

32767 если точнее. Число со знаком, значит под значение только 15 бит остаётся.

NOP прокручивает столько же тактов как и остальные простые команды, для ПИК-ов это стандартные 4 такта или один машинный цикл. За столько же выполняется операция сложения, логические, побитовый сдвиг...

Зачем тут прокручиваются такты? и сколько конкретно тактов? Это связано с тем что значения нули?

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

Ведь такие операции как изменение одного биты порта контроллер делать не способен, он работает наборами по 8 бит, и чтобы изменить один бит нужно считать их все наложить маску (AND для обнуления бита, или OR для установки бита) и сохранить обратно(эта операция называется ЧМЗ - чтение-модификация-запись). Беда в том что на такой скорости, за скажем 500нс напряжение на выводе может не успеть изменится, и при выполнении dig2 = 0 в ходе чтения 8 бит порта вывод на котором сидит dig1 может прочитаться как "1" и когда мы будем сохранять значение обратно в порт для dig2 в dig1 сохранится "1"...

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

Но впрочем этот эффект имеет своё применение - если подтянуть вывод к + через резистор в 1МОм, то после перевода порта из состояния выход "0" на вход и сразу же прочитать его значение можно определить емкость подключенную к выводу - т.е. есть ли палец на сенсоре. Если есть, напряжение будет меняться дольше и дольше будет читаться "0" сразу после перевода порта в режим чтения.

Учение - изучение правил. Опыт - изучение исключений.

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

7 АЦП включили, сделали задержку для заряда емкости холд, можете убрать и протез сразу посыпит варнинги

Емкость заряжается один раз при старте МК верно?

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

Ух как сложно =)))) Потом еще перечитаю =) Но вкратце для дилетантов я бы объяснил так: МК работает очень быстро и такие мелкие команды как врубание или вырубание портов могут не успеть отработать и будут глюки.

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

просто пока прога считает математику емкость успевает перезарядится...

а каким образом эта задержка выполняется каждый раз? я вроде как читал что МК выполняет тело мэйн, а в теле мэйн идет инициализация задержка и вход в бесконечный цикл while (1). И вот в бесконечном цикле то как раз и нет этой задержке которая была в самом начале

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

И вот в бесконечном цикле то как раз и нет этой задержке которая была в самом начале

ну-да... а процедуру convert () по вашему время не тратится? если че только на матиматику тратится 1283 маш.циклов
Ссылка на комментарий
Поделиться на другие сайты

Чего то не работает тот код, ну я его под себя попробывал переделать и вот пытался разобраться в функции convert и вообще её до простого упростил. Один фиг не работает.

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

convert () по вашему время не тратится?
Понятное дело что время тратиться но вопрос был про задержку for(i=255;i>0;i--);

я не понимаю как она выполняется постоянно если её нет в теле бесконечного цикла while в которой работает МК

или же мк постоянно крутит тело мэйн? Но как он выйдет из бесконечного цикла while чтобы заново запустить тело мэйн?

Нашел проблему Иероглифов!

Иероглифы выводились вот изза этих строк а именно изза значка ~

case 2: dig1=0; dig3=0; dig2=1; LED=~(LEDS[1]); break;

Что это за значок и зачем он был поставлен?

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

код рабочий...

вообще-то это инверсия, файл протеза я вроде прикреплял или нет? там индикатор с обшим анодом на прямую к МК прикручен

управляющим для катода является лог0, а в сегменты заносилось лог1, для этого и инверсия...

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

Еще вопрос по этому моменту:

while (ADCON0bits.GO){NOP();};

adc= (ADRESH<<8)+ADRESL;

adc = (adc*500L)/1024;

volt = adc;

if ( volt==499)

так как у нас включено правое выравнивание то АЦП у нас будет 10 бит, тоесть от 0 до 1023

при 5 вольтах adc равно 1023 (максимальное значение) как я понимаю вот этой записью оно получается adc= (ADRESH<<8)+ADRESL;

А почему нельзя сразу считать 10 битное значение? Потому что МК 8 битный и у него все регистры по 8 бит? и каждый регистр не может содержать в себе больше чем 8 бит?

Ну и чтобы получить 10 битный результат МК хитрит не знаю как он это делает но раскидывает значение 10 битное по двум регистрам. Поэтому мы пишем adc= (ADRESH<<8) тем самым записываем в переменную adc значение регистра ADRESH сдвинутое на 8 бит влево? зачем? и прибавляем 8 битное значение регистра ADRESL

вообще-то это инверсия, файл протеза я вроде прикреплял или нет?

ну там всего 5 файлов. и помойму протеусовского нету. c, cof, dsn, hex, h

Про инверсию не очень понял =)

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

так как у нас включено правое выравнивание то АЦП у нас будет 10 бит, тоесть от 0 до 1023

при 5 вольтах adc равно 1023 (максимальное значение) как я понимаю вот этой записью оно получается adc= (ADRESH<<8)+ADRESL;

А почему нельзя сразу считать 10 битное значение? Потому что МК 8 битный и у него все регистры по 8 бит? и каждый регистр не может содержать в себе больше чем 8 бит?

Да, поскольку контроллер 8 разрядный, шина данных у него позволяет одномоментно передать только эти 8 разрядов.

Но в этих условиях есть ДВА способа переместить два байта из буфера АЦП в переменную типа unsigned int, которая тоже содержит два байта.

1. Способ описан в примере моего коллеги и он заключается в том, что два регистра источника (буфера АЦП) никак между собой не связаны и находятся в произвольных адресах ОЗУ. Напомню Вам, что все регистры специального назначения (SFR) находятся в адресном пространстве ОЗУ контроллера и ничем с этой точки зрения от обычного ОЗУ не отличаются, можно даже их использовать как рабочие регистры в программе, если аппаратная часть с ними связанная не задействована. Так вот, запись двух байт в двухбайтную переменную производится путем логического сдвига старшего байта на 8 разрядов влево и сложения с выходной переменной, с которой складывается и младший байт, но без сдвига. Сиречь, старший байт перед сложением умножается на 256 (это равнозначно 8 разрядному сдвигу влево).

2. Второй способ использует СОСЕДСТВО байт принадлежащих одной переменной в ОЗУ. Есть ДВА ОСНОВНЫХ порядка размещения (https://ru.wikipedia.../Порядок_байтов):

- little endian - в младшем адресе размещен младший разряд

- big endian - в старшем адресе размещен младший разряд

В памяти 8 битных контроллеров традиционным является little endian, поскольку математические операции большей частью начинаются с младших разрядов. Но есть довольно много ПЛАТФОРМ контроллеров, где порядок байт реверсный, либо ПЕРЕКЛЮЧАЕМЫЙ в определенных случаях (middle endian), либо управляемый пользователем.

Используя этот порядок, принятый в компиляторе Си НА КОНКРЕТНУЮ ПЛАТФОРМУ и используя тот факт, что оба регистра АЦП размещены в ОЗУ именно в этом принятом порядке (младший байт в младшем адресе), можно объявить переменную ADRES (физически такого регистра нет), как unsigned int, что приведет к тому, что старшие два разряда в ADRESH станут старшим байтом этой переменной, а младший ADRESL, соответственно, - младшим байтом.

Тогда компилятор просто произведет две пересылки с инкрементом адреса, вместо сдвига и сложения. Хотя чаше всего компилятор ОПТИМИЗИРУЕТ первый вариант записи до второго, следуя типу платформы.

С точки зрения ЧИТАБЕЛЬНОСТИ кода - второй вариант записи лучше. С точки зрения ПЕРЕНОСИМОСТИ кода - лучше первый.

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

戦う前に相手のベルトの色に注目

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

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

Программа не компилируется видимо я как то не правильно функцию LinearAPPROX в функцию convert запихнул =) И вообще не знаю можно ли так делать и как правильно.

С разбитием на разряды я так и не разобрался с кодом поэтому снес и написал свой проверенный вариант =)

Кстати я тут подумал может сделать adc глобальной переменной? А где тогда описывать чего она означает? В отдельной функции?

Комментарии кое где могут быть старыми не актуальными.

/*
* File: newmain.c
* Author: Vlad
*
* Created on 16 ???????? 2015 ?., 0:37
'11-a RB5
'13-b RB7
'7-c RB1
'9-d RB3
'6-e RB0
'10-f RB4
'12-g RB6
'8-dp RB2
' RA3 dig1
' RA2 dig2
' RA7 dig3
*
* $82 - E, $08 -R
*
*/
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF	 // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON	 // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF	 // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = ON	 // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF	 // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF	 // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF	 // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB2	 // CCP1 Pin Selection bit (CCP1 function on RB2)
#pragma config CP = OFF		 // Flash Program Memory Code Protection bit (Code protection off)
#include <xc.h>
#include <pic.h>
#include <pic16f819.h>

#define dig1 RA3 //индикатор 1
#define dig2 RA2 //индикатор 2
#define dig3 RA7 //индикатор 3
//#define tochka RB2
#define warning RA1
//#define _XTAL_FREQ 4000000
#define LED PORTB
const unsigned char digits [13] = {0x44,0x7D,0x16,0x15,0x2D,0x85,0x84,0x5D,0x04,0x05,0xFF,0x86,0x0C}; //0,1,2,3,4,5,6,7,8,9,пусто, E,R

		 unsigned char i			 ; //
volatile	 unsigned char a			 ;//
volatile	 unsigned char LEDS[3]		 ; //

//***********************************************************************
//* ИНИЦИАЛИЗАЦИЯ МК
//***********************************************************************
void init(void)
{
INTCON =0x00; // запрет всех прерываний
OSCCON = 0b01100100; //с 4 по 6 бит значение 110 означает 4mhz
// настройка портов
PORTA = 0; //обнуляем порт а
PORTB = 0;
TRISA = 0b01110001; //порты RA2, RA3, RA7, RA1 на выход а остальные на вход
TRISB = 0b00000000; // все порты RB на выход
PORTA = 0; //обнуляем порт а
PORTB = 0;
warning=1;
// настройка АЦП
ADCON0=0b01000001; //тактирование АЦП Fosc/8, выбран канал AN0, модуль АЦП включен
ADCON1=0b10001110; //правое выравнивание, включен аналоговый вход RA0/AN0, остальные входы цифровые
// настройка таймера TMR0
TMR0 = 0; //сбрасываем таймер в 0
OPTION_REG = 0b00000011; // настройки таймера 1:16 и установка Set timer TMR0 даташит page 54:
// разрешение прерываний
TMR0IE = 1;
GIE = 1;
};


void interrupt Timer (void)
{ //прерывание по таймеру для динамической индикации
if(TMR0IF)
 {
	 TMR0IF=0;
	 dig1=0; NOP(); dig2=0;NOP(); dig3=0; LED=(digits [10]); // гасим все разряды
	 a++;
	 switch(a)
 {	 // Динамическая индикация.
		 case 1: dig1=0; NOP(); dig2=0; NOP(); dig3=1; LED=(LEDS[2]); break; // Первый разряд
		 case 2: dig1=0; NOP(); dig3=0; NOP(); dig2=1; LED=(LEDS[1]); break; // второй разряд
		 case 3: dig2=0; NOP(); dig3=0; NOP(); dig1=1; LED=(LEDS[0]); a=0; break; // третий
 }
}
}
void LinearAPPROX()
{

 int tm;
 unsigned int adc;
 adc=(ADRESH<<8)+ADRESL;	
 //906 - 0
// t1=(-227L*x+215109L)/1024;		 // y = - 79 /355 x + 71574/355 от 0 до 15.8
 //835-15.8
 // t2=(-132L*x+126644L)/1024;		 // y = - 104/ 805 x + 99559 /805 от 15.8 до 36.6
 //674-36.6
 // t3=(-130L*x+125344L)/1024 ;	 // y = - 317/ 2490 x + 152396 /1245 от 36.6 до 100
 //176-100
if (adc>837) {
 tm=1023;
}
if(adc<674){
tm=((-130L*adc+125344)/1024); //уравнение от 36.6 до 100
}
if(adc<835){
tm=((-132L*adc+126644)/1024); //уравнение от 15.8 до 36.6
}
 if(adc<906){
tm=((-227L*adc+215109)/1024); //уравнение от 15.8 до 36.6
}
 tm=1023;
}
void convert (void)
{
unsigned int adc,value, d1_1	 ; //
unsigned char DS,j;
unsigned char tempLEDS[3]		 ; // масив числа
 ADCON0bits.GO = 1; //запускаем ацп
 while (ADCON0bits.GO){NOP();}; // если ацп работает то ниче не делаем
 adc= (ADRESH<<8)+ADRESL; //значение ацп в adc

 value = adc; //
if ( value==1023) //если значение ацп равно 1023 то выполняем тело
 {
 tempLEDS[2]= digits [12]; //тело, отправляется ERR
 tempLEDS[1]= digits [11];
 tempLEDS[0]= digits [11];
 warning=0; //и врубается варнинг
}
else // если не 1023 то выполняется тело
 {
 warning=1; //гасится варнинг
 LinearAPPROX();
 if(LinearAPPROX()<10){
	 tempLEDS[2]=digits [10];
	 NOP();
	 tempLEDS[1]=digits [10];
	 NOP();
	 tempLEDS[0]=digits [volt];
	 }// если значение меньше 10 то подаем цифру пусто на 1 и 2 слева индикатор
 if (LinearAPPROX() >= 10 && LinearAPPROX() < 100){
	 tempLEDS[2]=digits [10]; // если значение меньше от 10 до 100 то на 1 индикатор подаем цифру пусто. Заметил что там почемуто еле светиться цифра.
	 NOP();
	 d1_1=LinearAPPROX()%100;
	 tempLEDS[1]=digits [d1_1/10];				 // Получаем разряд
	 tempLEDS[0]=digits [d1_1%10];			 // Получаем разряд
	 }
 if (LinearAPPROX() >= 99 ){
	 d1_1=LinearAPPROX()%100;
	 tempLEDS[2]=LinearAPPROX()/100;// Получаем разряд
	 tempLEDS[1]=digits [d1_1/10]; // Получаем разряд
	 tempLEDS[0]=digits [d1_1%10]; // Получаем разряд
	 }

 }
GIE = 0;// глобальный запрет прерываний чтобы три переменных записались и запись не прервалась.
 LEDS[2]= tempLEDS[2];
 LEDS[1]= tempLEDS[1];
 LEDS[0]= tempLEDS[0];
GIE = 1;// врубаем прерывания заново.	

}
//***********************************************************************
//* ОСНОВНАЯ ПРОГРАММА
//***********************************************************************
void main (void)
{
 init();
 for(i=255;i>0;i--);
 //******** ГЛАВНЫЙ ЦИКЛ *****************
 while (1)
	 {
	 convert ();
	 };
}

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

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

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

	 LinearAPPROX();
	 if(LinearAPPROX()<10){
			 tempLEDS[2]=digits [10];
			 NOP();
			 tempLEDS[1]=digits [10];
			 NOP();
			 tempLEDS[0]=digits [volt];
			 }// если значение меньше 10 то подаем цифру пусто на 1 и 2 слева индикатор
	 if (LinearAPPROX() >= 10 && LinearAPPROX() < 100){
			 tempLEDS[2]=digits [10]; // если значение меньше от 10 до 100 то на 1 индикатор подаем цифру пусто. Заметил что там почемуто еле светиться цифра.
			 NOP();
			 d1_1=LinearAPPROX()%100;
			 tempLEDS[1]=digits [d1_1/10];						   // Получаем разряд
			 tempLEDS[0]=digits [d1_1%10];				   // Получаем разряд
			 }
	 if (LinearAPPROX() >= 99 ){
			 d1_1=LinearAPPROX()%100;
			 tempLEDS[2]=LinearAPPROX()/100;// Получаем разряд
			 tempLEDS[1]=digits [d1_1/10]; // Получаем разряд
			 tempLEDS[0]=digits [d1_1%10]; // Получаем разряд
			 }

Представляете, сколько раз тут может вызываться функция LinearAPPROX ?

Например, если её возвращаемое значение будет >99, то 7 раз ! :crazy: За место того, чтобы вызвать её всего 1 раз и записать результат во временную переменную.

Мало того, если она будет возвращать значение 99, то у вас сработает 2 последних условия. Или это так нужно ?

Вот тут тоже :

if(adc<674){
}
if(adc<835){
}
if(adc<906){
}

все 3 условия сработают, если adc будет < 674.

Тоже так нужно ?

Кстати, у функции LinearAPPROX возвращаемое значение void, т.б. ничего не возвращает, а Вы пытаетесь с неё взять какое то значение.

Компилятор не материт Вас ? :)

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

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

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

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

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

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

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

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

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

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

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

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