勝手な電子工作・・

勝手なオリジナル電子工作に関する記事を書きます

省エネ用のSleep + Watch Dog Timer(Arduinoでもできる!)

f:id:a-tomi:20210718204525j:plain

単3電池を長期間(2~3年)もたせるため、これまではPICでSleepとWatch Dog Timer(WDT)を使うようにしていました。今回は、それをやったついでに、Arduinoで同じことができるかを試してみました。上の写真はArduino-UNOからとり出したATmega328P単体を使って実験している様子です。

WDTはマイコンの動きを監視し一定時間以上反応がなければリセットして再起動をする機能です。この記事で書くのは、何が普通でないのかといえば、WDT検出でマイコンをリセットはせず、Sleepの直後にある命令から自動的に再開したいという目的です。これがうまくできれば、別途に割り込みを作らずWDTだけですむので、しかけが単純になりとても便利です。そして、Arduinoでやってみて分かった方法を、まずはこの記事に書いておきたいというわけです。

事の発端は、2階のベランダにスズメ一家が立ち入らないようにするためのちょっとした工作です。

庭で遊んでいるときは雀の学校のようで可愛らしいのですが、どうやら早朝のトイレの教育(?)にベランダを使うというのは感心しません。最近は毎朝欠かさずですから、毎度の掃除はたいへんです。そして、「このベランダには来ないように何とかならない?」と家内に頼まれたわけです^^;

一般的にはCDを吊るすとか、鳥よけテープを使うとか、最悪ではネットを張るとか、方法は色々とあるようです。たぶんですが、いちばん簡単な方法は、眩しい超高輝度白色LEDを付近でチカチカさせることではないでしょうか。勝手な電子マンとしては、早速週末にそれを試すことに。

ベランダに設置して放置し、単3電池を数か月はもたせる必要がありそうで、どうしても省エネ処理が必要です。前に作った次のリンク先のドロボー除けと同じようなものです。

いちばん簡単なドロボー除け(かな?) - 勝手な電子工作・・

そちらは設置してから1年半近くたちますが、未だにどれも単3電池を代えずに完動中。その時はSleepに加えて外付けRCによりクロックの長周期化で、電池が数年間持つようににしたのがうまく実現できていますから。

今回は数か月もたせれば良さそうなので、内蔵クロック(16MHz)で動かすことにして回路を簡素にすることにしました。外付けは超高輝度LEDとその直列抵抗だけです。

f:id:a-tomi:20210718210942j:plain

超高輝度LEDは10mmφ砲弾型で、20mAで20カンデラも光ります(カタログ仕様)。前に千石電商で購入しました。詳しいデータシートがないので照射角を測ってみると半値角が僅か4.5°の鋭いビームです。最終的にはこれを水平に向けるように設置します。鳥の立場で考えれば、まぶしい目に合うと二度と来ないかと思うからです。

順方向3.3V以上が必要のため4.5V電源とし、10mA程度で点灯させるよう直列抵抗を100Ωにしました。これで消費電流を測るとSleep状態(全体時間の97%)は20μA、点灯状態(3%)はほぼ10mAです。よって平均400μA未満。これだと連続半年はもちそうです。

点滅は次の動画のようになります。動画の後ろのほうでWatchDogが吠えるのでビックリしないでください、冗談にいれてみたのですが^^

 

youtu.be

 このPICプログラムは記事の最後、Arduinoのスケッチの後ろにご参考用につけておきます。

動作確認後、ユニバーサル基板に作り電池ボックスに貼り付けました。ごく簡単なので短時間に3つ作りました。

f:id:a-tomi:20210718211315j:plain

そして雨除けのため、それぞれ全体をビニールのチャック袋に収めました。

f:id:a-tomi:20210719101253j:plain

この3つをベランダの長手方向に向けて並べて配置。翌朝はベランダへの来訪はぴたりと止まり、フンが全くありません^^ しめしめ!

とはいえ鳥も頭がよいので、そのうちに慣れてまた来るかもしれません。このまましばらく様子を見ることにします。

 

さて、省エネアプリケーションに毎度PICアセンブラを持ち出すのもどうかと思うわけですから、今回は同じことをArduinoでやってみるわけです

省エネが目的なので、Arduino UNOなどの開発ボードのまま動かす(電流ジャンジャン食う)のではなく、UNOでプログラムを書き込んだら、そこからATmega328P単体を取り出して製作に使うわけです。取り出しやすくするためには、UNOに無圧ソケットを挿しておくと楽です。

f:id:a-tomi:20210719111421j:plain


ATmega328Pを何度も取り出すための、無圧ソケット(ゼロプレッシャーソケット)の上手な取り付け方は、前に次の記事に詳しく書きましたのでご参照ください。

Zoom用かんたん操作ボタンをArduino-UNOで作る(その1) - 勝手な電子工作・・

 

ちょっと脱線しましたが、本論であるWatch Dog Timerによるリセットを伴わないSleepからの復帰方法についてです。

そもそもWDTは稼働していることをタイマーで見張る番犬なので、起動すればマイコンにリセットがかかる、つまり再起動させる使い方が普通なわけです。それでも省エネアプリケーションを工夫してできないことはないのですが、再起動時にはSleepの次の命令に自動的に戻って欲しいものです。

Watch Dog Timerではなく他の割り込みを使えばできるわけなのですが、毎度それを考えるのも面倒。PICのやり方と同じように、WDTにシステムリセットをしない割り込みとして使えれば、回路もプログラムも簡単になるわけです。

まずATmega328PのデータシートでWatch Dog Timerのあたりを何度も読み返してみました。一番主なところはWDTCSRというコントロールレジスターの使い方です。下の図では文言をカットしてありますが、長々と書かれています。やや複雑なのですがシツコク読みます。

f:id:a-tomi:20210719112447j:plain

そして、ついにMCUにResetをかけず割り込みだけしてSleepから目覚めそうな方法をUNOで試しました。結構複雑で何度かやりなおしましたが、しつこくやってやっと正解らしき方法にたどり着きました。そのスケッチを後ろにつけておきます。

省エネの電流を測るために、次のようにATmega328P単体用の回路を組みます。

f:id:a-tomi:20210719112853j:plain

普通に16MHzのクリスタルを使い5Vでテストしたところ、POWER-DOWNさせるSleep時でも80μAほどを消耗します。そこで、Sleepの間はADCへのPower供給を止めるようにしてみたところ、これで26.8μAしか消耗しないことがわかりました。

クロックを遅くするなど更に色々やってみることがあるかとは思いますが、とにかく今後はSleepとWatch Dog Timerの組み合わせだけで、Arduinoでも簡単に省エネ処理ができそう\(^_^)/

次が今回のArduino-UNOのテストスケッチです。その後ろにPICアセンブラーの実プログラムをつけておきます。

/*******************************************************
   Watch Dog Timer test for Arduino (ATmega328P)
      Initial version 7/18, 2021   by Akira Tominaga
 *******************************************************/
#include "avr/sleep.h"
#include "avr/wdt.h"
#define LED 13

void setup() { // ***** Arduino setup() *****
// sleep time definitions for Watch-dog-timer
#define sT1 B00000110     // 1 second
#define sT2 B00000111     // 2 seconds
#define sT4 B00100000     // 4 seconds
#define st8 B00100001     // 8 seconds
#define sleepTime sT4     // select sleep-time from above
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  // for Sleep and Watch-dog-timer
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  setWDT(sleepTime);
}

void loop() { // ***** Arduino loop() *****
  digitalWrite(LED, HIGH); // LED on
  delay(20);              // for 20mS
  digitalWrite(LED, LOW); // and off
  deepSleep();            // sleep + ADCpower-off
}

ISR(WDT_vect) { // *** Intrpt svc rtn for WDT ISR(vect) *****
}                    // do nothing here

/**********************************
   User defined functions
 **********************************/
// ***** Setting Watch dog timer *** setWDT(seconds) *****
void setWDT(byte sleepT) {
  sleepT += B00010000;    // sleepTime + Enalbe WD-change bit-on
  MCUSR &=  B11110111;    // Prepare WDT-reset-flag in MCU-status-Reg
  WDTCSR |= B00011000;    // Enable WD-system-reset + WD-change
  WDTCSR  = sleepT;       // Set sleepTime + Enable WD-change
  WDTCSR |= B01000000;    // Finally, enable WDT-interrrupt
}
// ***** Sleep + Stopp ADC power *** deepSleep() *****
void deepSleep(void) {
  ADCSRA &= B01111111;    // disable ADC to save power
  sleep_enable();
  sleep_cpu();            // sleep until WDT-interrup
  sleep_disable();
  ADCSRA |= B10000000;    // enable ADC again
}
// *** End of program

 

細かい説明は省略させていただきますが、とにかく別途の割り込みのしかけもいらず、短くて簡単ですね。要は単に休ませるというDelayの代わりに所定時間のSleepを入れるだけですから。おそらく4秒のWatchDogTimerだけ用意しておけば、Loopさせることで1分とか10分とかにも対応しやすいかと思います。

このやり方は簡単だしメモリー消費なども殆どない点がよいかと勝手に思います。

もし正確に10分単位などでの計測が必要なら、9分56秒だけスリープさせてから次にRTCの分の値の変化タイミングで処理することなどで精密にできると思います。

 

次に今回の雀よけPICプログラムをご参考までに載せておきます。

;U210718-WDT-12F1822-V00t.asm			     		As of 7/18, 2021
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
;    Sleep and Restart by WDT for PIC12F1822 V00 				;
;	        (C)2015-2021 Akira Tominaga, All rights reserved.		;
;	  Function								;
;		1. Blink bright LED to drive mischievous birds away		;
;	  Input/output       							;
;		RA0 LED output							;
;	  Remarks								;
;		1. Clock = HFINTOSC (	16MHz)					;
;			Hence 1 step = 0.25 micro seconds			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
	list		p=12F1822      ; list directive to define processor
	#include	"p12F1822.inc" ; device specific variable definitions
    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_SWDTEN & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Macro definitions					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Device dependent Macros			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
DEVset	macro	
	BANKSEL	OSCCON		; Bank=1
	movlw	B'01111010'	; 16MHz and internal oscillator
	movwf	OSCCON
;
;	BANKSEL	INTCON		; Interrupt Con (in all banks hence comment)
	clrf	INTCON		; Disable all interrupts
;
; PORTA initialization
	BANKSEL	PORTA		; Bank=0
	clrf	PORTA
;	BANKSEL	LATA		; Bank=2
;	clrf	LATA
	BANKSEL	ANSELA		; Bank=3
	clrf	ANSELA		; No use of ADC
	BANKSEL	ADCON0		; Bank=1
	clrf	ADCON0		; No use of ADC
;
	BANKSEL	TRISA		; Bank=1
	movlw	B'11111110'	; RA0 is output
	movwf	TRISA
;
	BANKSEL	OPTION_REG	; Bank=1
	bcf	OPTION_REG,7	; Enable weak pull-up
	BANKSEL	WPUA		; Bank=4
	movlw	B'00111110'	; Weak Pull-up for RA 1 to RA5
	movwf	WPUA		;  
;
	BANKSEL WDTCON		; Bank=1
	clrf	WDTCON		; WDT is set by program
;
	clrf	BSR		; Bank=0
	InitP			; Initialize ports
	endm
;
InitP	macro			; Initialize ports
	movlw	B'11111110'	; All inputs pulled-up and outputs L
	movwf	PORTA
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	I/O macros			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	For general purpose	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LEDon	macro			; LED on
	goto	$+1
	bsf	PORTdbg,LED
	goto	$+1
	endm
;
LEDoff	macro			; LED off
	goto	$+1
	bcf	PORTdbg,LED
	goto	$+1
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Time cosuming macros			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic	macro			;Consume 1 μS only
	goto	$+1
	goto	$+1
	endm
;
Mic2	macro	mic2p		;Consume 2 μS x n
	movlw	mic2p
	call	Mic2r
	endm
;
Mic2p5	macro 	mic25p		; Consume 2.5μS x n
	movlw	mic25p
	call	Mic25r
	endm
;
Mic5	macro	mic5p		; Consume 5μS x n
	movlw	mic5p
	call	Mic25r
	movlw	mic5p
	call	Mic25r
	endm
;
Mic50	macro	mic50p		; Consume 50μS x n
	movlw	mic50p
	call	Mic50r
	endm
;
Milli	macro	millip		; Consume mS x n
	movlw	millip
	call 	Millir
	endm
;
Mil100	macro	mil100p		; Consume 100 mS x n
	movlw	mil100p
	call 	Mil100r
	endm
; 
Secs	macro	secsp		; Consume Second x n
	movlw	secsp
	call	Secsr
	endm
;
Mins	macro	minsp		; Consume Minute x n
	movlw	minsp
	call	Minsr
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Files and Equations					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Files				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	cblock	H'20'
;
; For Application support
;
; Areas for time consuming subroutines
; Do not change the sequences from Mic5c to Minsc
;	if co-used with calculation parameters
	Mic25c
	Mic50c
	Millic
	Mil100c
	Secsc
	Minsc
;
	endc		
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Equations			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LedOnT	equ	D'25'		; LED-on Time(25mS)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	For PORTA		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;LED	equ	0
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***	Logical PORTdbg		; Change this when port changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PORTdbg	equ	PORTA		;
LED	equ	0		; LED for debugging
Trig	equ	0		; DSO trigger pulse port for test use
;
	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Initializing						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	org	0
	goto	Startp		; Go to start entry
	org	4		; This is Interrupt entry
	retfie			; 
;
Startp	DEVset			; Define ports
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Main program loop					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp	nop
;Step1	Blink LED once and wait a second
	call 	WDoffr		; Off watch-dog-timer
	LEDon			; Blink LED once
	Milli	LedOnT		; for LedOnT (25mS)
	LEDoff
	call WD1Sr		; On watch-dog-timer 1 Sec
	sleep			; This includes clrwdt
;
;Step2	Blink LED once again and wait a second
	call 	WDoffr		; Off watch-dog-timer
	LEDon			; Blink LED once
	Milli	LedOnT		; for LedOnT (25mS)
	LEDoff
	call	WD1Sr		; On watch-dog-timer 1Sec
	sleep			; This includes clrwdt
;
;Step3	Blink twice with 0.5 sec sleep and wait a few seconds
	call 	WDoffr		; Off watch-dog-timer
	LEDon			; Blink LED 1st time
	Milli	LedOnT		; for LedOnT (25mS)
	LEDoff
	call	WDqSr		; On watch-dog-timer short
	sleep			; This includes clrwdt
	LEDon			; Blink LED 2ndt time
	Milli	LedOnT		; for LedOnT (25mS)
	LEDoff
	call	WD1Sr		; On watch-dog-timer long
	sleep			; This includes clrwdt
	goto	Mainp		; Contilue infinite loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Watch-dog-timer subrooutines				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WDT bit0=0 : WDToff  bit0=1 : WDTon
; WDT bit5-1: Time value
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Set 1-Second WDT		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WD1Sr	equ	$
	BANKSEL	WDTCON
	movlw	B'00010101'	; Enable 1 sec WDT
	movwf	WDTCON
	clrf	BSR		; Set Bank=0
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Set a quarter Second = 256mS WDT;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WDqSr	equ	$
	BANKSEL	WDTCON
	movlw	B'00010001'	; Enable 256mS WDT
	movwf	WDTCON
	clrf	BSR		; Set Bank=0
	return
;l
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Set 8-Second WDT		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WD8Sr	equ	$
	BANKSEL	WDTCON
	movlw	B'00011011'	; Enable 8 sec WDT
	movwf	WDTCON
	clrf	BSR		; Set Bank=0
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Set WDT off			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
WDoffr	equ	$
	BANKSEL	WDTCON
	bcf	WDTCON,SWDTEN	; Disable SW Watch Dog Timer
	clrf	BSR		; Bank = 0
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Timing subrooutines for general purposes		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.0 micro S x n	(Mic2)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2r	movwf	Mic25c		; + Wset + call = 1 micro sec 
;
Mic2l	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic2li		; else go out (2nd time 1.75 mic sec)
	return		
;
Mic2li	goto	$+1		;            (2nd time 2.25 mic sec)
	nop			;	     (2nd time 2.5 mic sec)
	goto	Mic2l		; go back    (2nd time 3 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.5 micro S x n (Mic2p5)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic25r	movwf	Mic25c		; + Wset + call = 1 micro sec 
	nop			; 1.25 micro sec
;
Mic25l	nop			; 1.5 micro sec (2nd time 4 mic sec)
	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic25li		; else go out (2nd time 2.25 mic sec)
	return		
;
Mic25li	Mic			;	      (2nd time 3.25 mic sec)
	goto	Mic25l		; go back    (2nd time 3.75 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	50 Microseconds	x n	Mic50  	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Mic50r	movwf	Mic50c	 	; set how many 50 microsec (1 micro sec to here)
	nop			; 1.25 micro sec up to here
;
Mic50l	Mic2p5	D'19'		; + 47.5 = 48.75 mic sec (2nd time 98.75 mic sec)
	nop			; + 0.25 = 49 micro sec (2nd time 99 mic sec)
; 
	decfsz	Mic50c,F	; If exhausted then 1 mic S hereafter
	goto	Mic50li		; else go out (2nd time 49.75 mic sec)
	return
;
;
Mic50li	Mic			; 	  (2nd time 50.75 mic sec)
	goto	Mic50l		; go back (2nd time 51.25 mic sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Milliseconds x n	(Milli)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Millir	movwf	Millic 		; set how many 1 mil sec (1 mic S up to here)
	nop			; 1.25 micro sec
;
Millil	Mic50	D'19'		; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25) 
	Mic2p5	D'19'		; + 47.5 mic = 998.75 micro S  (2nd, 1998.75)
	nop			; +0.25 mic = 999 micro sec    (2nd, 1999)
;
	decfsz	Millic,F	; If  exhausted then 1 micro sec hereafter
	goto	Millili		; else go out (2nd, 999.75 mic S)
	return
;
Millili	Mic			; 		(2nd time 1000.75 mic S)
	goto	Millil		; go back (2nd time 1001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	100 Milliseconds x n	(Mil100);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mil100r	movwf	Mil100c		;set how many 100 ms(1 micr sec up to here)
	nop			; 1.25 micro sec
;
Milhl	Milli	D'99'		;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
	Mic50	D'19'		; + 950 mic = 99951.25 micS(2nd.199951.25mic)
	Mic2p5	D'19'		; + 47.5 mic = 99998.75micS(2nd,199998.75mic)
	nop			; + 0.25 mic = 99999 mic S (2nd,199999 micS)
;
	decfsz	Mil100c,F	; If exhausted then 1 micro sec hereafter
	goto	Milhli		; else go out (2nd time, 99999.75 mic S)
	return
;
Milhli	Mic			;  	    	(2nd time, 100000.75 mic S)
	goto	Milhl		; 		(2nd time, 100001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Seconds x n	 (Secs)		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Secsr	movwf	Secsc 		; set how many sec ( 1 mic sec up to here)
	nop			; 1.25 micro sec
;
Secsl	Mil100	D'9'		; 
	Milli	D'99'		; + 999 milli sec = 999001.25 micro sec
;
	Mic50	D'19'		; + 950 mic = 999951.25 micro sec
	Mic2p5	D'19'		; + 47.5 mic = 999998.75 micro sec
	nop			; + 0.25 mic = 999999 micro sec
;
	decfsz	Secsc,F		; If exhausted then 1 micro sec hereafter
	goto	Secsli		; else, go out 
	return
;
Secsli	Mic
	goto	Secsl		; (Second time, Sec + 1.25 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Minutes	x n	 (Mins)		;
;	 Overhead ignored, that is only	;
;	 751.25 Mic S even when 100 Min	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Minsr	movwf	Minsc		;set how many minutes from parameter
;
Minsl	Secs	D'60'		; 1 Seconds x 60
	decfsz	Minsc,F
	goto	Minsl
	return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	End of program						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	end

 出かける寸前に慌てて書いた記事でしたため、行き届かない点があればすみません。省エネが必要な測定などにもしお役に立てば幸いです。

 

©2021 Akira Tominaga, All rights reserved.