{"id":3443,"date":"2026-06-26T11:52:19","date_gmt":"2026-06-26T03:52:19","guid":{"rendered":"https:\/\/jir.idv.tw\/wordpress\/?p=3443"},"modified":"2026-06-26T15:14:11","modified_gmt":"2026-06-26T07:14:11","slug":"arduino%e6%87%89%e7%94%a8-rpm%e8%bd%89%e9%80%9f%e8%a1%a8-%e9%ab%98%e5%a3%93%e7%b7%9a%e5%9c%88%e8%a8%8a%e8%99%9f%e6%93%b7%e5%8f%96%e9%9b%bb%e8%b7%af%e5%9c%96","status":"publish","type":"post","link":"https:\/\/jir.idv.tw\/wordpress\/?p=3443","title":{"rendered":"Arduino\u61c9\u7528 RPM\u8f49\u901f\u8868 \u9ad8\u58d3\u7dda\u5708\u8a0a\u865f\u64f7\u53d6\u96fb\u8def\u5716"},"content":{"rendered":"<p>\u7d66\u81ea\u5df1\u7d00\u9304\u3002<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?resize=640%2C341&#038;ssl=1\" alt=\"\" width=\"640\" height=\"341\" class=\"alignnone size-large wp-image-3444\" srcset=\"https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?resize=1024%2C546&amp;ssl=1 1024w, https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?resize=300%2C160&amp;ssl=1 300w, https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?resize=768%2C409&amp;ssl=1 768w, https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?resize=1536%2C819&amp;ssl=1 1536w, https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?w=1634&amp;ssl=1 1634w, https:\/\/i0.wp.com\/jir.idv.tw\/wordpress\/wp-content\/uploads\/2026\/06\/RPM-tacho-meter-from-spark-coil-signal.jpg?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p>\u96fb\u8def\u8a0a\u865f\u6a21\u64ec\uff1a<br \/>\n<a href=\"https:\/\/is.gd\/F7SgHH\" target=\"_blank\" rel=\"noopener\">https:\/\/is.gd\/F7SgHH<\/a><\/p>\n<p>Arduino\u7a0b\u5f0f\u78bc\uff1a<br \/>\n\u540c\u6b65\u653e\u5728GITHUB\u88e1\u9762 <a href=\"https:\/\/github.com\/Jir8taiwan\/engine_RPM_Tachometer_with_OLED_display\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/Jir8taiwan\/engine_RPM_Tachometer_with_OLED_display<\/a><br \/>\n<code><br \/>\n\/\/ ======================================================================<br \/>\n\/\/ RPM \u986f\u793a\u5668\uff08External Interrupt \u786c\u9ad4\u4e2d\u65b7\u7248\uff09<br \/>\n\/\/ \u7248\u672c\uff1a 1.0 20260626<br \/>\n\/\/ \u786c\u9ad4\uff1a<br \/>\n\/\/   D2  \u2192 \u9ede\u706b\u8a0a\u865f\u8f38\u5165\uff08FALLING \u908a\u7de3\u89f8\u767c\u4e2d\u65b7\uff09<br \/>\n\/\/   OLED SH1106 SPI\uff1aD0=13, D1=11, CS=10, DC=9, Reset=8<br \/>\n\/\/ ======================================================================<br \/>\n#include \"U8glib.h\"<\/p>\n<p>U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8);<\/p>\n<p>\/\/ -----------------------------------------------------------------------<br \/>\n\/\/ Arduino \u8173\u4f4d\u5b9a\u7fa9<br \/>\n\/\/ -----------------------------------------------------------------------<br \/>\nconst int SIGNAL_PIN = 2;   \/\/ \u786c\u9ad4\u4e2d\u65b7\u8173\u4f4d\uff08Uno\/Nano \u53ea\u6709 D2\u3001D3\uff09<\/p>\n<p>\/\/ -----------------------------------------------------------------------<br \/>\n\/\/ \u8108\u885d\u4fc2\u6578\uff08\u4f9d\u5be6\u8eca\u78ba\u8a8d\uff0c\u4e5f\u8a31\u8981\u6539\u62102.0\uff09<br \/>\n\/\/ \u56db\u7f38\u56db\u884c\u7a0b\uff0c\u6bcf\u8f491\u500b\u8108\u885d \u2192 1.0<br \/>\n\/\/ -----------------------------------------------------------------------<br \/>\nconst float PULSE_PER_REV = 1.0;<\/p>\n<p>\/\/ -----------------------------------------------------------------------<br \/>\n\/\/ RPM \u8a08\u7b97\u7528\u8b8a\u6578\uff08volatile\uff1aISR \u8207\u4e3b\u7a0b\u5f0f\u5171\u7528\uff09<br \/>\n\/\/ -----------------------------------------------------------------------<br \/>\nvolatile unsigned long last_pulse_time = 0;  \/\/ \u4e0a\u4e00\u500b\u8108\u885d\u7684\u6642\u9593\uff08\u5fae\u79d2\uff09<br \/>\nvolatile unsigned long pulse_interval  = 0;  \/\/ \u5169\u500b\u8108\u885d\u4e4b\u9593\u7684\u9593\u9694\uff08\u5fae\u79d2\uff09<br \/>\nvolatile bool new_pulse = false;             \/\/ \u65d7\u6a19\uff1a\u6709\u65b0\u8108\u885d\u9032\u4f86<\/p>\n<p>\/\/ -----------------------------------------------------------------------<br \/>\n\/\/ \u986f\u793a\u7528\u8b8a\u6578<br \/>\n\/\/ -----------------------------------------------------------------------<br \/>\nint current_rpm = 0;<\/p>\n<p>\/\/ -----------------------------------------------------------------------<br \/>\n\/\/ \u8d85\u6642\u8a2d\u5b9a\uff1a\u8d85\u904e\u6b64\u6642\u9593\u6c92\u6536\u5230\u8108\u885d\uff0c\u8996\u70ba RPM = 0<br \/>\n\/\/ 6000 RPM \u2192 \u6bcf\u8108\u885d 10ms\uff1b\u6020\u901f\u7d04 700 RPM \u2192 \u6bcf\u8108\u885d 85ms<br \/>\n\/\/ \u8a2d 500ms \u6c92\u8a0a\u865f\u5c31\u6b78\u96f6\uff0c\u5408\u7406\u7bc4\u570d<br \/>\n\/\/ -----------------------------------------------------------------------<br \/>\nconst unsigned long RPM_TIMEOUT_US = 500000UL;  \/\/ 500ms\uff08\u55ae\u4f4d\u5fae\u79d2\uff09<\/p>\n<p>\/\/ ======================================================================<br \/>\n\/\/ ISR\uff1a\u4e2d\u65b7\u670d\u52d9\u51fd\u5f0f\uff08\u8a0a\u865f FALLING \u908a\u7de3\u6642\u81ea\u52d5\u547c\u53eb\uff09<br \/>\n\/\/ \u6ce8\u610f\uff1aISR \u5167\u4e0d\u80fd\u7528 Serial.print()\u3001delay()<br \/>\n\/\/ ======================================================================<br \/>\nvoid onPulse() {<br \/>\n  unsigned long now = micros();<\/p>\n<p>  if (last_pulse_time > 0) {<br \/>\n    pulse_interval = now - last_pulse_time;  \/\/ \u8a08\u7b97\u8108\u885d\u9593\u9694<br \/>\n    new_pulse = true;<br \/>\n  }<\/p>\n<p>  last_pulse_time = now;<br \/>\n}<\/p>\n<p>\/\/ ======================================================================<br \/>\n\/\/ setup()<br \/>\n\/\/ ======================================================================<br \/>\nvoid setup() {<br \/>\n  Serial.begin(115200);<\/p>\n<p>  pinMode(SIGNAL_PIN, INPUT);<\/p>\n<p>  \/\/ \u7d81\u5b9a\u4e2d\u65b7\uff1aD2 = INT0\uff0cFALLING = \u8a0a\u865f\u5f9e HIGH \u4e0b\u964d\u5230 LOW \u6642\u89f8\u767c<br \/>\n  attachInterrupt(digitalPinToInterrupt(SIGNAL_PIN), onPulse, FALLING);<\/p>\n<p>  \/\/ OLED \u958b\u6a5f\u756b\u9762<br \/>\n  u8g.firstPage();<br \/>\n  do {<br \/>\n    u8g.setFont(u8g_font_helvB08);<br \/>\n    u8g.drawStr(3, 20, \"RPM Monitor\");<br \/>\n    u8g.drawStr(3, 40, \"Initializing...\");<br \/>\n  } while (u8g.nextPage());<\/p>\n<p>  delay(1000);<br \/>\n}<\/p>\n<p>\/\/ ======================================================================<br \/>\n\/\/ loop()\uff1a\u4e0d\u6703\u5361\u4f4f\uff0c\u53ef\u4ee5\u96a8\u6642\u66f4\u65b0\u756b\u9762<br \/>\n\/\/ ======================================================================<br \/>\nvoid loop() {<\/p>\n<p>  \/\/ --------------------------------------------------------------------<br \/>\n  \/\/ \u7b2c\u4e00\u6b65\uff1a\u8b80\u53d6 ISR \u66f4\u65b0\u7684\u8108\u885d\u9593\u9694\uff08\u9700\u66ab\u6642\u95dc\u4e2d\u65b7\u4fdd\u8b77\u8b80\u53d6\uff09<br \/>\n  \/\/ --------------------------------------------------------------------<br \/>\n  unsigned long interval_copy = 0;<br \/>\n  bool got_new_pulse = false;<br \/>\n  unsigned long last_time_copy = 0;<\/p>\n<p>  noInterrupts();  \/\/ \u66ab\u505c\u4e2d\u65b7\uff0c\u78ba\u4fdd\u8b80\u53d6\u671f\u9593\u8cc7\u6599\u4e0d\u88ab ISR \u4fee\u6539<br \/>\n  interval_copy  = pulse_interval;<br \/>\n  got_new_pulse  = new_pulse;<br \/>\n  last_time_copy = last_pulse_time;<br \/>\n  new_pulse      = false;  \/\/ \u6e05\u9664\u65d7\u6a19<br \/>\n  interrupts();   \/\/ \u6062\u5fa9\u4e2d\u65b7<\/p>\n<p>  \/\/ --------------------------------------------------------------------<br \/>\n  \/\/ \u7b2c\u4e8c\u6b65\uff1a\u5224\u65b7\u662f\u5426\u8d85\u6642\uff08\u592a\u4e45\u6c92\u8108\u885d \u2192 RPM \u6b78\u96f6\uff09<br \/>\n  \/\/ --------------------------------------------------------------------<br \/>\n  unsigned long now = micros();<br \/>\n  bool timed_out = (last_time_copy > 0) &&<br \/>\n                   ((now - last_time_copy) > RPM_TIMEOUT_US);<\/p>\n<p>  if (timed_out) {<br \/>\n    current_rpm = 0;<\/p>\n<p>    \/\/ \u91cd\u7f6e\uff0c\u8b93\u4e0b\u6b21\u91cd\u65b0\u8a08\u7b97<br \/>\n    noInterrupts();<br \/>\n    last_pulse_time = 0;<br \/>\n    pulse_interval  = 0;<br \/>\n    interrupts();<br \/>\n  }<br \/>\n  else if (got_new_pulse && interval_copy > 0) {<br \/>\n    \/\/ --------------------------------------------------------------------<br \/>\n    \/\/ \u7b2c\u4e09\u6b65\uff1a\u8a08\u7b97 RPM<br \/>\n    \/\/ \u516c\u5f0f\uff1aRPM = (60 \u00d7 1,000,000) \/ (interval_us \u00d7 PULSE_PER_REV)<br \/>\n    \/\/ --------------------------------------------------------------------<br \/>\n    current_rpm = (int)(60000000.0 \/ ((float)interval_copy * PULSE_PER_REV));<br \/>\n  }<\/p>\n<p>  \/\/ --------------------------------------------------------------------<br \/>\n  \/\/ \u7b2c\u56db\u6b65\uff1aSerial \u8f38\u51fa<br \/>\n  \/\/ --------------------------------------------------------------------<br \/>\n  Serial.print(\"RPM: \");<br \/>\n  Serial.println(current_rpm);<\/p>\n<p>  \/\/ --------------------------------------------------------------------<br \/>\n  \/\/ \u7b2c\u4e94\u6b65\uff1a\u66f4\u65b0 OLED<br \/>\n  \/\/ --------------------------------------------------------------------<br \/>\n  u8g.firstPage();<br \/>\n  do {<br \/>\n    u8g.setFont(u8g_font_helvR12);<\/p>\n<p>    u8g.drawStr(0, 20, \"RPM:\");<br \/>\n    u8g.setPrintPos(55, 20);<br \/>\n    u8g.print(current_rpm);<\/p>\n<p>  } while (u8g.nextPage());<\/p>\n<p>  delay(100);  \/\/ \u66f4\u65b0\u983b\u7387\u7d04 10Hz\uff0c\u907f\u514d\u756b\u9762\u9583\u720d<br \/>\n}<br \/>\n<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u7d66\u81ea\u5df1\u7d00\u9304\u3002 \u96fb\u8def\u8a0a\u865f\u6a21\u64ec\uff1a https:\/\/is.gd\/F7SgHH Arduino\u7a0b\u5f0f\u78bc\uff1a \u540c\u6b65\u653e\u5728GITHUB\u88e1\u9762 https:\/\/github.com\/Jir8taiwan\/engine_RPM_Tachometer_with_OLED_display \/\/ ====================================================================== \/\/ RPM \u986f\u793a\u5668\uff08External Interrupt \u786c\u9ad4\u4e2d\u65b7\u7248\uff09 \/\/ \u7248\u672c\uff1a 1.0 20260626 \/\/ \u786c\u9ad4\uff1a \/\/ D2 \u2192 \u9ede\u706b\u8a0a\u865f\u8f38\u5165\uff08FALLING \u908a\u7de3\u89f8\u767c\u4e2d\u65b7\uff09 \/\/ OLED SH1106 SPI\uff1aD0=13, D1=11, CS=10, DC=9, Reset=8 \/\/ ====================================================================== #include &#8220;U8glib.h&#8221; U8GLIB_SH1106_128X64 u8g(13, 11, 10, 9, 8); \/\/ &#8212;&#8211; [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[6,5],"tags":[],"class_list":["post-3443","post","type-post","status-publish","format-standard","hentry","category-6","category-5"],"jetpack_featured_media_url":"","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3443"}],"version-history":[{"count":4,"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3443\/revisions"}],"predecessor-version":[{"id":3449,"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3443\/revisions\/3449"}],"wp:attachment":[{"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jir.idv.tw\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}