ラジオ少年の楽しい電子工作、その他

AVRを使った簡単な回路の実験、そして日々のちょっとした出来事を書きます。

AVR版 OSCILISCOPE 時計のプログラム

2011年03月01日 | 日記
AVR版オシロスコープ時計のプログラムです。
/*
*******************************************************************************
* AVRCLOCK : AVR Oscilloscope CLOCK
*******************************************************************************
* Author : Bruno Gavand, October 2007 (for PIC).
* Ref. http://www.micro-examples.com/
* Radio Boy modified for AVR, ATmega88P 2011/2/27.
* This program shows how to display a digital clock on an oscilloscope
* with a AVR and only 4 resistors.
*
* Circuit schematics :
*
* ------------+
* RD0 +----------------> to oscilloscope X trigger input
* |
* RD1 +----------------> pull-down to ground with 22Kohm, push button to Vcc: minutes adjustment
* RD2 +----------------> pull-down to ground with 22Kohm, push button to Vcc : hours adjustment
* AVR | ____
* RB1 +----|____|-----+---------> to oscilloscope Y input
* | 330 |
* | +-+
* | | | 210 RD1+----|---Push SW ----Vcc
* | +-+ |
* | ____ | 22Kohm
* RB0 +----|____|-----+ |
* | 330 | |
* ------------+ +-+ GND
* | | 330
* +-+
* |
* -----
* --- GND
* -

*/

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <string.h>
#define F_CPU 4000000UL // 4MHz
#include <util/delay.h>


/* target : AVR ATmega88P, 4Mhz external clk
* no watchdog. Fuse Low = E0
*
* Fuse High = DF (WDT disable)
*/

//PORTD bit definition
#define TRIGGER 0 // PORTD(bit0), this output is to be connected to oscilloscope trigger input
#define TRIGGER_ON PORTD |= (1<<TRIGGER)
#define TRIGGER_OFF PORTD &= ~(1<<TRIGGER) // input keys mask
#define KEY_MIN_UP 1 // PORTD(bit1)minute adjust button
#define KEY_HH_UP 2 // PORTD(bit2)hour adjust button

#define HIGH PORTB = 0b00000011 // uper line
#define MID PORTB = 0b00000010 // middle line
#define LOW PORTB = 0b00000001 // lower line
#define ZERO PORTB = 0b00000000 // lowest line

#define MAX_SCALER 15625 // number of timer 0 overflow per second @ 12 Mhz = 12000000/256

#define MAX_DIGIT 6 // number of digits to be displayed
#define SLOTS (MAX_DIGIT * 3 + 4) // number of time slots : 2 for header, 3 per digits, 2 for trailer

/*
* 10 digits 7 segment encoding + blank
*/
const uint8_t septSeg[11] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x00 } ;

/*
* slot index for digit start
*/
const uint8_t sIdx[] = {1, 4, 8, 11, 15, 18} ;

uint8_t display[MAX_DIGIT] ; // digit to be displayed

/*
* time slot encoded line flags :
* bit 0 is upper line
* bit 1 is middle line
* bit 2 is lower line
* (if no line flag is set, spot is redirected to lowest line)
* bit 6 is lower vertical bar
* bit 7 is upper vertical bar
*/
uint8_t line[SLOTS] ;

uint8_t dIdx = 0 ; // time slot counter
uint8_t fIdx = 0 ; // frame counter

uint16_t scaler = 0 ; // RTC scaler
uint8_t ss = 0, mn = 0, hh = 0 ; // RTC



void timer0_ovf_interrupt_init(void)
{
TCCR0A = 0x00;
TCCR0B = 0x01; //timer0 prescaler is 1:1
TIFR0 = 7; //clear flag of TIFR0
TCNT0 = 0; //timer/counter initialize
TIMSK0 = 1<<TOIE0;
return;
}

/*
* ISR
*/

ISR( TIMER0_OVF_vect )
{

scaler++ ; // increment scaler
if(scaler > MAX_SCALER) // one second has expired ?
{
scaler = 0 ; // clear scaler
ss++ ; // next second
if(ss == 60) // last second in minute ?
{
ss = 0 ; // clear second
mn++ ; // next minute
if(mn == 60) // last minute in hour ?
{
mn = 0 ; // clear minute
hh++ ; // next hour
if(hh == 24) // last hour in day ?
{
hh = 0 ; // clear hour
}
}
}
}


if((line[dIdx] & 0x02) && (line[dIdx] & 0x04)) // if full vertical bar(right)
{
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
}

else if(line[dIdx] & 0x04) // if lower vertical bar(right)
{
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
}


else if(line[dIdx] & 0x02) // if upper vertical bar(right)

{
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
}

if((line[dIdx] & 0x10) && (line[dIdx] & 0x20)) // if full vertical bar(left)
{
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
LOW; HIGH; LOW; HIGH ;
}



else if(line[dIdx] & 0x10) // if lower vertical bar(left)
{
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
MID; LOW; MID; LOW ;
}


else if(line[dIdx] & 0x20) // if upper vertical bar(left)

{
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
MID; HIGH; MID; HIGH ;
}

if(dIdx == 7) // hour : minute separator
{
LOW;
_delay_us(5) ;
MID;
_delay_us(5) ;
}
else if(dIdx == 14) // minute : second separator
{
if(scaler < MAX_SCALER / 2) // blink 0.5 Hz
{
LOW;
_delay_us(5) ;
MID;
_delay_us(5) ;
}
}

switch(fIdx) // depending on frame index
{
case 0: // upper line
if(line[dIdx] & 1)
{
HIGH ;
}
else
{
ZERO ;
}
break ;
case 1: // middle line
if(line[dIdx] & 0x40)
{
MID ;
}
else
{
ZERO ;
}
break ;
case 2: // lower line
if(line[dIdx] & 0x08)
{
LOW; LOW ;
}
else
{
ZERO ;
}
break ;
}

dIdx++ ; // next slot
if(dIdx == SLOTS) // last slot ?

{
dIdx = 0 ; // clear slot

TRIGGER_ON; // triggers the scope

fIdx++ ; // next frame
if(fIdx == 3) // last frame ?

{
fIdx = 0 ; // clear frame
}
TRIGGER_OFF; // end trigger

}
}


// main entry

int main()
{


DDRD = 0b00000001 ; // PORTA direction register
PORTD = 0b00000000 ;

DDRB = 0b00000011; // PORTB is output
PORTB = 0b00000000 ;

/*
* clear buffers
*/
memset(line, 0, sizeof(line)) ;
memset(display, 0, sizeof(display)) ;


timer0_ovf_interrupt_init();
sei();

for(;;) // main loop
{
uint8_t i ;


if(PIND & (1<<KEY_MIN_UP)) // adjust minutes

{
ss = 0 ;
mn++ ;
}

else if(PIND & (1<<KEY_HH_UP)) // adjust hours
{
ss = 0 ;
hh++ ;
}


mn %= 60 ; // prevent minute overflow
hh %= 24 ; // prevent hours overflow
_delay_ms(100) ; // debounce

/*
* prepare display buffer
*/

display[5] = ss % 10 ; // seconds
display[4] = ss / 10 ;

display[3] = mn % 10 ; // minutes
display[2] = mn / 10 ;

display[1] = hh % 10 ; // hours
display[0] = (hh > 9) ? hh / 10 : 10 ;
// blank first digit if zero

/*
* prepare time slot flags
*/
for(i = 0 ; i < MAX_DIGIT ; i++) // for each digit
{
uint8_t s;
uint8_t *p ;

s = septSeg[display[i]] ; // get 7 segment encoding

p = &line[sIdx[i]] ; // get pointer to time slot, left part of the digit

*p = s & 0b01111001;

p++ ; // next slot, center part of the digit

*p = s & 0b01001001;

p++ ; // next slot, right part of the digit

* p = s & 0b00000110;

}
}
}


/*Instruction for use

* Connect X1 (see circuit diagram above) to the Y input (vertical deviation) of the oscilloscope
* Connect X2 (see circuit diagram above) to the external trigger input of the oscilloscope
* Set on your oscilloscope :
o timebase to 0.1 ms
o vertical deviation 1/V division
o external trigger
* Power the circuit : display starts with 0:00:00
* Press hours button to change hours
* Press minutes button to change minutes
* Enjoy !

Please add comments, suggestions and report bugs to me in my forums
All trademarks and registered trademarks are the property of their respective owners */



コメント (17)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする