{"id":20989953,"url":"https://github.com/robtillaart/countdown","last_synced_at":"2026-01-16T23:19:33.973Z","repository":{"id":45426287,"uuid":"251103049","full_name":"RobTillaart/CountDown","owner":"RobTillaart","description":"Arduino library to implement a countdown clock (in software by polling, no hardware timer).","archived":false,"fork":false,"pushed_at":"2026-01-15T15:11:39.000Z","size":64,"stargazers_count":14,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-15T18:59:52.172Z","etag":null,"topics":["arduino","countdown","polling"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobTillaart.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"RobTillaart","custom":"https://www.paypal.me/robtillaart"}},"created_at":"2020-03-29T18:26:14.000Z","updated_at":"2026-01-15T15:11:29.000Z","dependencies_parsed_at":"2025-07-17T13:41:48.706Z","dependency_job_id":"ee12d5a0-97b7-4ba0-90c9-80333f5cca26","html_url":"https://github.com/RobTillaart/CountDown","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/RobTillaart/CountDown","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FCountDown","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FCountDown/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FCountDown/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FCountDown/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobTillaart","download_url":"https://codeload.github.com/RobTillaart/CountDown/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FCountDown/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28487586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T22:54:02.790Z","status":"ssl_error","status_checked_at":"2026-01-16T22:50:10.344Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","countdown","polling"],"created_at":"2024-11-19T06:27:02.800Z","updated_at":"2026-01-16T23:19:33.954Z","avatar_url":"https://github.com/RobTillaart.png","language":"C++","funding_links":["https://github.com/sponsors/RobTillaart","https://www.paypal.me/robtillaart"],"categories":[],"sub_categories":[],"readme":"\n[![Arduino CI](https://github.com/RobTillaart/CountDown/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)\n[![Arduino-lint](https://github.com/RobTillaart/CountDown/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/CountDown/actions/workflows/arduino-lint.yml)\n[![JSON check](https://github.com/RobTillaart/CountDown/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/CountDown/actions/workflows/jsoncheck.yml)\n[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/CountDown.svg)](https://github.com/RobTillaart/CountDown/issues)\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/CountDown/blob/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/RobTillaart/CountDown.svg?maxAge=3600)](https://github.com/RobTillaart/CountDown/releases)\n[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/CountDown.svg)](https://registry.platformio.org/libraries/robtillaart/CountDown)\n\n\n# CountDown\n\nArduino Library to implement a CountDown clock (in software polling, no hardware timer).\n\n\n## Description\n\nThe CountDown library is a clock that counts down from a given time to zero, like an hour glass.\nIt does not call any function or so when reaching zero as the user is responsible to check the time remaining.\nTypically one checks the remaining time at least once in every **loop()**.\n\nA CountDown object can be used for \n- to detect a timeout\n- to show to a user how long to wait e.g. for a traffic light to become green.\n- to learn count backwards (educational)\n- etc.\n\nUnder the hood the CountDown object uses **micros()** or **millis()** which results in a maximum time\nof 4294 seconds in micros (about 1h 10m) or about 49+ days when using milliseconds.\n\nFor longer periods one could cascade CountDown objects, so when one is finished the next one starts.\n\nNote the CountDown object is as accurate as the underlying **millis()** or **micros()**.\nInterrupts etc. might cause deviations.\n\nFeedback as always is welcome.\n\n\n### Related\n\n- https://github.com/RobTillaart/CountDown\n- https://github.com/RobTillaart/dateTimeHelpers  formatting date / time strings\n- https://github.com/RobTillaart/printHelpers\n- https://github.com/RobTillaart/stopWatch_RT\n- https://github.com/RobTillaart/timing  wrappers around millis() and micros()\n\n\n## Interface\n\n```cpp\n#include \"CountDown.h\"\n```\n\nThe main functions of the CountDown clock are straightforward:\n\n### Constructor\n\n- **CountDown(const enum Resolution res = MILLIS)** constructor, with default resolution of milliseconds.\n- **void setResolution(const enum Resolution res = MILLIS)** set the resolution,\ndefault to MILLIS. See table below.\n- **enum Resolution resolution()** return the current resolution (integer).\n- **char getUnits()** return the current resolution as printable char (u,m,s,M)\n\n\n### Start / Stop functions\n\n- **bool start(uint32_t ticks)** (re)start in current resolution.\nTypical used for MILLIS and MICROS which must be set manually.\n- **bool start(uint8_t days, uint16_t hours, uint32_t minutes, uint32_t seconds)** Implicit set resolution to SECONDS.\nReturns false if total exceeds 2^32 milliseconds ~49 days.\nNote that **remaining()** will report in SECONDS.\n- **bool start(uint8_t days, uint16_t hours, uint32_t minutes)** Implicit set resolution to MINUTES.\nReturns false if total exceeds 2^32 milliseconds ~49 days.\nNote that **remaining()** will report in MINUTES.\n- **void stop()** stop the count down.\n- **void resume()** resumes / continues the count down.\n- **void restart()** restart the CountDown with the same resolution and ticks as before.\nresets the \\_ticks and starts again.\n\nObsolete in future (0.4.0).\n- **void cont()** resumes / continue the count down.\n*(note continue is a C-Keyword)*\n\n\n### Status \n\n- **uint32_t remaining()** returns the remaining ticks in current resolution.\n- **bool isRunning()** idem.\n- **bool isStopped()** idem.\n\n\n## Operation\n\nThe function **start(days, hours, minutes, seconds)** allows all combinations\nas long as the total time not exceeds 2^32 milliseconds. \nThe function will return false if it exceeds this (rounded) maximum.\nExample calls are:\n- four hundred minutes **start(0, 0, 400, 0)** \n- a million seconds **start(0, 0, 0, 1000000)** \n- an unusual mix **start(0, 0, 400, 1000)** as parameter.\nNote: the resolution is implicitly set to **CountDown::SECONDS**.\n\nSince 0.2.4 all **start()** functions will check if the parameters cause an overflow\nin the underlying math. \n- If there is no overflow, **start()** returns true. \n- If there is an overflow, **start()** returns false.\n\nTotal amount of time to countdown for **CountDown::MICROS** may not exceed 2\\^32 micros \nwhich equals about 1 hour and 10 minutes.\nTotal amount of time to countdown for **CountDown::MILLIS**, **CountDown::SECONDS** \nand **CountDown::MINUTES** may not exceed 2\\^32 milliseconds, about 49 days.\n\nThe function **start(days, hours, minutes)** is new since 0.2.2.\nIt also uses **millis()** under the hood. \nThe resolution is implicitly set to **CountDown::MINUTES**.\n\n\n|  Call to start()                       |  resolution        |  max time  |  comments  |\n|:---------------------------------------|:-------------------|:----------:|:-----------|\n|  start(days, hours, minutes, seconds)  |  SECONDS = millis  |  49+ days  |            |\n|  start(days, hours, minutes)           |  MINUTES = millis  |  49+ days  |            |\n|  start(ticks)                          |  MILLIS  = millis  |  49+ days  |  default   |\n|  start(ticks)                          |  MICROS  = micros  |  ~70 min   |  setResolution(CountDown::MICROS)  |\n|  start(ticks)                          |  SECONDS = millis  |  49+ days  |  setResolution(CountDown::SECONDS) |\n|  start(ticks)                          |  MINUTES = millis  |  49+ days  |  setResolution(CountDown::MINUTES) |\n|  start(ticks)                          |  HOURS   = millis  |  49+ days  |  setResolution(CountDown::HOURS)   |\n\n\nThe Countdown clock uses by default **millis()** to do the time keeping,\nalthough this can be changed runtime by **setResolution(res)**. \n\nThe parameter **res** can be:\n\n|  unit                |  uses      |  getUnits()  |  Notes  |\n|:---------------------|:-----------|:------------:|:--------|\n|  CountDown::MICROS   |  micros()  |     u        |\n|  CountDown::MILLIS   |  millis()  |     m        |  default\n|  CountDown::SECONDS  |  millis()  |     s        |\n|  CountDown::MINUTES  |  millis()  |     M        |\n|  CountDown::HOURS    |  millis()  |     H        |\n\nAlthough possible one should not change the resolution of the CountDown \nclock while it is running as you mix up different timescales.\nThe user should handle this by selecting the smallest resolution needed.\n\nAlternative one can get the remaining units, stop the countdown, and start\nwith another resolution and converted time. \nThis will probably lead to rounding errors i the total countdown time.\nSee example **countdown_adaptive_display.ino**\n\nFinally the user has to check **remaining()** as frequent as needed to meet \nthe accuracy. E.g checking once a minute while doing milliseconds makes only sense\nif the number of milliseconds is still very large. Think of an adaptive strategy.\n\n\n### Watchdog \n\nOne can call **start(...)** at any time to reset the running clock to a new value. \nThis allows to implement a sort of watchdog clock in which e.g. \nthe user must press a button at least once per minute to show he is still awake.\n\nSince version 0.3.1 the library supports **restart()** to start the countdown with\nthe last used parameters of **start()**. The user does not need to remember the \nnumber of ticks or hours + minutes + seconds any more. Much easier tom implement \na repeating (timed) function or a watchdog. See examples.\n\n\n## Future\n\n#### Must\n\n- documentation\n\n#### Should\n\n\n#### Could\n\n- does **restart()** need to return some information? what?\n- add examples\n  - visualisations - hexadecimal - alphabetical (radix 26)\n  - depends on sensor\n- implement a CountDown64 class\n  - far longer timespan\n  - inaccurate at best\n  - interesting for longer micros() time span?\n- implement a CountDownRTC class\n  - which RTC?\n\n#### Wont (unless)\n\n- if counting MINUTES and reaching 1 MINUTES and automatic\n  change to SECONDS could be NICE\n  - easy implementable by user, by starting in seconds \n    and handle the display oneself.\n- incorporate a real time clock\n  - or EEPROM to be reboot proof? cannot be guaranteed.\n- Countdown based upon external pulses.\n  - pulse counter class\n- uint64_t version ==\u003e **CountDown64** class? \n  - would be useful for micros() in theory \n    but drift / interrupts would make it fail in practice.\n- countdown with a big number e.g. billions/ second ==\u003e national deficit counter.\n  - not time triggered (is just a big variable)\n- printable interface (stopwatch_rt)\n- add call-back function when **0** is reached\n  - cannot be guaranteed as interface polls.\n- enum State { RUNNING, PAUSED, STOPPED };  // stopped =\u003e remaining = 0;\n\n\n## Support\n\nIf you appreciate my libraries, you can support the development and maintenance.\nImprove the quality of the libraries by providing issues and Pull Requests, or\ndonate through PayPal or GitHub sponsors.\n\nThank you,\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobtillaart%2Fcountdown","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobtillaart%2Fcountdown","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobtillaart%2Fcountdown/lists"}