AtTiny13Aでラジコンサーボのコントロール

#はじめに
AtTiny13Aを使用してボリュームの角度に応じてラジコンサーボを動作させるだけのテスト回路を作成します。ラジコンサーボのちょっとしたテストに便利に利用可能です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/b0ca6b96-ceba-2fe4-fce3-2d7251d461a7.png)

#用意するもの
##AtTiny13a開発環境
以下の4つです。詳しくは[AtmelStudioとUSBtinyISPでAVR(AtMega, ATtin)の開発環境を作る](https://qiita.com/tlab/items/eded982637a786486829)を参照ください。
1. Atmel Studio
2. USBtinyISP
3. AVR
4. ArduinoIDE

#接続
ボリュームで電源を分圧しADC2に入力、PB0からサーボ出力するだけです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/892db114-23fb-3563-2297-98a8f393caea.png)

#プログラム
高速モード(9.6MHz)で動作させ、100kHzで割り込みをかけます。割り込み100回で1msecとなります。ボリュームのADC読取データを100から210にスケーリングしています。

```CPP:ServoControlByVolume.cpp
/*
 * ServoControl.cpp
 *
 * Created: 22-Aug-18 09:44:06
 * Author : ikeda
 */ 

// For delay.h
#ifndef F_CPU
#define	F_CPU	9600000UL		// 9.6MHz
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile unsigned int Tick;	// 100KHz pulse
volatile unsigned int sPulse;	// Servo pulse variable
volatile unsigned int Tick_20ms;	// Servo frame variable

unsigned char AnalogRead8bit(unsigned char Ch);
unsigned int AnalogRead(unsigned char Ch);


int main (void)
{
	sei(); //  Enable global interrupts
	DDRB |= (1<<PB0) | (1<<PB1); // PB0 and PB1 as outputs
	TCCR0A |= (1<<WGM01); // Configure timer 1 for CTC mode
	TIMSK0 |= (1<<OCIE0A); // Enable CTC interrupt
	OCR0A = 95; // Set CTC compare value
	TCCR0B |= (1<<CS00); // No prescaler
	Tick = 0;
	sPulse = 100;
	Tick_20ms = 0;

	unsigned long VolumeRead = 0;
	while(1)
	{
		VolumeRead = AnalogRead(2);
		
		// 1000 - 2100にスケーリング(1ms - 2.1ms)
		int setValue;
		setValue = 10 + (VolumeRead*2/10);
		sPulse = setValue ;
		_delay_ms(10);
	}
}

ISR(TIM0_COMPA_vect)	// 100 KHz interrupt frequency
{
	if(Tick >= 2000)	// One servo frame (20ms) completed
	{
		Tick = 0;
		Tick_20ms = Tick_20ms + 1;
	}

	Tick = Tick + 1;
	if(Tick <= sPulse)	// Generate servo pulse
	{
		PORTB |= (1<<PB0);	// Servo pulse high
	}
	else
	{
		PORTB &= ~(1<<PB0);	// Servo pulse low
	}
}

// https://blog.goo.ne.jp/paramako/e/aaea8ec6c7618ca6e083c95776c551d1
unsigned char AnalogRead8bit(unsigned char Ch)
{
	//8bit分解能で十分なのを前提に設定を行っている。
	
	//デジタル入出力からの切り離し
	DIDR0
	= (0<<ADC0D)	//ADC0ピンの切り離し。しかし、ADC0はリセット端子になってるから設定しちゃダメ
	| (0<<ADC1D)	//同ADC1
	| (1<<ADC2D)	//同・・
	| (0<<ADC3D);	//同・・
	
	ADMUX
	= (0<<REFS0)	//Reference: 0でVCC参照, 1で1.1V内部電圧源
	| (1<<ADLAR)	//ADC Left Adjust Result: 1にセットすると左詰で結果を出してくる
	| (Ch);			//ADMUX1, ADMUX0で入力チャンネルを選べる　00から11までADC0からADC3まで対応
	
	ADCSRA
	= (1<<ADEN)		//ADC enable
	| (1<<ADSC)		//ADC Start Conversion 1にすると変換開始
	| (0<<ADATE)	//ADC Auto Trigger Enable (for Continuous Conversion)
	| (0<<ADIF)		//ADC Interrupt Flag	変換完了すると1になるらしい
	| (0<<ADIE)		//ADC Interrupt Enable　変換完了したときに割り込み許可
	| (0b100);		//Clock Division: ADコンバータはクロック50-200kHzで性能がよい
	//分周は0のとき2、それ以上の時2^n分周	1.2MHz(Default)のとき16分周(100)で75kHz。9.6MHzのとき128分周(111)で75kHz
	loop_until_bit_is_set(ADCSRA,ADIF);	//ADIFビットが1になるまでムダループ
	return ADCH;
}



unsigned int AnalogRead(unsigned char Ch)
{
	//10bit分解能用ルーチン
	
	//デジタル入出力からの切り離し
	DIDR0
	= (0<<ADC0D)	//ADC0ピンの切り離し。しかし、ADC0はリセット端子になってるから設定しちゃダメ
	| (0<<ADC1D)	//同ADC1
	| (1<<ADC2D)	//同・・
	| (0<<ADC3D);	//同・・

	ADMUX
	= (0<<REFS0)	//Reference: 0でVCC参照, 1で1.1V内部電圧源
	| (0<<ADLAR)	//ADC Left Adjust Result: 1にセットすると左詰で結果を出してくる
	| (Ch);			//ADMUX1, ADMUX0で入力チャンネルを選べる　00から11までADC0からADC3まで対応
	
	ADCSRA
	= (1<<ADEN)		//ADC enable
	| (1<<ADSC)		//ADC Start Conversion 1にすると変換開始
	| (0<<ADATE)	//ADC Auto Trigger Enable (for Continuous Conversion)
	| (0<<ADIF)		//ADC Interrupt Flag	変換完了すると1になるらしい
	| (0<<ADIE)		//ADC Interrupt Enable　変換完了したときに割り込み許可
	| (0b100);		//Clock Division: ADコンバータはクロック50-200kHzで性能がよい

	//分周は0のとき2、それ以上の時2^n分周	1.2MHz(Default)のとき16分周(100)で75kHz。9.6MHzのとき128分周(111)で75kHz
	loop_until_bit_is_set(ADCSRA,ADIF);	//ADIFビットが1になるまでムダループ

	return ADC;

}
```

#Fuse設定
初期値はクロック設定が低速になっています(1.2MHz)ので、高速(9.6MHz)にする必要があります。

```TXT:FUSE_INITIAL(LOWSPEED)
CKSEL1 = 1
CKSEL0 = 0 
```

これを高速に設定する必要があります。

```TXT:FUSE_HIGHSPEED
CKSEL1 = 0
CKSEL0 = 1
```

#テスト
HDDのブラシレスモータをラジコン用ブラシレスモータコントローラで回してみました。最高速にするとちょっと怖いです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/5b68f27c-f59a-ab7b-a430-789310640571.png)

#基板に
ユニバーサル基板に載せて完成です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/7403547d-d78f-6f72-3196-e87578ecbda4.png)

#おわりに
このようなツールを作っておくとデバッグに役に立つかと思います。

2018/08/28 Ikeda