|
|
  |
Организация программ, дайте вектор куда копать |
|
|
|
Mar 31 2017, 13:47
|
Знающий
   
Группа: Участник
Сообщений: 634
Регистрация: 27-10-10
Пользователь №: 60 464

|
Цитата(syoma @ Mar 31 2017, 16:22)  Zelepuk, а не хотите попробовать Matlab/Simulink/Embedded Coder под это дело? Ваша задача выглядит типовой для этого. Т.е. всю обработку данных и свои алгоритмы нарисовать в Simulink в виде модели, которую вы сможете моделировать на PC вместе с входными данными, а затем всю модель выгрузить за несколько кликов в Си код, который будет исполняться в реальном времени на вашем контроллере. И все это без морок с глобальными флагами и переменными и часто даже без ОСРВ. Это достаточно "красивый" подход с заделом на будущее. Называется Model-Based Design. Почем-то мне думается что там не все так просто и красиво как описывается. посмотреть бы пример реализации такого подхода. Генерируемый код весьма труден для понимания. Увидеть бы готовый вариант простой процедуры: принять байт от SPI, накопить буфер, посчитать среднее раз в 100мс.
|
|
|
|
|
Mar 31 2017, 14:19
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата Генерируемый код весьма труден для понимания. Его не надо читать и понимать. Достаточно знать, что он делает то же самое, что и в симуляции. Цитата принять байт от SPI, накопить буфер, посчитать среднее раз в 100мс. Вопрос - сколько байт надо накопить за 100мс? или как часто приходят новые данные?
|
|
|
|
|
Mar 31 2017, 14:26
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Zelepuk @ Mar 31 2017, 15:47)  Почем-то мне думается что там не все так просто и красиво как описывается. посмотреть бы пример реализации такого подхода. Генерируемый код весьма труден для понимания. Увидеть бы готовый вариант простой процедуры: принять байт от SPI, накопить буфер, посчитать среднее раз в 100мс. Что там трудного?: CODE void MboxPost(OS_EVENT *mbox) { int e = OSMboxPost(mbox, (void *)1); if (e != OS_ERR_NONE && e != OS_ERR_MBOX_FULL) trap(TRAP_OS, e); } void MboxPend(OS_EVENT *mbox) { u8 e; OSMboxPend(mbox, 0, &e); if (e != OS_ERR_NONE) trap(TRAP_OS, e); } isr() { if (PERIPH.EMPTY) return; t1 = sysTimer; do { //Вычитываем все байты из FIFO периферии в программный FIFO. uint i = PERIPH.READ; if (!FIFO.isFull()) FIFO.write(i); } while (!PERIPH.EMPTY); if (FIFO.cnt() < N) if ((uint)(sysTimer - t1) < (uint)T) return; //Смотрим если в программном FIFO накопилось менее чем N байт (FIFO.cnt) и прошло менее чем T мсек с момента t1, то return; иначе: IsrEnter(); MboxPost(mbox); //посылаем сообщение сервисному процессу обработать накопленный программный FIFO. IsrExit(); } __noreturn void Task(void *) { //сервисный процесс, обслуживающий программный FIFO t1 = sysTimer; while (1) { while (!FIFO.isEmpty()) { FIFO.read(); ... } MboxPend(mbox); } } Всё. Это для uCOS. Для других ОС примерно так же.
|
|
|
|
|
Mar 31 2017, 19:31
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата(Zelepuk @ Mar 31 2017, 16:33)  примерно 50кБ. Если считать, что принять байт от SPI, накопить буфер, - это делает Ваш драйвер SPI, а сама процедура посчитать среднее вызывается раз в 100мс, и ей передается массив из 50000 значений, то в Симулинке она будет выглядеть так:
Рассчитано для исходного типа int8, результата суммы int32. Тогда сгенерированный код будет выглядеть вот так: ert_main.c - функция main CODE /* /* * File: ert_main.c * * Code generated for Simulink model 'Average'. * * Model version : 1.39 * Simulink Coder version : 8.11 (R2016b) 25-Aug-2016 * C/C++ source code generated on : Fri Mar 31 21:32:35 2017 * * Target selection: ert.tlc * Embedded hardware selection: 32-bit Generic * Code generation objectives: Unspecified * Validation result: Not run */
#include <stddef.h> #include <stdio.h> /* This ert_main.c example uses printf/fflush */ #include "Average.h" /* Model's header file */ #include "rtwtypes.h"
static RT_MODEL_Average_T Average_M_; static RT_MODEL_Average_T *const Average_M = &Average_M_;/* Real-time model */
/* '<Root>/In1' */ static int8_T Average_U_In1[50000];
/* '<Root>/Out1' */ static int8_T Average_Y_Out1;
/* * Associating rt_OneStep with a real-time clock or interrupt service routine * is what makes the generated code "real-time". The function rt_OneStep is * always associated with the base rate of the model. Subrates are managed * by the base rate from inside the generated code. Enabling/disabling * interrupts and floating point context switches are target specific. This * example code indicates where these should take place relative to executing * the generated code step function. Overrun behavior should be tailored to * your application needs. This example simply sets an error status in the * real-time model and returns from rt_OneStep. */ void rt_OneStep(RT_MODEL_Average_T *const Average_M); void rt_OneStep(RT_MODEL_Average_T *const Average_M) { static boolean_T OverrunFlag = false;
/* Disable interrupts here */
/* Check for overrun */ if (OverrunFlag) { return; }
OverrunFlag = true;
/* Save FPU context here (if necessary) */ /* Re-enable timer or interrupt here */ /* Set model inputs here */
/* Step the model */ Average_step(Average_M, Average_U_In1, &Average_Y_Out1);
/* Get model outputs here */
/* Indicate task complete */ OverrunFlag = false;
/* Disable interrupts here */ /* Restore FPU context here (if necessary) */ /* Enable interrupts here */ }
/* * The example "main" function illustrates what is required by your * application code to initialize, execute, and terminate the generated code. * Attaching rt_OneStep to a real-time clock is target specific. This example * illustrates how you do this relative to initializing the model. */ int_T main(int_T argc, const char *argv[]) { /* Unused arguments */ (void)(argc); (void)(argv);
/* Pack model data into RTM */
/* Initialize model */ Average_initialize(Average_M, Average_U_In1, &Average_Y_Out1);
/* Attach rt_OneStep to a timer or interrupt service routine with * period 0.1 seconds (the model's base sample time) here. The * call syntax for rt_OneStep is * * rt_OneStep(Average_M); */ printf("Warning: The simulation will run forever. " "Generated ERT main won't simulate model step behavior. " "To change this behavior select the 'MAT-file logging' option.\n"); fflush((NULL)); while (((void*) 0) == (NULL)) { /* Perform other application tasks here */ }
/* The option 'Remove error status field in real-time model data structure' * is selected, therefore the following code does not need to execute. */ #if 0
/* Disable rt_OneStep() here */
/* Terminate model */ Average_terminate(Average_M);
#endif
return 0; }
/* * File trailer for generated code. * * [EOF] */
Функция average - собственно сам расчет среднего CODE /* * File: Average.c * * Code generated for Simulink model 'Average'. * * Model version : 1.39 * Simulink Coder version : 8.11 (R2016b) 25-Aug-2016 * C/C++ source code generated on : Fri Mar 31 21:22:13 2017 * * Target selection: ert.tlc * Embedded hardware selection: 32-bit Generic * Code generation objectives: Unspecified * Validation result: Not run */
#include "Average.h" #include "Average_private.h"
void mul_wide_s32(int32_T in0, int32_T in1, uint32_T *ptrOutBitsHi, uint32_T *ptrOutBitsLo) { uint32_T absIn0; uint32_T absIn1; uint32_T in0Lo; uint32_T in0Hi; uint32_T in1Hi; uint32_T productHiLo; uint32_T productLoHi; absIn0 = in0 < 0 ? ~(uint32_T)in0 + 1U : (uint32_T)in0; absIn1 = in1 < 0 ? ~(uint32_T)in1 + 1U : (uint32_T)in1; in0Hi = absIn0 >> 16U; in0Lo = absIn0 & 65535U; in1Hi = absIn1 >> 16U; absIn0 = absIn1 & 65535U; productHiLo = in0Hi * absIn0; productLoHi = in0Lo * in1Hi; absIn0 *= in0Lo; absIn1 = 0U; in0Lo = (productLoHi << /*MW:OvBitwiseOk*/ 16U) + /*MW:OvCarryOk*/ absIn0; if (in0Lo < absIn0) { absIn1 = 1U; }
absIn0 = in0Lo; in0Lo += /*MW:OvCarryOk*/ productHiLo << /*MW:OvBitwiseOk*/ 16U; if (in0Lo < absIn0) { absIn1++; }
absIn0 = (((productLoHi >> 16U) + (productHiLo >> 16U)) + in0Hi * in1Hi) + absIn1; if (!((in0 == 0) || ((in1 == 0) || ((in0 > 0) == (in1 > 0))))) { absIn0 = ~absIn0; in0Lo = ~in0Lo; in0Lo++; if (in0Lo == 0U) { absIn0++; } }
*ptrOutBitsHi = absIn0; *ptrOutBitsLo = in0Lo; }
int32_T mul_s32_hiSR(int32_T a, int32_T b, uint32_T aShift) { uint32_T u32_chi; uint32_T u32_clo; mul_wide_s32(a, b, &u32_chi, &u32_clo); return (int32_T)u32_chi >> aShift; }
/* Model step function */ void Average_step(RT_MODEL_Average_T *const Average_M, int8_T Average_U_In1 [50000], int8_T *Average_Y_Out1) { int32_T i; int32_T rtb_SumofElements;
/* Sum: '<S1>/Sum of Elements' incorporates: * Inport: '<Root>/In1' */ rtb_SumofElements = Average_U_In1[0]; for (i = 0; i < 49999; i++) { rtb_SumofElements += Average_U_In1[i + 1]; }
/* End of Sum: '<S1>/Sum of Elements' */
/* Outport: '<Root>/Out1' incorporates: * Gain: '<S1>/Gain' */ *Average_Y_Out1 = (int8_T)mul_s32_hiSR(351843721, rtb_SumofElements, 12U); UNUSED_PARAMETER(Average_M); }
/* Model initialize function */ void Average_initialize(RT_MODEL_Average_T *const Average_M, int8_T Average_U_In1[50000], int8_T *Average_Y_Out1) { /* Registration code */
/* external inputs */ (void)memset(&Average_U_In1[0], 0, 50000U * sizeof(int8_T));
/* external outputs */ (*Average_Y_Out1) = 0; UNUSED_PARAMETER(Average_M); }
/* Model terminate function */ void Average_terminate(RT_MODEL_Average_T *const Average_M) { /* (no terminate code required) */ UNUSED_PARAMETER(Average_M); }
/* * File trailer for generated code. * * [EOF] */
По коду можно сказать, что матлаб сгенерировал хитрый умножитель на 1/50000. Почему - это зависит от того, что поддерживает, а что нет конкретная платформа Цитата Оч интересно, а каким таким образом Simulink вдруг гарантирует нам выполнение в реальном времени? Посмотрите первый комментарий в первом из сгенерированных файлов.
|
|
|
|
|
Mar 31 2017, 20:19
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(syoma @ Mar 31 2017, 22:31)  Посмотрите первый комментарий в первом из сгенерированных файлов. Цитата Associating rt_OneStep with a real-time clock or interrupt service routine is what makes the generated code "real-time". Они над вами смеются. Заметили скобочки? Прочитайте весь комментарий. Они оставляют за собой право сделать "Overrun" и посылают вас самих это расхлебывать. Причем флаг "Overrun" оставили статическим внутри функции. Феерично! Так что не надо нам этих фэйков. Цитата(Lagman @ Mar 31 2017, 19:16)  Я ее как раз и не стал использовать, только потому, что она очень дорого выходит для штучных коммерческих изделий. Не знаю, я делаю штучные и коммерческие, я мэйкер. Мне бесплатно.
|
|
|
|
|
Mar 31 2017, 20:26
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата(AlexandrY @ Mar 31 2017, 22:17)  Они оставляют за собой право сделать "Overrun" и посылают вас самих это расхлебывать. А как вы предлагаете расхлебывать ситуацию в реальном времени, если разработанная вами функция не выполнится за заданное время? Цитата Причем флаг "Overrun" оставили статическим внутри функции. Феерично! А в чем проблема? rt_OneStep в примере предлагается вызывать в прерывании от таймера. Во время исполнения модельного кода флаг Overrun ставится в true, а после завершения сбрасывается. Если следующее прерывание от таймера произойдет до окончания исполнения модельного кода, факт overrun ловится и делай, сам, что считаешь нужным. Вообще-то ert_main.c - это всего лишь пример, как можно запустить функцию на исполнение в реальном времени без ОСРВ. Его можно без проблем изменять по своему усмотрению.
|
|
|
|
|
Mar 31 2017, 20:37
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(syoma @ Mar 31 2017, 23:26)  А как вы предлагаете расхлебывать ситуацию в реальном времени, если разработанная вами функция не выполнится за заданное время? Никак, в Simulink вы её не расхлебаете и даже не узнаете о ней. Симулинк будет тупо раз за разом перезаписывать свои заглушки поверх ваших правок. Его код предназначен для устойчивой среды исполнения на базе RTOS уже сделанной в микроконтроллере. Вы же так и делаете. Используете vxWorks, а тут подсовываете надуманную лабуду.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|