// ===========================================================================
// AC100V インバータ H8/3694 2006.01.28 Jaku.
// ===========================================================================
//
// ---------------------------------------------------------------------------
// リンク
//   コード( main   他:標準なら Section "P")は H'0000 から
//   データ( WaitCt   :標準なら Section "C")は コードの後へ
//   ワーク( AcLineCt 他:標準なら Section "B")は H'F780 から
//   へ割当てて下さい。
// ---------------------------------------------------------------------------
// 日立以外のコンパイラでは通らないと思います。通ったら教えて下さい!
// ---------------------------------------------------------------------------
// CPU Clock は 16MHz です
// ---------------------------------------------------------------------------

#define INTV_SPAN 30000 // AC100V 半波の ON カウンタ UP 値

#define ON 1
#define OFF 0

#define u_char unsigned char
#define u_int unsigned int
#define u_long unsigned long

// ---------------------------------------------------------------------------

void AdTrig(u_int); // A/D変換 トリガ (シングルモード)
u_int AdRead(u_int); // A/D変換 結果の読み出し
void AcDrvOn(void); // AC100V 半波出力 ON

// ---- I/O割付け ---------------------------------------------------------

// P14: (37) IRQ0 AC ゼロクロス検出入力 ( H で検出)
// P87: (33) P87 SSR 駆動出力 ( H で SSR ON)
// PB0: (48) AN0 動作周波数設定用電圧入力(VRトリマ)

#define TMRW (*(volatile u_char *)0xFF80) // タイマW モード
#define TCRW (*(volatile u_char *)0xFF81) // タイマW コントロール
#define TCNT (*(volatile u_int *)0xFF86) // タイマW カウンタ
#define ADDRA (*(volatile u_int *)0xFFB0) // A/D データ A
#define ADCSR (*(volatile u_char *)0xFFB8) // A/D コントロール/ステータス
#define ADCR (*(volatile u_char *)0xFFB9) // A/D コントロール
#define PUCR1 (*(volatile u_char *)0xFFD0) // ポート1 プルアップ制御
#define PDR5 (*(volatile u_char *)0xFFD8) // ポート5 データ
#define PDR8 (*(volatile u_char *)0xFFDB) // ポート8 データ
#define PCR8 (*(volatile u_char *)0xFFEB) // ポート8 コントロール
#define PMR1 (*(volatile u_char *)0xFFE0) // ポート1 モード
#define PCR1 (*(volatile u_char *)0xFFE4) // ポート1 コントロール
#define PCR2 (*(volatile u_char *)0xFFE5) // ポート2 コントロール
#define PCR5 (*(volatile u_char *)0xFFE8) // ポート5 コントロール
#define PCR7 (*(volatile u_char *)0xFFEA) // ポート7 コントロール
#define IEGR1 (*(volatile u_char *)0xFFF2) // 割込エッジセレクト 1
#define IENR1 (*(volatile u_char *)0xFFF4) // 割込イネーブル
#define IRR1 (*(volatile u_char *)0xFFF6) // 割込制御

// ---- ワーク ---------------------------------------------------------------

struct flag1 { // フラグ 色々
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int ZeroX :1 ; // ゼロクロス検出
unsigned int OutTim :1 ; // 出力タイミング
unsigned int LastCt :1 ; // 前回出力時のカウンタ値 0:EVEN 1:ODD
} OutFlag;

u_int AcLineCt; // AC Line ゼロクロスカウンタ
u_int IntervalCt; // 半波出力タイミング計測カウンタ
u_int AdLevel; // A/Dデータ 0 - 255 (8ビット!)
u_int Tim16Last; // IRQ0 起動時の タイマW の値

// ---------------------------------------------------------------------------

// ------------------------------
// 駆動周期テーブル (60Hz)
// ------------------------------
// 1.0165 等比級数 1 - 60Hz
// INTV_SPAN が最大値(全ての「半波」が ON になる値)

const u_int WaitCt[] = {
500, 500, 500, 508, 517, 525, 534, 543,
552, 561, 570, 579, 589, 599, 608, 619,
629, 639, 650, 660, 671, 682, 694, 705,
717, 729, 741, 753, 765, 778, 791, 804,
717, 729, 741, 753, 765, 778, 791, 804,
817, 830, 844, 858, 872, 887, 901, 916,
931, 947, 962, 978, 994, 1011, 1027, 1044,
1061, 1079, 1097, 1115, 1133, 1152, 1171, 1190,
1210, 1230, 1250, 1271, 1292, 1313, 1335, 1357,
1379, 1402, 1425, 1449, 1473, 1497, 1522, 1547,
1572, 1598, 1624, 1651, 1678, 1706, 1734, 1763,
1792, 1822, 1852, 1882, 1913, 1945, 1977, 2010,
2043, 2076, 2111, 2145, 2181, 2217, 2253, 2291,
2328, 2367, 2406, 2446, 2486, 2527, 2569, 2611,
2654, 2698, 2742, 2788, 2834, 2880, 2928, 2976,
3025, 3075, 3126, 3178, 3230, 3283, 3338, 3393,
3449, 3505, 3563, 3622, 3682, 3743, 3804, 3867,
3931, 3996, 4062, 4129, 4197, 4266, 4337, 4408,
4481, 4555, 4630, 4706, 4784, 4863, 4943, 5025,
5108, 5192, 5278, 5365, 5453, 5543, 5635, 5728,
5822, 5918, 6016, 6115, 6216, 6319, 6423, 6529,
6636, 6746, 6857, 6970, 7085, 7202, 7321, 7442,
7565, 7690, 7816, 7945, 8077, 8210, 8345, 8483,
8623, 8765, 8910, 9057, 9206, 9358, 9513, 9671,
9829, 9991, 10156, 10324, 10494, 10667, 10843, 11022,
11204, 11389, 11577, 11768, 11962, 12159, 12360, 12564,
12771, 12982, 13196, 13414, 13635, 13860, 14089, 14321,
14558, 14798, 15042, 15290, 15542, 15799, 16060, 16325,
16594, 16868, 17146, 17429, 17717, 18009, 18306, 18608,
18915, 19227, 19544, 19867, 20195, 20528, 20867, 21211,
21561, 21917, 22278, 22646, 23020, 23399, 23785, 24178,
24577, 24982, 25395, 25814, 26240, 26672, 27113, 27560,
28015, 28477, 28947, 29424, 29910, 30000, 30000, INTV_SPAN
};

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

void main(void)

#pragma asm
; ----- リスタート/割込ベクタ -----
.DATA.W RESET ; V0 0000 リスタート(WDTを含む)
.DATA.W _INT_IRET ; V1 0002 システム予約
.DATA.W _INT_IRET ; V2 0004   〃
.DATA.W _INT_IRET ; V3 0006   〃
.DATA.W _INT_IRET ; V4 0008   〃
.DATA.W _INT_IRET ; V5 000A   〃
.DATA.W _INT_IRET ; V6 000C   〃
.DATA.W _INT_IRET ; V7 000E NMI
.DATA.W _INT_IRET ; V8 0010 トラップ命令 #0
.DATA.W _INT_IRET ; V9 0012    〃   #1
.DATA.W _INT_IRET ; V10 0014    〃   #2
.DATA.W _INT_IRET ; V11 0016    〃   #3
.DATA.W _INT_IRET ; V12 0018 アドレスブレーク
.DATA.W _INT_IRET ; V13 001A スリープ命令実行による遷移
.DATA.W _INT_IRQ0 ; V14 001C IRQ0 (低電圧検出割込 :option)
.DATA.W _INT_IRET ; V15 001E IRQ1
.DATA.W _INT_IRET ; V16 0020 IRQ2
.DATA.W _INT_IRET ; V17 0022 IRQ3
.DATA.W _INT_IRET ; V18 0024 ウェイクアップ
.DATA.W _INT_IRET ; V19 0026 タイマA オーバフロー
.DATA.W _INT_IRET ; V20 0028 システム予約
.DATA.W _INT_IRET ; V21 002A タイマW
.DATA.W _INT_IRET ; V22 002C タイマV
.DATA.W _INT_IRET ; V23 002E SIO
.DATA.W _INT_IRET ; V24 0030 I2C
.DATA.W _INT_IRET ; V25 0032 A/D変換終了

RESET:
MOV.W #H'FF00,R7 ; set Stack Pointer

#pragma endasm

{
// ---- I/Oポート初期化 ---------------

// 7------- IRQ3 P17 0: Port, 1: IRQ3 入力端子
// |6------ IRQ2 P16 0: Port, 1: IRQ2  〃
// ||5----- IRQ1 P15 0: Port, 1: IRQ1  〃
// |||4---- IRQ0 P14 0: Port, 1: IRQ0  〃
// |||| 1- TXD P22 0: Port, 1: TxD 出力端子
// |||| |0 TMOW P1O 0: Port, 1: TMOW 出力端子
PMR1 = 0x10; // 00010000 // ポートモード (端子機能選択)
// 7
// |6
// ||5
// |||4---- IRQ0 ゼロクロス検出
// |||| 2
// |||| |1
// |||| ||0
PCR1 = 0xef; // 11101111 // ポート1 入出力  0:入力, 1:出力
PUCR1 = 0xff; // ポート1 入力 Pull-Up MOS 1:ON
// 7------- P87 SSR 駆動出力
// |6------ P86
// ||5----- P85 LED (負論理: Low で点灯)
// |||4---- FTIOD P84
// ||||3--- FTIOC P83
// |||||2-- FTIOB P82
// ||||||1- FTIOA P81
// |||||||0 FTCI P80
PDR8 = 0x20; // 00100000 // ポート8 データ LED(P85) OFF
PCR8 = 0xff; // ポート8 コントロール 全出力ポート
PCR2 = 0x05;
PCR5 = 0xff;
PCR7 = 0x70;

// 7------- CCLR カウンタ TCNT クリア
// | 0: カウンタはフリーラン
// | 1: コンペアマッチAでクリア
// |6------ CKS2 入力CLK選択
// ||5----- CKS1 000: 内部クロック φ 
// |||4---- CKS0 001:    〃   φ/ 2
// |||| 010:    〃   φ/ 4
// |||| 011:    〃   φ/ 8
// |||| 1xx: 外部イベント FTCI の↑エッジ
// ||||3--- TOD 初期タイマ出力レベル設定
// |||||2-- TOC  最初のコンペアマッチ x が発生する
// ||||||1- TOB  までの FTIOx 端子の出力レベルを設定
// |||||||0 TOA 0: 0, 1: 1
TCRW = 0x30; // 00110000 // 入力 CLK 0.4uS/20MHz, 0.5uS/16MHz
TMRW = 0x80; // タイマW カウント開始

ADCSR = 0x08; // A/D control (fast mode)

// ---- ワーク初期化 ---------------------
OutFlag.OutTim = OFF; // 出力タイミング
OutFlag.LastCt = 0; // 前回出力時のカウンタ値 0:EVEN 1:ODD
AdLevel = 0; // A/Dデータ 0-255
IntervalCt = 0; // 半波出力タイミング計測カウンタ
AcLineCt = 0; // AC Line ゼロクロスカウンタ
Tim16Last = 0; // IRQ0 起動時の タイマW の値

// ---- 割込み初期化 ---------------------
IEGR1 = IEGR1 | 0x01; // IRQ0 割込エッジ ↑
IENR1 = IENR1 | 0x01; // IRQ0 割込イネーブル
#pragma asm
ANDC #H'7F,CCR ; CPU 割込許可
#pragma endasm

// ---------------------------------------
while (1) { // メインループ
if (OutFlag.ZeroX == ON) { // ゼロクロス検出なら
OutFlag.ZeroX = OFF;
AdTrig(0); // チャネル0 A/Dトリガ
AdLevel = AdRead(0) >> 2; // A/Dデータ 読み出し(8ビット)
}
} // ---------------------------------------
}

// ----------------------------------------
// A/D変換 トリガ (シングルモード)
// ----------------------------------------
// 引数 u_int チャネル番号 0-7
// 返値 void 無し
//
// 76543210 [ADCSR]
// |||||210---- MUX 入力チャネル選択
// ||||3------- CKS 変換CLK 0: 134, 1: 70
// |||4-------- SCAN スキャンモード 0: Single 1: Scan
// ||5--------- ADST A/Dスタート 0: Stop 1: Start
// |6---------- ADIE A/D変換割込 0: 禁止 1: 許可
// 7----------- ADF A/D終了フラグ 1: 終了

#define AD_TRIG 0x20

void AdTrig(u_int ch)
{
ch &= 0x07; // Mask A/D CH
ADCSR = (ADCSR & 0x08) | (u_char)ch | AD_TRIG; // set A/D CH , Triger A/D
}

// ----------------------------
// A/D変換 結果の読み出し
// ----------------------------
// 引数 u_int チャネル番号
// 返値 u_int 変換値 0-1023
//
// 注意:A/D変換中なら終わるまで待つ

#define AD_ENDF 0x20

u_int AdRead(u_int ch)
{
u_int d;

while ( !(ADCSR & AD_ENDF) ) ; // A/D 変換終了待ち
switch(ch % 4) {
case 0: d = ADDRA; break;
// case 1: d = ADDRB; break;
// case 2: d = ADDRC; break;
// case 3: d = ADDRD; break;
default: d = 0; break;
}
ADCSR = ADCSR & ~AD_ENDF; // A/D End Flag Clear
d = d >> 6; // 10ビット精度なので
return(d);
}

// -----------------------------
// V14 001C IRQ0 割込処理
// -----------------------------
// 商用電源 ゼロクロス「付近」割込み
//
// ┌────┐            ┌────┐
// IRQ0 ─┘    └────────────┘    └────
// : 0.5mS→:→→→→→ 7.8mS→→→→: (60Hz時)
//
//  5mS以下の周期は無視(IRQ0 起動時刻は非記録)
//  9mS以上の周期は無視(IRQ0 起動時刻を記録)

#define AC_CYCLE_L 10000 // 5mS (unit:0.5uS/16MHz)
#define AC_CYCLE_H 18000 // 9mS (unit:0.5uS/16MHz)

#pragma interrupt INT_IRQ0

void INT_IRQ0(void)
{
u_int now_tim, last_phase;

IRR1 = IRR1 & 0xfe; // IRQ0 割込みフラグ クリア
// ---- IRQ0 起動周期確認
now_tim = TCNT;
if ( (now_tim - Tim16Last) < AC_CYCLE_L ) return;
if ( (now_tim - Tim16Last) > AC_CYCLE_H ) {
Tim16Last = now_tim;
return;
}
Tim16Last = now_tim; // 起動時刻?を記録

PDR8 = PDR8 & 0x7f; // AC100V OFF

// 「位相調整待ち」のチェック
// (前回は「同位相」で半波待ち?)
if (OutFlag.OutTim == ON) AcDrvOn(); // 出力タイミングなら AC100V ON

IntervalCt += WaitCt[AdLevel]; // 半波出力タイミング計測カウンタ 加算

if (IntervalCt > INTV_SPAN) { // 出力タイミング ?
OutFlag.OutTim = ON; // 出力タイミング!
IntervalCt -= INTV_SPAN; // 半波出力インターバル 消化!
// ---- 出力する位相を調べる
last_phase = AcLineCt % 2; // AC Line ゼロクロスカウンタ
if (last_phase != OutFlag.LastCt) { // 前回と位相が異なれば
AcDrvOn(); // AC100V ON
}
}
OutFlag.ZeroX = ON; // ゼロクロス検出
AcLineCt++; // ACゼロクロスカウンタ 更新
}
// -----------------------------------
// AC100V 半波出力 ON
// -----------------------------------
void AcDrvOn(void)
{
PDR8 = PDR8 | 0x80; // AC100V ON
OutFlag.OutTim = OFF; // 出力タイミング フラグ
OutFlag.LastCt = AcLineCt % 2; // 最終 ON 出力時の AC100V 位相
}

// -----------------------------
// IRQ (not Use)
// -----------------------------

#pragma interrupt INT_IRET

void INT_IRET(void)
{
}


Top      戻る