この連載の途中でだいぶ日にちが空いてしまいましたが、Arduino地震計の第2回目、プログラムの説明に入ります。
オリジナル工作が、「できる」ということがわかったとたんに、その後の取り組みスピードが遅くなりますね^^; 今月は仕事と旅程でだいぶふさがったのが原因ではありますが、掲載がゆっくりですみません。
上の写真は試作回路の現状で、前の記事の後でRTC(リアルタイムクロック)のDS3231をI2C接続し、そして使用中のSRAMを表示するためのLED(赤、緑、青)をつけた状態です。最初はLEDは右上のブレッドボードにつけていましたが、配線が込み合うので左上に小さいブレッドボードを加えてつけなおしました。右上のブレッドボードからLEDのグランド配線(右下に3本ある裸ジャンパー)を取り除くの忘れてますが後で外しておきます。
次に回路図を再掲します。
LED3個とI2C接続のDS3231を、この回路図のとおりに加えただけです。
Arduinoスケッチのグローバル変数等の定義部分は次のとおりです。
/**********************************************************
New Seismometer Nov.24,2019
(c)2019 Akira Tominaga, All rights reserved.
**********************************************************/
#include "Wire.h"
#include "SPI.h"
// SPI MOSI:11 MISO:12 SCK:13
int cS; // chip-select pin (variable)
#define cS0 10 // chip-select 0 for SRAM0
#define cS1 9 // chip-select 1 for SRAM1
#define cS2 8 // chip-select 2 for SRAM2
#define cSmin 8 // for chip-select shifting
#define cSmax 10 // for chip-select shifting
int LED; // LED to show currently used SRAM
#define LED0 7 // SRAM0 used now - Red
#define LED1 6 // SRAM1 used now - Green
#define LED2 5 // SRAM2 used now - Blue
#define LEDmin 5 // for LED shifting
#define LEDmax 7 // for LED shifting
#define Sw 3 // Tact switch at D3
// (to be replaced by PIC signal(L) generated by IR sig)
#define Timing 16 // Timing signal(L) at A2=D16
#define testPin 2 // Test signal pin D2
// Accelerometer LSM6DS3
#define Accel 0x6B // Accelorometer addr 0x6B (PIC=D6)
int16_t Galx10[3] = {0, 0, 0}; // measured Gal x 10
int32_t usualGalx10[3]; // usual Galx10 for calculation
byte Qflags = B00000000; // status to record to SRAM
#define nowQ B10000000 // currently quaking
#define wasQ B01000000 // there was a quake
float qVal = 0; // quake value
int32_t magQ = 0; // total/avg Q to check quake
#define magQth 20 // quake threshold (10 in real env ?)
int16_t magQctr = 0; // counter to get average magQ
#define magQcmax 50 // magQ counter max value (1 sec)
int16_t qEctr = 0; // Q end counter to judge end of Q
#define qEcmax 250 // no quake for continuous 5 secs
#define serSpeed 9600
#define srCM 0x01 // Mode command of SRAM
#define srCMseq 0x40 // Mode=sequential
#define srCW 0x02 // Write command of SRAM
#define srCR 0x03 // Read command of SRAM
uint32_t srAdr = 0; // address in SRAM
#define srAdrMax 131071
/* One rec consists of 4x16bit-int [fileID+Qflags,X,Y,Z]
[rec at Time of quakeEnd to be replaced with the Time
of which format is ["FFFF",YY*12+MM,DD*24+hh,mm*60+ss]
*/
int16_t Rec[4]; // integer array for recording
int16_t fileID = 0; // file ID(repeat 0-250, 16384 recs/file)
#define fileIDmax 250 // repeat from 0 to 250
// for RTC (real time clock)
byte vR[8]; // values in RTC registers
int vI[8] = { 0, 0, 0, 0, 0, 0, 0, 0}; // integers for RTC data
#define RTC_addr 0x68 // I2C address
#define mds 1 // ss
#define mdm 2 // mm
#define mdh 3 // hh
#define mdW 4 // WW=Day of Week
#define mdD 5 // DD
#define mdM 6 // MM
#define mdY 7 // YY
ピンの割り当てはスケッチをみていただいたほうが、分りやすいかもしれません。
これから本番機を少しずつ作りながら、Arduinoのスケッチを説明していこうと思います。
本番機では、SRAMを交換する際に振動を感知させない処理をいれることと、取り出したSRAMのデータをSDカードへテキストに変換して移す別装置を加えるつもりです。
次にこのArduinoスケッチの現在のSetup内容を掲載します。ここは今後の本番機の仕上がり状況によっては少し変える可能性がありますが。
void setup() {
Serial.begin(serSpeed);
pinMode(Sw, INPUT_PULLUP);
pinMode(Timing, INPUT_PULLUP);
for (cS = 0; cS < 3; cS++) {
pinMode(cS, OUTPUT);
digitalWrite(cS, HIGH);
}
for (LED = 0; LED < 3; LED++) {
pinMode(LED, OUTPUT);
digitalWrite(cS, LOW);
}
pinMode(testPin, OUTPUT);
digitalWrite(testPin, LOW);
//Initialize accelerometer
Wire.begin();
delay(1); // unneeded ?
initAcc();
SPI.begin();
// SPISettings mySPI = SPISettings(4000000, MSBFIRST, SPI_MODE0);
// SPI.beginTransaction(mySPI); // default values are okay
//Set SRAMs sequential mode (though default)
for (cS = 0; cS < 3; cS++) {
digitalWrite(cS, LOW);
SPI.transfer(srCM); // command "Mode Writing"
SPI.transfer(srCMseq); // set seequential mode
digitalWrite(cS, HIGH);
delay(1); // delay for debug purpose
}
cS = cS0; // prepare chip-select as SRAM0
LED = LED0; // prepare to show SRAM0 is used
// get usual galx10 values
#define nAvg 100
delay(500); // avoid initial vibration
for (int j = 0; j < nAvg; j++) {
readAcc(); // read values in Galx10[3]
delay(1); // set plenty of time
for (int i = 0; i < 3; i++) {
usualGalx10[i] = usualGalx10[i] + Galx10[i];
}
}
for (int i = 0; i < 3; i++) {
usualGalx10[i] = usualGalx10[i] / nAvg;
}
/*
Serial.print("10x usualX=");
Serial.print(usualGalx10[0]);
Serial.print(" Y=");
Serial.print(usualGalx10[1]);
Serial.print(" Z=");
Serial.println(usualGalx10[2]);
*/
/* wPushButton(); // wait for button pushed
delay(500); // avoid vibration by button
Serial.println("Start");
*/
}
Loop部分以降は今後の本番機製作続行に合わせて載せていきたいと思います。現時点でのユーザー定義関数は次のとおりです。まだコメントが十分に入っておらずすみませんが、とりあえず現状です。装置の初期化などもこちらに入っています。
ライブラリーを使う代わりに必要箇所だけ装置異存のコーディングにしたところは、絶対値等含め良いコーディングではないです^^; しかし、Loop部分を含め全体でスケッチ、グローバル変数共に容量の1/4未満しか使用せず、ATmega328Pの余裕はたっぷりです。
/***************************************
User defined functions
***************************************/
// *** Initialize LSM6DS3 "initAcc()"
void initAcc(void) { //
Wire.beginTransmission(Accel);
Wire.write(0x18); //CTLr9_L
Wire.write(0x38); //Acc XYZ axis enabled
Wire.endTransmission();
Wire.beginTransmission(Accel);
Wire.write(0x11); //CTL2_G
Wire.write(0x00); //Gyro not used
Wire.endTransmission();
Wire.beginTransmission(Accel);
Wire.write(0x10); //CTRL1_XL
Wire.write(B00110011); //range2G, anti-alias 50Hz
Wire.endTransmission();
Wire.beginTransmission(Accel);
Wire.write(0x13); //CTL4_C
Wire.write(10000000); //BandW set by CTRL1_XL
Wire.endTransmission();
Wire.beginTransmission(Accel);
Wire.write(0x15); //CTL4_C
Wire.write(0x80); // disable Gyro trig and XL high performance
Wire.endTransmission();
Wire.beginTransmission(Accel);
Wire.write(0x11); //CTL2_G
Wire.write(0x00); //Gyro not used
Wire.endTransmission();
}
// *** read LSM6DS3 "readAcc()"
void readAcc(void) {
Wire.beginTransmission(Accel);
Wire.write(0x28); // address of top of measured values
Wire.endTransmission();
Wire.requestFrom(Accel, 6);
delay(1); // wait for measurement ready
while (Wire.available() < 6) {} // wait for data ready
int16_t Bytes;
for (int i = 0; i < 3; i++) {
// Data sent LSB first (little endian by default),
// defined by BLE bit1=0 in CTRL3_C reg(0X12)
byte ByteL = Wire.read();
byte ByteH = Wire.read();
Bytes = ByteH * 256 + ByteL;
// followings are of no use for Arduino (for other mc only)
// if ((ByteH & 0x80) == 0x80) // if negative value
// {
// ByteH = ~ByteH; // get complement of ByteH
// ByteL = ~ByteL; // get complement of BYteL
// Bytes = -(uint16_t)(ByteH * 256 + ByteL)-1;
// }
// calc Galx10: refer to Table18 in AN4650 of LSM6DS3
Galx10[i] = Bytes * 10.0 * (980.655 / 16393.0);
}
}
// *** Write 8 byte Rec at srAdr "wRec()"
void wRec(void) {
digitalWrite(cS, LOW);
SPI.transfer (srCW);
SPI.transfer ((byte)(srAdr >> 16));
SPI.transfer ((byte)(srAdr >> 8));
SPI.transfer ((byte)srAdr);
for (int i = 0; i < 4; i++) {
SPI.transfer ((byte)(Rec[i] >> 8));
SPI.transfer ((byte)Rec[i]);
}
digitalWrite(cS, HIGH);
}
// *** Shift SRAM to next
void shiftSram(void) {
// write quake-end inf, as the last record
// which is ["FFFF",YY*12+MM,DD*24+hh,mm*60+ss]
rRTC();
cR2I(); // convert RTC to Integer format
Rec[0] = -1;
Rec[1] = vI[mdY] * 12 + vI[mdM];
Rec[2] = vI[mdD] * 24 + vI[mdh];
Rec[3] = vI[mdm] * 60 + vI[mds];
wRec(); // write Rec to current srAdr
// shift cS (shift SRAM)
cS--;
srAdr = 0;
if (cS < cSmin)
{
cS = cSmax;
}
// shift LED
digitalWrite(LED, LOW);
LED--;
if (LED < LEDmin)
{
LED = LEDmax;
}
digitalWrite(LED, HIGH);
}
// *** Read 8 byte Rec at srAdr : rRec()
void rRec(void) {
digitalWrite(cS, LOW);
SPI.transfer (srCR);
SPI.transfer ((byte)(srAdr >> 16));
SPI.transfer ((byte)(srAdr >> 8));
SPI.transfer ((byte)srAdr);
for (int i = 0; i < 4; i++) {
byte rByte0 = SPI.transfer(0x00);
byte rByte1 = SPI.transfer(0x00);
Rec[i] = rByte0 * 256 + rByte1;
}
digitalWrite(cS, HIGH);
}
// *** wait for button pushed : wPushButton()
void wPushButton(void) {
Serial.println("Button pls");
while (digitalRead(Sw) == HIGH) {}
while (digitalRead(Sw) == LOW) {}
}
// *** read Real-Time-Clock
void rRTC(void) {
Wire.beginTransmission(RTC_addr);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(RTC_addr, 7);
while (Wire.available() < 7) {} // wait for data ready
for (int i = 1; i < 8; i++) {
vR[i] = Wire.read();
}
// Wire.endTransmission();
}
// *** convert RTC-format to Integers
void cR2I(void) {
vI[mds] = ((vR[mds] & B01110000) / 16) * 10 + (vR[mds] & B00001111);
vI[mdm] = ((vR[mdm] & B01110000) / 16) * 10 + (vR[mdm] & B00001111);
vI[mdh] = ((vR[mdh] & B00100000) / 32) * 20 + ((vR[mdh] & B00010000) / 16) * 10 + (vR[mdh] & B00001111);
// vI[mdW] = vR[mdW];
vI[mdD] = ((vR[mdD] & B01110000) / 16) * 10 + (vR[mdD] & B00001111);
vI[mdM] = ((vR[mdM] & B00010000) / 16) * 10 + (vR[mdM] & B00001111);
vI[mdY] = ((vR[mdY] & B11110000) / 16) * 10 + (vR[mdY] & B00001111);
}
// *** for test only
void testEnd(void) {
for (srAdr = 0; srAdr < 131072; srAdr = srAdr + 8) {
Serial.print(srAdr);
Serial.print("=");
rRec();
for (int i = 0; i < 4; i++) {
Serial.print(Rec[i]);
Serial.print(",");
}
Serial.println("");
}
while (1) {}
}
最後にある関数は単なるテスト用ですので無視してください。
上のコーディング中、Junichi Takao様にご指摘をいただき直させていただいたのは次のミスです(2019.11.26)。的確なご指摘ありがとうございます。また、お手数をおかけしました。
間違い: if ((ByteH && 0x80) == 0x80) { // if negative value
修正済: if ((ByteH & 0x80) == 0x80) { // if negative value
テストではロジックアナライザーで受けた信号を手計算した値とこのプログラムのアウトプットの値とが、どれも一致していたため気づきませんでした。前の記事の最後のグラフはこのプログラムのアウトプットで不自然な点もありませんですし。
(以下2019.11.29追加記述)簡単なテスト結果はif文以下が不要で削除(コメント化)しました。追加のご指摘もそのように頂きました(ありがとうございます)。
他のマイクロコントローラー機種では演算がintegerにどう変換されるかが違うことも多くありますので、ATmega環境に不案内にて余計なコーディングをしたうえ、そこへ行かない間違いをしました<(_ _)>。テストをして確認したところ、前のif文以下がもし実行されると下位1ビットに誤差1(0.03ガルほど)が出ます(0をブール反転すると-1になるためです)。使うのが0.1ガル単位なのでほぼ無視できそうですが、後でFFT変換したりするのに若干影響しそう。今ではコメントの中とはいえ一応正しい式に直しておきました。これと関係ありませんが、例えばArduinoでReferenceになかったatoiかitoa関数が動きましたが、使うとLoop内で多数回に1度だけエラーがでるのをかつて経験、以後自信のない仕様は面倒なので避けるという癖となっておりました^^; 今回の件の簡単なテスト結果をこの記事の最後につけておきます。
さて、前の記事で書いたとおり、正確なタイミングで20mS単位のサンプリングをするためのトリガーを出しているのは8ピンPICです。そのアセンブラー・プログラムを示します。正確な50.00Hz(周期20.00mS)信号が得られます。
Cで正確に作るのは困難のためアセンブラーで作っています。ですが作る時間はわずか。筆者が普段作っているPICプログラムからのコピペだけで殆どできましたから。
;U1910-Xtal-Timer-12F1822-V00-01.asm As of Oct. 30, 2019
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; Xtal Timer with PIC12F1822 Version 00-01 ;
; All rights reserved. 2018(C) Akira Tominaga ;
; Function ;
; ;
; Input/Output for 16F1823 ;
; RA0 LEDr output (on =H) ;
; RA1 NC ;
; RA2 Timing Signal output Tmg(on =L) ;
; RA4 Osc2 for Xtal HS 16MHz ;
; RA5 Osc1 for Xtal HS 16MHz ;
; Remarks ;
; 1. Clock = HF Xtal ( 16.000MHz) ;
; Hence 1 step = 0.25 micro seconds ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
page
list p=12F1822 ; list directive to define processor
#include ;P12F1822 processor specific variable definitions
__CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _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_19 & _LVP_OFF
;
page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Macro definitions ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Device dependent Macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
DEVset macro
BANKSEL OSCCON ; Bank=1
movlw B'00000000' ; HS Xtal 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
movlw B'00000000' ; No use of Analog input
movwf ANSELA
BANKSEL TRISA ; Bank=1
movlw B'11111010' ; RA0 and 2 are output
movwf TRISA
;
BANKSEL ADCON0 ; Bank=1
clrf ADCON0 ; No use of ADC
;
BANKSEL OPTION_REG ; Bank=1
bcf OPTION_REG,7 ; Enable weak pull-up
BANKSEL WPUA ; Bank=4
movlw B'00001000' ; Weak Pull-up for RA3
movwf WPUA ;
;
clrf BSR ; Bank=0
endm
;
OUTini macro ; L for LEDs, and H for Signal
nop ; Timing for PORTA
movlw B'11001100' ; Set space (H) to RA2
movwf PORTA
goto $+1 ; Timing for PORTA
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; I/O macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; For general purpose ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LEDon macro
goto $+1
bsf PORTA,LED
goto $+1
endm
;
LEDoff macro
goto $+1
bcf PORTA,LED
goto $+1
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Constant time consuming ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Debug and Abend macros ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Udebug macro Addr
movf Addr,W
call Udbgr
endm
;
Ustop macro ; Stop until Sw2 on (=L)
call Udstopr ;
endm
;
Trigger macro ; DSO external trigger
goto $+1
bsf PORTtrg,Trig
Mic2
bcf PORTtrg,Trig
goto $+1
endm
;
Uabend macro abn ; User Abnormal-end number
movlw abn
goto Uabendr
endm
;
Ublink macro bno ; Blink LED for specified times
movlw bno
call Ublinkr
endm
;
Ucp macro CPNo ; Check point literal chr to display to LCD
movlw CPNo
movwf Ucpc
Udebug Ucpc
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Files and Equations ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Files ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cblock H'20' ; available from H'20' to H'6F' (80 bytes)
;
; For application support
Flags ; Flag byte
;
; Areas for time consuming subroutines
; Do not change the sequences from Mic5c to Minsc
; as these areas are co-used with calculation parameters
Mic25c
Mic50c
Millic
Mil100c
Secsc
Minsc
;
; Areas for debugging routine
DmpA ; Display byte area
Dmp8C ; Bit counter for loop (Initial Dmp8V =8)
BlinkC ; Counter for blinking (set for Debugb or Abendb)
Abendn ; Abend number
Ucpc ; User Check point chr to trace
;
endc
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Equations ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; For PORTA ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LED equ 0 ; LED
Tmg equ 2 ; Timing signal(L)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Values ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Flags Byte ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LEDsv equ 0 ; LED save bit for debug
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; For Debug ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Dmp8V equ D'8' ; Debug display bit counter initial value
Debugb equ D'8' ; number of blinkings to show Debugging
Abendb equ D'30' ; number of blinkings to notify Abend
;
page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initializing ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
org 0
goto Startp ; Go to start entry
org 4 ; This is Interrupt entry
retfie ;
;
Startp DEVset ; Define ports
OUTini ; L for LED(0), and H for Clk and Dio
clrf Flags ; Clear Flags byte
;
LEDon ; Indicate I am awake
Mil100 1 ; ***
LEDoff
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main program loop = precise 20mS/loop required ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp bcf PORTA,Tmg ; Tmg on (L)
Mic5 D'10' ; On for 50 micro seconds
bsf PORTA,Tmg ; Yes, clear Tmg signal
;
goto $+1 ; +0.5microS = 51microS up to here
;
; Requires 20mS-0.052mS = 19.948mS here
Milli D'19' ; / 19.0mS
Mic50 D'18' ; / 19.9mS
Mic5 D'9' ; / 19.945mS
Mic2 1 ; / 19.947mS
Mic ; / 19.948mS Total 19.999 mS
;
; Last segment consumes 0.001mS ;
goto $+1 ; consume 1microS hereafter
goto Mainp ; and loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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
;
space
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; User debug subroutine ;
; Show bit 7 to 0 ;
; of specified area ;
; by Udebug macro ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Udbgr clrf BSR ; Set Bank=0
movwf DmpA ; move data to Dmpa
;
btfss PORTA,LED ; Check if LED=on (on=High)
goto UdbLoff ; if LED=off(Low), skip saving process
bsf Flags,LEDsv ; Save LEDon status
LEDoff ; and off LED
Mil100 D'5' ; wait for 0.5 sec5 in case LED has been on
;
UdbLoff movlw Dmp8V ; set counter 8
movwf Dmp8C ; to Dmp8C
;
Udblp Ublink Debugb ; Blink for Debugging = 8 times
btfsc DmpA,7 ; check top bit 7
goto UdbOn ; if on then to UdbOn
goto UdbOff ; if off then to UdbOff
;
UdbOn LEDon
Mil100 D'5' ;
goto Udbeck
;
UdbOff LEDoff
Mil100 D'5' ;
; goto Udbeck
;
Udbeck decfsz Dmp8C,F
goto Udbnext
goto Udbend
;
Udbnext rlf DmpA,F
goto Udblp
;
Udbend Ublink Debugb ; end blinking and
Mil100 D'30' ; blank for 3 seconds to write down
;
btfss Flags,LEDsv ; Check if LED was on
goto Udbret ; no, goto return
LEDon ; if it was on, then on again
bcf Flags,LEDsv ; Clear LED save flag
;
Udbret return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Blinking to show debug or abend ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Ublinkr movwf BlinkC
Ublinkl LEDon ; LED on
Milli D'10' ; for 10ms
LEDoff ; LED off
Milli D'50' ; for 50ms
;
decfsz BlinkC,F
goto Ublinkl
return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Abend routine ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Uabendr clrf BSR
movwf Abendn ; Set Uabend number
;
Ublink Abendb ; Blinking 30 times
Udebug Abendn ; Show Abend number
goto $
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; End of program ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
この場合PIC内蔵のオシレータは使いません。外付けの16MHzクリスタルを用いることで十分な精度が出せます。回路図のPIC部分をご参照ください。
このArduino地震計連載への追加記事は今後も少しずつ載せていく予定です。途中で別の記事が入るかもしれませんが、本番機ができあがるまでしつこく書き足していくつもりです。据え付け完了までにはまだいくつかの難関が予想されますがクリアできそう。
趣味だけでなく、仕事もこんなに少しずつのマイペースでゆっくりできると楽ですね^^;
以下に珍しく余談を書いておきますので読み飛ばされてもかまいません。
こういう活動はプロジェクトというよりは長期の「プログラム」です。個人がコツコツとやりながら何かを成し遂げるにはうってつけのやり方だと思います。
目的意識が強くないとそうはいきませんね。できるかどうか不明確なオリジナル電子工作が、「できる」と分ったとたんにペースがおちる理由は、目的意識、言い換えれば追求する意欲が減るからでしょう。目的のために活動しますが、全体的に言えばたとえば次の図が一例です。
余談を書き始めるときりがありません。こういうことは次のKindle本にしたためてありますのでご参考まで。
https://www.amazon.co.jp/ /dp/B079WNNHW8/
(2019.11.29追記)
符号なしバイト属性の演算結果を符号付きInteger 属性に変換する簡単なテストの結果を添付します。Arduino言語を熟知されている方には初歩的なことかと思いますので、これまた読み飛ばしてください。今回の簡単なテストプログラムは次です。
byte ByteL;
byte ByteH;
int16_t Bytes;
void setup()
{
Serial.begin(9600);
// case 01
Serial.print("Case 01: ");
ByteH = B10000000;
ByteL = B00000000;
Bytes = ByteH * 256 + ByteL;
printResults();
// Case 02
Serial.print("Case 02: ");
ByteH=B10000000;
ByteL=B00000001;
Bytes = ByteH * 256 + ByteL;
printResults();
// Case 03
Serial.print("Case 03: ");
ByteH=B11111111;
ByteL=B00000000;
Bytes = ByteH * 256 + ByteL;
printResults();
// Case 04
Serial.print("Case 04: ");
ByteH=B11111111;
ByteL=B00000001;
Bytes = ByteH * 256 + ByteL;
printResults();
// Case 05
Serial.print("Case 05: ");
ByteH=B11111111;
ByteL=B11111111;
Bytes = ByteH * 256 + ByteL;
printResults();
// Case 06
Serial.print("Case 06: ");
ByteH=B11111111;
ByteL=B11111110;
Bytes = ByteH * 256 + ByteL;
printResults();
Serial.println("** Past negative process");
// Case 11
Serial.print("Case 11: ");
ByteH=B10000000;
ByteL=B00000000;
ByteH=~ByteH; // complement
ByteL=~ByteL; // complement
Bytes = -(ByteH * 256 + ByteL);
printResults();
// Case 12
Serial.print("Case 12: ");
ByteH=B10000000;
ByteL=B00000001;
ByteH=~ByteH;
ByteL=~ByteL;
Bytes = -(ByteH * 256 + ByteL);
printResults();
// *** Corrected
Serial.println("** Corrected negative process");
// Case 21
Serial.print("Case 21: ");
ByteH=B10000000;
ByteL=B00000000;
ByteH=~ByteH; // complement
ByteL=~ByteL; // complement
Bytes = -(ByteH * 256 + ByteL)-1;
printResults();
// Case 22
Serial.print("Case 22: ");
ByteH=B10000000;
ByteL=B00000001;
ByteH=~ByteH; // complement
ByteL=~ByteL; // complement
Bytes = -(ByteH * 256 + ByteL)-1;
printResults();
// infinit loop
while(1){}
}
void loop()
{
}
void printResults(void)
{
Serial.print(" ByteH=");
Serial.print(ByteH,HEX);
Serial.print(" and ByteL=");
Serial.print(ByteL,HEX);
Serial.print(", then Bytes=");
Serial.println(Bytes);
}
次がテストの結果です。
では今回はここまでにします。
©2019 Akira Tominaga, All rights reserved.