#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[]の内容（フォントパターン）で表示 */
}
