目次
前
PIC10活用
8ピンの手軽なマイコンとして使ってきたPIC12F1501の
値段が、半導体不足で一気に値上がりしました。
はじめてPIC12F1501を入手した頃は、¥70だったのが
2023年2月現在では、¥140と2倍の金額に。
ハードウエアの置き換えに、金額がかかり過ぎるのは問題。
8ピンで安価なPICマイコンがないのかを探そう。
こう考えて秋月電子のサイトを見ると、PIC10F322が出て
きました。
仕様を見てみます。
プログラムメモリは、512ワード(256バイト)で
RAMが64バイトというので、ハードウエアを置換え
する用途では、充分と判断。
利用できるGPIOが4ピンなので、2入力1出力という
条件を入れて使えば、問題はない。
こう判断して回路で使うために、ピン配置を確認。
6ピンと8ピンのデバイスがって、8ピンだと
リセットピンが8番ピンに割当て。
8ピンのICソケットを使って、基板に実装すれば
リセット回路だけに注意して半田付けするとよい
と判断。
GPIOで使いたい機能をリストして、利用するか否か
の判断をしてみます。
備えていればよい機能は、以下。
データシートで、これらの機能を具備しているか確認。
内蔵レジスタの表から、プルアップ抵抗、外部割込み
タイマー割込みができると理解しました。
内蔵クロックの周波数を、ブロック図から確認。
ハードウエアを置換えるとして、1MHz以上の
クロックで動作するとすれば、充分だと認識して
いるので、問題はないでしょう。
次の回路を、PIC10F322で置換えて、プログラム
サイズがどのくらいになるか、試してみます。
スイッチの接続は、以下。
動作は、次のタイミングチャートを実現すると仮定。
GreateCowBasicを利用して、プログラムを作成してみます。
クロックを4MHzとして、内蔵にします。
また、リセットピンを活用に指定。
#chip 10F322,4
#config MCLRE = On , OSC = Int
4MHzを分周して、タイマー0に与えて1kHzを生成。
このカラクリは、以下。
システムクロックの1/4である1MHzを
プリスケーラで1/4として250kHzを
生成。
250kHzを250分周して、1kHzの
生成とする。
これをBasicのコードで指定。
InitTimer0 Osc,PS0_4
On Interrupt Timer0Overflow Call t0EXEC
1kHzでタイマー割込みを発生させて
変数millisのインクリメントを実現。
Sub t0EXEC
' initialize
TMR0 = 6
' increment
millis = millis + 1
End Sub
カウンタTMR0に6を設定しているのは
255から0に変化するときに割込み
を発生させるので、256-6=250として
250分周に持ち込むため。
変数millisの値を参照して、インターバルを
求めれられれば、いろいろな応用ができると
考えて、タイマー割込みでインクリメントと
します。
変数millisをシステムタイマーのカウント値に
していると、シフトレジスタを使い、スイッチ
のチャタリングを除去できます。
2個のスイッチのチャタリング除去は、次のように
まとめて処理できます。
Sub getSW
' time interval
tflag = 0
gcur = millis
tmpx = gcur - gpre
If tmpx >= GINTERVAL Then
gpre = gcur
tflag = 1
End If
IF tflag = 0 Then
return
End If
' shift
xpsw_sft = xpsw_sft * 2
xwsw_sft = xwsw_sft * 2
' mask
xpsw_sft = xpsw_sft and 0b00001111
xwsw_sft = xwsw_sft and 0b00001111
' update LSB
ptmp = PORTA
If (ptmp and 2) = 0 Then
xpsw_sft = xpsw_sft + 1
End If
If (ptmp and 4) = 0 Then
xwsw_sft = xwsw_sft + 1
End If
' judge
eflag = 0
If xpsw_sft = 7 Then
eflag = 1
End if
If xwsw_sft = 7 Then
eflag = 1
End if
End Sub
指定時間を経過するたびに、スイッチの状態を入力して
レジスタ値を更新していきます。
レジスタ値が規定値になったら、フラグで出力論理レベル
を扱うブロックに通知。
出力論理レベルを扱うブロックは、ステートマシンを
使って、規定時間だけ'H'を出力させます。
ステートマシンは、次の状態遷移図で表現。
プログラムでは、次のようにまとめられます。
Sub do_perform
Select Case state
' wait trigger
Case 0
state = 0
If eflag = 1 Then
eflag = 0
state = state + 1
End If
' set counter and send 'H'
Case 1
state = state + 1
xcur = millis + XINTERVAL
LATA = 1
' Wait
Case 2
state = 2
If xcur <= millis Then
state = state + 1
End If
' reset and first state
Case 3
state = 0
LATA = 0
' others
Case Else
state = 0
End Select
End Sub
GPIOの初期化、変数の初期値設定等を
ひとつにまとめます。
Sub InitPort
' initial value
LATA = 0
' direction
TRISA = 0xFE
' pull up
WPUA = 0x06
' others
TMR0 = 6
state = 0
xpsw_sft = 0
xwsw_sft = 0
eflag = 0
tflag = 0
gpre = millis
gcur = gpre
millis = 0
End Sub
スイッチの状態を判断し、出力に論理値の'H'か'L'を
出力するのは、ループで実現。
Do
' get switch state
getSW
' perform
do_perform
'
LOOP
GreateCowBasicの全体コードは、以下。
' PIC10F322 test code
#chip 10F322,4
#config MCLRE = On , OSC = Int
#define GINTERVAL 10
#define XINTERVAL 1000
Dim millis As Long
Dim xpsw_sft As Byte
Dim xwsw_sft As Byte
Dim eflag As Bit
Dim tflag As Bit
Dim tmpx As Byte
Dim ptmp As Byte
Dim xcur As Long
Dim gcur As Long
Dim gpre As Long
Dim state As Byte
InitTimer0 Osc,PS0_4
On Interrupt Timer0Overflow Call t0EXEC
' initialize port direction
InitPort
' enable timer 0
StartTimer 0
' endless loop
Do
' get switch state
getSW
' perform
do_perform
'
LOOP
' subroutine initialize
Sub InitPort
' initial value
LATA = 0
' direction
TRISA = 0xFE
' pull up
WPUA = 0x06
' others
TMR0 = 6
state = 0
xpsw_sft = 0
xwsw_sft = 0
eflag = 0
tflag = 0
gpre = millis
gcur = gpre
millis = 0
End Sub
Sub t0EXEC
' initialize
TMR0 = 6
' increment
millis = millis + 1
End Sub
Sub getSW
' time interval
tflag = 0
gcur = millis
tmpx = gcur - gpre
If tmpx >= GINTERVAL Then
gpre = gcur
tflag = 1
End If
IF tflag = 0 Then
return
End If
' shift
xpsw_sft = xpsw_sft * 2
xwsw_sft = xwsw_sft * 2
' mask
xpsw_sft = xpsw_sft and 0b00001111
xwsw_sft = xwsw_sft and 0b00001111
' update LSB
ptmp = PORTA
If (ptmp and 2) = 0 Then
xpsw_sft = xpsw_sft + 1
End If
If (ptmp and 4) = 0 Then
xwsw_sft = xwsw_sft + 1
End If
' judge
eflag = 0
If xpsw_sft = 7 Then
eflag = 1
End if
If xwsw_sft = 7 Then
eflag = 1
End if
End Sub
Sub do_perform
Select Case state
' wait trigger
Case 0
state = 0
If eflag = 1 Then
eflag = 0
state = state + 1
End If
' set counter and send 'H'
Case 1
state = state + 1
xcur = millis + XINTERVAL
LATA = 1
' Wait
Case 2
state = 2
If xcur <= millis Then
state = state + 1
End If
' reset and first state
Case 3
state = 0
LATA = 0
' others
Case Else
state = 0
End Select
End Sub
コンパイル、リンクして、どのくらいの
プログラムサイズになるのかを見ると
次のようになりました。
プログラムメモリ容量の半分くらいとなったので
ハードウエアの置換えには使えると、判断してます。
どんなアセンブリ言語に変換されているのかを、見ると
以下のようになっています。
;********************************************************************************
;Set up the assembler options (Chip type, clock source, other bits and pieces)
LIST p=10F322, r=DEC
#include <P10F322.inc>
__CONFIG _LVP_OFF & _MCLRE_ON & _WDTE_OFF & _FOSC_INTOSC
;********************************************************************************
;Set aside memory locations for variables
GCUR EQU 64
GCUR_E EQU 67
GCUR_H EQU 65
GCUR_U EQU 66
GPRE EQU 68
GPRE_E EQU 71
GPRE_H EQU 69
GPRE_U EQU 70
MILLIS EQU 72
MILLIS_E EQU 75
MILLIS_H EQU 73
MILLIS_U EQU 74
PTMP EQU 76
SAVEPCLATH EQU 77
STATE EQU 78
SYSBITVAR0 EQU 79
SYSBYTETEMPA EQU 117
SYSBYTETEMPB EQU 121
SYSBYTETEMPX EQU 112
SYSLONGTEMPA EQU 117
SYSLONGTEMPA_E EQU 120
SYSLONGTEMPA_H EQU 118
SYSLONGTEMPA_U EQU 119
SYSLONGTEMPB EQU 121
SYSLONGTEMPB_E EQU 124
SYSLONGTEMPB_H EQU 122
SYSLONGTEMPB_U EQU 123
SYSSTATUS EQU 127
SYSTEMP1 EQU 80
SYSTEMP2 EQU 81
SYSW EQU 126
TMPX EQU 82
TMRNUMBER EQU 83
TMRPRES EQU 84
TMRSOURCE EQU 85
XCUR EQU 86
XCUR_E EQU 89
XCUR_H EQU 87
XCUR_U EQU 88
XPSW_SFT EQU 90
XWSW_SFT EQU 91
;********************************************************************************
;Vectors
ORG 0
pagesel BASPROGRAMSTART
goto BASPROGRAMSTART
ORG 4
Interrupt
;********************************************************************************
;Save Context
movwf SysW
swapf STATUS,W
movwf SysSTATUS
banksel STATUS
;Store system variables
movf PCLATH,W
movwf SavePCLATH
clrf PCLATH
;On Interrupt handlers
btfss INTCON,TMR0IE
goto NotTMR0IF
btfss INTCON,TMR0IF
goto NotTMR0IF
call T0EXEC
bcf INTCON,TMR0IF
goto INTERRUPTDONE
NotTMR0IF
;User Interrupt routine
INTERRUPTDONE
;Restore Context
;Restore system variables
movf SavePCLATH,W
movwf PCLATH
swapf SysSTATUS,W
movwf STATUS
swapf SysW,F
swapf SysW,W
retfie
;********************************************************************************
;Start of program memory page 0
ORG 27
BASPROGRAMSTART
;Call initialisation routines
call INITSYS
;Enable interrupts
bsf INTCON,GIE
bsf INTCON,PEIE
;Start of the main program
;PIC10F322 test code
;
;#define GINTERVAL 10
;#define XINTERVAL 1000
;Dim millis As Long
;Dim xpsw_sft As Byte
;Dim xwsw_sft As Byte
;Dim eflag As Bit
;Dim tflag As Bit
;Dim tmpx As Byte
;Dim ptmp As Byte
;Dim xcur As Long
;Dim gcur As Long
;Dim gpre As Long
;Dim state As Byte
;InitTimer0 Osc,PS0_4
movlw 1
movwf TMRSOURCE
movlw 1
movwf TMRPRES
call INITTIMER0156
;On Interrupt Timer0Overflow Call t0EXEC
bsf INTCON,TMR0IE
;initialize port direction
;InitPort
call INITPORT
;enable timer 0
;StartTimer 0
clrf TMRNUMBER
call STARTTIMER
;endless loop
;Do
SysDoLoop_S1
;get switch state
;getSW
call GETSW
;perform
;do_perform
call DO_PERFORM
;
;LOOP
goto SysDoLoop_S1
SysDoLoop_E1
;subroutine initialize
BASPROGRAMEND
sleep
goto BASPROGRAMEND
;********************************************************************************
DO_PERFORM
;Select Case state
;wait trigger
;Case 0
SysSelect1Case1
movf STATE,F
btfss STATUS, Z
goto SysSelect1Case2
;state = 0
clrf STATE
;If eflag = 1 Then
btfss SYSBITVAR0,0
goto ENDIF7
;eflag = 0
bcf SYSBITVAR0,0
;state = state + 1
incf STATE,F
;End If
ENDIF7
;set counter and send 'H'
;Case 1
goto SysSelectEnd1
SysSelect1Case2
decf STATE,W
btfss STATUS, Z
goto SysSelect1Case3
;state = state + 1
incf STATE,F
;xcur = millis + XINTERVAL
movlw 232
addwf MILLIS,W
movwf XCUR
movlw 3
btfsc STATUS,C
movlw 3 + 1
addwf MILLIS_H,W
movwf XCUR_H
movlw 0
btfsc STATUS,C
movlw 0 + 1
addwf MILLIS_U,W
movwf XCUR_U
movlw 0
btfsc STATUS,C
movlw 0 + 1
addwf MILLIS_E,W
movwf XCUR_E
;LATA = 1
movlw 1
movwf LATA
;Wait
;Case 2
goto SysSelectEnd1
SysSelect1Case3
movlw 2
subwf STATE,W
btfss STATUS, Z
goto SysSelect1Case4
;state = 2
movlw 2
movwf STATE
;If xcur <= millis Then
movf XCUR,W
movwf SysLONGTempB
movf XCUR_H,W
movwf SysLONGTempB_H
movf XCUR_U,W
movwf SysLONGTempB_U
movf XCUR_E,W
movwf SysLONGTempB_E
movf MILLIS,W
movwf SysLONGTempA
movf MILLIS_H,W
movwf SysLONGTempA_H
movf MILLIS_U,W
movwf SysLONGTempA_U
movf MILLIS_E,W
movwf SysLONGTempA_E
call SysCompLessThan32
comf SysByteTempX,F
btfsc SysByteTempX,0
;state = state + 1
incf STATE,F
;End If
ENDIF8
;reset and first state
;Case 3
goto SysSelectEnd1
SysSelect1Case4
movlw 3
subwf STATE,W
btfss STATUS, Z
goto SysSelect1Case5
;state = 0
clrf STATE
;LATA = 0
clrf LATA
;others
;Case Else
goto SysSelectEnd1
SysSelect1Case5
;state = 0
clrf STATE
;End Select
SysSelectEnd1
return
;********************************************************************************
GETSW
;time interval
;tflag = 0
bcf SYSBITVAR0,1
;gcur = millis
movf MILLIS,W
movwf GCUR
movf MILLIS_H,W
movwf GCUR_H
movf MILLIS_U,W
movwf GCUR_U
movf MILLIS_E,W
movwf GCUR_E
;tmpx = gcur - gpre
movf GPRE,W
subwf GCUR,W
movwf TMPX
;If tmpx >= GINTERVAL Then
movlw 10
subwf TMPX,W
btfss STATUS, C
goto ENDIF1
;gpre = gcur
movf GCUR,W
movwf GPRE
movf GCUR_H,W
movwf GPRE_H
movf GCUR_U,W
movwf GPRE_U
movf GCUR_E,W
movwf GPRE_E
;tflag = 1
bsf SYSBITVAR0,1
;End If
ENDIF1
;IF tflag = 0 Then
btfss SYSBITVAR0,1
;return
return
;End If
ENDIF2
;shift
;xpsw_sft = xpsw_sft * 2
bcf STATUS,C
rlf XPSW_SFT,F
;xwsw_sft = xwsw_sft * 2
bcf STATUS,C
rlf XWSW_SFT,F
;mask
;xpsw_sft = xpsw_sft and 0b00001111
movlw 15
andwf XPSW_SFT,F
;xwsw_sft = xwsw_sft and 0b00001111
movlw 15
andwf XWSW_SFT,F
;update LSB
;ptmp = PORTA
movf PORTA,W
movwf PTMP
;If (ptmp and 2) = 0 Then
movlw 2
andwf PTMP,W
movwf SysTemp1
movwf SysBYTETempA
clrf SysBYTETempB
call SysCompEqual
btfsc SysByteTempX,0
;xpsw_sft = xpsw_sft + 1
incf XPSW_SFT,F
;End If
ENDIF3
;If (ptmp and 4) = 0 Then
movlw 4
andwf PTMP,W
movwf SysTemp1
movwf SysBYTETempA
clrf SysBYTETempB
call SysCompEqual
btfsc SysByteTempX,0
;xwsw_sft = xwsw_sft + 1
incf XWSW_SFT,F
;End If
ENDIF4
;judge
;eflag = 0
bcf SYSBITVAR0,0
;If xpsw_sft = 7 Then
movlw 7
subwf XPSW_SFT,W
btfsc STATUS, Z
;eflag = 1
bsf SYSBITVAR0,0
;End if
ENDIF5
;If xwsw_sft = 7 Then
movlw 7
subwf XWSW_SFT,W
btfsc STATUS, Z
;eflag = 1
bsf SYSBITVAR0,0
;End if
ENDIF6
return
;********************************************************************************
INITPORT
;initial value
;LATA = 0
clrf LATA
;direction
;TRISA = 0xFE
movlw 254
movwf TRISA
;pull up
;WPUA = 0x06
movlw 6
movwf WPUA
;others
;TMR0 = 6
movlw 6
movwf TMR0
;state = 0
clrf STATE
;xpsw_sft = 0
clrf XPSW_SFT
;xwsw_sft = 0
clrf XWSW_SFT
;eflag = 0
bcf SYSBITVAR0,0
;tflag = 0
bcf SYSBITVAR0,1
;gpre = millis
movf MILLIS,W
movwf GPRE
movf MILLIS_H,W
movwf GPRE_H
movf MILLIS_U,W
movwf GPRE_U
movf MILLIS_E,W
movwf GPRE_E
;gcur = gpre
movf GPRE,W
movwf GCUR
movf GPRE_H,W
movwf GCUR_H
movf GPRE_U,W
movwf GCUR_U
movf GPRE_E,W
movwf GCUR_E
;millis = 0
clrf MILLIS
clrf MILLIS_H
clrf MILLIS_U
clrf MILLIS_E
return
;********************************************************************************
INITSYS
;asm ShowDebug ChipIntOSCCONFormat is ChipIntOSCCONFormat
;1 is 1
;The section now handles two true table for frequency
;Supports 18f2425 (type1 max frq of 8mhz) classes and 18f26k22 (type2 max frq of 16mhz) classes
;Assumes that testing the ChipMaxMHz >= 48 is a valid test for type2 microcontrollers
;Supports IntOsc MaxMhz of 64 and not 64 ... there may be others true tables that GCB needs to support
;asm showdebug OSCCON type is 104' NoBit(SPLLEN) And NoBit(IRCF3) Or Bit(INTSRC)) and ifdef Bit(HFIOFS)
;osccon type is 104
;OSCCON = OSCCON AND b'10001111'
movlw 143
andwf OSCCON,F
;Address the two true tables for IRCF
;[canskip] IRCF2, IRCF1, IRCF0 = b'101' ;101 = 4 MHz
bsf OSCCON,IRCF2
bcf OSCCON,IRCF1
bsf OSCCON,IRCF0
;Ensure all ports are set for digital I/O and, turn off A/D
;Switch off A/D with NoVar(ADCON0)
;Set ADCON.ADON Off
bcf ADCON,ADON
;Commence clearing any ANSEL variants in the part
;ANSELA = 0
clrf ANSELA
;End clearing any ANSEL variants in the part
;Turn off all ports
;GPIO = 0
clrf PORTA
;PORTA = 0
clrf PORTA
return
;********************************************************************************
;Overloaded signature: BYTE:BYTE:
INITTIMER0156
;Some PICS (18F+) Use T0CON for timer0 Control
;ALL OTHER PICS USE OPTION_REG for timer0 control
;Sub modified to set all TMR Control bits at once
;* TMRPres, TMRSource & TMRPost now shared *
;if TMRPRes > 7 then TMRPRes = 0 'failsafe
movf TMRPRES,W
sublw 7
btfss STATUS, C
clrf TMRPRES
ENDIF10
;If Timer0 is 16-bit capable
;Re-Use TMRPres as T0CON Temp_register
;Keep T0CON 7:6 and write bits 2:0 from TMRPres
;Bits 5,4 & 3 will be cleared!
;TMRPres = (OPTION_REG AND 192) OR TMRPres
movlw 192
andwf OPTION_REG,W
movwf SysTemp1
iorwf TMRPRES,F
;IF TMRSource = EXT then
movlw 2
subwf TMRSOURCE,W
btfss STATUS, Z
goto ELSE11_1
;Set TMRPres.5 ON 'EXT
bsf TMRPRES,5
;ELSE
goto ENDIF11
ELSE11_1
;Set TMRPres.5 OFF 'OSC
bcf TMRPRES,5
;END IF
ENDIF11
;Now Write the OPTION_REG
;OPTION_REG = TMRPres
movf TMRPRES,W
movwf OPTION_REG
;Added For baseline Chips with write only option_reg
;If Timer0 is 16-bit capable
return
;********************************************************************************
STARTTIMER
;IF TMRNumber = 2 then Set TMR2ON on
movlw 2
subwf TMRNUMBER,W
btfsc STATUS, Z
bsf T2CON,TMR2ON
ENDIF9
return
;********************************************************************************
SYSCOMPEQUAL
;Dim SysByteTempA, SysByteTempB, SysByteTempX as byte
;clrf SysByteTempX
clrf SYSBYTETEMPX
;movf SysByteTempA, W
movf SYSBYTETEMPA, W
;subwf SysByteTempB, W
subwf SYSBYTETEMPB, W
;btfsc STATUS, Z
btfsc STATUS, Z
;comf SysByteTempX,F
comf SYSBYTETEMPX,F
return
;********************************************************************************
SYSCOMPLESSTHAN32
;dim SysLongTempA as long
;dim SysLongTempB as long
;dim SysByteTempX as byte
;clrf SysByteTempX
clrf SYSBYTETEMPX
;Test Exp, exit if more
;movf SysLongTempA_E,W
movf SYSLONGTEMPA_E,W
;subwf SysLongTempB_E,W
subwf SYSLONGTEMPB_E,W
;btfss STATUS,C
btfss STATUS,C
;return
return
;If not more and not zero, is less
;btfss STATUS,Z
btfss STATUS,Z
;goto SCLT32True
goto SCLT32TRUE
;Test Upper, exit if more
;movf SysLongTempA_U,W
movf SYSLONGTEMPA_U,W
;subwf SysLongTempB_U,W
subwf SYSLONGTEMPB_U,W
;btfss STATUS,C
btfss STATUS,C
;return
return
;If not more and not zero, is less
;btfss STATUS,Z
btfss STATUS,Z
;goto SCLT32True
goto SCLT32TRUE
;Test High, exit if more
;movf SysLongTempA_H,W
movf SYSLONGTEMPA_H,W
;subwf SysLongTempB_H,W
subwf SYSLONGTEMPB_H,W
;btfss STATUS,C
btfss STATUS,C
;return
return
;If not more and not zero, is less
;btfss STATUS,Z
btfss STATUS,Z
;goto SCLT32True
goto SCLT32TRUE
;Test Low, exit if more or equal
;movf SysLongTempB,W
movf SYSLONGTEMPB,W
;subwf SysLongTempA,W
subwf SYSLONGTEMPA,W
;btfsc STATUS,C
btfsc STATUS,C
;return
return
SCLT32TRUE
;comf SysByteTempX,F
comf SYSBYTETEMPX,F
return
;********************************************************************************
T0EXEC
;initialize
;TMR0 = 6
movlw 6
movwf TMR0
;increment
;millis = millis + 1
incf MILLIS,F
btfsc STATUS,Z
incf MILLIS_H,F
btfsc STATUS,Z
incf MILLIS_U,F
btfsc STATUS,Z
incf MILLIS_E,F
return
;********************************************************************************
END
アセンブリ言語で見ると、IF文の条件判断で冗長な処理を
していると、わかったので、次のように記述を変更して
プログラム容量が減るかを試してみます。
' update LSB
ptmp = PORTA
ptmpa = ptmp and 2
ptmpb = ptmp and 4
If ptmpa = 0 Then
xpsw_sft = xpsw_sft + 1
End If
If ptmpb = 0 Then
xwsw_sft = xwsw_sft + 1
End If
コンパイル、リンクの結果は、次のようになりプログラム容量が
減ったことがわかります。
50%以上から50%未満になりました。
GCBasicのプログラムは、判定処理を高速にするには
メモリ(レジスタ)の値だけに注目する方がよいと
ノウハウを得たと言ってよいでしょう。
目次
前