勝手な電子工作・・

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

しっかり記録! Arduino地震計 その2 プログラム1

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

この連載の途中でだいぶ日にちが空いてしまいましたが、Arduino地震計の第2回目、プログラムの説明に入ります。

オリジナル工作が、「できる」ということがわかったとたんに、その後の取り組みスピードが遅くなりますね^^; 今月は仕事と旅程でだいぶふさがったのが原因ではありますが、掲載がゆっくりですみません。

上の写真は試作回路の現状で、前の記事の後でRTC(リアルタイムクロック)のDS3231をI2C接続し、そして使用中のSRAMを表示するためのLED(赤、緑、青)をつけた状態です。最初はLEDは右上のブレッドボードにつけていましたが、配線が込み合うので左上に小さいブレッドボードを加えてつけなおしました。右上のブレッドボードからLEDのグランド配線(右下に3本ある裸ジャンパー)を取り除くの忘れてますが後で外しておきます。

次に回路図を再掲します。

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

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地震計連載への追加記事は今後も少しずつ載せていく予定です。途中で別の記事が入るかもしれませんが、本番機ができあがるまでしつこく書き足していくつもりです。据え付け完了までにはまだいくつかの難関が予想されますがクリアできそう。

趣味だけでなく、仕事もこんなに少しずつのマイペースでゆっくりできると楽ですね^^; 

 

以下に珍しく余談を書いておきますので読み飛ばされてもかまいません。

こういう活動はプロジェクトというよりは長期の「プログラム」です。個人がコツコツとやりながら何かを成し遂げるにはうってつけのやり方だと思います。

 

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

 目的意識が強くないとそうはいきませんね。できるかどうか不明確なオリジナル電子工作が、「できる」と分ったとたんにペースがおちる理由は、目的意識、言い換えれば追求する意欲が減るからでしょう。目的のために活動しますが、全体的に言えばたとえば次の図が一例です。

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

 余談を書き始めるときりがありません。こういうことは次の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); 
}

 次がテストの結果です。

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

 

では今回はここまでにします。

 

 

©2019 Akira Tominaga, All rights reserved.