2008年9月30日火曜日

TinyでPONG!(予告)


こんなものを準備中です。レトロすぎますか?あと2年とちょっとでアナログTV放送も終わるというのに…(涙)…。

Tiny2313(秋月で100円!)を使っています。パドルもボールも滑らかに動きます。音も出ますよ。そのうち動画をアップしようと思います。

2008年9月29日月曜日

AVR書込み器が安い!


毎度おなじみ秋月電子でアトメル純正のAVR用書込み器(ライターとかプログラマーとかとも言いますね)AVRISPmkIIが税込4,000円で販売されています。これは安い。デバッガーの機能などはなくて、ISPコネクタ経由のシリアル書き込みだけしかできませんが、ほとんどの場合これで十分です。

秋月はPICの販売に力を入れていて、AVRはずっと脇役のままだったので、このまま扱いがフェードアウトしてしまうのではないかとひやひやしていたのですが、ほっとしました。安価な純正プログラマーの投入でAVRユーザが増えてくれるとうれしいですね。

ちなみに私はAVRDragonという基板むき出しのデバッガ兼プログラマーも持っているのですが、ISP書き込みに関してはAVRISPmkIIよりもスピードが遅いです。2倍以上違うような気がします。書き込みアルゴリズムが違うんでしょうか、単にチューニングを怠っているんでしょうか…。

2008年9月27日土曜日

Tiny26Lがディスコンに…

AVRの主な入手先である秋月電子。以前からTiny26Lを激安(150円だったかな?)で置いてあったが、いつの間にか品切れに…あらら。どきどきしながらアトメルのホームページで調べると、すでに生産完了品(=ディスコン=mature deviceってやつ)になっていました。なるほど。共立電子とかDigikeyとかには在庫はあるようだけど。

アトメルによれば代替品としてTiny261を推奨しています。ピン配列含めてほぼ互換なのは助かりますね。フラッシュ容量の大きい461/861もラインナップしているのもいいですね。ただ、まだ店頭での入手性があまり良くないのがつらいです。先日マルツ電波のマルツメイク館でTiny461を入手できました。通販でも買えるみたいです。

2008年9月26日金曜日

Tiny26Lで電圧計(4)

Sourceforgeにソースコードと回路図PDFを置いてみました。初めてなので、こんな方法でいいのかどうか不安ですが…。

Tiny26Lで電圧計(3)


電圧計のソースコードです。Cで書いてあります。下の「+expand source」というリンクをクリックすると表示されます。私はWinAVRを導入して、開発環境AVR Studioからビルドしています。

Tiny26Lへのプログラムの書き込みはAVRISPmkIIを使っています。ヒューズ設定をデフォルトのまま「内蔵RC発振=1MHz」として使えばOKです。特にいじる必要はありません。ただし、一度設定をいじったヒューズをデフォルトの状態に戻そうとした場合には注意が必要です。AVR Studio 4.13というバージョンではTiny26Lの構成ファイルにバグがあり、ヒューズの設定をプルダウンメニューから正しく選ぶことができないのです。その場合にはデータシートとにらめっこして、直接ヒューズの下位バイトに数値を入力してください。今回の場合はLow Byte=0xE1です。上のイメージはその時のウィンドウのスナップショットです。

電圧計 main.c

#define F_CPU 1000000L /* システムクロック=1 MHz(内蔵RC発振) */
#define COM_MAX 3 /* LEDのcommon端子の数 */
#define CALIB_REAL_MV 5080L /* リアル校正電圧[mV] */
#define CALIB_ADC_MV 2570L /* ADC校正電圧[mV](リアル校正電圧の約半分で入ってくる) */
#define LED_REFRESH_MS 15 /* LEDのリフレッシュレート[ms] */
#define LUMINOUS_PERSENT 30 /* LED輝度[%] */
#define ADC_REFRESH_MS 200 /* ADCの更新周期[ms] */
#define ADC_REFRESH (ADC_REFRESH_MS / LED_REFRESH_MS) /* ADCの更新周期[LEDリフレッシュ回数] */

#define COM_SWITCH_MS (LED_REFRESH_MS / COM_MAX) /* COM端子1本当たりの時間[ms] */
#define LED_ON_MS (COM_SWITCH_MS * LUMINOUS_PERSENT / 100) /* LEDがONしている時間[ms] */
#define LED_OFF_MS (COM_SWITCH_MS - LED_ON_MS) /* LEDがOFFしている時間[ms] */

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>

//
// Globals
//
uint16_t CurVolt;
uint8_t SegRAM[3];
uint8_t CurCom = 0; /* Current COM Number 0, 1, 2, 0, 1, 2, ... */
uint8_t SegFont[10] PROGMEM = {
//_abcdefg
0b10000001, /* 0 */
0b11001111, /* 1 */
0b10010010, /* 2 */
0b10000110, /* 3 */
0b11001100, /* 4 */
0b10100100, /* 5 */
0b10100000, /* 6 */
0b10001101, /* 7 */
0b10000000, /* 8 */
0b10000100, /* 9 */
};

//
// Prototypes
//
void wdt_off(void);
void init_io(void);
void adc_cont_start(void);
void put_digit(void);
void print_volt(void);

//
// MAIN LOOP
//
int main(void)
{
wdt_off(); /* ウォッチドッグタイマーをOFF */
init_io(); /* I/Oの初期化 */
adc_cont_start(); /* ADCを連続変換モードでスタート */

uint8_t adcref = 0; /* ADCのリフレッシュカウンタ */

while(1) {
if (adcref == 0 && (ADCSR & _BV(ADIF))) {
ADCSR |= _BV(ADIF); /* ADCの読み込み */
CurVolt = ADCW; /* 現在電圧の更新 */
}
print_volt(); /* 電圧の表示 */

if (++CurCom >= COM_MAX) { /* 各カウンタの回転 */
CurCom = 0;
if (++adcref >= ADC_REFRESH)
adcref = 0;
}

_delay_ms(LED_ON_MS); /* 輝度調整:ONの時間 */
PORTB |= 0b00111000; /* 全消灯 */
_delay_ms(LED_OFF_MS); /* 輝度調整:OFFの時間 */
}

return 0;
}

//
// Functions
//
void wdt_off(void)
{
cli();
wdt_reset();
MCUSR &= ~(1 << WDRF);
WDTCR |= (1 << WDCE) | (1 << WDE);
WDTCR = 0x00;
//sei();
}

void init_io(void)
{
PORTA = 0xff;
DDRA = 0xff;

PORTB = 0b10111111;
DDRB = 0b00111000;

ADMUX = 0x29; /* REFS[1:0]/ADLAR/MUX[4:0] = 00101001 */
/* AVCCピン基準電圧、左揃え、シングルエンドCH9 */
ADCSR = 0x87; /* ADEN/ADSC/ADATE/ADIF/ADIE/ADPS[2:0] = 10000111 */
/* 完了割り込み禁止、クロック128分周 */
}

void adc_cont_start(void)
{
ADCSR |= _BV(ADSC) + _BV(ADFR);
}

void put_digit(void)
{
uint8_t pb, pa;

pb = PORTB | 0b00111000;
pb &= ~(0b00001000 << CurCom);
pa = SegRAM[CurCom];

PORTB = pb; /* COM端子のスイッチ */
PORTA = pa; /* フォントパターンの出力 */
}

void print_volt(void)
{
uint32_t r;
uint16_t p;

if (CurCom == 0) {
r = CurVolt;
//r = r * VCC_MV / 1000;
r = r * (CALIB_REAL_MV * CALIB_REAL_MV / CALIB_ADC_MV) / 1000L;
p = r >> 16;
if (p > 9)
p = 9;
SegRAM[0] = pgm_read_byte(&SegFont[p]) & 0b01111111; /* 最上位桁+小数点 */

r -= p * 65536L;
r *= 10;
p = r >> 16;
SegRAM[1] = pgm_read_byte(&SegFont[p]); /* 中位桁 */

r -= p * 65536L;
r *= 10;
p = r >> 16;
SegRAM[2] = pgm_read_byte(&SegFont[p]); /* 最下位桁 */

// r -= p * 65536L;
// r *= 10;
}

put_digit(); /* SegRAM[]の内容(フォントパターン)で表示 */
}

Tiny26Lで電圧計(2)



電圧計の回路図です。図中左下のオレンジ枠の部分はブレッドボード用の可変電圧電源であって、電圧計とは直接の関係はありません。ただ、この電源の出力の電圧を表示するという意図で載せてあります。

電圧測定入力はちょうど半分の電圧になるようにR10とR14で分圧してあり、これをTiny26L内蔵のAD変換器に入力しています。こうすることでTiny26Lの電源電圧を超える電圧も読むことができるようになります(フルスイングしても電源電圧どまりになってしまうので)。ただ、この入力抵抗でそこそこ電力消費をしますので、もう少し大きな抵抗値のほうがよかったかもしれません。47kΩずつくらいがちょうどいいかも。

LEDは3コモン×(7セグメント+DP)のダイナミックドライブを構成しています。部品点数が増えるので本当はLEDのコモンも直接AVRでドライブしたかったんですが、十分な輝度を出すためにはチップの定格を超えてしまうので涙をのんでPNPトランジスタでドライブしています。

さあ、次はソースコードの紹介です。

Tiny26Lで電圧計(1)


第一弾は、簡易電圧計を。

実験用のブレッドボードにお手製の可変電圧電源を組み込んで使っているのですが、出力電圧を調整するのにいちいちテスターで測っていました。これが面倒くさくなり、専用の電圧計を作ってしまいました。


ATTiny26Lを使って0.00V~9.99Vで0.01V刻みでLED表示します。実際には可変電圧源の可変範囲1.24V~5.09Vでしか試していません。

電圧計そのものへの電源は、写真では切れていますがお隣の可変電圧電源の一次側(DC7.5~12V)から引いてきています。これを三端子レギュレータで5Vに落として使っています。 LEDのコモン側のドライバーは手元にあったチップトランジスター2SA1202を使っていますが、裏面に実装してあるので写真には写っていません。

回路図とソースコードは次回以降にて。

電子工作ブログを始めます!



ご来訪ありがとうございます。Hazie(へいじー)と申します。 このブログでは私が趣味に仕事に愛用しているAVRというアトメル社の8ビットマイコンを使った工作を中心に紹介していきたいと思います。回路図もソースも公開していきます。皆さんの電子工作ライフに少しでも役に立てばうれしい限りです。

また、電子工作に限らず様々な工作ネタ、技術ネタ、科学教材ネタなども雑多につづっていこうと思います。

インターネットとの付き合いはものすごく長いのですが、いままでずっとROM野郎で、自ら発信するのは初めてです。ちょっと緊張しています。どうかよろしくお願いします。