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

  • AVRMacPack-20080514.dmg
  • md_pl2303H_HX_X_dmg_v1.2.1r2.zip(秋月USBシリアル用ドライバ)

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