そのオリンパスのデジカメで撮ったアサガオ開花動画
いろんな連続写真で遊んでいこうとおもう。
wdtサンプル
_delay_msは電力の無駄なのでwdtでLEDをチカチカさせるサンプル。
// tiny2313V @ 1MHz #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <avr/wdt.h> #include <util/delay.h> /* volatile long timer = 0; ISR(WDT_OVERFLOW_vect) { } */ EMPTY_INTERRUPT(WDT_OVERFLOW_vect); int main(void) { int i; // start WDT cli(); wdt_reset(); MCUSR &= ~(1<<WDRF); // 「WDTリセットされた」フラグクリア WDTCSR |= (1<<WDCE)|(1<<WDE); // wdt変更前処理 #define _WDT_15MS ((0<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0)) #define _WDT_30MS ((0<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0)) #define _WDT_60MS ((0<<WDP3)|(0<<WDP2)|(1<<WDP1)|(0<<WDP0)) #define _WDT_120MS ((0<<WDP3)|(0<<WDP2)|(1<<WDP1)|(1<<WDP0)) #define _WDT_250MS ((0<<WDP3)|(1<<WDP2)|(0<<WDP1)|(0<<WDP0)) #define _WDT_500MS ((0<<WDP3)|(1<<WDP2)|(0<<WDP1)|(1<<WDP0)) #define _WDT_1S ((0<<WDP3)|(1<<WDP2)|(1<<WDP1)|(0<<WDP0)) #define _WDT_2S ((0<<WDP3)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0)) #define _WDT_4S ((1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0)) #define _WDT_8S ((1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0)) WDTCSR = (1<<WDIE)|(0<<WDE)|_WDT_1S; // wdt設定 reset=0, interrupt=1, 1sec. sei(); DDRB = 0b00001111; for(i=0;i<5;i++){ PORTB = 0b00001111; _delay_ms(100); PORTB = 0b00000000; _delay_ms(100); } set_sleep_mode(SLEEP_MODE_PWR_DOWN); for(;;){ for(i=0; i<8; i++){ // 0.02mA PORTB = i % 16; sleep_mode(); } for(i=8; i<16; i++){ // 5.5mA-6.0mA PORTB = i % 16; _delay_ms(1000); } } }
参考: http://avrwiki.jpn.ph/wiki.cgi?page=Getting+Started+Notes+%2D+SLEEP
オリンパスのデジカメのリモコンをAVRで作った
オリンパスのリモコンRM-1
のコードを5分おきに送信してシャッターを切ります。
材料
- Atmel AVR Tiny2313V
- 赤外線LEDが1個
- (パスコン)
- 単三電池2本&電池ボックス
// Olympus Remocon #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <avr/wdt.h> #include <util/delay.h> #define nop() __asm__ __volatile__ ("nop") void send_ir(int us, char on) { // 38KHz 1sec=1000ms=1000000us => 38000 // 1000000/38000 = 26.3157895us on/off 13.1578947us // 1MHz => 1sec => 1000000 => 1op=1us for(; 0<=us; us-=26){ PORTB = on ? 0b00000011 : 0b00000000; nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); // ON 12 / OFF 1.. 6 // ON 10 / 3.. 8 // ON 5 / 8..13 PORTB = 0b00000000; nop(); nop(); nop(); nop(); nop(); } } void send_data(char* data, int bits) { int i; int lead_high_len = 9000; int lead_low_len = 4500; int data_high_len = 560; int data_low0_len = 560; int data_low1_len = 1690; int stop_high_len = 560; DDRB = 0b00000011; send_ir(lead_high_len, 1); send_ir(lead_low_len, 0); for(i=0; i<bits; i++){ int on = data[i/8] & (1<<(7-i%8)); send_ir(data_high_len, 1); send_ir(on ? data_low1_len : data_low0_len, 0); } send_ir(stop_high_len, 1); _delay_ms(1000); } EMPTY_INTERRUPT(WDT_OVERFLOW_vect); void init_wdt_interrupt(int interval) { cli(); wdt_reset(); MCUSR &= ~(1<<WDRF); // 「WDTリセットされた」フラグクリア WDTCSR |= (1<<WDCE)|(1<<WDE); // wdt変更前処理 #define _WDT_15MS ((0<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0)) #define _WDT_30MS ((0<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0)) #define _WDT_60MS ((0<<WDP3)|(0<<WDP2)|(1<<WDP1)|(0<<WDP0)) #define _WDT_120MS ((0<<WDP3)|(0<<WDP2)|(1<<WDP1)|(1<<WDP0)) #define _WDT_250MS ((0<<WDP3)|(1<<WDP2)|(0<<WDP1)|(0<<WDP0)) #define _WDT_500MS ((0<<WDP3)|(1<<WDP2)|(0<<WDP1)|(1<<WDP0)) #define _WDT_1S ((0<<WDP3)|(1<<WDP2)|(1<<WDP1)|(0<<WDP0)) #define _WDT_2S ((0<<WDP3)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0)) #define _WDT_4S ((1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0)) #define _WDT_8S ((1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0)) WDTCSR = (1<<WDIE)|(0<<WDE)|interval; // wdt設定 reset=0, interrupt=1 sei(); } void main_olympus(void) { char shutter[] = {0b01100001, 0b11011100, 0b10000000, 0b01111111}; char wide[] = {0b01100001, 0b11011100, 0b01000000, 0b10111111}; char tele[] = {0b01100001, 0b11011100, 0b11000000, 0b00111111}; char minus[] = {0b01100001, 0b11011100, 0b00100000, 0b11011111}; char plus[] = {0b01100001, 0b11011100, 0b10100000, 0b01011111}; int i, t; init_wdt_interrupt(_WDT_1S); set_sleep_mode(SLEEP_MODE_PWR_DOWN); for(;;){ send_data(shutter, 32); send_data(shutter, 32); send_data(shutter, 32); for(i=0; i<57; i++){ sleep_mode(); } // 57sec.. for(t=0; t<4; t++){ // 1min x 4. send_data(wide, 32); for(i=0; i<59; i++){ sleep_mode(); } } } } int main(void) { main_olympus(); }
秋月通販で買えるAVRの比較
tiny2313V | mega88 | mega164P | mega644P | ||
---|---|---|---|---|---|
秋月価格 | 100 | 250 | 400 | 550 | |
ピン数 | 20 | 28 | 40 | 40 | |
フラッシュメモリ | 2k | 8k | 16k | 64k | |
EEPROM | 128 | 512 | 512 | 2048(2k) | |
SRAM | 128 | 1024(1k) | 1024(1k) | 4096(4k) | |
タイマー | 8*1,16*1 | 8*2,16*1 | 8*2,16*1 | ← | |
RTC | - | ○ | ○ | ← | |
PWM | 4 | 6 | 6 | ← | |
ADC | - | 6 | 8 | ← | |
AC | 1 | 8 | 8 | ← | |
2線シリアル | USI | TWI | TWI | ← | |
USART | 1 | 1 | 2 | ← | |
SPI | USI | SPI | SPI | ← |
AVRホタル
暗いところに持っていくと点滅します。
部品はtiny2313とLEDを1個ずつ。
LEDを光センサーとして使っています。
// AVR Hotaru #include <avr/io.h> //#include <avr/interrupt.h> #include <util/delay.h> #define nop() __asm__ __volatile__ ("nop") #define SERIAL_DEBUG 0 #if SERIAL_DEBUG #define BAUD 2400 //#define SET_PORT(PORT, MASK, VALUE) PORT = (VALUE & MASK)|((~MASK) & PORT) void usart_init(void) { #define _UBRR (F_CPU/16/BAUD-1) UBRRH = _UBRR>>8; UBRRL = _UBRR; UCSRB = 0b00011000; UCSRC = 0b00000110; } #endif #define LED_DEBUG 1 int main(void) { char ac0; int count = 0; int on_count = 0; int on_rate = 0; int i,j,k; int bright = 0; int led_on = 1; #if SERIAL_DEBUG usart_init(); #endif #if LED_DEBUG DDRD = 0b01111100; PORTD = 0b00000000; #endif for(;;){ // 参考) http://elm-chan.org/junk/leddet/report.html // LEDポートに短時間"L"レベルを出力して接合容量Cjや浮遊容量Csを放電する。 DDRB = 0b00000001; PORTB = 0b00000000; _delay_ms(1); // LEDポートを入力に設定する→光電流により容量が充電され、入力電圧が直線的に上昇してくる。 DDRB = 0b00000000; PORTB = 0b00000000; // 4ms待ってから入射有りか判断 _delay_ms(4); ac0 = ACSR & 0b00100000; if(ac0){ on_count++; } count++; if(50<=count){ on_rate = 100*on_count/count; // 50サンプル取って平均 count = 0; on_count = 0; } #if SERIAL_DEBUG while(!(UCSRA & 0b00100000)); UDR = ac0 ? '*' : '.'; #endif #if LED_DEBUG { unsigned char d = 0; if(on_rate<45){ d |= (1<<2); } if(on_rate<40){ d |= (1<<3); } if(on_rate<35){ d |= (1<<4); } if(on_rate<30){ d |= (1<<5); } if(on_rate<25){ d |= (1<<6); } PORTD = d; } #endif DDRB = 0b00000001; if(0){ // 閾値でON/OFF if(on_rate<20){ PORTB = 0b00000001; }else{ PORTB = 0b00000000; } _delay_ms(30); }else{ // 明るさ 0-100,100-0 のこぎり型に明滅 int b; bright++; b = bright; if(100<bright){ b = 200-bright; if(200<bright){ bright = 0; led_on = (on_rate<20); } } //b = 100-on_rate; for(j=0; j<10; j++){ if(led_on){ PORTB = 0b00000001; } for(i=0; i<b; i++){ _delay_ms(0.01); } PORTB = 0b00000000; for(i=0; i<100-b; i++){ _delay_ms(0.01); } } } } }
MacにAVR開発環境をつくった
http://www.obdev.at/products/avrmacpack/index.html
No.19 入門用AVR-ISPライター
http://homepage2.nifty.com/denshiken/AVW019.html
用の設定。
# Name: Makefile # Author: <insert your name here> # Copyright: <insert your copyright message here> # License: <insert your license reference here> # This is a prototype Makefile. Modify it according to your needs. # You should at least check the settings for # DEVICE ....... The AVR device you compile for # CLOCK ........ Target AVR clock rate in Hertz # OBJECTS ...... The object files created from your source files. This list is # usually the same as the list of source files with suffix ".o". # PROGRAMMER ... Options to avrdude which define the hardware you use for # uploading to the AVR and the interface where this hardware # is connected. # FUSES ........ Parameters for avrdude to flash the fuses appropriately. DEVICE = attiny2313 CLOCK = 1000000 PROGRAMMER = -c avrispv2 -P /dev/tty.usbserial OBJECTS = main.o FUSES = -U hfuse:w:0xDF:m -U lfuse:w:0x64:m # ATTiny2313 fuse bits (fuse bits for other devices are different!): # WinAVR Extend:0xFF HIGH:0xDF LOW:0x64 # Example for 8 MHz internal oscillator # Fuse high byte: # 0xDF = 1 1 0 1 1 1 1 1 <-- 0RSTDISBL (default:1) if set to 0, RESET pin is disabled # ^ ^ ^ ^ ^ ^ ^------ 1BODLEVEL0 (default:1) -- # | | | | | +-------- 2BODLEVEL1 (default:1) -- # | | | | +---------- 3BODLEVEL2 (default:1) BODLEVEL2-0 : 111 : disable low bat. # | | | +-------------- 4WDTON (default:1) if set to 0, watchdog is always on # | | +---------------- 5SPIEN (default:0) if set to 1, serial programming is disabled # | +------------------ 6EESAVE (default:1) set to 0 to preserve EEPROM over chip erase # +-------------------- 7DWEN (default:1) debug wire # # Fuse low byte: # 0x64 = 0 1 1 0 0 1 0 0 <-- CKSEL0 (default:0) -- # ^ ^ ^ ^ ^ ^ ^------ CKSEL1 (default:0) -- # | | | | | +-------- CKSEL2 (default:1) -- # | | | | +---------- CKSEL3 (default:0) CKSEL3-0 : 0100 : 8MHz RC # | | | +-------------- SUT0 (default:0) -- # | | +---------------- SUT1 (default:1) SUT1-2 : 10 : 6*CK 14*CK+64ms # | +------------------ CKOUT (default:1) # +-------------------- CKDIV8 (default:0) # Tune the lines below only if you know what you are doing: AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) # symbolic targets: all: main.hex .c.o: $(COMPILE) -c $< -o $@ .S.o: $(COMPILE) -x assembler-with-cpp -c $< -o $@ # "-x assembler-with-cpp" should not be necessary since this is the default # file type for the .S (with capital S) extension. However, upper case # characters are not always preserved on Windows. To ensure WinAVR # compatibility define the file type manually. .c.s: $(COMPILE) -S $< -o $@ flash: all $(AVRDUDE) -U flash:w:main.hex:i fuse: $(AVRDUDE) $(FUSES) # Xcode uses the Makefile targets "", "clean" and "install" install: flash fuse # if you use a bootloader, change the command below appropriately: load: all bootloadHID main.hex clean: rm -f main.hex main.elf $(OBJECTS) # file targets: main.elf: $(OBJECTS) $(COMPILE) -o main.elf $(OBJECTS) main.hex: main.elf rm -f main.hex avr-objcopy -j .text -j .data -O ihex main.elf main.hex # If you have an EEPROM section, you must also create a hex file for the # EEPROM and add it to the "flash" target. # Targets for code debugging and analysis: disasm: main.elf avr-objdump -d main.elf cpp: $(COMPILE) -E main.c
直接使うときは↓
avrdude -v -c avrispv2 -P /dev/tty.usbserial -p attiny2313 -U flash:w:ISP2313T.hex:i avrdude -vv -c avrispv2 -p t2313 -P /dev/tty.usbserial