
電圧計のソースコードです。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[]の内容(フォントパターン)で表示 */
- }
0 件のコメント:
コメントを投稿