Re: ESP32 domácí automatizace

Jan Půhoný konference na puhy.cz
Úterý Srpen 3 07:35:46 CEST 2021


Tak jsem to přepsal na vTaskDelayUntil , ale chová se to stejně. Problém je
totiž v tom, že když se stiskne tlačítko we webovém rozhraní pro ovládání
toho ventilu rychleji než se provede ten task, pustí se task pro otevírání
a zavírání přes sebe a pak dochází k tomu, že to zůstane viset někde
uprostřed. Pro tuto aplikaci asi nebude zásadní rozdíl mezi vTaskDelayUntil
a vTaskDelay.

Ošetřil jsem to přidáním proměnné unBlock, která blokuje čtení tlačítka po
dobu spuštění tasku. Takto to funguje spolehlivě. Nicméně předpokládám, že
to jde vyřešit nějak elegantněji. *Jak se to správně dělá?*

Díky,

HP

Callback tlačítka:
button1.attachCallback([&](bool value)
                         {
                           /* Print our new button value received from
dashboard */
                           Serial.println("Button Triggered: " + String((
value) ? "true" : "false"));
                           /* Make sure we update our button's value
and send update to dashboard */

                           digitalWrite(ledPinRed, value);

                           if (unBlock)
                           {

                             if (value)
                             {

                               xTaskCreatePinnedToCore(
                                   vent1On,
   // Function that should be called
                                   "vent1On",
 // Name of the task (for debugging)
                                   2000,      // Stack size (bytes)
                                   NULL,      // Parameter to pass
                                   1,         // Task priority
                                   NULL,      // Task handle
                                   0          // Core 1/0
                               );
                             }
                             else
                             {

                               xTaskCreatePinnedToCore(
                                   vent1Off,
   // Function that should be called
                                   "vent1Off",
 // Name of the task (for debugging)
                                   2000,       // Stack size (bytes)
                                   NULL,       // Parameter to pass
                                   1,          // Task priority
                                   NULL,       // Task handle
                                   0           // Core 1/0
                               );
                             }
                           }

                           dashboard.sendUpdates();
                         });

Ovládání ventilů:
void vent1On(void *parameter)
{
  TickType_t xLastWakeTime;
  const TickType_t xFrequency = (20000 / portTICK_PERIOD_MS);
  // Initialise the xLastWakeTime variable with the current time.
  xLastWakeTime = xTaskGetTickCount();
  for (;;)
  {

    unBlock = 0;

    digitalWrite(ventMain1, HIGH);
    digitalWrite(ventOn1, HIGH);
    digitalWrite(ledPinRed, HIGH);

    button1.update(1);
    systemCard.update((float)xFrequency);

    // Pause the task fo 20s
    vTaskDelayUntil(&xLastWakeTime, xFrequency);
    //vTaskDelay(20000 / portTICK_PERIOD_MS);

    digitalWrite(ventMain1, LOW);
    digitalWrite(ventOn1, LOW);
    digitalWrite(ledPinRed, LOW);

    unBlock = 1;

    vTaskDelete(NULL); //spustí se jen jednou
  }
}

void vent1Off(void *parameter)
{
  TickType_t xLastWakeTime;
  const TickType_t xFrequency = (20000 / portTICK_PERIOD_MS);
  // Initialise the xLastWakeTime variable with the current time.
  xLastWakeTime = xTaskGetTickCount();
  for (;;)
  { // infinite loop

    unBlock = 0;

    digitalWrite(ventMain1, HIGH);
    digitalWrite(ventOn1, LOW);
    digitalWrite(ledPinRed, HIGH);

    button1.update(0);
    systemCard.update((float)xFrequency);

    // Pause the task fo 20s
    vTaskDelayUntil(&xLastWakeTime, xFrequency);
    //vTaskDelay(20000 / portTICK_PERIOD_MS);

    digitalWrite(ventMain1, LOW);
    digitalWrite(ventOn1, LOW);
    digitalWrite(ledPinRed, LOW);

    unBlock = 1;

    vTaskDelete(NULL); //spustí se jen jednou
  }
}



po 2. 8. 2021 v 16:11 odesílatel Jaroslav Buchta <jaroslav.buchta na hascomp.cz>
napsal:

> A zrovna nad tim badam a jedna vec mi nejde do hlavy:
> v modulu port.c je obsluha
>
> BaseType_t xPortSysTickHandler( void )
> {
>     BaseType_t ret;
>
>     portbenchmarkIntLatency();
>     traceISR_ENTER(SYSTICK_INTR_ID);
>     ret = xTaskIncrementTick();
>     if( ret != pdFALSE )
>     {
>         portYIELD_FROM_ISR();
>     } else {
>         traceISR_EXIT();
>     }
>     return ret;
> }
>
> Je logicky umistena v IRAM sekci ale proc??? Funkce nema specifikovany
> IRAM_ATTR, ani v hlavicce.
> zrovna tak BaseType_t xTaskIncrementTick( void ) v tasks.c
>
> Tady uz treba attribut je
> void IRAM_ATTR esp_vApplicationTickHook(void)
> {
>     int n;
>     int core = xPortGetCoreID();
>     for (n=0; n<MAX_HOOKS; n++) {
>         if (tick_cb[core][n]!=NULL) {
>             tick_cb[core][n]();
>         }
>     }
> }
>
> Funkce se vnoruji v tomto poradi.
>
> Zkousel jsem se povesit na hook od toho casovace a funguje to, jak z
> Flash, tak z IRAM (to je asi rozumnejsi, kdyz je to v ISR)
>
>
> Dne 02.08.2021 v 12:32 Jaroslav Buchta napsal(a):
>
> At to ctu stale dokola, nevidim prostor pro zkraceni FreeRTOS - ESP32 - —
> ESP-IDF Programming Guide latest documentation (espressif.com)
> <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html#task-api>
> Jen je tam upozorneni, ze je nejista prodleva, kdy bude zavolana funkce a
> az od te doby se to pocita.  vTaskDelayUntil bude mit asi jediny rozdil v
> tom, ze je tam dany cas ukonceni cekani jako parametr, u vTaskDelay se tato
> hodnot asi ulozi v okamziku volani.
> A i tak by se jednalo spis o milisekundy nez sekundy...
>
> Koukam na to, ze ty funkce pracuji v principu uplne stejne, pouziji pro
> uspani
>     prvAddCurrentTaskToDelayedList(...);
>  jenom jinak pocitaji dobu pro uspani...
>
> Pokud opravdu muze dojit ke zkraceni intervalu, bylo by v systemu neco
> velmi spatne. Neprobehne nahodou spis restart?
>
> //////////////////////////////
>
>     void vTaskDelay( const TickType_t xTicksToDelay )
>     {
>     BaseType_t xAlreadyYielded = pdFALSE;
>
>         /* A delay time of zero just forces a reschedule. */
>         if( xTicksToDelay > ( TickType_t ) 0U )
>         {
>             configASSERT( uxSchedulerSuspended[xPortGetCoreID()] == 0 );
>             taskENTER_CRITICAL( &xTaskQueueMutex );
>             {
>                 traceTASK_DELAY();
>
>                 /* A task that is removed from the event list while the
>                 scheduler is suspended will not get placed in the ready
>                 list or removed from the blocked list until the scheduler
>                 is resumed.
>
>                 This task cannot be in an event list as it is the currently
>                 executing task. */
>                 prvAddCurrentTaskToDelayedList( xPortGetCoreID(),
> xTicksToDelay );
>             }
>             taskEXIT_CRITICAL( &xTaskQueueMutex );
>         }
>         else
>         {
>             mtCOVERAGE_TEST_MARKER();
>         }
>
>         /* Force a reschedule if xTaskResumeAll has not already done so,
> we may
>         have put ourselves to sleep. */
>         if( xAlreadyYielded == pdFALSE )
>         {
>             portYIELD_WITHIN_API();
>         }
>         else
>         {
>             mtCOVERAGE_TEST_MARKER();
>         }
>     }
>
>
>
>     void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const
> TickType_t xTimeIncrement )
>     {
>     TickType_t xTimeToWake;
>     BaseType_t xAlreadyYielded = pdFALSE, xShouldDelay = pdFALSE;
>
>         configASSERT( pxPreviousWakeTime );
>         configASSERT( ( xTimeIncrement > 0U ) );
>         configASSERT( uxSchedulerSuspended[xPortGetCoreID()] == 0 );
>
>         taskENTER_CRITICAL( &xTaskQueueMutex );
>         {
>             /* Minor optimisation.  The tick count cannot change in this
>             block. */
>             const TickType_t xConstTickCount = xTickCount;
>
>             /* Generate the tick time at which the task wants to wake. */
>             xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
>
>             if( xConstTickCount < *pxPreviousWakeTime )
>             {
>                 /* The tick count has overflowed since this function was
>                 lasted called.  In this case the only time we should ever
>                 actually delay is if the wake time has also    overflowed,
>                 and the wake time is greater than the tick time.  When this
>                 is the case it is as if neither time had overflowed. */
>                 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake
> > xConstTickCount ) )
>                 {
>                     xShouldDelay = pdTRUE;
>                 }
>                 else
>                 {
>                     mtCOVERAGE_TEST_MARKER();
>                 }
>             }
>             else
>             {
>                 /* The tick time has not overflowed.  In this case we will
>                 delay if either the wake time has overflowed, and/or the
>                 tick time is less than the wake time. */
>                 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake
> > xConstTickCount ) )
>                 {
>                     xShouldDelay = pdTRUE;
>                 }
>                 else
>                 {
>                     mtCOVERAGE_TEST_MARKER();
>                 }
>             }
>
>             /* Update the wake time ready for the next call. */
>             *pxPreviousWakeTime = xTimeToWake;
>
>             if( xShouldDelay != pdFALSE )
>             {
>                 traceTASK_DELAY_UNTIL();
>
>                 /* prvAddCurrentTaskToDelayedList() needs the block time,
> not
>                 the time to wake, so subtract the current tick count. */
>                 prvAddCurrentTaskToDelayedList( xPortGetCoreID(),
> xTimeToWake - xConstTickCount );
>             }
>             else
>             {
>                 mtCOVERAGE_TEST_MARKER();
>             }
>         }
>         taskEXIT_CRITICAL( &xTaskQueueMutex );
>
>         /* Force a reschedule if xTaskResumeAll has not already done so,
> we may
>         have put ourselves to sleep. */
>         if( xAlreadyYielded == pdFALSE )
>         {
>             portYIELD_WITHIN_API();
>         }
>         else
>         {
>             mtCOVERAGE_TEST_MARKER();
>         }
>     }
>
>
> Dne 02.08.2021 v 12:09 as5s napsal(a):
>
> Netusim ako to presne funguje, ale v dokumentacii na to upozornuju.
>
> ale je mi cudne ze sa to skrati. O kolko sa to skrati?
>
> Myre
>
>
> On 2. 8. 2021 10:35, Jaroslav Buchta wrote:
>
> To jako opravdu vTaskDelay muze fungovat nespolehlive, teda jeste k tomu
> se zkratit?
> To snad primo pocita systemova preruseni od casovace (default tusim
> 100Hz), ze by se nejaky nestihly bych jeste pochopil...
>
> Dne 02.08.2021 v 9:49 as5s napsal(a):
>
> Dobry den,
>
> skuste pozriet na vTaskDelayUntil()
>
>
> https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html#_CPPv415vTaskDelayUntilPC10TickType_tK10TickType_t
>
> mozno vam to bude stacit.
>
> Myre
> On 2. 8. 2021 9:45, Jan Půhoný wrote:
>
> Dobrý den,
>
> mám tady další zádrhel - mějme funkci, která ovládá výstupní piny,
> potřebuji po nastavení udžet cca 20 sekund v HIGH a pak vrátit vše do low.
> Jedná se o otevítání a zavírání ventilu. Přidal jsem tedy mezi to
> vTaskDelay(20000 / portTICK_PERIOD_MS);  , problém je v tom, že někdy se
> to zpoždění značně zkrátí a ventil zůstane napolo otevřený. Jak se toto dá
> ošetřit aby se vTaskDelay(20000 / portTICK_PERIOD_MS); nikdy nemohlo
> zkrátit a bylo dodrženo.
>
> Volám to pak standardně přes xTaskCreatePinnedToCore() ....
>
> void vent1On(void * parameter){
>   for(;;){ // infinite loop
>     button1.update(1);
>     digitalWrite(ventMain1, HIGH);
>     digitalWrite(ventOn1, HIGH);
>     digitalWrite(ledPinRed, HIGH);
>     // Pause the task fo 20s
>     vTaskDelay(20000 / portTICK_PERIOD_MS);
>
>     digitalWrite(ventMain1, LOW);
>     digitalWrite(ventOn1, LOW);
>     digitalWrite(ledPinRed, LOW);
>     vTaskDelete(NULL); //spustí se jen jednou
>   }
> }
>
>
> xTaskCreatePinnedToCore(
>     vent1On,    // Function that should be called
>     "vent1On",   // Name of the task (for debugging)
>     1000,            // Stack size (bytes)
>     NULL,            // Parameter to pass
>     1,               // Task priority
>     NULL,            // Task handle
>     0            // Core 1/0
>   );
>
> HP
>
>
> so 31. 7. 2021 v 8:27 odesílatel Jan Půhoný <konference na puhy.cz> napsal:
>
>> Díky, zkusil jsem jak 2000 tak 4000 ale stále stejné. Resetuje se to
>> pořád dokola s tímto:
>>
>> rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
>> configsip: 0, SPIWP:0xee
>> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
>> mode:DIO, clock div:2
>> load:0x3fff0018,len:4
>> load:0x3fff001c,len:1044
>> load:0x40078000,len:10124
>> load:0x40080400,len:5828
>> entry 0x400806a8
>>
>> *Ale zjistil jsem, že to dělá jen pokud to napájím z USB. Když to dám
>> přímo do svého zapojení, kde je pořádná kapacita na Vin, tak to drží. Takže
>> skutečně jen problém s napájením.*
>>
>> Teď už to budu programovat jen přes OTA, takže vyřešeno.
>>
>> HP
>>
>>
>> so 31. 7. 2021 v 6:44 odesílatel Jaroslav Buchta <
>> jaroslav.buchta na hascomp.cz> napsal:
>>
>>> kod jsem nezkoumal ale na prvni pohled mi prijde maly zasobnik pro
>>> vlakno, tady je to tusim v btech. dal bych 2 nebo 4K na zkousku
>>> _______________________________________________
>>> HW-list mailing list  -  sponsored by www.HW.cz
>>> Hw-list na list.hw.cz
>>> http://list.hw.cz/mailman/listinfo/hw-list
>>>
>>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.czHw-list na list.hw.czhttp://list.hw.cz/mailman/listinfo/hw-list
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.czHw-list na list.hw.czhttp://list.hw.cz/mailman/listinfo/hw-list
>
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.czHw-list na list.hw.czhttp://list.hw.cz/mailman/listinfo/hw-list
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.czHw-list na list.hw.czhttp://list.hw.cz/mailman/listinfo/hw-list
>
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.czHw-list na list.hw.czhttp://list.hw.cz/mailman/listinfo/hw-list
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
>
------------- další část ---------------
HTML příloha byla odstraněna...
URL: <http://list.hw.cz/pipermail/hw-list/attachments/20210803/3564ad02/attachment-0001.html>


Další informace o konferenci Hw-list