Arduino

2025年9月15日 (月)

ラジオペンチさんの「ダイソーのゆらゆらLEDキャンドルライト」#2

ラジオペンチさんの「ダイソーのゆらゆらLEDキャンドルライト」
3ch出力にした回路をでっち上げました。
Photo_20250915170901
図では出力コネクタが3つですが、2パラにして
(抵抗の左から分岐)合計6つのキャンドルを駆動
できるようにしました。
Cd21
  LEDの色を変えたのを追加
  VF=3Vほどの高輝度タイプは青と緑
  しか手持ちがなかった。
  元の橙色LED、発光角が広いのでしょう、
  手持ちの青と緑と違って「ろうそくの中」
  までエエ感じで光っています。
  青と緑の、中を照らすLEDを増設しようかしら。

LEDの直列抵抗、値を小さくして最大10mAほど
流れるようにしています。
  (ラジペンさんの回路だと560Ω)

Arduino UNO環境ですが、発振子無し
内蔵8MHzクロックで動かしています。
ATmega328Pに8MHz用ブートローダを書いて、
ヒューズを内蔵8MHzにしなくちゃなりません。

そして、Arduino IDEのボード選択を"UNO"ではなく
"Arduino Pro or Pro Mini"を選び、
プロセッサを
 "ATmega328p (3.3V,8MHz)"にします。

これで発振子無しの8MHzで動いてくれるはず。
  ・ダウンロード - candle01b.txt
    テキストファイル(UTF8N)にしてます
スケッチをアップできて、115.2kBPSで通信が
できてれば大丈夫じゃないかしら。
  PB5のLEDは0.2秒ちょい周期で点滅。

スケッチそのものは、8MHzも16MHzも変わりま
せんので、Arduino UNO R3環境でも手直しなしで
動作します。
  このあたり、たいへん便利なんですが、
  昔人間が思うところ・・・
   「どこでその違いを補正してるねん」
  が気になって、「16MHz→8MHzでも
  動くでぇ~」が「ほんまかいな」状態で
  落ち着きません。
  F_CPUが駆動周波数を示しています。
  それを「誰が(どのファイルが)、どこで(どのフォルダで)
  決めてるねん」をつかんでおきたいのですが、
  ワケワカメ。

元の基板のチップ部品3つを取り去り2つを間をジャンパ。
ダイオードもこの基板のコイル端子にハンダして3本の
電線を引き出しています。
Cd22

ゆらゆらキャンドル、「出窓」 へのデビューは女房次第でっす。
  『まだ「夏」のまんまやしなぁ~』
なんて言っとりましたんで。


そしてそして・・・
  ラジペンさんの「三つ編みケーブル」。
こちらでは手抜きで、ドリルを使って
電線をよじっています。
Cd24
チャックで電線を挟み込み、ギュイ~ン。
完成。
Cd25
  ※GX200で写したんだけどホワイトバランスに差がぁ。

| | コメント (4)

2025年9月11日 (木)

ラジオペンチさんの「ダイソーのゆらゆらLEDキャンドルライト」

ダイソーのゆらゆらLEDキャンドルライト(1/f ゆらぎに改造):ラジオペンチさん
「出窓」に面白そうと、ご近所のダイソーを3軒探したの
ですが、見つからず。
やむを得ず、ダイソーの通販に注文しました。
  送料がかかるけど・・・単3Looperもいっしょに
Cc11_20250911093901
  ※しかし・・・今朝見たら、商品ページが消えてました。
    ちゃんと届くのか不安がぁぁ

ラジオペンチさんのArduino UNOによる駆動系、
せっかくですんで使えるPWM出力6つを全部使って、
3つのキャンドルライトを駆動できるようにスケッチを
手直ししてみました。

・PWM出力チャンネル番号をテーブルに。
・明るさデータを3つの配列に。
・3chのループを回して独立して処理。
・「チラツキ防止のため、10回に分けて」
 「補間1ステップ時間(全体ではこの10倍)」
 は、loopの一番外側に「for(i = 1」を持ってきて
 コイル駆動は i = 1のときだけにして、LED処理
 は毎回で、というふうに。

// ラジオペンチさん:
// ダイソーのゆらゆらLEDキャンドルライト(1/f ゆらぎに改造)
// http://radiopench.blog96.fc2.com/blog-entry-1355.html
// 20250908_LedCandleCaosMethod.ino
// カオス方を使った 1/f ゆらぎを持つLEDキャンドル
// 2025/9/8 ラジオペンチ
// 9/11 3ch出力に改造:居酒屋ガレージ店主(JH3DBO)
byte COIL_PIN[] = { 6, 9, 11 }; // コイル駆動PWM出力 3ch
byte LED_PIN[] = { 5, 10, 3 }; // LED駆動
float xx[3] = { 0.7, 0.7, 0.7};
float last_xx[3];
float xxx[3];

void setup() {
Serial.begin(115200);
pinMode(13, OUTPUT); // LED
Serial.println("Start ");
}

void loop() {
PINB |= (1 << 5); // PB5 LED on/off
for (int i = 1; i <= 10; i++) { // チラツキ防止のため、10回に分けて、
for (byte j = 0; j < 3; j++){ // 3ch loop (0,1,2)
if (i == 1){ // 10loopの最初だけ実行
xx[j] = fluctuate(xx[j]); // カオス法で新しい明るさを決定
Serial.print(j);
Serial.print(", ");
Serial.print(xx[j]);
Serial.print(", ");
// コイルに通電して炎の板を揺らす
xxx[j] = last_xx[j] - xx[j]; // 明るさの差(減光量)が、
if (xxx[j] > 0.15) { // 一定値を超えていたら(値は要調整)
analogWrite(COIL_PIN[j], 255 * sqrt(xxx[j])); // コイルに通電
//(sqrtは値を1に近付けるため)
Serial.println(sqrt(xxx[j]));
} else { // 超えてなければ
analogWrite(COIL_PIN[j], 0); // コイル通電OFF
Serial.println(0);
}
}
// LEDの明るさを変える (i=1~10)
xxx[j] = last_xx[j] + (xx[j] - last_xx[j]) * i / 10.0; // 指定値まで直線補完で、
analogWrite(LED_PIN[j], 70 + xxx[j] * 180); // LEDの明るさを設定
last_xx[j] = xx[j];
}
delay(10); // 補間1ステップ時間(全体ではこの10倍)
}
}

float fluctuate(float x) { // 間欠カオス法で 1/f波形を生成
if (x < 0.5) { // 0.5以上なら
x = x + 2 * x * x; // 2x^2で徐々に増加
} else { // 0.5以下なら
x = x - 2 * (1.0 - x) * (1.0 - x); // 2(1-x)^2で徐々に減少
} //
if (x < 0.05 || x > 0.95) { // 結果が上下限を外れていたら、
x = random(100, 900) / 1000.0; // 乱数で0.1-0.9の範囲に戻す
}
return x;
}

こんな具合にスケッチはできたけど、キャンドルライトが
来ないことには試運転もできません。
  出力パルスをオシロで見てるだけ。

商品ページが消えてしまったキャンドルライト、
はたしてちゃんと届くのでしょうか。

※PWM出力の順番
 コイル駆動PWM出力 : 6, 9, 11
 LED駆動PWM出力 : 5, 10, 3 
これはATmega328Pにある3つのタイマーユニット
出力のペアに合わせてるので飛び飛びになってます。
  OC0A 6
  OC0B 5
  OC1A 9
  OC1B 10
  OC2A 11
  OC2B 3

※3ch版、完成形に
ラジオペンチさんの「ダイソーのゆらゆらLEDキャンドルライト」#2
  出窓へのデビューはいつになりますか・・・

| | コメント (1)

2025年9月 9日 (火)

ATtiny402サンプル:"Wire.h"を使わずI2Cで液晶表示 AQM1602だと

ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら
で使った液晶AC0802は、コントラストを外付け
ボリュームで調整します。

AQM1602Y-NLW(FLW、FLB)やAQM1602XA-RNは
内部レジスタの操作でコントラストが変わります。

電源電圧3.3Vなら内部ブースター回路をオンに
して、液晶の駆動電圧を上げるので、5Vで使う
時とで微妙にコントラストが変わりますが
両方とも「35」あたりでOKのようです。

バックライト付のAQM1602Y-FLW-FBWを試したのが
このページ。 ※ずいぶん前だぁ
 ・秋月電子16文字x2行のI2Cインターフェース液晶AQM1602Y

今回はATtiny402でバックライト無しの
AQM1602Y-RN-GBWを試してみました。
  電源電圧は3.3Vでこんな回路。
Sch21
VRを回すとコントラストが変わります。
Cc01_20250909165301

※制御スケッチ
  ・ダウンロード - lcd_test2a.zip
    ※BCD変換ルーチンを別ファイルにしてあります。

これで、
  スケッチが1537バイト(37%)
  グローバル変数が37バイト(14%)
というメモリー使用量。

"Wire.h”をやめたおかげでRAMへの圧迫が
取り除かれています。

初期化のところで、文字数と行数、SCL周波数、
電源電圧を設定します。

  LCD.begin(16, 2, 100, LCD_V3R3);
   // I2C液晶 ★wire.hは使わない
   // 液晶初期化 16文字x2行,100kHz,3.3V
   // (5V:LCD_V5R0,3.3VならLCD_V3R3に)

3.3Vならブースター回路をオン。
5Vならオフに。

tiny402の動作周波数はArduino IDEの画面で設定
します。
3.3V動作なら10MHzが最大。
Ide02

電源電圧5Vでは必ず電圧ブースターをオフにという
のが注意点です。
  LCD.begin()での電圧設定をLCD_V5R0
  にしたらオフになります。

Arduinoでのアナログ入力といえば「analogRead() 」ですが、
tiny402には連続変換モード(自由走行という表現)というのが
あって、変換を始めたらいつでも最新値を読み出せるのです。
  入力チャンネルを切り替えるとなると
  タイミングがちょっとややこしいけど。
累積加算の機能と合わせて、割り込みで処理しなくて
良いのでなかなか便利。

もうひとつ。
内蔵クロック32.768kHzベースのRTCタイマに付随する
PIT(Periodic Interrupt Timer)が、メインクロック周波数が
変わっても一定時間を数えてくれるので、これも便利。
  通常はF_CPUで動作クロックが分かるのですが、
  例えばこのサンプルでは0.25秒(1/4秒)サイクル
  でPITフラグが立つようにしています。
  メイン周波数が変わっても、一定タイミングが
  得られます。
    delay()を使わなくてもエエんです。

| | コメント (0)

ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら

ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)
これの続き。

I2C液晶、スペックを見ると電源5VならSCL周波数は
400kHzに対応しています。
そこで・・・液晶の文字数・行数をセットするときに
SCL周波数をセットできるようにしてみました。

//  I2C液晶
LCD.begin(8, 2, 400); // 液晶初期化 8文字x2行,SCL=400kHz

設定処理はこんな具合。
  WIFビットのタイムアウトチェックは無くしました。

/*****  TWI 初期化      *****/
// _scl_frq(kHz)からTWI周波数を設定
// MBAUD = F_CPU/2/fSCL - 5
void i2c_lcd_acm0802_tn::twiInit()
{
int16_t d;
// TWI0.MBAUD = 50; // TWI SCL周波数設定
// CPUクロックから計算してみる
d = F_CPU / 1000; // CPU クロック周波数(kHz)
d = (d / 2 / _scl_frq) - 5; // F_CPU/2/fSCL-5
if(d < 0) d = 1; // 1~255
if(d > 255) d = 255;
TWI0.MBAUD = d; // TWI SCL周波数設定
TWI0.MCTRLA = 0b00000001;
// || ||||+----- ENABLE 主装置許可
// || |||+------ SMEN 簡便動作しない
// || |++------- TIMEOUT 使わない
// || +--------- QCEN 迅速指令 しない
// |+----------- WIEN 書き込み割り込み なし
// +------------ RIEN 読み込み割り込み なし
TWI0.MSTATUS = 0b00000001;
// ||||||++----- BUSSTATE アイドル状態に
// |||||+------- BUSERR
// ||||+-------- ARBLOST
// |||+--------- RXACK
// ||+---------- CLKHOLD
// |+----------- WIF
// +------------ RIF
}
/***** TWI 書込み送出開始 *****/
void i2c_lcd_acm0802_tn::twiStartW(uint8_t adrs)
{
TWI0.MADDR = adrs << 1; // アドレス 書き込みで(0)
while(!(TWI0.MSTATUS & TWI_WIF_bm)); // WIF=1を待つ
}
/***** TWI データ書き込み *****/
void i2c_lcd_acm0802_tn::twiWrite(uint8_t data)
{
TWI0.MDATA = data; // データ書き込み
while(!(TWI0.MSTATUS & TWI_WIF_bm)); // WIF=1を待つ
}
/***** TWI 送出終了 *****/
void i2c_lcd_acm0802_tn::twiStop()
{
TWI0.MCTRLB = TWI_MCMD_STOP_gc; // Stop Condition
}

メイン側の記述でSCL周波数が設定できてエエかな
っと思ったのですが、「割り算」が入るので、単純に
「TWI0.MBAUD」に値を書くだけの元のに比べると
「90バイト」ほど肥大してしまいました。

ここらは目をつぶってSCL周波数を設定できるほうが
便利になるかと。
  100kHz→400kHzにしたら液晶表示のための
  処理速度が1データの書き込み単位で4倍に。

※スケッチ全体の様子
  ・ダウンロード - lcd_test1a.zip
    上で示したのとはちょっと変えてます

※表示画面
At41
回路図はこの記事の
 ・ATtiny402マイコン サンプル:I2Cで液晶表示

| | コメント (0)

2025年9月 8日 (月)

ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)

ATtiny402マイコン サンプル:I2Cで液晶表示 この続き。

ATtiny402での液晶表示、ちょっとでも「軽く」する
(メモリ使用量を減らす)ため、"Wire.h"を使わない
液晶表示ルーチンを仕立ててみました。

■LCD_TEST0 : "Wire.h"を使った場合

// "Wire.h"を使ってのACM0802液晶テスト
// ATtiny402 20MHz Arduino IDE環境
// PA0 6pin UPDI
// PA1 4pin - SDA I2C液晶
// PA2 5pin - SCL I2C液晶
// PA3 7pin out
// PA6 2pin out
// PA7 3pin out
// ボードマネージャー:
// http://drazzy.com/package_drazzy.com_index.json
#include "Wire.h" // I2C ACM0802液晶
#include "i2c_lcd_acm0802.h" // LCD制御ヘッダーファイル
i2c_lcd_acm0802 LCD(0x3C); // LCD I2Cアドレスを設定
/***** SETUP *****/
void setup() {
cli(); // 割込禁止
PORTA.DIR = 0b11001000; //ポート出力指定
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in SDA
// || |+------ PA2 5pin in SCL
// || +------- PA3 7pin out
// |+---------- PA6 2pin out
// +----------- PA7 3pin out
// PIT 1秒タイミング
RTC.CLKSEL = 0b00000001;
// ++---- INT1K 1024Hz
RTC.CTRLA = 0b00000001;
// ||||| +---- RTCEN RTC周辺機能許可
// |++++------- CLK_RTC DIV1 1/1
// +----------- RUNSTBY
RTC.PITCTRLA = 0b01001001;
// |||| +-- PITEN
// ++++----- PERIOD 1/1024 →1秒
// I2C液晶
Wire.begin(); // I2C開始
LCD.begin(8, 2); // 液晶初期化 8文字x2行
}
/***** LOOP ******/
void loop() {
byte c = '0';
LCD.setCursor(0, 0); // LCD上段
LCD.strdisp("Test LCD"); // タイトル
while(1){
if(RTC_PITINTFLAGS & 0x01){ // 1秒経過
RTC_PITINTFLAGS = 1; // PIフラグクリア
LCD.setCursor(7, 1); // LCD右下段
LCD.write(c); // 0~9
c++;
if(c > '9') c = '0';
}
}
}

結果。
  スケッチが1523バイト(37%)
  グローバル変数が100バイト(39%)

~~~~~~~~~~~~~~~~~~~~~~~~~~
■LCD_TEST1 : "Wire.h"を使わない場合

// "Wire.h"を使わないACM0802液晶テスト
#include "i2c_lcd_acm0802_tn.h" // LCD制御ヘッダーファイル
// ★wire.hは使わない
i2c_lcd_acm0802_tn LCD(0x3C); // LCD I2Cアドレスを設定
/***** SETUP *****/
void setup() {
cli(); // 割込禁止
PORTA.DIR = 0b11001000; //ポート出力指定
// || |||+---- PA0 6pin UPDI
// || ||+----- PA1 4pin in SDA
// || |+------ PA2 5pin in SCL
// || +------- PA3 7pin out
// |+---------- PA6 2pin out
// +----------- PA7 3pin out
// PIT 1秒タイミング
RTC.CLKSEL = 0b00000001;
// ++---- INT1K 1024Hz
RTC.CTRLA = 0b00000001;
// ||||| +---- RTCEN RTC周辺機能許可
// |++++------- CLK_RTC DIV1 1/1
// +----------- RUNSTBY
RTC.PITCTRLA = 0b01001001;
// |||| +-- PITEN
// ++++----- PERIOD 1/1024 →1秒
// I2C液晶
// Wire.begin(); // I2C開始 ★wire.hは使わない
LCD.begin(8, 2); // 液晶初期化 8文字x2行
}
/***** LOOP ******/
void loop() {
byte c = 'A';
LCD.setCursor(0, 0); // LCD上段
LCD.strdisp("Test LCD"); // タイトル
while(1){
if(RTC_PITINTFLAGS & 0x01){ // PIT 1秒経過
RTC_PITINTFLAGS = 1; // PIフラグクリア
LCD.setCursor(7, 1); // LCD右下段
LCD.write(c); // A~Z
c++;
if(c > 'Z') c = 'A';
}
}
}

結果。
  スケッチが773バイト(18%)
  グローバル変数が14バイト(5%)

8文字×2行の液晶、1行目にタイトルを表示して
右下に1文字の数字(TEST0)あるいは大文字英字
(TEST1)を1秒サイクルでインクリメント。

例題の違いはWire.hを使うか使わないか。
TEST0の下請けルーチン、i2c_lcd_acm0802は
これまでどおりにWire.hとtwi.hで制御。

TEST1のi2c_lcd_acm0802_tnはtiny402の
TWIレジスタを直接操作。
手抜きで、I2Cの制御にエラーが生じても(ACKが来ない
ゾ)そこでストップさせずにそのまま最後まで進んじゃ
います。

その結果、Wire.h仕様のTEST0だと、
  スケッチが1523バイト(37%)
  グローバル変数が100バイト(39%)

それがTEST1だと
  スケッチが773バイト(18%)
  グローバル変数が14バイト(5%)
と、大幅に使用メモリが少なくなりました。
RAMの使用量を減らせたのが大きいかと。

スケッチと下請けルーチンはダウンロードで。(zip圧縮)

 ・ダウンロード - lcd_test0.zip Wire.h使用

 ・ダウンロード - lcd_test1.zip TWIレジスタ直書きで


TEST1(i2c_lcd_acm0802_tn)で使ったTWIレジスタ
のアクセス方法。

/********************************/
/* TWIモジュールのアクセス */
/********************************/
// ATtiny402のTWIハードウェアを制御
// 割り込みを使わなない
// タイムアウトチェックカウンタを設けて異常でも抜けるように
// 正しくACKが帰ってこない場合も処理を続行
/***** TWI 初期化 *****/
// TWI周波数を設定 100kHz
void twiInit(void )
{
TWI0.MBAUD = 100; // 20MHz/2/fSCL
// 100kHz→100
// 400kHz→25
TWI0.MCTRLA = 0b00000001;
// || ||||+----- ENABLE 主装置許可
// || |||+------ SMEN 簡便動作しない
// || |++------- TIMEOUT 使わない
// || +--------- QCEN 迅速指令 しない
// |+----------- WIEN 書き込み割り込み なし
// +------------ RIEN 読み込み割り込み なし
TWI0.MSTATUS = 0b00000001;
// ||||||++----- BUSSTATE アイドル状態に
// |||||+------- BUSERR
// ||||+-------- ARBLOST
// |||+--------- RXACK
// ||+---------- CLKHOLD
// |+----------- WIF
// +------------ RIF
}
/***** TWI 書込み送出開始 *****/
void twiStartW(uint8_t adrs)
{
uint16_t tt; // time out check counter
TWI0.MADDR = adrs << 1; // アドレス 書き込みで(0)
tt = 2000; // 2000 loop
while(tt){ // time out?
if(TWI0.MSTATUS & TWI_WIF_bm) break; // WIF=1を待つ
tt--;
}
}
/***** TWI データ書き込み *****/
void twiWrite(uint8_t data)
{
uint16_t tt; // time out check counter
TWI0.MDATA = data; // データ書き込み
tt = 2000; // 2000 loop
while(tt){ // time out?
if(TWI0.MSTATUS & TWI_WIF_bm) break; // WIF=1を待つ
tt--;
}
}
/***** TWI 送出終了 *****/
void twiStop(void)
{
TWI0.MCTRLB = TWI_MCMD_STOP_gc; // Stop Condition
}

 

| | コメント (1)

2025年9月 5日 (金)

ATtiny402マイコン サンプル:I2Cで液晶表示

ATtiny402マイコン サンプル:割り込みでシリアル出力
ATtiny402マイコン サンプル:RCサーボモータテスター
に続いて、あらたなATtiny402マイコンのサンプルです。
これらに、I2C液晶を追加してみました。

Sch01

※参:Arduino IDEの環境
Ide01

・シリアル出力を割り込みで。
  出力完了を待たなくても、次の仕事が
  できる。

・A/D変換データ取得を割り込みで。
  変換完了を待たなくても最近値を
  いつでも読める。

・1ms割り込みでタイマー。
  この中でA/D変換開始を指令。


液晶表示の様子
Tn11

ざっと、タイミングを見てもらいましょう。
上から
  PWM出力 50Hz(20ms)でサーボ用パルスを出力
  シリアル出力データ(9600BPS)
  I2C SCL 液晶表示
  I2C SDA  〃

01m

4文字+6文字の液晶表示を行った後、シリアルデータを出力。
2msの時間待ちをしてから2文字を表示。
シリアル出力が割り込みで処理されるので、
2ms待ちと2文字表示が、シリアル出力完了を待たなくても
処理が進んでいます。

さて、なんとかしたいのが液晶表示のためのI2Cアクセス。
「Wire」「twi」ライブラリを使うので複雑になっています。
液晶表示だけなら書くだけ。
余計な処理はいらないので、もっと短くシンプルに
できるはず。

※参考
I2C液晶のアクセス、割り込み処理で遅れる原因らしきもの
I2C液晶のアクセス、割り込みで処理しないようにすると

Arduino UNO R3のI2C制御とATtiny402の制御が
異なるので、ATmega328用のプログラムは動きません。
もうちょい勉強です。

~~~~~~~~~~~~~~~~
  超低速2相パルス発生回路・ケース入れ で、
  I2C液晶表示をwireライブラリを使わない
  ようにしたら(wireの中からtwiを呼んでいる)、
  プログラムのサイズが1.8kバイトほど減少。
  RAMエリアも200バイトほど減りました。
~~~~~~~~~~~~~~~~
てな具合なので、なんとかしたいです。

※バックアップ代わりに今回のスケッチ
  液晶表示処理は別ファイルになってます
   ・ダウンロード - lcd_pwm_txint0.zip


※注意:I2Cのプルアップ抵抗
 ・秋月の液晶表示器 ACM0802C-NLW-BBW-IIC、I2Cのプルアップ抵抗
モジュールに2.2kΩのプルアップ抵抗が内蔵されています。

※続き
 ・ATtiny402マイコン サンプル:I2Cで液晶表示(Wire.hを使わないで)
   プログラムエリアとRAMエリアを縮小できます。

 ・ATtiny402サンプル:I2Cで液晶表示 SCL周波数を設定できるようにしたら


| | コメント (0)

2025年7月 3日 (木)

DDS IC「AD9833」をArduino UNO R3で制御:箱入れ #2

DDS IC「AD9833」をArduino UNO R3で制御:箱に入れる
ここからちょっと手直し。
 ・高い周波数で方形波を出力するとちゃんとした
  波形が出てこない。原因はアンプの飽和。
 ・AD9833の出力、正弦波と三角波だとおよそ
  0.6V(p-p)なのが、方形波だと電源電圧フルスイング
  になってしまう。
 ・このため、前の回路では前段のアンプ(4V(p-p)まで増幅)
  が飽和。
 ・そこで、方形波の時にレベルを下げるような細工
  を入れ込む。
 ・使ったのは2入力のアナログマルチプレクサ。
    74LVC2G53 8pinのIC
      「2G」なんで2ゲートかと思いきや
      機能ブロック的には一つだけ。
      なんかへんな感じ。
 ・方形波を出力する時は、出力レベルを1/9した側に
  切り替える。
 ・飽和しないしLPFを通らないので、まっとうな
  方形波(今度はアンプでの帯域制限)が出るように。

ということで、こんな回路になりました。
  ※回路変更あり(一連のコメントを参照)
Ad9833
・BSch3Vのデータ
   ・ダウンロード - ad9833_04.ce3

切り替え機能を追加したスケッチ。
   ・ダウンロード - ad9833_03.zip

AD9833を使う時の参考にどうぞ。

周波数を高くするときにいるのは、やっぱ、フィルタです。
これ以上の高速アンプは電気食いだし、電池運用はちょい
としんどいか。

※回路図をちょっと訂正
LVC2G53の手前の2段CRフィルタ。
マルチプレクサの入力容量がけっこうあるようなので
(データシートでオン時約20PF)フィルタ部を変更しました。
9833a
  入力部の抵抗を200Ω→1Kに。
  コンデンサをなしに。
1MHzあたりからレベルが落ち始めます。
4MHzになると出力電圧はほぼ半分に。

※追記
AD9833の出力を
  ・出力レベルを可変したい
  ・出力ののDCオフセット電圧を可変したい
ときの方法、面倒でもこんな構成かと。
Pm4
方形波の時はLPFを通さずできるだけ「生」信号
を使えるよう、MPXで分けます。
正弦波、三角波の時だけLPFを通します。
12dB/octので描きましたが、2段にして24dB/octや
LCフィルタでも良いわけです。
方形波出力のとき、後段アンプを飽和させないように
します。
  飽和させると電源ラインが汚くなります。
周波数が高くなると、高抵抗が使えなくなるので
ボリュームの入力部が面倒になります。

現スケッチのままで動くように
 マルチプレクサのプルアップ抵抗をプルダウンに。

04a


| | コメント (22)

2025年6月30日 (月)

DDS IC「AD9833」をArduino UNO R3で制御:箱に入れる

DDS IC「AD9833」をArduino UNO R3で制御
DDS IC「AD9833」の出力にバッファアンプを
DDS IC「AD9833」の出力にバッファアンプを #2

この時は、むき出しのユニバーサル基板でした。
便利に使おうとすると、
 ・箱に入ってて欲しい
 ・電池運用したい
となってしまいます。

百均屋で買ってきた透明樹脂の「箱」に入れました。
  回路は、元のとほぼ同じ。
  出力アンプはOPA2863で。
  1MHzちょいが安定して出ればOK。
  ほんとは出力レベルを可変したかったけど、
  DCオフセットの調整だけ。

Sw11
手組みした基板の様子。
Ss12_20250630150301
回路図。 (クリックで拡大↓)
Ad9833_dds03
スケッチ
  ・ダウンロード - ad9833_02.zip

AD9833のクロックをATmega328Pから出してますんで
ヒューズを書き換えて、16MHzクロックを出すようにし
なくちゃなりません。
  テストするだけならPB1に出してる8MHzも
  使えます。

役に立つかどうかは不明ですが、周波数スイープ機能を
入れてます。
  ラジオのIFトランスの調整あたりに
  使えないかなぁ。
ジャンクボックス内で拾った455kHzのセラミック・フィルタ
とTrラジオのIFTで試してみました。
Sw13

Sw14
フィルタの中心、455kHzが見えています。

スイープ速度を速くすると、周波数計算を行っている
サイクルが見えてきます。
Sw15
計算はもっと早くできるんですが液晶表示が遅い。
液晶表示は0.1秒に1回。

もうひとつ。
AD9833をはじめ、さまざまなDDS IC、無線家の皆さんが
VFOとして使われることが多いようで「スプリアス」を
気にされています。
しかし・・・原理的に、クロック周波数に近い、高い周波数
を出そうとすると、DDS処理に絡むジッタの割合が大きく
なり、きれいな波形が得られません。

これ、正弦波じゃなく方形波(DACデータのMSB)で見ると、
「なんじゃこりゃ」が見えてきます。
今回の回路では16MHzが基準クロック。
割り切れる8MHzや4MHz、2MHz、1.6MHz、1MHzは
きれいな波が出てきます。

4MHzだとまっとうな方形波。
Aa001_20250630170201
16クロックで1μsになり、そこに4発の方形波
が並びます。
1発あたり4クロック。

ところが5MHzになると・・・
  発生周波数を自由にできるのが
  DDSの取り柄なんですけれど。
Aa000_20250630170401
1μs間に5発のパルスが続くんで間違いなく5MHz。
でもそのパルスの間隔、周期は1クロック幅で右に
行ったり左に行ったり。

例えば、1秒ゲートの周波数カウンタで計ったら
こんな波形でもほんとにジャスト5MHzになります。
  それがDDSの原理。

オシロで単発波形を採るんじゃなくちょいと
流してみるとこんな波形になります。
Aa002
「なんじゃこりゃ」のデジタルデータを使って正弦波の
データが入ったROMをアクセスしてD/A変換。
周波数が高いほど、影響が大きく出てきます。
この波形が元になるんで、
  「スプリアス、そりゃ出まっせ」
かと。
クロック周波数に近い、高い周波数が欲しいときは、
出す周波数ギリギリのフィルタで高調波を落と
すしかないでしょ。

※追記
もう一つ、スイープ波形。
制限波出力で1kHz→4MHzを4秒かけてスイープ。
 上段がスイープトリガ用出力。
 中段がAD9833の出力。
 下段だOPA2863を2段通った出力。
  リニアでのスイープなんでこういった周波数特性
  を見る時はLOGスイープが欲しくなります。

Wv12
4MHzになるとレベルが約半分に。
OPA2863の性能が見えてます。
  オペアンプ前段に入れた220Ω+100PF2段の
  LPFのせいです。
  OPA2863はもっと優秀。

※MAX038発振器では ・・・
昔に組んだMAX038発振器では出力オペアンプとして
「AD811」を使ってました。
  帯域幅    140MHz
  スルーレート 2500V/μs
DigiKeyでの現在価格2200円。

※続き
DDS IC「AD9833」をArduino UNO R3で制御:箱入れ #2


| | コメント (0)

2025年6月 3日 (火)

UNO R4はanalogWrite(n,128)でデュティー50%の方形波が出るぞ

Arduino UNO R3のanalogWriteはちょいと欠陥品。
 ・2020年2月10日:ArduinoのanalogWrite 1/255なの?

D6ポートにデューティ50%の方形波を出すつもりで
  analogWrite(6 ,128)
としても、デューティ50.4%くらいの方形波が出てきます。
きっちり50%にしたいのなら、
  analogWrite(6,127)
としなくちゃなりません。
そして、D9,D10,D11,D3ポートへのPWMだと
  analogWrite(3 ,127)
  analogWrite(3 ,128)
これのどちらも50%にならないのです。
(D5,D6とは周波数も変わって2.040ms周期)

6つの50%デューティの方形波を得たいスケッチ

/* duty 50%の方形波を出すつもり */
void setup() {
analogWrite(6, 128); // OC0A
analogWrite(5, 128); // OC0B
analogWrite(9, 128); // OC1A
analogWrite(10,128); // OC1B
analogWrite(11,128); // OC2A
analogWrite(3, 128); // OC2B
}
void loop() { }

これだとUNO R3でもUNO R4、どちらでも動きます。
しかし、UNO R3だと前述のしがらみが残り、analogWriteと
呼ぶには誤差が大きすぎます。

UNO R4だとどうでしょか。
周波数は6つとも同じで490Hz(ほど)になってます。
   例のジッタで下位桁が変動
そしてデューティは、128できっちり50%。
さて、他の数値は・・・
  0だとLに張り付き
  1だと8μsだけHのパルス。
  254で16μsだけL。
  255で8μsだけL。
  256でHに張り付き。
エエ感じで「val/256」のanalogWriteしてます。

ただ気になったのが、6つのPWM出力ポートに出てくる
周波数が「3つ・3つ」で微妙に違うのです。
  D6=D11=D3
  D5=D9=D10
この組みになっていて、例えばD5とD6の出力波形を
オシロで観察すると、ゆっくりと波形が流れるのです。
1分ちょいで一周します。
クロックの大もとは同じですし、使ってるタイマの
分周比が微妙に異なっているのかと推測しています。

※UNO R4での微妙な周波数差
黄色がD6ポートのPWM。緑がD5ポート。
Dd11_20250603151001
16秒経過↓で1/4サイクルほどのズレが発生。
Dd12_20250603151001
緑が左へズレて行きます。

※参
Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMの例
ラズピコ analogWriteの誤差



| | コメント (0)

2025年5月27日 (火)

DDS IC「AD9833」の出力にバッファアンプを

2025年5月25日:DDS IC「AD9833」をArduino UNO R3で制御 
この続き。
便利そうなツールになりそうなのでケース(百均の)に
入れるつもりですが、作業はまだ。

AD9833の出力レベルが小さいので、もうちょい大きくして
みました。

定格だと、Vout(max)が0.65V。
正弦波や三角波だとGNDからちょっと上がったところ
から波形が始まり、ピークが約0.6Vちょい。
P-P値で0.6Vほど。
RF用途では、このままで良いかもしれませんが、
正確で安定した周波数を出せるんで、低周波発振器としても
役立ちそうです。

そこで、現状の
・0.6V(P-P)を6倍ちょいして0~4Vの振幅に。
・マイナス電源を用意して
  0~+4V、-2V~+2V、-4V~0V
 くらいの範囲で出力電圧をオフセットできるように。
   0Vを中心に4V(P-P)の波形を上下。
・オフセット電圧の調整はボリュームで。
・1MHzを越える周波数はちょっと置いておいて。
・低周波用に直流結合で。

こんな回路を付加してみました。
Ad98_01
手持ちの Rail to Rail In/Outのオペアンプで
使えそうなのが(帯域が欲しいゾ)AD823あたり。
  とりあえず、様子見で
出力波形を切り替えて方形波にしても、ドカンと大レベル
のが出ちゃうということがなくなります。
  正弦波や三角波だと0.6Vですが、方形波にすると
  電源電圧いっぱいの信号になります。
  4V(p-p)になるようにしてるのが、5Vで頭が
  制限されるので、信号が大きくなってびっくり
  することがありません。

帯域があって使いやすそうで安価なアンプ、
このあたりかな。
・OPA810 FET入力 70MHz 1コ入り
・OPA863 バイポーラ入力 110MHz 1コ入り
     OPA2863が2コ入り
     入力バイアス電流が大(0.3uA)
何かのついでに買ってみます。

OPA2863、OPA810での実験

| | コメント (0)

より以前の記事一覧