{"id":135774,"date":"2018-10-19T15:28:00","date_gmt":"2018-10-19T12:28:00","guid":{"rendered":"https:\/\/ruuvi.com\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/"},"modified":"2026-06-11T07:40:35","modified_gmt":"2026-06-11T04:40:35","slug":"ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert","status":"publish","type":"post","link":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/","title":{"rendered":"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"536\" src=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13-1024x536.jpeg\" alt=\"Introbild zur Ruuvi-Firmware-Serie, Teil 13\" class=\"wp-image-3803\" srcset=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13-1024x536.jpeg 1024w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13-450x236.jpeg 450w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13-768x402.jpeg 768w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13-600x314.jpeg 600w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg 1400w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">In diesem Teil des Tutorials synchronisieren wir die Messung der Batteriespannung mit Funk\u00fcbertragungen. Den finalen Code dieses Blogposts kannst du bei <a href=\"https:\/\/github.com\/ruuvi\/ruuvi.firmware.c\">Ruuvi GitHub<\/a> im Branch <em>ruuviblog<\/em>, Tag <em>3.13.0-alpha<\/em> herunterladen. <\/p>\n\n<p class=\"wp-block-paragraph\">Bitte folge <a href=\"https:\/\/ruuvi.com\/ruuvi-firmware-part-1-sleep\/\">Teil 1 der Serie<\/a> f\u00fcr Details zum Klonen des Repositories und Kompilieren des Codes. Die finale Hex-Datei dieses Tutorials kann vom <a href=\"http:\/\/jenkins.ruuvi.com:8080\/job\/ruuvi.firmware.c\/35\/\">Ruuvi Jenkins<\/a> heruntergeladen werden. <\/p>\n\n<h2 class=\"wp-block-heading\">Update auf SDK 15.2<\/h2>\n\n<p class=\"wp-block-paragraph\">Im vorherigen Teil des Blogs haben wir das <a href=\"https:\/\/developer.nordicsemi.com\/nRF5_SDK\/nRF5_SDK_v15.x.x\/nRF5_SDK_15.2.0_9412b96.zip\"><em>Nordic Software Development Kit<\/em><\/a> (<strong>SDK<\/strong>) in Version 15.2 f\u00fcr den Bootloader-Code und <a href=\"https:\/\/www.nordicsemi.com\/eng\/nordic\/download_resource\/67248\/5\/60778059\/141008\"><em>Softdevice s132 6.1.0<\/em><\/a> als Funk-Software verwendet. Aktualisieren wir jetzt auch das Hauptprojekt. <\/p>\n\n<p class=\"wp-block-paragraph\">Das Update ist schnell erledigt: Wir suchen das alte <strong>SDK<\/strong> und ersetzen es in der Projektdatei durch das neue <strong>SDK<\/strong> und entfernen das Pr\u00e4fix \u201eexperimental_\u201c in den Pfaden <em>log<\/em>, <em>ringbuf<\/em> und <em>memobj<\/em>. Die Datei <em>pm_mutex.c<\/em> wird entfernt. Zus\u00e4tzlich <em>#define <\/em><strong>NRF_LOG_STR_PUSH_BUFFER_SIZE APPLICATION_LOG_BUFFER_SIZE<\/strong> in <em>nrf5_sdk15_application_config.h<\/em>, damit die Makrobenennung zum <strong>SDK15.2 <\/strong>-Logging passt. Das Logging nutzt jetzt <em>ringbuf.c<\/em>, wir f\u00fcgen es dem Build hinzu. Dann reservieren wir in unserer <em>flash_placement.xml<\/em> Platz f\u00fcr <em>log_backends<\/em>, indem wir eine Definition zu den Flash-Sektionen hinzuf\u00fcgen:    <\/p>\n\n<pre class=\"wp-block-code\"><code>&lt;ProgramSection alignment=\"4\" keep=\"Yes\" load=\"Yes\" name=\".log_backends\" inputsections=\"*(SORT(.log_backends*))\" address_symbol=\"__start_log_backends\" end_symbol=\"__stop_log_backends\" \/&gt;<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Die Clock-Enable-Direktive hat sich ebenfalls von <strong>CLOCK_ENABLED<\/strong> zu <strong>NRF_CLOCK_ENABLED<\/strong> ge\u00e4ndert, daher f\u00fcgen wir einen Wrapper in <em>sdk_config.h<\/em> hinzu<\/p>\n\n<pre class=\"wp-block-code\"><code>#ifndef NRF_CLOCK_ENABLED\n#define NRF_CLOCK_ENABLED CLOCK_ENABLED\n#endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Nordic hat dem <strong>SDK<\/strong> Definitionen f\u00fcr <em>nfc_fixes.h<\/em> hinzugef\u00fcgt, wir ben\u00f6tigen daher die Definition <strong>HAL_NFC_ENGINEERING_BC_FTPAN_WORKAROUND<\/strong> in den in <em>ruuvi.firmware.c.emProject<\/em> definierten Preprocessor-Makros nicht mehr. Nach dem Entfernen kompiliert das Projekt ohne Warnungen, und wir k\u00f6nnen auf Basis des aktualisierten <strong>SDK<\/strong> weiterbauen. Vor dem Flashen muss die <em>Softdevice<\/em>-Version in der Projektdatei auf 6.1.0 aktualisiert werden.  <\/p>\n\n<h2 class=\"wp-block-heading\">Batteriemessung erneut betrachtet<\/h2>\n\n<p class=\"wp-block-paragraph\">Seit <a href=\"https:\/\/ruuvi.com\/ruuvi-firmware-part-11-scheduler\/\">Teil 11 \u2014 Scheduler<\/a> messen wir die Batteriespannung in einem Intervall von ungef\u00e4hr 30 Sekunden, ohne darauf zu achten, wie das Programm sonst l\u00e4uft.<\/p>\n\n<p class=\"wp-block-paragraph\">Das ist bei einer frischen Batterie bei Raumtemperatur ein guter Ansatz. Wenn jedoch der Innenwiderstand der Batterie durch K\u00e4lte und Entladung steigt, erleben wir w\u00e4hrend der Spitzenlast \u2013 der Funkaktivit\u00e4t \u2013 einen Spannungseinbruch an der Batterie.<\/p>\n\n<p class=\"wp-block-paragraph\">Daher registrieren wir einen Event-Handler, der nach einer Funk\u00fcbertragung aufgerufen wird, und pr\u00fcfen darin, ob es Zeit ist, eine weitere Messung mit dem Analog-Digital-Wandler (<strong>ADC<\/strong>) an der Batterie durchzuf\u00fchren.<\/p>\n\n<h2 class=\"wp-block-heading\">Schnittstelle<\/h2>\n\n<p class=\"wp-block-paragraph\">Wir haben bereits ein Funkaktivit\u00e4ts-Event in <em>ruuvi_interface_communication_radio.h<\/em> definiert. Wir f\u00fcgen eine Funktion hinzu, um in Zeile 41 einen Application-Event-Handler f\u00fcr Funk-Interrupts einzurichten: <\/p>\n\n<pre class=\"wp-block-code\"><code>typedef enum\n{\n  RUUVI_INTERFACE_COMMUNICATION_RADIO_BEFORE,\n  RUUVI_INTERFACE_COMMUNICATION_RADIO_AFTER\n}ruuvi_interface_communication_radio_activity_evt_t;\n\ntypedef enum\n{\n  RUUVI_INTERFACE_COMMUNICATION_RADIO_UNINIT = 0,\n  RUUVI_INTERFACE_COMMUNICATION_RADIO_ADVERTISEMENT,\n  RUUVI_INTERFACE_COMMUNICATION_RADIO_GATT,\n  RUUVI_INTERFACE_COMMUNICATION_RADIO_MESH\n}ruuvi_interface_communication_radio_user_t;\n\n\/**\n *  Type of radio activity interrupt. This is common to all radio modules, i,e, the callback gets called for every radio action.\n *\/\ntypedef void(*ruuvi_interface_communication_radio_activity_interrupt_fp_t)(const ruuvi_interface_communication_radio_activity_evt_t evt);\n\n\/\/ Enable \/ disable radio stacks\nruuvi_driver_status_t ruuvi_interface_communication_radio_init  (const ruuvi_interface_communication_radio_user_t handle);\nruuvi_driver_status_t ruuvi_interface_communication_radio_uninit(const ruuvi_interface_communication_radio_user_t handle);\n\n\/**\n * Writes maximum 64-bit unique address of the device to the pointer. This address\n * may be changed during runtime. The address is identifier of the device on radio network,\n * such as BLE MAC address.\n *\n * parameter address: Output, value of address.\n *\n * return RUUVI_DRIVER_SUCCESS on success\n * return RUUVI_DRIVER_ERROR_NOT_SUPPORTED if address cannot be returned on given platform\n *\/\nruuvi_driver_status_t ruuvi_interface_communication_radio_address_get(uint64_t* const address);\n\n\/**\n * Setup radio activity interrupt\n *\n * parameter handler: Function to call on radio event NULL to disable radio-level callback, however module-level callbacks (advertising, GATT etc) will be called.\n *\/\nvoid ruuvi_interface_communication_radio_activity_callback_set(const ruuvi_interface_communication_radio_activity_interrupt_fp_t handler);<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/56765f8db453077d5863b2d265a5c882\/raw\/6988bd97b117128d589f8e402d491a10c8669aba\/ruuvi_interface_communication_radio_3.13.h\">Rohdaten anzeigen<\/a><\/p>\n\n<h2 class=\"wp-block-heading\">Treiber<\/h2>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes implementieren wir die Schnittstelle in <em>nrf5_sdk15_platform\/ruuvi_platform_communication_radio.c<\/em>. Wir f\u00fcgen einen statischen Funktionszeiger hinzu, der gesetzt werden soll, sowie eine Setup-Funktion. Dann f\u00fcgen wir einen Handler f\u00fcr den <em>Softdevice<\/em>-Funkinterrupt hinzu, der den Funktionszeiger aufruft, sowie einen Event-Handler des Advertising-Moduls, falls wir sp\u00e4ter advertising-spezifische Aktionen ausf\u00fchren m\u00f6chten.  <\/p>\n\n<p class=\"wp-block-paragraph\">In Zeile 43 haben wir die Interrupt-Initialisierung <em>ble_radio_notification<\/em> hinzugef\u00fcgt. Die Interrupt-Priorit\u00e4t ist in <em>application_config\/ruuvi_platform_nrf5_sdk15_config.h<\/em> als <em>2<\/em> definiert, das ist die h\u00f6chste Application-Priorit\u00e4t. \u201eDistance\u201c definiert, wie lange vor und nach dem Event der Interrupt ausgel\u00f6st wird; 800 <em>\u03bcs<\/em> ist der kleinste Abstand, den wir erreichen k\u00f6nnen.  <\/p>\n\n<pre class=\"wp-block-code\"><code>\/\/ Application callback for radio events\nstatic ruuvi_interface_communication_radio_activity_interrupt_fp_t on_radio_activity_callback = NULL;\n\n\/**\n * Task to run on radio activity - call event handlers of radio modules and a common radio event handler.\n * This function is in interrupt context, avoid long processing or using peripherals.\n * Schedule any long tasks in application callbacks.\n *\n * parameter active: True if radio is going to be active after event, false if radio was turned off (after tx\/rx)\n *\/\nstatic void on_radio_evt(bool active)\n{\n\n  ruuvi_interface_communication_radio_activity_evt_t evt = active ? RUUVI_INTERFACE_COMMUNICATION_RADIO_BEFORE : RUUVI_INTERFACE_COMMUNICATION_RADIO_AFTER;\n  \/\/ Call advertising event handler\n  ruuvi_platform_communication_ble4_advertising_activity_handler(evt);\n\n  \/\/ Call common event handler if set\n  if(NULL != on_radio_activity_callback ){ on_radio_activity_callback(evt); }\n\n}\n\nruuvi_driver_status_t ruuvi_interface_communication_radio_init  (const ruuvi_interface_communication_radio_user_t _handle)\n{\n  if(RUUVI_INTERFACE_COMMUNICATION_RADIO_UNINIT != handle) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n\n  ret_code_t err_code = NRF_SUCCESS;\n  handle = _handle;\n  err_code = nrf_sdh_enable_request();\n  RUUVI_DRIVER_ERROR_CHECK(err_code, NRF_SUCCESS);\n\n  \/\/ Configure the BLE stack using the default settings.\n  \/\/ Fetch the start address of the application RAM.\n  uint32_t ram_start = 0;\n  err_code |= nrf_sdh_ble_default_cfg_set(NRF5_SDK15_BLE4_STACK_CONN_TAG, &amp;ram_start);\n  RUUVI_DRIVER_ERROR_CHECK(err_code, NRF_SUCCESS);\n\n  \/\/ Enable BLE stack.\n  err_code |= nrf_sdh_ble_enable(&amp;ram_start);\n  RUUVI_DRIVER_ERROR_CHECK(err_code, NRF_SUCCESS);\n\n  \/\/ Initialize radio interrupts\n  err_code |= ble_radio_notification_init(NRF5_SDK15_RADIO_IRQ_PRIORITY,\n                                          NRF_RADIO_NOTIFICATION_DISTANCE_800US,\n                                          on_radio_evt);\n\n  return ruuvi_platform_to_ruuvi_error(&amp;err_code);\n}\n\n.\n.\n.\n\nvoid ruuvi_interface_communication_radio_activity_callback_set(const ruuvi_interface_communication_radio_activity_interrupt_fp_t handler)\n{\n  \/\/ Warn user if CB is not NULL and non-null pointer is set, do not overwrite previous pointer.\n  if(NULL != handler &amp;&amp; NULL != on_radio_activity_callback) { RUUVI_DRIVER_ERROR_CHECK(RUUVI_DRIVER_ERROR_INVALID_STATE, ~RUUVI_DRIVER_ERROR_FATAL); }\n  else { on_radio_activity_callback = handler; }\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/012efdeaa67df824786e18969f7e24c7\/raw\/1a206a102e225f4d0e1facf2c05ab3eede56b20a\/ruuvi_platform_communication_radio.3.13.c\">Rohdaten anzeigen<\/a><\/p>\n\n<h2 class=\"wp-block-heading\">Testen<\/h2>\n\n<p class=\"wp-block-paragraph\">Der \u00dcbersichtlichkeit halber ist der Zwischenstand w\u00e4hrend der Entwicklung hier nicht enthalten, der finale Code wird sp\u00e4ter gezeigt. Kurz gesagt: Die <strong>ADC<\/strong>-Task wurde so eingestellt, dass sie beim Funkinterrupt den <strong>ADC<\/strong> sampelt und einen General-Purpose-Input\/Output-Pin (<strong>GPIO<\/strong>) toggelt. Dieses Toggling wurde genutzt, um Oszilloskopmessungen an der Versorgungsspannung zu triggern. Zuerst wurde eine wenig genutzte Batterie getestet.  <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"822\" src=\"https:\/\/ruuvi.com\/i\/u\/oscilloscope-1024x822.png\" alt=\"Oszilloskop zeigt DC- und AC-Kopplung an der Batteriespannung\" class=\"wp-image-3804\" srcset=\"https:\/\/ruuvi.com\/i\/u\/oscilloscope-1024x822.png 1024w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-450x361.png 450w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-768x616.png 768w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-1536x1233.png 1536w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-2048x1644.png 2048w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-600x482.png 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Blaue Linie ist DC-gekoppelt an GPIO, rote Linie ist AC-gekoppelt an der Batteriespannung<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Die <a href=\"http:\/\/blog.prosig.com\/2013\/01\/15\/what-are-ac-and-dc-coupling\/\"><em>AC-gekoppelte<\/em><\/a> Linie zeigt, dass wir einen Einbruch von etwa <strong>150 <em>mV<\/em><\/strong> auf der Leitung haben, und das ADC-Sample trifft nicht exakt den niedrigsten Punkt. Die Versorgungsspannung liegt etwas \u00fcber 3 <em>V<\/em>. Als N\u00e4chstes pr\u00fcfen wir eine entladene CR2450-Batterie aus der Kickstarter-\u00c4ra 2016.  <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"827\" src=\"https:\/\/ruuvi.com\/i\/u\/oscilloscope-2-1024x827.png\" alt=\"Oszilloskop gekoppelt an GPIO und Batteriespannung\" class=\"wp-image-3805\" srcset=\"https:\/\/ruuvi.com\/i\/u\/oscilloscope-2-1024x827.png 1024w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-2-450x363.png 450w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-2-768x620.png 768w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-2-1536x1240.png 1536w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-2-600x485.png 600w, https:\/\/ruuvi.com\/i\/u\/oscilloscope-2.png 1746w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Blaue Linie ist DC-gekoppelt an GPIO, rote Linie ist AC-gekoppelt an der Batteriespannung<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Hier sehen wir einen deutlich tieferen Einbruch von <strong>\u00fcber 500 <em>mV<\/em><\/strong>, obwohl die Ruhespannung ebenfalls etwas \u00fcber 3 <em>V<\/em> liegt. Das bringt uns auf eine Idee: Wie w\u00e4re es, statt der absoluten Spannung die Tiefe des Spannungseinbruchs zu nutzen, um den Batteriezustand zu bestimmen? Diese Idee schauen wir uns sp\u00e4ter noch an.  <\/p>\n\n<h2 class=\"wp-block-heading\">Integration in die Anwendung<\/h2>\n\n<p class=\"wp-block-paragraph\">Jetzt haben wir 3 unterschiedliche Modi f\u00fcr den ADC-Betrieb:<\/p>\n\n<ul class=\"wp-block-list\"><li><em>Einfach<\/em>: In regelm\u00e4\u00dfigen Intervallen messen<\/li><li><em>Funk<\/em>: Nach Funkaktivit\u00e4t messen<\/li><li><em>Droop<\/em>: Spannung nach Funkaktivit\u00e4t und einige Millisekunden sp\u00e4ter messen, um die Tiefe des Spannungseinbruchs zu sehen<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">Definieren wir diese Modi in <em>application_config.h<\/em><\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Data format configuration\n *\/\n\/\/ Voltage mode - select one\n#ifndef APPLICATION_BATTERY_VOLTAGE_MODE\n#define APPLICATION_BATTERY_VOLTAGE_SIMPLE   0  \/\/ Simple mode: Not synchronized to anything, sampled at regular interval\n#define APPLICATION_BATTERY_VOLTAGE_RADIO    1  \/\/ Radio mode: Voltage is sampled after radio tx, refreshed after interval has passed.\n#define APPLICATION_BATTERY_VOLTAGE_DROOP    0  \/\/ Droop mode: Battery is read after TX and after a brief recovery period. Droop is reported\n#endif\n#define APPLICATION_BATTERY_DROOP_DELAY_MS   2  \/\/ Milliseconds between active and recovered tx\n#if(APPLICATION_BATTERY_VOLTAGE_SIMPLE + APPLICATION_BATTERY_VOLTAGE_RADIO + APPLICATION_BATTERY_VOLTAGE_DROOP != 1)\n  #error \"Select application battery voltage monitor mode by defining one constant as 1\"\n#endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/6602fd0d72778a7bf5d990a4faf7a048\/raw\/f86bbd61218e3749d7ed85fb07074e79d761b40b\/ruuvi_firmware_application_config_adc_modes.h\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes aktualisieren wir <em>task_adc.c<\/em>: <em>Initialisierung<\/em>, <em>Timer<\/em>&#8211; und <em>Scheduler<\/em>-Funktionen, und registrieren die <strong>ADC<\/strong>-Task beim Funk.<\/p>\n\n<pre class=\"wp-block-code\"><code>RUUVI_PLATFORM_TIMER_ID_DEF(adc_timer);\nstatic ruuvi_driver_sensor_t adc_sensor = {0};\nstatic uint64_t t_sample = 0;\nstatic float droop = 0;\nstatic float after_tx = 0;\n\n\/* Use these functions for using ADC at regular, timed intervals\n * Remember to start the timer at init\n *\/\n\/\/handler for scheduled accelerometer event\nstatic void task_adc_scheduler_task(void *p_event_data, uint16_t event_size)\n{\n  ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n\n  \/\/ Take new sample\n  status |= task_adc_sample();\n  \/\/ Log warning if adc sampling failed.\n  RUUVI_DRIVER_ERROR_CHECK(status, ~RUUVI_DRIVER_ERROR_FATAL);\n}\n\n\/\/ Timer callback, schedule event here or execute it right away if it's timing-critical\nstatic void task_adc_timer_cb(void* p_context)\n{\n  ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n  ruuvi_interface_adc_data_t rest;\n\n  \/\/ Simple mode\n  if(APPLICATION_BATTERY_VOLTAGE_SIMPLE)\n  {\n    ruuvi_platform_scheduler_event_put(NULL, 0, task_adc_scheduler_task);\n  }\n\n  \/\/ Droop mode\n  if(APPLICATION_BATTERY_VOLTAGE_DROOP)\n  {\n  \/\/ Take new ADC sample\n  status |= task_adc_sample();\n\n  \/\/ Read new sample\n  status |= adc_sensor.data_get(&amp;rest);\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Subtract active sample from rest sample\n  droop = rest.adc_v - after_tx;\n  if(0.0 &gt; droop) { droop = 0.0; }\n  }\n}\n\n\n\/\/ Callback for radio event. Configured to radio on TASK ADC INIT on droop mode and radio mode,\n\/\/ see application_config.h\nstatic void task_adc_trigger_on_radio(const ruuvi_interface_communication_radio_activity_evt_t evt)\n{\n\n  \/\/ If event is after radio activity\n  if(RUUVI_INTERFACE_COMMUNICATION_RADIO_AFTER == evt)\n  {\n    \/\/ Sample\n    if((APPLICATION_ADC_SAMPLE_INTERVAL_MS &lt; ruuvi_platform_rtc_millis() - t_sample || 0 == t_sample))\n    {\n      \/\/ TEST: LED ON to see the sample time relative to supply voltage, oscilloscope triggered by this signal\n      \/\/ task_led_write(RUUVI_BOARD_LED_GREEN, RUUVI_BOARD_LEDS_ACTIVE_STATE);\n\n      t_sample = ruuvi_platform_rtc_millis();\n      task_adc_sample();\n\n      \/\/ Read radio-synched ADC sample\n      ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n      ruuvi_interface_adc_data_t active;\n      status |= adc_sensor.data_get(&amp;active);\n      RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n      after_tx = active.adc_v;\n\n      \/\/ task_led_write(RUUVI_BOARD_LED_GREEN, !RUUVI_BOARD_LEDS_ACTIVE_STATE);\n\n      \/\/ Sample again for droop mode\n      if(APPLICATION_BATTERY_VOLTAGE_DROOP)\n      {\n        ruuvi_platform_timer_start(adc_timer, APPLICATION_BATTERY_DROOP_DELAY_MS);\n      }\n    }\n  }\n}\n\nstatic ruuvi_driver_status_t task_adc_configure(void)\n{\n  ruuvi_driver_sensor_configuration_t config;\n  config.samplerate    = APPLICATION_ADC_SAMPLERATE;\n  config.resolution    = APPLICATION_ADC_RESOLUTION;\n  config.scale         = APPLICATION_ADC_SCALE;\n  config.dsp_function  = APPLICATION_ADC_DSPFUNC;\n  config.dsp_parameter = APPLICATION_ADC_DSPPARAM;\n  config.mode          = APPLICATION_ADC_MODE;\n  if(NULL == adc_sensor.data_get) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n  return adc_sensor.configuration_set(&amp;adc_sensor, &amp;config);\n}\n\nruuvi_driver_status_t task_adc_init(void)\n{\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  ruuvi_driver_bus_t bus = RUUVI_DRIVER_BUS_NONE;\n  uint8_t handle = RUUVI_INTERFACE_ADC_AINVDD;\n\n  \/\/ Initialize timer for adc task.\n  \/\/ Note: the timer is not started.\n  \/\/ Note: use REPEATED mode for free-running sampling.\n  ruuvi_interface_timer_mode_t mode = APPLICATION_BATTERY_VOLTAGE_SIMPLE ? RUUVI_INTERFACE_TIMER_MODE_REPEATED : RUUVI_INTERFACE_TIMER_MODE_SINGLE_SHOT;\n  err_code |= ruuvi_platform_timer_create(&amp;adc_timer, mode, task_adc_timer_cb);\n\n  err_code |= ruuvi_interface_adc_mcu_init(&amp;adc_sensor, bus, handle);\n  RUUVI_DRIVER_ERROR_CHECK(err_code, RUUVI_DRIVER_SUCCESS);\n\n  if(RUUVI_DRIVER_SUCCESS == err_code)\n  {\n    err_code |= task_adc_configure();\n\n    \/\/ Start the ADC timer here if you use timer-based battery measurement\n    if(true == APPLICATION_BATTERY_VOLTAGE_SIMPLE)\n    {\n      err_code |= ruuvi_platform_timer_start(adc_timer, APPLICATION_ADC_SAMPLE_INTERVAL_MS);\n    }\n\n    \/\/ Configure the radio callback here to synchronize radio to ADC, unless we're in simple mode\n    if(false == APPLICATION_BATTERY_VOLTAGE_SIMPLE)\n    {\n      ruuvi_interface_communication_radio_activity_callback_set(task_adc_trigger_on_radio);\n    }\n    return err_code;\n  }\n\n  \/\/ Return error if ADC could not be configured\n  return RUUVI_DRIVER_ERROR_NOT_FOUND;\n}\n\n.\n.\n.\n\nruuvi_driver_status_t task_adc_battery_get(ruuvi_interface_adc_data_t* const data)\n{\n  if(NULL == data) { return RUUVI_DRIVER_ERROR_NULL; }\n  if(NULL == adc_sensor.data_get) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  data-&gt;timestamp_ms = t_sample;\n  if(APPLICATION_BATTERY_VOLTAGE_SIMPLE) { err_code |= task_adc_data_get(data); }\n  if(APPLICATION_BATTERY_VOLTAGE_RADIO)  { data-&gt;adc_v = after_tx; }\n  if(APPLICATION_BATTERY_VOLTAGE_DROOP)  { data-&gt;adc_v = droop; }\n  return err_code;\n}\n<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/77e94186a3520fe7f3f06f80251ee1f3\/raw\/e08a878e7ade7ae30736bfd81f6ec316d117f303\/ruuvi_firmware_task_adc.3.13.c\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Unsere <em>Scheduler<\/em>-Task bleibt unver\u00e4ndert: Wir sampeln den <strong>ADC<\/strong>, wenn der <em>Scheduler<\/em> dazu kommt. Unsere <em>Timer<\/em>-Task enth\u00e4lt jetzt deutlich mehr: Im <em>Einfach<\/em>-Modus <em>planen<\/em> wir das <strong>ADC<\/strong>-Lesen wie zuvor, im <em>Droop<\/em>-Modus sampeln wir die Batterie jedoch sofort erneut und speichern die Differenz zur funksynchronisierten Messung. Ist die Differenz kleiner als null, setzen wir sie auf null, da das Datenformat einen unsigned Wert erwartet.  <\/p>\n\n<p class=\"wp-block-paragraph\">Der Funk-Callback nimmt ein Sample, wenn das Event nach Funkaktivit\u00e4t liegt und seit dem letzten Sample-Intervall genug Zeit vergangen ist, und liest es in die Variable <em>after_tx<\/em>.<\/p>\n\n<p class=\"wp-block-paragraph\">Zum Schluss definieren wir <em>task_adc_battery_get<\/em>, das entscheidet, ob die Anwendung das neueste Sample, das nach der \u00dcbertragung gespeicherte Sample oder den Droop-Wert erhalten soll.<\/p>\n\n<p class=\"wp-block-paragraph\">Dann passen wir <em>task_advertising.c<\/em> an, um die Batteriespannung aus der neuen Task zu beziehen.<\/p>\n\n<h2 class=\"wp-block-heading\">Leistungsprofiling<\/h2>\n\n<p class=\"wp-block-paragraph\">Dieses Leistungsprofil wurde im Modus <em>funksynchronisiert<\/em> aufgenommen, also ohne zus\u00e4tzliches Aufwachen 2 ms nach der Messung. Unser letztes Ergebnis lag knapp unter 23 <em>\u03bcA<\/em>, und es scheint, dass diese Synchronisierung keinen Einfluss auf den Stromverbrauch hatte. <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"774\" src=\"https:\/\/ruuvi.com\/i\/u\/power-profile-1024x774.png\" alt=\"BME280-Sample\" class=\"wp-image-3806\" srcset=\"https:\/\/ruuvi.com\/i\/u\/power-profile-1024x774.png 1024w, https:\/\/ruuvi.com\/i\/u\/power-profile-450x340.png 450w, https:\/\/ruuvi.com\/i\/u\/power-profile-768x581.png 768w, https:\/\/ruuvi.com\/i\/u\/power-profile-1536x1161.png 1536w, https:\/\/ruuvi.com\/i\/u\/power-profile-2048x1548.png 2048w, https:\/\/ruuvi.com\/i\/u\/power-profile-600x454.png 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Wir sehen die Programmereignisse: <strong>BME280<\/strong>-Sample, Sensoren auslesen, Daten im Profil \u00fcbertragen.<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Bootloader-Integration<\/h2>\n\n<p class=\"wp-block-paragraph\">Bis hierhin haben wir nur eine kabelgebundene Verbindung genutzt. Im letzten Teil haben wir einen Bootloader f\u00fcr unser Projekt erstellt \u2013 nutzen wir ihn. Da das <em>Segger Embedded Studio<\/em> (<strong>SES<\/strong>)-Projekt <a href=\"http:\/\/infocenter.nordicsemi.com\/index.jsp?topic=%2Fcom.nordic.infocenter.tools%2Fdita%2Ftools%2Fnrfutil%2Fnrfutil_intro.html\"><em>nrfutil<\/em><\/a> und die Generierung der Bootloader-Settings nicht \u201eversteht\u201c, m\u00fcssen wir einen manuellen Schritt hinzuf\u00fcgen, um das mit <strong>SES<\/strong> erstellte Projekt auf den RuuviTag zu flashen.  <\/p>\n\n<p class=\"wp-block-paragraph\">Wir erstellen ein Skript \u201e<em>flash.sh<\/em>\u201c, das den ver\u00f6ffentlichten Bootloader und den Encryption-Key von GitHub herunterl\u00e4dt und ein Paket erstellt, das Softdevice, Bootloader, Bootloader-Konfiguration und Application-Hex enth\u00e4lt, sowie ein DFU-Paket f\u00fcr die Anwendung.<\/p>\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\nNAME=\"dev\"\nVERSION=\"0.0.1\"\nwhile getopts \"n:v:\" option;\ndo\ncase \"${option}\"\nin\nn) NAME=${OPTARG};;\nv) VERSION=${OPTARG};;\nesac\ndone\n\nbootloader=\"ruuvitag_b_bootloader_3.0.0_s132_6.1.0_debug.hex\"     \nif &#091; -f $bootloader ]; then\n   echo \"Found bootloader.\"\nelse\n   wget https:\/\/github.com\/ruuvi\/ruuvi.nrf5_sdk15_bootloader.c\/releases\/download\/3.0.0\/ruuvitag_b_bootloader_3.0.0_s132_6.1.0_debug.hex\nfi\n\nkey=\"ruuvi_open_private.pem\"     \nif &#091; -f $key ]; then\n   echo \"Found key\"\nelse\n   wget https:\/\/github.com\/ruuvi\/ruuvi.nrf5_sdk15_bootloader.c\/releases\/download\/3.0.0\/ruuvi_open_private.pem\nfi\n\nnrfutil settings generate --family NRF52 --application Output\/Debug\/Exe\/ruuvi.firmware.c.hex --application-version 1 --application-version-string \"$VERSION\" --bootloader-version 1 --bl-settings-version 1 settings.hex\nmergehex -m ..\/..\/..\/..\/nRF5_SDK_15.2.0_9412b96\/components\/softdevice\/s132\/hex\/s132_nrf52_6.1.0_softdevice.hex ruuvitag_b_bootloader_3.0.0_s132_6.1.0_debug.hex settings.hex -o sbc.hex\nmergehex -m sbc.hex Output\/Debug\/Exe\/ruuvi.firmware.c.hex -o packet.hex\nnrfjprog --family nrf52 --eraseall\nnrfjprog --family nrf52 --program packet.hex\nnrfjprog --family nrf52 --reset\n\nmv packet.hex ruuvitag_b\\_ses\\_$NAME\\_$VERSION\\_full.hex\ncp Output\/Debug\/Exe\/ruuvi.firmware.c.hex ruuvitag_b\\_ses\\_$NAME\\_$VERSION\\_app.hex\nnrfutil pkg generate --application Output\/Debug\/Exe\/ruuvi.firmware.c.hex --application-version 1 --application-version-string \"$VERSION\" --hw-version 0x0b --sd-req 0xA9 --key-file ruuvi_open_private.pem ruuvitag_b\\_ses\\_$NAME\\_$VERSION\\_dfu.zip<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/0c7f0719553939c70e3b5e04141813b0\/raw\/7a6adeb10d36dadb244ba73070177af532ea0eb0\/ruuvi_ses_flash_script.sh\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Das Skript pr\u00fcft auf die Argumente <em>-n<\/em> und <em>-v<\/em> f\u00fcr <em>Name<\/em> und <em>Version<\/em> und verwendet standardm\u00e4\u00dfig <em>dev 0.0.1<\/em>, wenn diese nicht angegeben sind. Danach pr\u00fcft das Skript, ob Bootloader und der private Schl\u00fcssel zum Signieren des Pakets vorhanden sind, und l\u00e4dt sie andernfalls von GitHub herunter. <\/p>\n\n<p class=\"wp-block-paragraph\">Dann erstellt das Skript die Bootloader-Settings und erzeugt das Zwischenpaket sbc.hex, das Softdevice+Bootloader mit konfigurierten Application-Settings enth\u00e4lt. Dieses Paket wird anschlie\u00dfend mit der Anwendung zusammengef\u00fchrt, um ein fertiges Paket zu erstellen, mit dem das komplette Programm auf den RuuviTag geflasht werden kann. <\/p>\n\n<p class=\"wp-block-paragraph\">Der RuuviTag wird gel\u00f6scht und das vollst\u00e4ndige Paket wird geflasht.<\/p>\n\n<p class=\"wp-block-paragraph\">Zum Schluss bekommen die Pakete sprechende Namen, zum Beispiel ergibt das Ausf\u00fchren<\/p>\n\n<pre class=\"wp-block-code\"><code>.\/flash.sh -n ruuvifw -v 3.13.0<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">folgendes:<\/p>\n\n<ul class=\"wp-block-list\"><li><em>ruuvitag_b_ses_ruuvifw_3.13.0_full.hex<\/em><\/li><li><em>ruuvitag_b_ses_ruuvifw_3.13.0_app.hex<\/em><\/li><li>r<em>uuvitag_b_ses_ruuvifw_3.13.0_dfu.zip<\/em><\/li><\/ul>\n\n<h2 class=\"wp-block-heading\">ARMGCC<\/h2>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes erstellen wir ein Packaging-Skript f\u00fcr unsere <strong>ARMGCC<\/strong>-Builds, damit Jenkins \u00e4hnliche Pakete erstellen kann. Wenn wir schon dabei sind, bauen wir Unterst\u00fctzung f\u00fcr Batch-Builds in verschiedenen Modi ein, indem per Command-Line-Flag ausgew\u00e4hlt wird, welche Settings in <em>application_config.h<\/em> verwendet werden. <\/p>\n\n<p class=\"wp-block-paragraph\">Wir f\u00fcgen <em>application_modes.h<\/em> hinzu, das Header mit Modus-Definitionen einbindet, wenn ein bestimmter Modus definiert ist, und wir f\u00fcgen <em>application_mode_longlife.h <\/em>als Beispiel hinzu.<\/p>\n\n<pre class=\"wp-block-code\"><code>#ifndef APPLICATION_MODES_H\n#define APPLICATION_MODES_H\n#ifdef APPLICATION_MODE_LONGLIFE\n  #include \"application_mode_longlife.h\"\n#endif\n\n#endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/e38c3428638e4f1d3b2f3d1c856f2910\/raw\/732f6acf6169915a2cb22af548141f9d6084d0a6\/ruuvi_firmware_application_modes_3.13.h\">Rohdaten anzeigen<\/a><\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Environmental sensor configuration\n **\/\n\/\/ Sample rate is in Hz. This configures only the sensor, not transmission rate of data.\n#define APPLICATION_ENVIRONMENTAL_CONFIGURED\n#define APPLICATION_ENVIRONMENTAL_SAMPLERATE RUUVI_DRIVER_SENSOR_CFG_MIN\n\n\/\/ Resolution and scale cannot be adjusted on BME280\n#define APPLICATION_ENVIRONMENTAL_RESOLUTION RUUVI_DRIVER_SENSOR_CFG_DEFAULT\n#define APPLICATION_ENVIRONMENTAL_SCALE      RUUVI_DRIVER_SENSOR_CFG_DEFAULT\n\n\/\/ Valid values for BME280 are: (RUUVI_DRIVER_SENSOR_DSP_)LAST, IIR, OS\n\/\/ IIR slows step response but lowers noise\n\/\/ OS increases power consumption but lowers noise.\n\/\/ See https:\/\/blog.ruuvi.com\/humidity-sensor-673c5b7636fc and https:\/\/blog.ruuvi.com\/dsp-compromises-3f264a6b6344\n#define APPLICATION_ENVIRONMENTAL_DSPFUNC    RUUVI_DRIVER_SENSOR_DSP_IIR\n\n\/\/ No effect on _LAST, use 1. On _OS and _IIR valid values are 2, 4, 8 and 16.\n#define APPLICATION_ENVIRONMENTAL_DSPPARAM   RUUVI_DRIVER_SENSOR_CFG_MAX\n\n\/\/ (RUUVI_DRIVER_SENSOR_CFG_)SLEEP, SINGLE or CONTINUOUS\n#define APPLICATION_ENVIRONMENTAL_MODE       RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS\n\n\n\/**\n * Accelerometer configuration\n **\/\n#define APPLICATION_ACCELERATION_CONFIGURED\n\/\/ 1, 10, 25, 50, 100, 200 for LIS2DH12\n#define APPLICATION_ACCELEROMETER_SAMPLERATE RUUVI_DRIVER_SENSOR_CFG_MIN\n\n\/\/ 8, 10, 12 for LIS2DH12\n#define APPLICATION_ACCELEROMETER_RESOLUTION 10\n\n\/\/ 2, 4, 8, 16 for LIS2DH12\n#define APPLICATION_ACCELEROMETER_SCALE   RUUVI_DRIVER_SENSOR_CFG_MIN\n\n\/\/ LAST or HIGH_PASS\n#define APPLICATION_ACCELEROMETER_DSPFUNC RUUVI_DRIVER_SENSOR_DSP_LAST\n#define APPLICATION_ACCELEROMETER_DSPPARAM 1\n\n\/\/ SLEEP or CONTINUOUS\n#define APPLICATION_ACCELEROMETER_MODE RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS\n\n\/**\n * Bluetooth configuration\n *\n *\/\n\/\/ Avoid \"even\" values such as 100 or 1000 to eventually drift apart from the devices transmitting at same interval\n\/\/ Min 100, Max 10000\n#define APPLICATION_ADVERTISING_CONFIGURED\n#define APPLICATION_ADVERTISING_INTERVAL 9990\n#define APPLICATION_ADVERTISING_POWER    RUUVI_BOARD_TX_POWER_MAX<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/9ff860e9b5429d8b9a8b5a53aa8db2ba\/raw\/7ef14a2d29addca5adec7fbf8163886092cfda14\/ruuvi_firmware_application_mode_longlife.3.13.h\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Unsere Hauptkonfigurationsdatei <em>application_config.h<\/em> enth\u00e4lt die Definitionen in #<em>ifdef<\/em>-Klauseln und <em>#define<\/em>t Standardwerte, sofern nicht etwas anderes #<em>definiert<\/em> ist.<\/p>\n\n<p class=\"wp-block-paragraph\">Dann f\u00fcgen wir das Compile-Flag in unser Root-Makefile ein mit<\/p>\n\n<pre class=\"wp-block-code\"><code>MODE=-DAPPLICATION_MODE_LONGLIFE<\/code><\/pre>\n\n<pre class=\"wp-block-code\"><code>.PHONY: all fw clean\n\nall: fw \n\nfw:\n\t@echo build FW\n\tgit submodule update --init --recursive\n\t$(MAKE) -C targets\/ruuvitag_b\/armgcc clean\n\t$(MAKE) -C targets\/ruuvitag_b\/armgcc MODE=-DAPPLICATION_MODE_LONGLIFE\n\ttargets\/ruuvitag_b\/armgcc\/package.sh -n ruuvifw_longlife\n\t$(MAKE) -C targets\/ruuvitag_b\/armgcc clean\n\t$(MAKE) -C targets\/ruuvitag_b\/armgcc\n\ttargets\/ruuvitag_b\/armgcc\/package.sh -n ruuvifw_default\n\n\nclean:\n\t@echo cleaning build files\u2026\n\t$(MAKE) -C targets\/ruuvitag_b\/armgcc clean<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/ff4a84378d70b0ed702a542f92cb8048\/raw\/e9be6da0caa953a7651d949352d822257f76b146\/ruuvi_firmware_makefile.3.13.sh\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Unser <strong>ARMGCC<\/strong>-Makefile h\u00e4ngt das Modus-Argument an <strong>CFLAGS<\/strong> an.<\/p>\n\n<p class=\"wp-block-paragraph\">Nachdem das Programm gebaut wurde, erstellt unser Package-Skript die Pakete f\u00fcr App-, Full- und DFU-Versionen und benennt die Version mit dem GitHub-Commit-Hash.<\/p>\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\ncd \"$(dirname \"$0\")\"\nNAME=\"ruuvifw\"\nVERSION=$(git rev-parse --short HEAD)\nwhile getopts \"n:v:\" option;\ndo\ncase \"${option}\"\nin\nn) NAME=${OPTARG};;\nv) VERSION=${OPTARG};;\nesac\ndone\n\nbootloader=\"ruuvitag_b_bootloader_3.0.0_s132_6.1.0_debug.hex\"     \nif &#091; -f $bootloader ]; then\n   echo \"Found bootloader.\"\nelse\n   wget https:\/\/github.com\/ruuvi\/ruuvi.nrf5_sdk15_bootloader.c\/releases\/download\/3.0.0\/ruuvitag_b_bootloader_3.0.0_s132_6.1.0_debug.hex\nfi\n\nkey=\"ruuvi_open_private.pem\"     \nif &#091; -f $key ]; then\n   echo \"Found key\"\nelse\n   wget https:\/\/github.com\/ruuvi\/ruuvi.nrf5_sdk15_bootloader.c\/releases\/download\/3.0.0\/ruuvi_open_private.pem\nfi\n\nnrfutil settings generate --family NRF52 --application _build\/nrf52832_xxaa.hex --application-version 1  --bootloader-version 1 --bl-settings-version 1 settings.hex\nmergehex -m ..\/..\/..\/..\/nRF5_SDK_15.2.0_9412b96\/components\/softdevice\/s132\/hex\/s132_nrf52_6.1.0_softdevice.hex ruuvitag_b_bootloader_3.0.0_s132_6.1.0_debug.hex settings.hex -o sbc.hex\nmergehex -m sbc.hex _build\/nrf52832_xxaa.hex -o packet.hex\n\nrm ruuvitag_b_armgcc*$NAME*.hex\nrm ruuvitag_b_armgcc*$NAME*.zip\n\nmv packet.hex ruuvitag_b\\_armgcc\\_$NAME\\_$VERSION\\_full.hex\ncp _build\/nrf52832_xxaa.hex ruuvitag_b\\_armgcc\\_$NAME\\_$VERSION\\_app.hex\nnrfutil pkg generate --application _build\/nrf52832_xxaa.hex --application-version 1 --hw-version 0x0b --sd-req 0xA9 --key-file ruuvi_open_private.pem ruuvitag_b\\_armgcc\\_$NAME\\_$VERSION\\_dfu.zip<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/bdbf1a175ef41183a63bdfefe722c7dd\/raw\/233f273fffba6715e704c1a387de83b02909efaa\/ruuvi_firmware_3.13.package.sh\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Das erzeugt<\/p>\n\n<ul class=\"wp-block-list\"><li>ruuvitag_b_armgcc_ruuvifw_default_cf94d5d_app.hex<\/li><li>ruuvitag_b_armgcc_ruuvifw_default_cf94d5d_dfu.zip<\/li><li>ruuvitag_b_armgcc_ruuvifw_default_cf94d5d_full.hex<\/li><li>ruuvitag_b_armgcc_ruuvifw_longlife_cf94d5d_app.hex<\/li><li>ruuvitag_b_armgcc_ruuvifw_longlife_cf94d5d_dfu.zip<\/li><li>ruuvitag_b_armgcc_ruuvifw_longlife_cf94d5d_full.hex<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">und entfernt alte Bin\u00e4rdateien. Dann konfigurieren wir Jenkins so, dass die Build-Artefakte gespeichert werden. Danke <a href=\"https:\/\/github.com\/scrin\">Scrin<\/a> f\u00fcr den Vorschlag!  <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"771\" src=\"https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-1024x771.png\" alt=\"Screenshot, der zeigt, dass unsere Long-Life-Variante den Stromverbrauch halbiert hat.\" class=\"wp-image-3807\" srcset=\"https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-1024x771.png 1024w, https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-450x339.png 450w, https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-768x578.png 768w, https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-1536x1157.png 1536w, https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-2048x1542.png 2048w, https:\/\/ruuvi.com\/i\/u\/long-life-variant-has-halved-power-consumption-600x452.png 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Unsere Long-Life-Variante hat den Stromverbrauch halbiert.<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n<p class=\"wp-block-paragraph\">Wir haben jetzt eine pr\u00e4zisere Batteriemessung und ein paar Ideen, wie wir die Sch\u00e4tzung der verbleibenden Laufzeit verbessern k\u00f6nnen. Au\u00dferdem haben wir automatische Builds verschiedener Varianten hinzugef\u00fcgt \u2013 eine Zeitersparnis f\u00fcr alle. <\/p>\n\n<p class=\"wp-block-paragraph\">Und schlie\u00dflich unterst\u00fctzen wir jetzt den Bootloader in der Anwendung und k\u00f6nnen die Anwendungen ohne Devkit aktualisieren.<\/p>\n\n<p class=\"wp-block-paragraph\"><strong>Bleib dran und folge <\/strong><a href=\"https:\/\/twitter.com\/ojousima\"><strong>@ojousima<\/strong><\/a><strong> und <\/strong><a href=\"https:\/\/twitter.com\/ruuvicom\"><strong>@ruuvicom<\/strong><\/a><strong> auf Twitter f\u00fcr #FirmwareFriday-Beitr\u00e4ge!<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Teil des Tutorials synchronisieren wir die Messung der Batteriespannung mit Funk\u00fcbertragungen. Den finalen Code dieses Blogposts kannst du bei Ruuvi GitHub im Branch ruuviblog, Tag 3.13.0-alpha herunterladen. Bitte folge Teil 1 der Serie f\u00fcr Details zum Klonen des Repositories und Kompilieren des Codes. Die finale Hex-Datei dieses Tutorials kann vom Ruuvi Jenkins heruntergeladen [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":135775,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[324],"tags":[],"class_list":["post-135774","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ruuvi-software-artikel"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert \u2013 Ruuvi<\/title>\n<meta name=\"description\" content=\"Batteriespannungsinfos direkt aufs Smartphone holen, indem du die Firmware auf SDK 15.2 aktualisierst und die Batteriemessung neu denkst.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert \u2013 Ruuvi\" \/>\n<meta property=\"og:description\" content=\"Batteriespannungsinfos direkt aufs Smartphone holen, indem du die Firmware auf SDK 15.2 aktualisierst und die Batteriemessung neu denkst.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/\" \/>\n<meta property=\"og:site_name\" content=\"Ruuvi\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ruuvi.cc\" \/>\n<meta property=\"article:published_time\" content=\"2018-10-19T12:28:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-11T04:40:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"1400\" \/>\n\t<meta property=\"og:image:height\" content=\"733\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Otso Jousimaa\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ruuvicom\" \/>\n<meta name=\"twitter:site\" content=\"@ruuvicom\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Otso Jousimaa\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"19\u00a0Minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/\"},\"author\":{\"name\":\"Otso Jousimaa\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\"},\"headline\":\"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert\",\"datePublished\":\"2018-10-19T12:28:00+00:00\",\"dateModified\":\"2026-06-11T04:40:35+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/\"},\"wordCount\":1520,\"image\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/ruuvi-firmware-series-part-13.jpeg\",\"articleSection\":[\"Ruuvi-Software-Artikel\"],\"inLanguage\":\"de\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/\",\"name\":\"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert \u2013 Ruuvi\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/ruuvi-firmware-series-part-13.jpeg\",\"datePublished\":\"2018-10-19T12:28:00+00:00\",\"dateModified\":\"2026-06-11T04:40:35+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\"},\"description\":\"Batteriespannungsinfos direkt aufs Smartphone holen, indem du die Firmware auf SDK 15.2 aktualisierst und die Batteriemessung neu denkst.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#primaryimage\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/ruuvi-firmware-series-part-13.jpeg\",\"contentUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/ruuvi-firmware-series-part-13.jpeg\",\"width\":1400,\"height\":733,\"caption\":\"Introbild zur Ruuvi-Firmware-Serie, Teil 13\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/front\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#website\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/\",\"name\":\"Ruuvi\",\"description\":\"Measure Your World\",\"potentialAction\":[],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\",\"name\":\"Otso Jousimaa\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g\",\"caption\":\"Otso Jousimaa\"},\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/author\\\/ojousima\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert \u2013 Ruuvi","description":"Batteriespannungsinfos direkt aufs Smartphone holen, indem du die Firmware auf SDK 15.2 aktualisierst und die Batteriemessung neu denkst.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/","og_locale":"de_DE","og_type":"article","og_title":"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert \u2013 Ruuvi","og_description":"Batteriespannungsinfos direkt aufs Smartphone holen, indem du die Firmware auf SDK 15.2 aktualisierst und die Batteriemessung neu denkst.","og_url":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/","og_site_name":"Ruuvi","article_publisher":"https:\/\/www.facebook.com\/ruuvi.cc","article_published_time":"2018-10-19T12:28:00+00:00","article_modified_time":"2026-06-11T04:40:35+00:00","og_image":[{"width":1400,"height":733,"url":"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg","type":"image\/jpeg"}],"author":"Otso Jousimaa","twitter_card":"summary_large_image","twitter_creator":"@ruuvicom","twitter_site":"@ruuvicom","twitter_misc":{"Verfasst von":"Otso Jousimaa","Gesch\u00e4tzte Lesezeit":"19\u00a0Minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#article","isPartOf":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/"},"author":{"name":"Otso Jousimaa","@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00"},"headline":"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert","datePublished":"2018-10-19T12:28:00+00:00","dateModified":"2026-06-11T04:40:35+00:00","mainEntityOfPage":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/"},"wordCount":1520,"image":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#primaryimage"},"thumbnailUrl":"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg","articleSection":["Ruuvi-Software-Artikel"],"inLanguage":"de"},{"@type":"WebPage","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/","url":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/","name":"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert \u2013 Ruuvi","isPartOf":{"@id":"https:\/\/ruuvi.com\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#primaryimage"},"image":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#primaryimage"},"thumbnailUrl":"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg","datePublished":"2018-10-19T12:28:00+00:00","dateModified":"2026-06-11T04:40:35+00:00","author":{"@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00"},"description":"Batteriespannungsinfos direkt aufs Smartphone holen, indem du die Firmware auf SDK 15.2 aktualisierst und die Batteriemessung neu denkst.","breadcrumb":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#primaryimage","url":"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg","contentUrl":"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-series-part-13.jpeg","width":1400,"height":733,"caption":"Introbild zur Ruuvi-Firmware-Serie, Teil 13"},{"@type":"BreadcrumbList","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ruuvi.com\/de\/front\/"},{"@type":"ListItem","position":2,"name":"Ruuvi Firmware \u2013 Teil 13: Batteriemessung mit Funk synchronisiert"}]},{"@type":"WebSite","@id":"https:\/\/ruuvi.com\/de\/#website","url":"https:\/\/ruuvi.com\/de\/","name":"Ruuvi","description":"Measure Your World","potentialAction":[],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00","name":"Otso Jousimaa","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g","caption":"Otso Jousimaa"},"url":"https:\/\/ruuvi.com\/de\/author\/ojousima\/"}]}},"_links":{"self":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/comments?post=135774"}],"version-history":[{"count":1,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135774\/revisions"}],"predecessor-version":[{"id":135780,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135774\/revisions\/135780"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/media\/135775"}],"wp:attachment":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/media?parent=135774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/categories?post=135774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/tags?post=135774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}