« トランジスタ技術付録「エンジニア手帳2026」 | トップページ | VCO IC「MAX2606」を使ったFMワイヤレスマイク »

2026年3月12日 (木)

1Hzパルス発生回路改造

2026年2月 1日:備忘録:1Hzパルス発生回路
ATtiny402を使った1Hzパルス発生回路
これをちょっと手直ししました。
 ・空いている3つのポートを入力にして
  ロータリーDIPスイッチを接続。
 ・「0~7」の3bitで8種類の発生周波数を設定。
 ・オシレータ出力を増幅していた
  74LVC1GU04を74HC1GU04に交換。
    LVCだと電流消費大だった!
てな、手直しを施しました。

8種類の固定周波数しか出せませんが、安定した
60Hz(地元の電源周波数)が欲しかったので、
1Hzだけよりはマシかと、手持ち部品を活用しま
した。
まず回路図。
1hz10

電源は5V。
12.8MHzの発振モジュールは秋月で購入。

小さなプラ箱に入れてます。
1hz12

中の様子。
1hz11_20260312144301

Arduino IDE環境での制御スケッチ。

/**************************/
/* 方形波発生回路 */
/**************************/
// "TINY402_1HZ02.ino"
// 2026-03-12
// 12.8MHz TCXOをクロックに
// DSW(0~7)の設定で方形波を出力
// 0 1Hz
// 1 10Hz
// 2 50Hz
// 3 60Hz (60.000375Hz)
// 4 100Hz
// 5 120Hz (120.00075Hz)
// 6 440Hz (440.01375Hz)
// 7 1kHz
/***** 分周データテーブル *****/
// 周波数発生モードなので12.8MHzを1/2した
// 6.4MHzを原発振周波数と考える
const struct{
const word cmp0; // TCA0 CMP0データ 1/(n-1)
const byte clksel; // プリスケーラ設定値 + ENABLE(b0)
// 1/1,2,4,8,16,64,256,1024
}frq_tbl[] = {
{ 6250 - 1, 0b00001111 }, // 0 1Hz 1/1024 6250Hz
{ 2500 - 1, 0b00001101 }, // 1 10Hz 1/256 25kHz
{ 64000 - 1, 0b00000011 }, // 2 50Hz 1/2 3.2MHz
{ 53333 - 1, 0b00000011 }, // 3 60Hz 1/2 3.2MHz
{ 64000 - 1, 0b00000001 }, // 4 100Hz 1/1 6.4MHz
{ 53333 - 1, 0b00000001 }, // 5 120Hz 1/1 6.4MHz
{ 14545 - 1, 0b00000001 }, // 6 440Hz 1/1 6.4MHz
{ 6400 - 1, 0b00000001 }, // 7 1kHz 1/1 6.4MHz
};
/***** DSW読み込み *****/
// 0~7を返す
// PORTA offで1 onで0
// PA2:DSW-1 PA6:DSW-2 PA7:DSW-4
byte inpdsw(void)
{
byte n;
byte d = 0; // リターンデータ
n = ~PORTA.IN; // ポートA反転して入力
if(n & 0b00000100) d |= 1; // DSW-1
if(n & 0b01000000) d |= 2; // DSW-2
if(n & 0b10000000) d |= 4; // DSW-4
return d;
}
// こんなコードに展開されていた
// 90 91 08 04 lds r25, 0x0408 ;PORTA.IN
// 90 95 com r25
// 92 fb bst r25, 2 ;2
// 88 27 eor r24, r24
// 80 f9 bld r24, 0 ;1
// 96 fd sbrc r25, 6 ;6
// 82 60 ori r24, 0x02 ;2
// 97 fd sbrc r25, 7 ;7
// 84 60 ori r24, 0x04 ;4
// 08 95 ret
// bld,bst命令が珍しい
/***** DSWデータ *****/
byte dsw_now; // 安定した現在値(0~7)
byte f_dswok; // 変化確定フラグ dsw_nowに安定値
/***** DSW変化チェック *****/
// 確定したらf_dswokを1に dsw_nowが確定値
// PITの1024Hz周期で実行
void chkdsw(void)
{
static byte exc; // 実行区分
static byte tm; // 1msタイマ
// PITの1024Hz周期でダウンカウント
static byte chk; // DSW入力安定チェックデータ
byte d;
d = inpdsw(); // DSWデータ入力
if(tm) tm--; // DSWチェックタイマダウンカウント
switch(exc){
case 0: // 変化チェック
if(dsw_now != d){ // DSW変化あり
chk = d; // チェックデータ
tm = 20; // 20ms
exc = 1;
}
break;
case 1:
if(chk != d){ // 変化続く?
chk = d; // チェックデータ再セット
tm = 20; // タイマも再セット 20ms
}
else{ // 安定
if(tm == 0){ // タイムアップ
dsw_now = d; // 新DSW値
f_dswok = 1; // 確定フラグをon
exc = 0; // 次の変化待ちに
}
}
break;
}
}
/***** 周波数設定 *****/
// d:DSW設定値 0~7
// 分周値は-1してある CMP0にセット
void setfrq(byte d)
{
TCA0.SINGLE.CTRLA = 0; // TCA0 タイマー停止
TCA0.SINGLE.CMP0 = frq_tbl[d].cmp0; // 分周値
TCA0.SINGLE.CNT = 0; // カウント 0から
TCA0.SINGLE.CTRLA = frq_tbl[d].clksel; // プリスケーラ+ENABLE
}

/***** SETUP *****/
void setup() {
cli(); // 割込禁止
// ポート設定
PORTA.DIR = 0b00000010;
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin out WO1 波形出力
// || |+------ PA2 5pin in DSW-1
// || +------- PA3 7pin in 12.8MHzクロック入力
// |+---------- PA6 2pin in DSW-2
// +----------- PA7 3pin in DSW-4
PORTA.PIN2CTRL = 0b00001000; // PA2 5pin DSW-1
PORTA.PIN3CTRL = 0b00001000; // PA3 7pin CLKIN
PORTA.PIN6CTRL = 0b00001000; // PA6 2pin DSW-2
PORTA.PIN7CTRL = 0b00001000; // PA7 3pin DSW-4
// +----- pull up有り
// クロック設定 PA3/CLKINに12.8MHz
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // プリスケーラなし
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, 3); // 外部からクロック
// タイマーTCA0, 分割モードで初期化されるので16bitモードに
TCA0.SPLIT.CTRLA = 0; // タイマー停止
TCA0.SPLIT.CTRLESET = 0x0F; // 強制リセット
PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに
// タイマ設定
TCA0.SINGLE.CMP1 = 0; // PA1 4pin WO1
TCA0.SINGLE.CTRLB = 0b00100001;
// ||||+++----- WGM 波形生成FRQ(周波数)
// |||+-------- ALUPD
// ||+--------- CMP0EN
// |+---------- CMP1EN PA1 4pin WO1 出力
// +----------- CMP2EN PA2 5pin
// DSW(0~7)で周波数を設定
dsw_now = inpdsw(); // DSW値(0~7)
setfrq(dsw_now); // 8選択で1Hz~1kHzセット
// RTC,PIT 有効に
while((RTC.STATUS & 0x0F) || // RTC busy ?
(RTC.PITSTATUS & 1)); // PIT busy ?
// PIT分周操作
RTC.PITCTRLA = 0b00100001;
// |||| +-- PITEN PIT有効
// ++++----- PERIOD 1/32 →1024Hz
sei(); // 割込有効
}

/***** LOOP *****/
// DSWの変化をチェック
void loop() {
if(RTC.PITINTFLAGS & 1){ // 1024Hz(約1ms)周期
RTC.PITINTFLAGS = 1;
chkdsw(); // DSW変化チェック
}
if(f_dswok){ // DSW変化あり
f_dswok = 0;
setfrq(dsw_now); // 1Hz~1kHz周波数セット
}
}
#if 0
最大4096バイトのフラッシュメモリのうち、
スケッチが534バイト(13%)を使っています。
最大256バイトのRAMのうち、グローバル変数が
5バイト(1%)を使っていて、ローカル変数で
251バイト使うことができます。
#endif
// end of "TINY402_1HZ02.ino"

inpdsw()関数の下にあるコメントに書きましたが、
DSWのビット操作で「bst」と「bld」命令が出て
おりました。
ステータスレジスタの「Tフラグ」の応用、珍しい
のじゃないでしょか。

・Arduino IDEの設定
Ide_set02

書き込みはMPLAB@SNAPで。

※チャタリング対策
ロータリーDIPスイッチ、一般的なスイッチのチャタリング
除去だけじゃなく、回転が安定したことを確かめてから
設定値を更新しなくちゃなりません。
こんな手順です。
 ・約1ms周期でポートからDSWの値を入力。
 ・確定データから変化したかをチェック。
 ・変化があればそれをメモ。
 ・20msタイマをセット。
 ・メモしたのと変化があればタイマを再セット
  してチェック時間を延長。
 ・変化が無ければ(20m間)安定したと判断して
  確定データを更新し、新しくなったことを
  フラグで知らせる。
普通はタイマ割り込み内で処理するのですが、
今回は、他に時間がかかる処理が走っていないの
でメインループで処理しました。
  メインの処理はこれだけなんで。

実際の波形を見てもらいましょう。
I11_20260313105301

上側のch1は方形波出力。
設定7の1kHzと設定6の440Hzが見えています。

下側の波形はスイッチのbit0。
 設定7ならLレベル。
 設定6ならHレベル。
設定の変化から20ms後に周波数が変わっています。

そこにチャタリングを加えます。
 ・「チャタリング除去回路」じゃなくって「チャタリング発生回路」をどうぞ

I12_20260313105501
bit0がバタバタしてる間は周波数は変化しません。
20ms間落ち着いてから周波数を変えています。

|

« トランジスタ技術付録「エンジニア手帳2026」 | トップページ | VCO IC「MAX2606」を使ったFMワイヤレスマイク »

発振回路」カテゴリの記事

ATtiny」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« トランジスタ技術付録「エンジニア手帳2026」 | トップページ | VCO IC「MAX2606」を使ったFMワイヤレスマイク »