半年前にACA302という加速度センサを試したが、秋月電子で手に入らなくなった(取り扱い品がACA302からACB302になった)ので、樹に薦められたKXM52-1050モジュールを試してみた。

ACA302は3.3Vを作らなければならなかったが、KXM52の動作電圧は2.7~5.5Vそのままで動くし、ノイズも全然無いのにACB302より200円安く、感度も6倍でいい感じ。Pileus2号機に採用する予定。

そういえば最近ACB302は2000円から1000円に値下げになったけどね

■とりあえず動かしてみた

SourceCode, hex, Makefile(avr-gcc 3.4.6)

ATmega168のADC0,1,2でX,Y,Z軸の出力値をAD変換し、文字列に変換してUARTでPCに送っている。



x,y軸の値は通常520ぐらいで、傾けると730~300ぐらいの間で変わる。これは重力加速度を検出しているということ



普段の値

Test of KXM52-1050 module

傾けた時

Test of KXM52-1050 module

あとYouTubeに他の人が使ってるのもアップされてた。クワクボリョウタさんのI/O ToolkitとProce55ingを使ってる。

■回路

付属のデータシートの通りにやった。

KXM52-1050 Accelerometer & ATmega168

「KXM52-1050モジュール」なので、チップが基盤に既にはんだづけされていてそこにコンデンサなど全部実装されている。1,2ピンにVCCを、3,5ピンにGNDを接続すれば、6,7,8ピンがそれぞれX,Y,Z軸として加速度を出力してくれる。Xout,Yout,ZoutをATmega168のADC0,1,2にそのまま接続する。

■プログラム

SourceCode, hex, Makefile(avr-gcc 3.4.6)

mainの中のforループで、ADC0,1,2の値を取って読みやすい文字列にしてUARTでPCに送っている。それだけ。ACA302の時の様に100回の平均を取る事はしないでも実用的な値が出た。

int main(void){
  port_init(); // PORT設定
  usart_init(MYUBRR); // USART設定
  adc_init(); // ADConverter設定
  
  LED_SET(); // 起動確認LED
  
  int adX, adY, adZ;
  char buf[6];
  
  for(;;){
    adX = adc_convert(0); // ADC0からAD変換
    adY = adc_convert(1);
    adZ = adc_convert(2);
    
    usart_sendStr("x:");
    usart_sendStr(intToStr(adX,buf)); // AD値を文字列にして送信
    usart_sendStr(" y:");
    usart_sendStr(intToStr(adY,buf));
    usart_sendStr(" z:");
    usart_sendStr(intToStr(adZ,buf));
    
    usart_sendStr("\r\n"); // 改行
  }
}

プログラム全体

#include <avr/io.h>
#include <avr/interrupt.h>
#define TRUE 1
#define FALSE 0
#define NULL '\0'
#define sbi(BYTE,BIT) BYTE|=_BV(BIT) // BYTEの指定BITに1をセット
#define cbi(BYTE,BIT) BYTE&=~_BV(BIT) // BYTEの指定BITをクリア
/** 動作設定 **/
#define FOSC 8000000 // 8MHz
/** UART設定 **/
#define BAUD 9600 // 9600bps
#define MYUBRR FOSC/16/BAUD-1 // UART分周率
// #define UCSR0A_U2X0 1 // 倍速フラグ 等速ならコメントアウト
#ifdef UCSR0A_U2X0 // 倍速が定義されているならば
 #define MYUBRR FOSC/16/(BAUD/2)-1 // UART分周率(倍速)
#endif
volatile char usart_recvData; // USARTで受信したデータ
#define LED_SET() sbi(PORTB, PB0) // 基盤上の動作確認LED
#define LED_CLR() cbi(PORTB, PB0)
/* PORT設定 */
void port_init(void){
  sbi(DDRB, PB0);
}
/* USART設定 */
void usart_init(unsigned int ubrr){
  UBRR0H = (unsigned char)(ubrr>>8); // ボーレート上位8bit
  UBRR0L = (unsigned char)ubrr; // ボーレート下位8bit
  UCSR0A = (0<<U2X0); // 等速
  UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); // 送受信許可、受信完了割り込み許可
  UCSR0C = (0<<UMSEL00)|(3<<UCSZ00)|(1<<USBS0)|(0<<UPM00);
  // フレーム設定 非同期通信 8ビット 1ストップビット パリティ無し
}
/* intの桁数を返す */
char getDigit(int n){
  char i;
  i = 0;
  while(n>0){
    n /= 10;
    i++;
  }
  return i;
}
/* int->String変換 */
char *intToStr(int n, char *buf){ // 変換する数、作業領域
  int i, digit;
  digit = getDigit(n); // 桁数
  for(i = digit-1; i >= 0; i--){ // intは最大5桁
    buf[i] = n%10+'0';
    n /= 10;
  }
  buf[digit] = '\0'; // 行末改行
  return buf;
}
/* UARTで文字列送信 */
void usart_sendStr(char *str){
  while(*str != NULL){
    loop_until_bit_is_set(UCSR0A,UDRE0); // 送信データレジスタ空きまで待機
    UDR0 = *str++; // 1文字送信、1文字進む
  }
}
/* ADコンバータ設定 */
void adc_init(void){
  ADMUX = (0<<REFS0); // 外部基準電圧
  ADCSRA =(1<<ADEN)|(1<<ADSC)|(0<<ADPS0);
  // A/D変換許可、1回目変換開始(調整)、分周率2
}
/* ピンを指定してAD変換 return 0-1023 */
int adc_convert(char pin){
  int ad;
  ADMUX = pin; // AD変換入力ピン
  cbi(ADCSRA,ADIF);
  sbi(ADCSRA,ADSC); // 変換開始
  loop_until_bit_is_set(ADCSRA,ADIF); // 変換完了まで待つ
  ad = ADCL; // 下位8bit取得
  return ad += (ADCH<<8); // 上位2bit取得
}
int main(void){
  port_init(); // PORT設定
  usart_init(MYUBRR); // USART設定
  adc_init(); // ADConverter設定
  
  LED_SET(); // 起動確認LED
  
  int adX, adY, adZ;
  char buf[6];
  
  for(;;){
    adX = adc_convert(0); // ADC0からAD変換
    adY = adc_convert(1);
    adZ = adc_convert(2);
    
    usart_sendStr("x:");
    usart_sendStr(intToStr(adX,buf)); // AD値を文字列にして送信
    usart_sendStr(" y:");
    usart_sendStr(intToStr(adY,buf));
    usart_sendStr(" z:");
    usart_sendStr(intToStr(adZ,buf));
    usart_sendStr("\r\n"); // 改行
  }
}