Jump to content

    

-=Женек=-

Свой
  • Content Count

    670
  • Joined

  • Last visited

Community Reputation

0 Обычный

About -=Женек=-

  • Rank
    Знающий

Recent Profile Visitors

1626 profile views
  1. CubeMX и User code

    Так я изначально так и сделал. Просто хочется более изящно. В других функциях я прямо внутри добавил, что хотел, а тут....
  2. CubeMX и User code

    Друзья, в генерируемых кубом проектах есть строки типа /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ для того, чтобы туда можно было вставить свой код и куб при изменении настроек и повторной генерации проекта не трогал то, что внутри них. Однако в функции static void MX_GPIO_Init(void) нет директив для user_code Если я вставляю свои и даже пытаюсь соблюсти синтаксис и пишу /* USER CODE BEGIN GPIO_Init 2 */ - то куб при повторной генерации кода безжалостно эти строки удаляет. МОжно ли как-то обойти это?
  3. Да.... вот что значит чужой код. Настроил разрешение измерения температуры - pid_out стал дробным, но все равно стал меняться с шагом 10. А цуцик вот где был зарыт double pid_Controller(int16_t setPoint, int16_t processValue) измеренная и целевая температуры выражались в целых числах. За всеми проверять нужно... Так все-таки, поясните Ваши слова? Какую методику я проигнорировал, в ней ли было дело? Или так - прочитали по диагонали и решили выпендриться?
  4. Да, действительно понял. Я любитель, без технического образования. Что такое интеграл - забыл. Что такое дифференциал - для меня это часть ходовой в автомобиле) шутка. Не надо было бояться этого ПИДа), вот и все. Если будет шаг в 2.5% мощности, то я думаю, это существенно улучшит ситуацию. Самое смешное, чтобы совсем не было мерцания от 0 до 2.5%, нужно увеличить величину тепловых потерь)))
  5. Хм... если вглядеться в формулу, то получается, что на каждый 1 градус ошибки при коэффициенте р=10 система увеличивает мощность на 10 %. То есть нужно просто точнее измерять температуру. Если этому коду скармливать значения ошибки с шагом в 0.1 градус, то тогда и шаг температуры будет 1%. В принципе у меня разрешение измерения -0.25 градуса. А у меня регулятору подается значение типа int.
  6. Зря я наверное график выложил. Проблема не в нем. Манипуляции с I , если мне не изменяет память, вносили задержку в реакции системы на отклонение температуры от заданной. Что-то мне подсказывает, что умножение прмежуточных значений на коэффициент p происходит поздновато. То есть система рассчитала некое значение с точностью до единицы, а потом тупо умножила его на 10. P.S. сколько раз убеждался, что стремление сэкономить время, взяв чужой код, не приносит желаемого результата. Хотя код-то не выдран откуда-то, он написан, скажем так, в экспортном формате, готов для использования
  7. Да.... если вдруг кто-то неправильно понял меня - график, что я привел, может навести кого либо (например форумца rkit) на мысль о том, что не настроен D коэффициент и имеет место статическая ошибка. Это не так. При коэффициенте p=3 -это лучшее, чего удается добиться за счет настройки остальных коэффициентов. И при p=3 проблема все равно остается - ПИД не выдает выходных значений кроме как кратных трем. Меня именно это беспокоит. Изначально у меня была ошибка в программе - вызов пид контроллера вызывался в основном цикле программы без каких либо условий, то есть работал так часто, насколько позволяло быстродействие контроллера. Я исправил ошибку - привязал вызов функции к таймеру, по которому у меня измеряется температура, то есть вызываю её тотчас после очередного измерения и строго один раз в 0.1 сек. Не изменилось ровным счетом ничего.
  8. Под методикой вы понимаете алгоритм расчета выходного сигнала или настройку коэффициентов?
  9. Друзья, помогите с натройкой PID-регулятора. Хотя тут наверное проблема не в настройке коэффициентов, а в самом коде. Работает он в печке, которая горячо обсуждалась в соседней теме. Забегая вперед, скажу, что термопрофиль она держит прекрасно. Но есть одно но. Мощность нагревателя у меня регулируется от 1 до 100. С шагом в 1. А регулятор выдает значения кратные 10-ти, то есть при его настройках он способен выдать всего 10 значений Стал настраивать, начал, как полагается с коэффициента P. Температура смогла "угнаться" за графиком только тогда, когда я поставил коэффициент P=10. При этом никогда не было необходимости во включении печки на полную мощность - максимум 50%. Если ставить скажем 3, то картина такая Если же ставить P=10, то, повторюсь, все нормально, однако регулятор выдает значения в диапазоне от 0 до 100 с шагом 10. То есть 0,10,20,30,40... И когда идеальным значением, к примеру было бы 5 - регулятор попеременно выдает 10 и 0. В виду температурной инерции это на конечный результат не влияет, но лампы мигают. Что не так? Код (не мой) /************************************************************************/ /* AVR PID Library source file */ /* @author Gazizov A.T. gazizov@tpu.eu */ /************************************************************************/ #include "stdint.h" #include "pid.h" /** Structure for storing PID data between calculations */ typedef struct PID_DATA { int16_t lastProcessValue; int32_t integralTerm; double kp; double ki; double kd; int16_t MAX_OUT; int16_t MIN_OUT; } pidData_t; struct PID_DATA pidData; /* PID controller initialization. Should be called only once. * @param kp - proportional coefficient. * @param ki - integral coefficient. * @param kd - differential coefficient. */ void pid_Init(double kp, double ki, double kd) { pidData.integralTerm = INITIAL_INTEGRAL_TERM; pidData.lastProcessValue = INITIAL_PROCESS_VALUE; pid_setParams(kp, ki, kd); pid_setOutputLimits(DEFAULT_MIN_OUT, DEFAULT_MAX_OUT); } /* Main PID controller function. It should be called regularly, each SAMPLE_TIME sec. * @param setPoint - level desired at output of the control object. * @param processValue - level obtained from the control object. * @returns input to control object. */ double pid_Controller(int16_t setPoint, int16_t processValue) { double error, p_term, d_term; double out; error = setPoint - processValue; pidData.integralTerm += pidData.ki * error; if (pidData.integralTerm > pidData.MAX_OUT) { pidData.integralTerm = pidData.MAX_OUT; out = pidData.MAX_OUT; } else { d_term = pidData.kd * (processValue - pidData.lastProcessValue); p_term = pidData.kp * error; out = (p_term + pidData.integralTerm - d_term); if (out > pidData.MAX_OUT) { out = pidData.MAX_OUT; } else if (out < pidData.MIN_OUT){ out = pidData.MIN_OUT; } } pidData.lastProcessValue = processValue; return out; } /** Restricts PID controller output. * @param Min - minimal allowed output value. * @param Min - maximal allowed output value. */ void pid_setOutputLimits(int16_t Min, int16_t Max) { if(Min > Max) return; pidData.MIN_OUT = Min; pidData.MAX_OUT = Max; } /** Set PID controller params with consideration of sampling time. * @param Kp - proportional coefficient. * @param Ki - integral coefficient. * @param Kd - differential coefficient. */ void pid_setParams(double Kp, double Ki, double Kd) { if (Kp<0 || Ki<0 || Kd<0) return; pidData.kp = Kp; pidData.ki = Ki * SAMPLE_TIME; pidData.kd = Kd / SAMPLE_TIME; } Заголовок /************************************************************************/ /* AVR PID Library header file */ /* @author Gazizov A.T. gazizov@tpu.eu */ /************************************************************************/ /** Range of allowed PID output range. Needed to avoid sign/overflow problems. */ #define DEFAULT_MIN_OUT 0 #define DEFAULT_MAX_OUT 100 /** Sample time in seconds. * How often PID control function (pid_Controller) will be called. * Important setting dependent on timer implementation in your program. */ #define SAMPLE_TIME 0.1 /** Parameters for initializing */ #define INITIAL_INTEGRAL_TERM 0 #define INITIAL_PROCESS_VALUE 0 /** Library functions declaration */ void pid_Init(double p_factor, double i_factor, double d_factor); void pid_setParams(double Kp, double Ki, double Kd); void pid_setOutputLimits(int16_t Min, int16_t Max); double pid_Controller(int16_t setPoint, int16_t processValue);
  10. Ёкерный бабай. Вы правы. Именно так. Я почему-то думал, что сообщение выдает не программа, а система. И пытался перехватить систему. А оказывается надо было бороться с программой)
  11. Как то раз при выдергивания шнура у меня выскочило "APRO Except!" Обрабатывает он исключения, но не все. Вот файл, где и работа порта и организация потоков... Не глянете? Может вам удастся понять, где там исключение ловить? AwUser.pas
  12. я пошел по этому пути, ориентируясь на описанный кем-то опыт борьбы с подобной проблемой. Там человек даже не лез в функцию writecom, а вызывал ее в блоке try except в функции put_block. Правда у него выскакивало не EInOutError, а EAccessViolation. У меня такая ошибка вылетает, если я после отключения и повторного подключения устройства не провожу закрытия и открытия порта. И в этом случае у меня исключение обрабатывается без проблем, без заходов в потоки. Вот я и надеялся что в случае с EInOutError это тоже прокатит. А Вам спасибо за подсказку, буду искать.
  13. Глубоко покопавшись в исходниках я нашел то место, где предположительно генерируется исключение function TApdWin32Dispatcher.WriteCom(Buf: PAnsiChar; Size: Integer): Integer; type PBArray = ^TBArray; TBArray = array[0..pred(High(Integer))] of Byte; var SizeAtEnd : Integer; LeftOver : Integer; begin {Add the data to the output QueueProp} EnterCriticalSection(OutputSection); try //we already know at this point that there is enough room for the block SizeAtEnd := OutQue - OBufHead; if SizeAtEnd >= Size then begin //can move data to output QueueProp in one block Move(Buf^, OBuffer^[OBufHead], Size); if SizeAtEnd = Size then OBufHead := 0 else Inc(OBufHead, Size); end else begin // need to use two moves Move(Buf^, OBuffer^[OBufHead], SizeAtEnd); LeftOver := Size - SizeAtEnd; Move(PBArray(Buf)^[SizeAtEnd], OBuffer^, LeftOver); OBufHead := LeftOver; end; finally LeaveCriticalSection(OutputSection); end; {...finally, wake up the output thread to send the data} SetEvent(OutputEvent); Result := Size; {report all was sent} end; 3 с конца строка SetEvent(OutputEvent); Если ее закомментировать, то ошибка не возникает. То есть, если выдернуть шнур, то все, что выше, выполняется, а на строке SetEvent происходит нечто, что приводит к появлению ошибкe EInOutError Я попробовал обрамить эту строку try-except try SetEvent(OutputEvent); except on E: EInOutError do begin ShowMessage('ERROR_1'); result := Error; end; end; Не ловится исключение, то есть алерт на экран вылетает, но ShowMessage не срабатывает. Мысли кончились... МОжет у кого будут какие идеи?
  14. Есть что-то вроде OnLine Error - но оно не работает Погодите.... я тут исходники копнул.... Идите-ка все спать, к утру наверное я эту недоработку разработчика устраню.