・バー型10連LEDアレイをマイコンで制御する回路だ。I/Oポートには、LEDの他に圧電サウンダと可変抵抗器が接続されている。圧電サウンダは音を鳴らす他、ADコンバータから値を読み取れば、入力デバイスとして使うこともできる。可変抵抗器はADコンバータに接続されており、アナログ入力が可能だ。
・今回は、お約束のラーメンタイマ(10分まで可)と鼻息測定器(大声も可)のファームウェアを公開した。
マイコン ATMEL ATmega168P-20PU
オプトサプライ10バーLEDアレイ 3色(緑5黄3赤2)タイプ OSX10201-GYR1
圧電サウンダ(他励振) Murata PKM13EPYH4000-A0
カーボン抵抗器 150Ω x 10個、10kΩ、100kΩ
可変抵抗器 500kΩ
積層セラミックコンデンサ 0.1uF x 2個
ピンヘッダ 2x3
電池ボックス 単三型2本用
タクトスイッチ
ユニバーサル基板 70mm x 90mm
(動作)
可変抵抗器のつまみを右回りに回すと、設定時間が増え、設定時間数だけLEDが点灯する。ただし、最初のLEDだけは3秒に設定される。
タクトスイッチを押すと、LEDが点滅を開始する。1分経過するごとに右端からLEDが消灯していく。
このときタクトスイッチを押すと、カウントダウンを停止し、スリープモードに移行する。
タクトスイッチが押されずに設定した時間が経過すると、LEDがすべて点滅し、ブザーが鳴る。
ブザーが鳴っている間にスイッチを押すと、スリープモードに移行する。
スリープモードに入っている間にスイッチを押すと、最初の状態に戻る。
(ソースコード barled-mega168-timer.c)
// PD0 : LED-BAR 01 0:ON 1:OFF
// PD1 : LED-BAR 02 0:ON 1:OFF
// PD2 : LED-BAR 03 0:ON 1:OFF
// PD3 : LED-BAR 04 0:ON 1:OFF
// PD4 : LED-BAR 05 0:ON 1:OFF
// PB6 : LED-BAR 06 0:ON 1:OFF
// PB7 : LED-BAR 07 0:ON 1:OFF
// PD5 : LED-BAR 08 0:ON 1:OFF
// PD6 : LED-BAR 09 0:ON 1:OFF
// PD7 : LED-BAR 10 0:ON 1:OFF
// PC0(ADC0/PCINT8) : Switch 1:OFF 0:ON
// PC1(ADC1) : Resister
// PC2(ADC2) : Piezo Buz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
void wait(volatile long i)
{
while (i-- > 0);
}
#define isSwOff() ( PINC & (1<<PC0) )
#define buz() ( PORTC ^= (1<<PC2) )
#define led01() PORTD ^= (1<<PD0)
#define led02() PORTD ^= (1<<PD1)
#define led03() PORTD ^= (1<<PD2)
#define led04() PORTD ^= (1<<PD3)
#define led05() PORTD ^= (1<<PD4)
#define led06() PORTB ^= (1<<PB6)
#define led07() PORTB ^= (1<<PB7)
#define led08() PORTD ^= (1<<PD5)
#define led09() PORTD ^= (1<<PD6)
#define led10() PORTD ^= (1<<PD7)
#define led01on() PORTD &= ~(1<<PD0)
#define led02on() PORTD &= ~(1<<PD1)
#define led03on() PORTD &= ~(1<<PD2)
#define led04on() PORTD &= ~(1<<PD3)
#define led05on() PORTD &= ~(1<<PD4)
#define led06on() PORTB &= ~(1<<PB6)
#define led07on() PORTB &= ~(1<<PB7)
#define led08on() PORTD &= ~(1<<PD5)
#define led09on() PORTD &= ~(1<<PD6)
#define led10on() PORTD &= ~(1<<PD7)
#define led01off() PORTD |= (1<<PD0)
#define led02off() PORTD |= (1<<PD1)
#define led03off() PORTD |= (1<<PD2)
#define led04off() PORTD |= (1<<PD3)
#define led05off() PORTD |= (1<<PD4)
#define led06off() PORTB |= (1<<PB6)
#define led07off() PORTB |= (1<<PB7)
#define led08off() PORTD |= (1<<PD5)
#define led09off() PORTD |= (1<<PD6)
#define led10off() PORTD |= (1<<PD7)
void led10bar(uint16_t bitvalue)
// bitvalue : 0b 0abcdefg 0:OFF, 1:ON
{
if (bitvalue & 0b1000000000) led10on(); else led10off();
if (bitvalue & 0b0100000000) led09on(); else led09off();
if (bitvalue & 0b0010000000) led08on(); else led08off();
if (bitvalue & 0b0001000000) led07on(); else led07off();
if (bitvalue & 0b0000100000) led06on(); else led06off();
if (bitvalue & 0b0000010000) led05on(); else led05off();
if (bitvalue & 0b0000001000) led04on(); else led04off();
if (bitvalue & 0b0000000100) led03on(); else led03off();
if (bitvalue & 0b0000000010) led02on(); else led02off();
if (bitvalue & 0b0000000001) led01on(); else led01off();
}
void led10barblink(uint16_t bitvalue)
// bitvalue : 0b 0abcdefg 0:OFF, 1:ON
{
if (bitvalue & 0b1000000000) led10();
if (bitvalue & 0b0100000000) led09();
if (bitvalue & 0b0010000000) led08();
if (bitvalue & 0b0001000000) led07();
if (bitvalue & 0b0000100000) led06();
if (bitvalue & 0b0000010000) led05();
if (bitvalue & 0b0000001000) led04();
if (bitvalue & 0b0000000100) led03();
if (bitvalue & 0b0000000010) led02();
if (bitvalue & 0b0000000001) led01();
}
void beep(int length, int pitch)
{
volatile unsigned int i, j;
for ( i = 0; i < length; i++) {
buz();
for (j = 0; j < pitch;j++);
}
}
void initAdc(void)
{
// AD Conv. Enable & Clock ferquency and the input clock to the ADC)
ADCSRA = ( (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0) );
}
uint8_t adc(uint8_t adcport)
{
uint8_t adcdata; // A/D Conv. data
ADMUX = (1<<ADLAR) | adcport; // AD-Conv. 8-bit precision, Use ADC-PORTx
ADCSRA |= (1<<ADIF); // Set ADC Interrupt flag
ADCSRA |= (1<<ADSC); // Start AD Conv.
while ( ( ADCSRA & (1<<ADIF) ) == 0); //Wait to complete adc
adcdata = ADCH; // 8-bit precision
return adcdata;
}
void initPCInt8(void)
{
PCICR |= (1<<PCIE1); // Pin change interrupt enable 0 (PCINT14..8)
PCMSK1 |= (1<<PCINT8); // PCINT8 enable
}
#define StSetTime 0x01
#define StCountdown 0x02
#define StStop 0x03
#define StSleep 0xff
volatile uint8_t STAGE = StSetTime; // Program STAGE definition
ISR(PCINT1_vect)
{
if (isSwOff()) {
switch(STAGE) {
case StSetTime:
STAGE = StCountdown;
break;
case StCountdown:
STAGE = StSleep;
break;
case StStop:
STAGE = StSleep;
break;
case StSleep:
STAGE = StSetTime;
break;
default:
STAGE = StSetTime;
}
}
}
void initInt0(void)
{
EIMSK |= (1<<INT0); // INT0 interrupt enable
EICRA |= (1<<ISC01) | (0<<ISC00); // The falling edge ofINT0 or INT1
}
ISR(INT0_vect)
{
}
// Timer0
void initTimer0(void)
{
TCCR0B |= (1<<CS01) | (1<<CS00); TCCR0B &= ~(1<<CS02);//Clock/64
TIMSK0 |= (1<<TOIE0); //Timer0 Overflow Interrupt Enable
}
volatile long TickCounter = 0;
#define TC10min 36621L
#define TC9min 32958L
#define TC8min 29297L
#define TC7min 25634L
#define TC6min 21972L
#define TC5min 18310L
#define TC4min 14648L
#define TC3min 10986L
#define TC2min 7324L
#define TC1min 3662L
#define TC10sec 610L
#define TC3sec 183L
ISR(TIMER0_OVF_vect)
{
TickCounter--;
}
#define VRADCPORT 0x01 // Trim Resister port no.
int main(void)
{
uint8_t adcdata;
unsigned int i;
long tc; // Setting Time
// Initialize I/O Port
DDRD = (1<<PD7) | (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2) | (1<<PD1) | (1<<PD0); // LED BAR Output mode
DDRB = (1<<PB6) | (1<<PB7); // LED BAR Output mode
PORTC = (1<<PC0); // Pull up resister on PC0 (Switch)
DDRC = (1<<PC2) ; // PC2 output mode Piezo Buzzer
// Initailize Pin Change Interrupt
initPCInt8();
// Initialize AD-convertor
initAdc();
//Initialize Timer0
initTimer0();
// LED, Buz initialize
for (i = 0; i < 3; i++) {
led10bar(0b1111111111);
beep(50, 5);
wait(5000);
led10bar(0b0000000000);
wait(10000);
}
sei(); // Enable Interrupt
STAGE = StSetTime;
while (1) {
switch (STAGE) {
case StSetTime:
// Set Time by Trim resistor
adcdata = adc(VRADCPORT);
if (adcdata > 0xd0) {
led10bar(0b1111111111);
tc = TC10min;
} else if (adcdata > 0xce) {
led10bar(0b1111111110);
tc = TC9min;
} else if (adcdata > 0xc2) {
led10bar(0b1111111100);
tc = TC8min;
} else if (adcdata > 0xb1) {
led10bar(0b1111111000);
tc = TC7min;
} else if (adcdata > 0xa7) {
led10bar(0b1111110000);
tc = TC6min;
} else if (adcdata > 0x9c) {
led10bar(0b1111100000);
tc = TC5min;
}else if (adcdata > 0x91) {
led10bar(0b1111000000);
tc = TC4min;
} else if (adcdata > 0x55) {
led10bar(0b1110000000);
tc = TC3min;
} else if (adcdata > 0x19) {
led10bar(0b1100000000);
tc = TC2min;
} else {
led10bar(0b1000000000);
tc = TC3sec;
}
TickCounter = tc;
break;
case StCountdown:
if (TickCounter > TC9min) {
led10bar(0b1111111111);
} else if (TickCounter > TC8min) {
led10bar(0b1111111110);
} else if (TickCounter > TC7min) {
led10barblink(0b1111111100);
} else if (TickCounter > TC6min) {
led10bar(0b1111111000);
} else if (TickCounter > TC5min) {
led10bar(0b1111110000);
} else if (TickCounter > TC4min) {
led10bar(0b1111100000);
} else if (TickCounter > TC3min) {
led10bar(0b1111000000);
} else if (TickCounter > TC2min) {
led10bar(0b1110000000);
} else if (TickCounter > TC3sec) {
led10bar(0b1100000000);
} else if (TickCounter > 0) {
led10bar(0b1000000000);
} else {
STAGE = StStop;
led10bar(0b0000000000);
}
wait(2500);
led10bar(0b0000000000); wait(2500);
break;
case StStop:
led10barblink(0b1111111111);
beep(500, 5);
wait(5000);
break;
case StSleep:
led10bar(0b0000000000);
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
break;
default:
led10bar(0b0000000000);
}
}
return 0;
}
(Makefile)
# AVR-GCC Makefile
PROJECT=barled-mega168-timer
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=atmega168
TARGETDEV=m168p
CFLAGS=-mmcu=$(MMCU) -Wall
$(PROJECT).hex: $(PROJECT).out
$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
$(PROJECT).out: $(SOURCES)
$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program: $(PROJECT).hex
sudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:
rm -f $(PROJECT).out
rm -f $(PROJECT).hex
鼻息測定器(barled-mega168-blow-meter)
(動作)
最初に3回LEDがすべて点滅し、音が鳴る。
次に、圧電サウンダに息を吹きかけると、その強さに応じていくつかのLEDが点滅し、音が鳴る。
鼻息ではなく、口笛や大声も検出できる。
タクトスイッチを押すとスリープモードに移行する。
スリープモード中にタクトスイッチを押すと最初に戻る。
(ソースコード barled-mega168-blow-meter.c)
// PD0 : LED-BAR 01 0:ON 1:OFF
// PD1 : LED-BAR 02 0:ON 1:OFF
// PD2 : LED-BAR 03 0:ON 1:OFF
// PD3 : LED-BAR 04 0:ON 1:OFF
// PD4 : LED-BAR 05 0:ON 1:OFF
// PB6 : LED-BAR 06 0:ON 1:OFF
// PB7 : LED-BAR 07 0:ON 1:OFF
// PD5 : LED-BAR 08 0:ON 1:OFF
// PD6 : LED-BAR 09 0:ON 1:OFF
// PD7 : LED-BAR 10 0:ON 1:OFF
// PC0(ADC0/PCINT8) : Switch 1:OFF 0:ON
// PC1(ADC1) : Resister
// PC2(ADC2) : Piezo Buz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
void wait(volatile long i)
{
while (i-- > 0);
}
#define BuzOutputMode() ( DDRC = (1<<PC2) )
#define BuzInputMode() ( DDRC &= ~(1<<PC2) )
#define isSwOff() ( PINC & (1<<PC0) )
#define buz() ( PORTC ^= (1<<PC2) )
#define led01() PORTD ^= (1<<PD0)
#define led02() PORTD ^= (1<<PD1)
#define led03() PORTD ^= (1<<PD2)
#define led04() PORTD ^= (1<<PD3)
#define led05() PORTD ^= (1<<PD4)
#define led06() PORTB ^= (1<<PB6)
#define led07() PORTB ^= (1<<PB7)
#define led08() PORTD ^= (1<<PD5)
#define led09() PORTD ^= (1<<PD6)
#define led10() PORTD ^= (1<<PD7)
#define led01on() PORTD &= ~(1<<PD0)
#define led02on() PORTD &= ~(1<<PD1)
#define led03on() PORTD &= ~(1<<PD2)
#define led04on() PORTD &= ~(1<<PD3)
#define led05on() PORTD &= ~(1<<PD4)
#define led06on() PORTB &= ~(1<<PB6)
#define led07on() PORTB &= ~(1<<PB7)
#define led08on() PORTD &= ~(1<<PD5)
#define led09on() PORTD &= ~(1<<PD6)
#define led10on() PORTD &= ~(1<<PD7)
#define led01off() PORTD |= (1<<PD0)
#define led02off() PORTD |= (1<<PD1)
#define led03off() PORTD |= (1<<PD2)
#define led04off() PORTD |= (1<<PD3)
#define led05off() PORTD |= (1<<PD4)
#define led06off() PORTB |= (1<<PB6)
#define led07off() PORTB |= (1<<PB7)
#define led08off() PORTD |= (1<<PD5)
#define led09off() PORTD |= (1<<PD6)
#define led10off() PORTD |= (1<<PD7)
void led10bar(uint16_t bitvalue)
// bitvalue : 0b 0abcdefg 0:OFF, 1:ON
{
if (bitvalue & 0b1000000000) led10on(); else led10off();
if (bitvalue & 0b0100000000) led09on(); else led09off();
if (bitvalue & 0b0010000000) led08on(); else led08off();
if (bitvalue & 0b0001000000) led07on(); else led07off();
if (bitvalue & 0b0000100000) led06on(); else led06off();
if (bitvalue & 0b0000010000) led05on(); else led05off();
if (bitvalue & 0b0000001000) led04on(); else led04off();
if (bitvalue & 0b0000000100) led03on(); else led03off();
if (bitvalue & 0b0000000010) led02on(); else led02off();
if (bitvalue & 0b0000000001) led01on(); else led01off();
}
void led10barblink(uint16_t bitvalue)
// bitvalue : 0b 0abcdefg 0:OFF, 1:ON
{
if (bitvalue & 0b1000000000) led10();
if (bitvalue & 0b0100000000) led09();
if (bitvalue & 0b0010000000) led08();
if (bitvalue & 0b0001000000) led07();
if (bitvalue & 0b0000100000) led06();
if (bitvalue & 0b0000010000) led05();
if (bitvalue & 0b0000001000) led04();
if (bitvalue & 0b0000000100) led03();
if (bitvalue & 0b0000000010) led02();
if (bitvalue & 0b0000000001) led01();
}
void beep(int length, int pitch)
{
volatile unsigned int i, j;
BuzOutputMode();
for ( i = 0; i < length; i++) {
buz();
for (j = 0; j < pitch;j++);
}
}
void initAdc(void)
{
// AD Conv. Enable & Clock ferquency and the input clock to the ADC)
ADCSRA = ( (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0) );
}
uint8_t adc8(uint8_t adcport)
{
uint8_t adcdata; // A/D Conv. data
ADMUX = (1<<ADLAR) | adcport; // AD-Conv. 8-bit precision, Use ADC-PORTx
ADCSRA |= (1<<ADIF); // Set ADC Interrupt flag
ADCSRA |= (1<<ADSC); // Start AD Conv.
while ( ( ADCSRA & (1<<ADIF) ) == 0); //Wait to complete adc
adcdata = ADCH; // 8-bit precision
return adcdata;
}
uint16_t adc(uint8_t adcport)
{
uint16_t adcdata; // A/D Conv. data
ADMUX = adcport; // AD-Conv. 10-bit precision ((0<<ADLAR)), Use ADC-PORTx
ADCSRA |= (1<<ADIF); // Set ADC Interrupt flag
ADCSRA |= (1<<ADSC); // Start AD Conv.
while ( ( ADCSRA & (1<<ADIF) ) == 0); //Wait to complete adc
adcdata = ADCL; // 10-bit precision
adcdata |= (ADCH<<8);
return adcdata;
}
void initPCInt8(void)
{
PCICR |= (1<<PCIE1); // Pin change interrupt enable 0 (PCINT14..8)
PCMSK1 |= (1<<PCINT8); // PCINT8 enable
}
#define StStart 0x01
#define StProc 0x02
#define StStop 0x03
#define StSleep 0xff
volatile uint8_t STAGE = StStart; // Program STAGE definition
ISR(PCINT1_vect)
{
if (isSwOff()) {
switch(STAGE) {
case StStart:
STAGE = StProc;
break;
case StProc:
STAGE = StStop;
break;
case StStop:
STAGE = StSleep;
break;
case StSleep:
STAGE = StStart;
break;
default:
STAGE = StSleep;
}
}
}
void initInt0(void)
{
EIMSK |= (1<<INT0); // INT0 interrupt enable
EICRA |= (1<<ISC01) | (0<<ISC00); // The falling edge ofINT0 or INT1
}
ISR(INT0_vect)
{
}
// Timer0
void initTimer0(void)
{
TCCR0B |= (1<<CS01) | (1<<CS00); TCCR0B &= ~(1<<CS02);//Clock/64
TIMSK0 |= (1<<TOIE0); //Timer0 Overflow Interrupt Enable
}
volatile long TickCounter = 0;
#define TC10min 36621L
#define TC9min 32958L
#define TC8min 29297L
#define TC7min 25634L
#define TC6min 21972L
#define TC5min 18310L
#define TC4min 14648L
#define TC3min 10986L
#define TC2min 7324L
#define TC1min 3662L
#define TC10sec 610L
#define TC3sec 183L
ISR(TIMER0_OVF_vect)
{
TickCounter--;
}
#define VRADCPORT 0x01 // Trim Resistor port no.
#define BUZPORT 0x02 // Piezo Buzzer port no.
int main(void)
{
uint16_t adcdata;
uint16_t maxadcdata = 0;
unsigned int i;
// Initialize I/O Port
DDRD = (1<<PD7) | (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2) | (1<<PD1) | (1<<PD0); // LED BAR Output mode
DDRB = (1<<PB6) | (1<<PB7); // LED BAR Output mode
PORTC = (1<<PC0); // Pull up resister on PC0 (Switch)
// Buz Output
BuzOutputMode();
// Initailize Pin Change Interrupt
initPCInt8();
// Initialize AD-convertor
initAdc();
//Initialize Timer0
initTimer0();
sei(); // Enable Interrupt
STAGE = StStart;
while (1) {
switch (STAGE) {
case StStart:
// LED, Buz initialize
for (i = 0; i < 3; i++) {
led10bar(0b1111111111);
beep(50, 5);
wait(5000);
led10bar(0b0000000000);
wait(10000);
}
STAGE = StProc;
maxadcdata = 0;
i = 0;
break;
case StProc:
// Get Analog signal by Piezo Buzzer
BuzInputMode();
adcdata = adc(BUZPORT);
if (adcdata > 0x04) {
if (adcdata > maxadcdata) {
maxadcdata = adcdata;
}
i++;
}
if (i > 4) {
led10bar(maxadcdata);
wait(5000);
led10bar(0x000);
STAGE = StStop;
}
break;
case StStop:
led10barblink(maxadcdata);
beep(500, 5);
wait(5000);
break;
case StSleep:
led10bar(0b0000000000);
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
break;
default:
led10bar(0b0000000000);
}
}
return 0;
}
(Makefile)
# AVR-GCC Makefile
PROJECT=barled-mega168-blow-meter
SOURCES=$(PROJECT).c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=atmega168
TARGETDEV=m168p
CFLAGS=-mmcu=$(MMCU) -Wall
$(PROJECT).hex: $(PROJECT).out
$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
$(PROJECT).out: $(SOURCES)
$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)
program: $(PROJECT).hex
sudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex
clean:
rm -f $(PROJECT).out
rm -f $(PROJECT).hex