目次

ゲート開閉

 サーボモータを利用し、ゲートの開閉を実現してみます。



 サーボモータで、バーの状態を、水平となす角度を
 0度か90度のいずれかにして対応します。




 サーボモータは、20ms周期で1msから2msの
 パルスを与えると、パルス幅に応じた角度を生成する
 アクチュエータと考えます。

 20ms周期は、50Hzに相当。

 周期で考えるとわかりにくいので、カウンタの値に
 置き換えて、サーボモータに与えるパルス幅を表現
 してみます。

 10kHzでカウンタを動かすと、200カウントで20msになります。
 1msから2msは、10カウントから20カウントに相当。

 カウンタの値が、10、15、20でバーの状態は0度、90度、180度に
 なります。




 バーの配置によりますが、カウンタの値を0と15の組合わせに
 するのか、20と15の組合わせにすると、開閉操作ができそう。

 10と15の組合わせで開閉を制御することにします。

 開と閉の2ボタンを用意し、ボタンを押すと
 バーがその状態になる仕様で動かします。

 2ボタンをポート2に接続し、押されたことを
 状態変化(L→H)で検出。



 状態は、開か閉かしかないので、論理値で表現できます。
 フラグを用意して、フラグがセットされているとOPEN
 クリアされているとCLOSEと状態を与えておきましょう。

 ボタンが押されたことは、シフトレジスタを利用し
 L→Hの変化を検出します。

 タイマー割込み発生を、イベント通知して貰い
 2ボタンの状態を取得。一つ前の状態と比較し
 変化があれば、ボタンが押されたと判断。

 擬似コーディングすると、次のようになります。

 2変数(sftc、sfto)を1ビット左にシフト
 2変数(sftc、sfto)の2ビットをマスク
 ポートから2ボタンの状態を取得し、変数(tmp)に格納
 変数tmpのCビットが1ならば、sftcに1を加える
 変数tmpのOビットが1ならば、sftoに1を加える
 sftcが1なら、状態をCLOSEにする
 sftoが1なら、状態をOPENにする

 擬似コーディングの内容を、アセンブリ言語の記述に変換。

  ; 2変数(sftc、sfto)を1ビット左にシフト
  xch a,r2
  rl  a
  xch a,r2
  xch a,r3
  rl  a
  xch a,r3
  ; 2変数(sftc、sfto)の2ビットをマスク
  xch a,r2
  anl a,#3
  xch a,r2
  xch a,r3
  anl a,#3
  xch a,r3
  ; ポートから2ボタンの状態を取得し、変数(tmp)に格納
  in  a,P2
  anl a,#0f0h
  swap a
  rr a
  rr a
  anl a,#3
  mov r4,a
  ; 変数tmpのCビットが1ならば、sftcに1を加える
  rrc a
  jnc next
  inc r2
  ; 変数tmpのOビットが1ならば、sftoに1を加える
next:
  rrc a
  jnc judge
  inc r3
  ; sftcが1なら、状態をCLOSEにする
judge:
  mov a,r2
  rrc a
  jnc next1
  mov r5,#CLOSE
  ; sftoが1なら、状態をOPENにする
next1:
  mov a,r3
  rrc a
  jnc exit
  mov r5,#OPEN
exit:

 冗長部分を削減しておきます。

  ; shift sftc
  xch a,r2
  rl  a
  ; masking sftc
  anl a,#3
  ; resume
  xch a,r2

  ; shift sfto
  xch a,r3
  rl  a
  ; masking sfto
  anl a,#3
  ; resume
  xch a,r3

  ; get both button state
  in  a,P2
  anl a,#0f0h
  swap a
  rr a
  rr a
  anl a,#3

  ; if C = 1 , then sftc increment
  rrc a
  jnc NEXT1
  inc r2

  ; if O = 1 , then sfto increment
NEXT1:
  rrc a
  jnc NEXT2
  inc r3

  ; if sftc = 1 , then state is CLOSE
NEXT2:
  mov a,r2
  rrc a
  jnc NEXT3
  mov r4,#CLOSE

  ; if sfto = 1 , then state is OPEN
NEXT3:
  mov a,r3
  rrc a
  jnc NEXT4
  mov r4,#OPEN

NEXT4:

 サーボモータのパルスを生成するには、Dタイプの
 フリップフロック4013を利用します。

 セット、リセット端子に、トリガーを入力し
 出力Qの論理値を制御します。

 タイミングチャートでみると、以下。




 0から199をカウントするカウンタの出力を
 デコードして、0でセット。リセットするのは
 11か16にすれば、10か15のパルス幅を
 作り出せます。

 カウンタにROMを接続し、ROMの出力データで
 カウンタのリセット、フリップフロップの
 セット、リセットを生成します。



 回路は、以下とすればよいでしょう。



 8048は、selectorに対し論理値を出力するだけ。

 CLOSE、OPENの論理値は、0か1なので、この
 論理値をselectorに与えます。

 この方式でプログラムを作成すると、以下。

;
;	TEST program for 8048 ( PROASM-II )
;	Copyright (C) 2017 Kensuke Ooyu
;
	INCLUDE 8048.LIB

;*******************
; value and address 
;*******************
TZERO	equ	6
TFLAG	equ	18h
MCNT	equ	19h

CLOSE	equ	0
OPEN	equ	1

;****************
; define symbols
;****************
ENTRY	equ	0h
E_INT	equ	3h
E_TIM	equ	7h

;*******************
; interrupt vectors
;*******************
	org	ENTRY
	jmp	START

	; external interrupt
	org	E_INT
	retr

	; timer interrupt
	org	E_TIM
	jmp	E_TIMX

	org	10h
;**************
; sub routines
;**************
INIT:
	; disable external interrupt
	dis	i
	; disable timer interrupt
	dis	tcnti
	; initialize I/O
	mov	a,#0
	outl	p1,a
	outl	p2,a
	; clear flag
	clr	F0
	; clear counter
	mov	r2,#0
	mov	r3,#0
	mov	r4,#CLOSE
	call	CON_HND
	;
	ret

INIT_TIM:
	; stop counter
	stop	tcnt
	; initialize
	mov	a,#TZERO
	mov	t,a
	; start timer
	strt	t
	;
	ret

E_TIMX:
	; set flag
	cpl	F0
	; stop counter
	stop	tcnt
	; initialize
	mov	a,#TZERO
	mov	t,a
	; start timer
	strt	t
	;
	retr

SFT_HND:
	; shift sftc
	xch	a,r2
	rl	a
	anl	a,#3	; masking sftc
	xch	a,r2	; resume

	; shift sfto
	xch	a,r3
	rl	a
	anl	a,#3	; masking sftc
	xch	a,r3	; resume

	; get both button state
	in	a,P2
	anl	a,#0f0h
	swap	a
	rr	a
	rr	a
	anl	a,#3

	; if C = 1 , then sftc increment
	rrc	a
	jnc	SFT_HND1
	inc	r2
SFT_HND1:
	; if O = 1 , then sfto increment
	rrc	a
	jnc	SFT_HND2
	inc	r3

SFT_HND2:
	; if sftc = 1 , then state is CLOSE
	mov	a,r2
	rrc a
	jnc	SFT_HND3
	mov r4,#CLOSE

SFT_HND3:
	; if sfto = 1 , then state is OPEN
	mov	a,r3
	rrc	a
	jnc	SFT_HND4
	mov r4,#OPEN

SFT_HND4:
	;
	ret

CON_HND:
	; get state
	mov	a,r4
	; impress
	outl	P1,a
	;
	ret

;**************
; main routine
;**************
	org	100h
START:
	call	INIT
	call	INIT_TIM
	; enable
	en	TCNTI
MAIN:
	; judge flag
	jf0	MAINL
	; always branch
	jmp	MAINE

MAINL:
	; clear flag
	clr	F0
	; judge states
	call	SFT_HND
	; set control signal
	call	CON_HND
	;
MAINE:
	;
	jmp	MAIN

	end

 アセンブル結果は、次のようになります。

0000          	;
0000          	;	TEST program for 8048 ( PROASM-II )
0000          	;	Copyright (C) 2017 Kensuke Ooyu
0000          	;
0000          		INCLUDE 8048.LIB
0000          		list
0000          	
0000          	;*******************
0000          	; value and address 
0000          	;*******************
0006          	TZERO	equ	6
0018          	TFLAG	equ 	18h
0019          	MCNT	equ 	19h
0000          	
0000          	CLOSE	equ	0
0001          	OPEN	equ	1
0000          	
0000          	;****************
0000          	; define symbols
0000          	;****************
0000          	ENTRY	equ	0h
0003          	E_INT	equ	3h
0007          	E_TIM	equ	7h
0000          	
0000          	;*******************
0000          	; interrupt vectors
0000          	;*******************
0000          		org	ENTRY
0000 2400    +		jmp	START
0002          	
0002          		; external interrupt
0002          		org	E_INT
0003 93      +		retr
0004          	
0004          		; timer interrupt
0004          		org	E_TIM
0007 0426    +		jmp	E_TIMX
0009          	
0009          		org	10h
0010          	;**************
0010          	; sub routines
0010          	;**************
0010          	INIT:
0010          		; disable external interrupt
0010 15      +		dis	i
0011          		; disable timer interrupt
0011 35      +		dis	tcnti
0012          		; initialize I/O
0012 2300    +		mov	a,#0
0014 39      +		outl	p1,a
0015 3A      +		outl	p2,a
0016          		; clear flag
0016 85      +		clr	F0
0017          		; clear counter
0017 BA00    +		mov	r2,#0
0019 BB00    +		mov	r3,#0
001B BC00    +		mov	r4,#CLOSE
001D 1454    +		call	CON_HND
001F          		;
001F 83      +		ret
0020          	
0020          	INIT_TIM:
0020          		; stop counter
0020 65      +		stop	tcnt
0021          		; initialize
0021 2306    +		mov	a,#TZERO
0023 62      +		mov	t,a
0024          		; start timer
0024 55      +		strt	t
0025          		;
0025 83      +		ret
0026          	
0026          	E_TIMX:
0026          		; set flag
0026 95      +		cpl	F0
0027          		; stop counter
0027 65      +		stop	tcnt
0028          		; initialize
0028 2306    +		mov	a,#TZERO
002A 62      +		mov	t,a
002B          		; start timer
002B 55      +		strt	t
002C          		;
002C 93      +		retr
002D          	
002D          	SFT_HND:
002D          		; shift sftc
002D 2A      +		xch	a,r2
002E E7      +		rl	a
002F 5303    +		anl	a,#3	; masking sftc
0031 2A      +		xch	a,r2	; resume
0032          	
0032          		; shift sfto
0032 2B      +		xch	a,r3
0033 E7      +		rl	a
0034 5303    +		anl	a,#3	; masking sftc
0036 2B      +		xch	a,r3	; resume
0037          	
0037          		; get both button state
0037 0A      +		in	a,P2
0038 53F0    +		anl	a,#0f0h
003A 47      +		swap	a
003B 77      +		rr	a
003C 77      +		rr	a
003D 5303    +		anl	a,#3
003F          	
003F          		; if C = 1 , then sftc increment
003F 67      +		rrc	a
0040 E643    +		jnc	SFT_HND1
0042 1A      +		inc	r2
0043          	SFT_HND1:
0043          		; if O = 1 , then sfto increment
0043 67      +		rrc	a
0044 E647    +		jnc	SFT_HND2
0046 1B      +		inc	r3
0047          	
0047          	SFT_HND2:
0047          		; if sftc = 1 , then state is CLOSE
0047 FA      +		mov	a,r2
0048 67      +		rrc a
0049 E64D    +		jnc	SFT_HND3
004B BC00    +		mov r4,#CLOSE
004D          	
004D          	SFT_HND3:
004D          		; if sfto = 1 , then state is OPEN
004D FB      +		mov	a,r3
004E 67      +		rrc	a
004F E653    +		jnc	SFT_HND4
0051 BC01    +		mov r4,#OPEN
0053          	
0053          	SFT_HND4:
0053          		;
0053 83      +		ret
0054          	
0054          	CON_HND:
0054          		; get state
0054 FC      +		mov	a,r4
0055          		; impress
0055 39      +		outl	P1,a
0056          		;
0056 83      +		ret
0057          	
0057          	;**************
0057          	; main routine
0057          	;**************
0057          		org	100h
0100          	START:
0100 1410    +		call	INIT
0102 1420    +		call	INIT_TIM
0104          		; enable
0104 25      +		en	TCNTI
0105          	MAIN:
0105          		; judge flag
0105 B609    +		jf0	MAINL
0107          		; always branch
0107 240E    +		jmp	MAINE
0109          	
0109          	MAINL:
0109          		; clear flag
0109 85      +		clr	F0
010A          		; judge states
010A 142D    +		call	SFT_HND
010C          		; set control signal
010C 1454    +		call	CON_HND
010E          		;
010E          	MAINE:
010E          		;
010E 2405    +		jmp	MAIN
0110          	
0110          		end

 ポートを入力で使うときには、論理値の'1'を
 書き込んでおかないと、いけないのです。

 パワーオンリセットでは、ポートに全ビットに
 対し、論理値の'1'を設定するので省略しました。

 ROMに入れるデータは、次のようにテキストファイルに
 入れておきます。(ニブル単位で入れています。)

0 0 1
1 0 0
2 0 0
3 0 0
4 0 0
5 0 0
6 0 0
7 0 0
8 0 0
9 0 0
10 0 0
11 0 2
12 0 0
13 0 0
14 0 0
15 0 0
16 0 4
17 0 0
18 0 0
19 0 0
20 0 0
21 0 0
22 0 0
23 0 0
24 0 0
25 0 0
26 0 0
27 0 0
28 0 0
29 0 0
30 0 0
31 0 0
32 0 0
33 0 0
34 0 0
35 0 0
36 0 0
37 0 0
38 0 0
39 0 0
40 0 0
41 0 0
42 0 0
43 0 0
44 0 0
45 0 0
46 0 0
47 0 0
48 0 0
49 0 0
50 0 0
51 0 0
52 0 0
53 0 0
54 0 0
55 0 0
56 0 0
57 0 0
58 0 0
59 0 0
60 0 0
61 0 0
62 0 0
63 0 0
64 0 0
65 0 0
66 0 0
67 0 0
68 0 0
69 0 0
70 0 0
71 0 0
72 0 0
73 0 0
74 0 0
75 0 0
76 0 0
77 0 0
78 0 0
79 0 0
80 0 0
81 0 0
82 0 0
83 0 0
84 0 0
85 0 0
86 0 0
87 0 0
88 0 0
89 0 0
90 0 0
91 0 0
92 0 0
93 0 0
94 0 0
95 0 0
96 0 0
97 0 0
98 0 0
99 0 0
100 0 0
101 0 0
102 0 0
103 0 0
104 0 0
105 0 0
106 0 0
107 0 0
108 0 0
109 0 0
110 0 0
111 0 0
112 0 0
113 0 0
114 0 0
115 0 0
116 0 0
117 0 0
118 0 0
119 0 0
120 0 0
121 0 0
122 0 0
123 0 0
124 0 0
125 0 0
126 0 0
127 0 0
128 0 0
129 0 0
130 0 0
131 0 0
132 0 0
133 0 0
134 0 0
135 0 0
136 0 0
137 0 0
138 0 0
139 0 0
140 0 0
141 0 0
142 0 0
143 0 0
144 0 0
145 0 0
146 0 0
147 0 0
148 0 0
149 0 0
150 0 0
151 0 0
152 0 0
153 0 0
154 0 0
155 0 0
156 0 0
157 0 0
158 0 0
159 0 0
160 0 0
161 0 0
162 0 0
163 0 0
164 0 0
165 0 0
166 0 0
167 0 0
168 0 0
169 0 0
170 0 0
171 0 0
172 0 0
173 0 0
174 0 0
175 0 0
176 0 0
177 0 0
178 0 0
179 0 0
180 0 0
181 0 0
182 0 0
183 0 0
184 0 0
185 0 0
186 0 0
187 0 0
188 0 0
189 0 0
190 0 0
191 0 0
192 0 0
193 0 0
194 0 0
195 0 0
196 0 0
197 0 0
198 0 0
199 0 0
200 0 8
201 0 0
202 0 0
203 0 0
204 0 0
205 0 0
206 0 0
207 0 0
208 0 0
209 0 0
210 0 0
211 0 0
212 0 0
213 0 0
214 0 0
215 0 0
216 0 0
217 0 0
218 0 0
219 0 0
220 0 0
221 0 0
222 0 0
223 0 0
224 0 0
225 0 0
226 0 0
227 0 0
228 0 0
229 0 0
230 0 0
231 0 0
232 0 0
233 0 0
234 0 0
235 0 0
236 0 0
237 0 0
238 0 0
239 0 0
240 0 0
241 0 0
242 0 0
243 0 0
244 0 0
245 0 0
246 0 0
247 0 0
248 0 0
249 0 0
250 0 0
251 0 0
252 0 0
253 0 0
254 0 0
255 0 0

 0から255をテキストに書き込んでおきます。
 AWKスクリプトで0から255をアドレスとみて
 4ビットのデータを生成。
 AWKスクリプトは、以下。

{
  d0 = 0
  d1 = 0
  d2 = 0
  d3 = 0
  if ( $1 == 0   ) { d0 = 1 }
  if ( $1 == 11  ) { d1 = 1 }
  if ( $1 == 16  ) { d2 = 1 }
  if ( $1 == 200 ) { d3 = 1 }
  res = ((d3 * 2 + d2) * 2 + d1) * 2 + d0
  printf("%d 0 %d\n",$1,res)
}

 テキストファイルからROMライターが受け付ける
 HEXファイルフォーマットに変換するときにも
 AWKスクリプトを使いました。その内容は以下。

# bit inverse
function xinverse(x) {
  # default
  result = 0 
  # judge
  if ( x == 0 ) { result = 1 }

  return result
}

# 1's compliment
function bnot(x) {
  # copy
  tmpx = x
  # separate
  x0 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x1 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x2 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x3 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x4 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x5 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x6 = int( tmpx % 2 ) ; tmpx = tmpx / 2 ;
  x7 = int( tmpx % 2 ) ;
  # inverse
  x0 = xinverse(x0) ; x1 = xinverse(x1)
  x2 = xinverse(x2) ; x3 = xinverse(x3)
  x4 = xinverse(x4) ; x5 = xinverse(x5)
  x6 = xinverse(x6) ; x7 = xinverse(x7)
  # calculate
  result = 0 ;
  result = result * 2 + x7 ; result = result * 2 + x6
  result = result * 2 + x5 ; result = result * 2 + x4
  result = result * 2 + x3 ; result = result * 2 + x2
  result = result * 2 + x1 ; result = result * 2 + x0

  return result
}

BEGIN {
  res = 0
}
{
  adr = $1
  ln  = NR - 1
  r = ln % 8
  # show address
  if ( r == 0 ) {
    # data size
    res = res + 8
    # address
    res = res + (adr / 256) + (adr % 256)
    # tmp
    tmp = $2 * 16 + $3
    # 2 data
    res = res + tmp
    # show
    printf(":08%04X00%02X",adr,tmp)
  }
  # add check sum
  if ( r == 7 ) {
    # tmp
    tmp = $2 * 16 + $3
    # add
    res = res + tmp
    # calculate check sum
    result = bnot(res % 256) + 1
    # show
    printf("%02X%02X\n",tmp,result % 256)
    # prepare next
    res = 0
  }
  # others
  if ( r != 0 && r != 7 ) {
    # tmp
    tmp = $2 * 16 + $3
    # add
    res = res + tmp
    # show
    printf("%02X",tmp)
  }
}
END {
  printf(":00000001FF\n")
}

 このスクリプト(mkrom.awk)で生成したHEXファイル
 の内容は、次のようになります。

:080000000100000000000000F7
:080008000000000200000000EE
:080010000400000000000000E4
:080018000000000000000000E0
:080020000000000000000000D8
:080028000000000000000000D0
:080030000000000000000000C8
:080038000000000000000000C0
:080040000000000000000000B8
:080048000000000000000000B0
:080050000000000000000000A8
:080058000000000000000000A0
:08006000000000000000000098
:08006800000000000000000090
:08007000000000000000000088
:08007800000000000000000080
:08008000000000000000000078
:08008800000000000000000070
:08009000000000000000000068
:08009800000000000000000060
:0800A000000000000000000058
:0800A800000000000000000050
:0800B000000000000000000048
:0800B800000000000000000040
:0800C000000000000000000038
:0800C800080000000000000028
:0800D000000000000000000028
:0800D800000000000000000020
:0800E000000000000000000018
:0800E800000000000000000010
:0800F000000000000000000008
:0800F800000000000000000000
:00000001FF


目次

inserted by FC2 system