ATmega328PBを使う (3) PWMでLEDを点ける

#初めに
LED調光にPWMを使いますので、テストプログラムで動作確認してみます。


#PWMモード
ATMega328PBタイマーの動作モードには、標準(Normal)、位相補正PWM(PWM,PhaseCorrect)、CTC、高速PWM(Fast PWM)モードがあります。
TC0であれば、動作モードやTOP値などの組み合わせで下表のようなモードを選べます。
![V04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68712/d2735978-415e-01cf-3073-296f57399ef8.png)
LED調光用のため高速PWMでTOP値0xFFのMode 3を設定します。
16bitタイマーのTC1などでは9bit,10bitも選択できますが。すべて8bitにしています。
クロックは8MHzの256分周としました。PWMの周期は約8.2msとなります。

#PWMの配置
PWM0～3を追加します。ただし他の用途で使うポートとぶつかるので全ては使えません。
今回PWM3に割り当てたTC3のOCAは他のポート（UART）とバッティングするのでOCBだけPWMとして使います。

![v01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68712/93eeea94-1583-60ac-1d3a-c4280b4b296a.png)

![V05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68712/c080ba70-1762-d330-8de5-fb3f28b71a47.png)


##コンポーネントの設定
![V02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68712/50c50318-80b6-a402-b7a3-993974bda3d4.png)
![V03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68712/e3a1751d-b2ea-89fc-bcea-5167da5e1623.png)


TC3/TC4をPWM出力として使う場合は注意が必要です。
TC3/TC4はOutput Compare Modulatorに接続されています。
そのためTC3/TC4を別々のPWM出力として使えません。またModulatorの設定にPD2を使います。
TC3をPWM出力とするにはPD2を出力とし、’1’を設定します。
![V06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68712/f810c446-23a9-eba5-2c45-242a56f92ef7.png)



##コード
7本のPWMを同時に変化させるコードです。
PWMの初期設定後、タイマーで明るさを変化させています。

```C++
#define NUMBER_OF_PWM	(7)

uint16_t PwmTbl[] ={
	 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
	90, 80, 70, 60, 50, 40, 30, 20, 10
};

int PwmTblSize;
static uint8_t PwmStage[NUMBER_OF_PWM];
static uint16_t PwmTopVal;

void PWM_0AB_init(void)
{
	// Enable pin output
	PWM_0_enable_output_ch0();
	PWM_0_enable_output_ch1();

	// Set channel 0 duty cycle value register value to specified value
	PWM_0_load_duty_cycle_ch0(0x3f);
	PWM_0_load_duty_cycle_ch1(0x3f);

	// Set counter register value
	PWM_0_load_counter(0);
}

void PWM_1AB_init(void)
{
	// Enable pin output
	PWM_1_enable_output_ch0();
	PWM_1_enable_output_ch1();

	// Set channel 0 duty cycle value register value to specified value
	PWM_1_load_duty_cycle_ch0(0x3f);
	PWM_1_load_duty_cycle_ch1(0x3f);

	// Set counter register value
	PWM_1_load_counter(0);
}

void PWM_2AB_init(void)
{
	// Enable pin output
	PWM_2_enable_output_ch0();
	PWM_2_enable_output_ch1();

	// Set channel 0 duty cycle value register value to specified value
	PWM_2_load_duty_cycle_ch0(0x3f);
	PWM_2_load_duty_cycle_ch1(0x3f);

	// Set counter register value
	PWM_2_load_counter(0);
}

void PWM_3AB_init(void)
{
	PWM_3_enable();
	// Enable pin output
	PWM_3_enable_output_ch1();

	// Set channel 0 duty cycle value register value to specified value
	PWM_3_load_duty_cycle_ch1(0x3f);

	// Set counter register value
	PWM_3_load_counter(0);
}


void timerIntr(void)
{
	static unsigned int count = 0;
	uint16_t width[NUMBER_OF_PWM];
	
	count++;
	if (count >= 400) {
		count = 0;
		for (int i = 0;i < NUMBER_OF_PWM; i++) {
			PwmStage[i]++;
			if (PwmStage[i] >= PwmTblSize) {
				PwmStage[i] = 0;
			}
			width[i] = ((uint16_t)PwmTopVal*(uint16_t)PwmTbl[PwmStage[i]]);
			width[i] /= 100;
		}
		PWM_0_load_duty_cycle_ch0((PWM_0_register_t)width[0]);
		PWM_0_load_duty_cycle_ch1((PWM_0_register_t)width[1]);
		PWM_1_load_duty_cycle_ch0((PWM_1_register_t)width[2]);
		PWM_1_load_duty_cycle_ch1((PWM_1_register_t)width[3]);
		PWM_2_load_duty_cycle_ch0((PWM_2_register_t)width[4]);
		PWM_2_load_duty_cycle_ch1((PWM_2_register_t)width[5]);
		PWM_3_load_duty_cycle_ch1((PWM_3_register_t)width[6]);
	}
}
int main(void)
{
	/* Initializes MCU, drivers and middleware */
	atmel_start_init();
	PwmTblSize = sizeof(PwmTbl)/sizeof(uint16_t);

	PwmTopVal = 0xff;

	PwmStage[0] = 0;
	PwmStage[1] = 0;
	PwmStage[2] = 0;
	PwmStage[3] = 0;
	PwmStage[4] = 0;
	PwmStage[5] = 0;
	PwmStage[6] = 0;

	PWM_0AB_init();
	PWM_1AB_init();
	PWM_2AB_init();
	PWM_3AB_init();

	/* Replace with your application code */
	while (1) {
		;
	}
}
```

内容に不備等ありましたら連絡お願いします。