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 */
/*
*******************************************************************************
* 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 */