ATmega328PB-AUの機能:ATmega328pとの比較

UNO-ATmega328

ATmega328PBは、Atmel(現在はMicrochip Technologyによって買収)によって開発されたマイクロコントローラで、Arduino Unoなどの人気開発ボードに使われているATmega328Pの後継モデルです。このチップは2015年に発表され、さらに多くの機能とより多くのピン配置オプションを提供します。ATmega328PBはATmega328Pと完全互換ですが、2つのSPIインターフェース、2つのI2Cインターフェース、3つのタイマーとその他の機能強化が含まれています。発売当初の市場価格は、大量購入時に$1〜$2の範囲で、単品での購入価格は若干高めです。

328Pと328PBの比較表と特徴

機能 / 特徴 ATmega328P ATmega328PB
ピン数(DIPパッケージ) 28ピン 32ピン
CPU 8-bit AVR 8-bit AVR
動作周波数 最大 20MHz 最大 20MHz
フラッシュメモリ 32KB 32KB
SRAM 2KB 2KB
EEPROM 1KB 1KB
UART 1 2
SPI 1 2
I2C (TWI) 1 2
タイマー 3 (2x 8-bit, 1x 16-bit) 3 (2x 8-bit, 1x 16-bit)
アナログ比較器 1 1
PWMチャンネル 6 8
アナログ入力 (ADCチャンネル) 6 8
外部割り込み 2 3
プログラム可能なゲイン増幅器 なし 4
タッチセンシング なし 16チャンネル QTouch®

主な変更点

  • ピン数: DIPパッケージにおいては、ATmega328PBは4ピン多くなることで、より多くの機能を搭載しています。
  • UART, SPI, I2C (TWI): ATmega328PBはこれらの通信インターフェースを倍増しており、複数のデバイスとの通信が可能になっています。
  • PWMチャンネルとアナログ入力: ATmega328PBはこれらのチャンネルが増えており、より複雑なアナログ処理や精密なPWM制御が可能です。
  • プログラム可能なゲイン増幅器とタッチセンシング: 新たに追加された機能で、特にユーザーインターフェースの改善や感度の高いアプリケーションに利点を提供します。

ピン機能比較表

ピン番号 ATmega328Pの機能 ATmega328PBの機能
1 PC6/RESET PC6/RESET
2 PD0/RXD PD0/RXD
3 PD1/TXD PD1/TXD
4 PD2/INT0 PD2/INT0
5 PD3/INT1/OC2B PD3/INT1/OC2B
6 PD4/XCK/T0 PD4/XCK/T0
7 VCC VCC
8 GND GND
9 PB6/XTAL1/TOSC1 PB6/XTAL1/TOSC1
10 PB7/XTAL2/TOSC2 PB7/XTAL2/TOSC2
11 PD5/T1/OC0B PD5/T1/OC0B
12 PD6/AIN0/OC0A PD6/AIN0/OC0A
13 PD7/AIN1 PD7/AIN1
14 PB0/CLKO/ICP1 PB0/CLKO/ICP1
15 PB1/OC1A PB1/OC1A
16 PB2/SS/OC1B PB2/SS/OC1B
17 PB3/MOSI/OC2A PB3/MOSI/OC2A
18 PB4/MISO PB4/MISO
19 PB5/SCK PB5/SCK
20 AVCC AVCC
21 AREF AREF
22 GND GND
23 PC0/ADC0 PC0/ADC0
24 PC1/ADC1 PC1/ADC1
25 PC2/ADC2 PC2/ADC2
26 PC3/ADC3 PC3/ADC3
27 PC4/SDA/ADC4 PC4/SDA/ADC4
28 PC5/SCL/ADC5 PC5/SCL/ADC5
29 PE0/RXD0 (USART0)
30 PE1/TXD0 (USART0)
31 PE2/XCK0 (USART0)
32 PE3/OC0B (Timer0)

ATmega328PBを使う上での注意点

ATmega328Pの電源ピンがIOピンに変更

ATnega328PではGND(ピン番号3)Vcc(ピン番号6)がATmega328PBではPE0PE1に変更されています。よってATmega328P用に設計した基板でATmega328PBをのせる場合はPE0,1の出力設定でPE0HIGH, PE1LOWにした場合マイコンが破損する可能性があります。

Timer3とTimer4に注意

ATmega328PB における Timer3 と Timer4 は、標準的な ATmega328P には存在しない追加のタイマー機能であり、これらを使用する際には特定の注意点があります。これらのタイマーを効果的に利用するためには、それぞれの特性と機能を理解し、適切な設定を行う必要があります。

Timer3

  • 機能と用途: Timer3 は 16ビットのタイマーで、高精度のタイムイベント生成や、PWM出力、周期測定などに使用されます。
  • 注意点:
    • 割り込みベクター: Timer3 は独自の割り込みベクターを持っており、これを適切に設定しないと予期せぬ動作が発生する可能性があります。
    • リソースの競合: Timer3 を使用する場合、他の機能やタイマーとのリソース競合を避けるため、割り込み優先度やタイマーの設定に注意する必要があります。

Timer4

  • 機能と用途: Timer4 は 10ビットの高分解能タイマーで、より精密なPWM制御や高速タイミングが求められる用途に適しています。
  • 注意点:
    • 解像度と設定: Timer4 は 10ビットの解像度を持っており、設定ミスが高精度制御に影響を与えるため、設定値の計算には特に注意が必要です。
    • 特殊な機能: Timer4 には独自の機能(例えば高分解能PWM)があり、これを活用するには専門的な知識が必要になることがあります。

ポート設定に注意

Timer3 コンペアBとTimer4コンペアBがPD2に繋がっており、PORTB7(PB7)の状態が1の時にOR 0の時にANDとなるため、PWMピンとして使いたい場合はTimer3か4かのどちらかを使いPB7(PORTB bit7)を1にしなくてはなりません。

ATmega328PBの新機能

追加のUART

ATmega328PBは2つのUARTを持っており、同時に複数のシリアルデバイスと通信が可能です。

追加のUARTを利用するサンプル

このサンプルでは、ATmega328PBの2つのUARTインターフェースを使用して、2つの異なるシリアルデバイスと通信します。1つはデバッグメッセージ用、もう1つは外部モジュール(例えばGPSモジュール)との通信用です。

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

void USART0_init() {
  // USART0を9600 bpsで初期化
  UBRR0 = 103; // ボーレート9600の設定
  UCSR0B = (1 << RXEN0) | (1 << TXEN0); // 受信と送信を有効化
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8-bitデータ
}

void USART1_init() {
  // USART1を9600 bpsで初期化
  UBRR1 = 103; // ボーレート9600の設定
  UCSR1B = (1 << RXEN1) | (1 << TXEN1); // 受信と送信を有効化
  UCSR1C = (1 << UCSZ11) | (1 << UCSZ10); // 8-bitデータ
}

void USART0_send(char data) {
  while (!(UCSR0A & (1 << UDRE0))); // 送信バッファが空になるのを待つ
  UDR0 = data;
}

void USART1_send(char data) {
  while (!(UCSR1A & (1 << UDRE1))); // 送信バッファが空になるのを待つ
  UDR1 = data;
}

int main(void) {
  USART0_init(); // USART0の初期化
  USART1_init(); // USART1の初期化

  while (1) {
    USART0_send('A'); // USART0を通じて文字を送信
    USART1_send('B'); // USART1を通じて文字を送信
    _delay_ms(1000); // 1秒待機
  }
}

追加のSPIとI2Cインターフェース

2つのSPIと2つのI2Cインターフェースを備えているため、より多くのデバイスを同時に制御できます。

SPI通信のサンプルコード

このサンプルでは、SPI1インターフェースを使用して外部のSPIデバイス(例えばEEPROM)と通信します。

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

// SPIの初期化
void SPI1_init() {
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB1); // SS, MOSI, SCKを出力に設定
  SPCR1 = (1 << SPE1) | (1 << MSTR1); // SPIをマスターモードで有効にする
}

// SPI通信関数
void SPI1_transmit(char data) {
  SPDR1 = data; // データをSPIデータレジスタに書き込む
  while (!(SPSR1 & (1 << SPIF1))); // 送信完了を待つ
}

int main(void) {
  SPI1_init(); // SPIの初期化
  while (1) {
    SPI1_transmit(0xAA); // データ0xAAを送信
    _delay_ms(1000);
  }
}

I2C通信のサンプルコード

このサンプルでは、I2C1インターフェースを使用してI2Cセンサー(例えば温度センサー)と通信します。

#include <avr/io.h>
#include <util/twi.h>

#define F_SCL 100000UL // SCLクロック周波数(100kHz)
#define TWI1_ADDRESS 0x5A // I2Cデバイスアドレス

void I2C1_init() {
  TWSR1 = 0x00; // プリスケーラ値を0に設定
  TWBR1 = ((F_CPU / F_SCL) - 16) / 2; // TWIビットレートレジスタを設定
}

void I2C1_start() {
  TWCR1 = (1 << TWINT1) | (1 << TWSTA1) | (1 << TWEN1);
  while (!(TWCR1 & (1 << TWINT1))); // スタートコンディションの送信完了を待つ
}

void I2C1_stop() {
  TWCR1 = (1 << TWINT1) | (1 << TWSTO1) | (1 << TWEN1);
}

void I2C1_write(uint8_t data) {
  TWDR1 = data; // データをTWIデータレジスタに書き込む
  TWCR1 = (1 << TWINT1) | (1 << TWEN1);
  while (!(TWCR1 & (1 << TWINT1))); // データ送信完了を待つ
}

int main(void) {
  I2C1_init(); // I2Cの初期化

  while (1) {
    I2C1_start();
    I2C1_write(TWI1_ADDRESS << 1); // デバイスアドレスの書き込み(書き込みモード)
    I2C1_write(0x01); // レジスタアドレスを書き込む
    I2C1_stop();
    _delay_ms(1000);
  }
}

タッチセンシングインターフェース

組み込みのタッチセンサー機能をサポートしており、より簡単にタッチベースのインターフェースを実装できます。この機能を活用することで、ボタン、スライダー、ホイールなどのタッチ入力デバイスを作成できます。

単一のタッチチャンネルでのタッチ検出プログラム

#include <avr/io.h>
#include <util/delay.h>
#include "qtouch.h"

#define TOUCH_SENSOR_PIN 0 // A0ピンをタッチセンサとして使用
#define LED_PIN 2 // ピン2にLED接続

int main(void) {
  // ピン設定
  DDRD |= (1 << LED_PIN); // LEDピンを出力として設定
  PORTD &= ~(1 << LED_PIN); // LEDをオフに
  // QTouchライブラリの初期化
  QTouch_Init(TOUCH_SENSOR_PIN);
  while (1) {
    if (QTouch_Sense(TOUCH_SENSOR_PIN)) {
      PORTD |= (1 << LED_PIN); // タッチが検出されたらLEDをオン
    } else {
      PORTD &= ~(1 << LED_PIN); // タッチが検出されなければLEDをオフ
    }
    _delay_ms(100); // 状態チェック間隔
  }
}

プロジェクトにQTouchライブラリを含める必要があります。Arduino IDEでは通常、追加のライブラリをインストールする必要がありますが、AVR GCC環境ではQTouchライブラリを手動でセットアップすることが一般的です。

より多くのPWM出力と高解像度のタイマー

ATmega328PBは、改善されたPWM機能を持ち、より多くのPWM出力と高解像度のタイマーを提供します。これにより、より精密なモータ制御やLEDの調光が可能になります。以下は、ATmega328PBのこれらの機能を活用するためのサンプルコードです。この例では、高解像度のタイマーを使用してLEDの明るさを滑らかに変化させるPWM制御を行います。

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

void PWM_Init() {
  // タイマー1を高解像度PWMモードで設定
  TCCR1A = (1 << WGM11) | (1 << COM1A1); // フェーズ正弦波PWMモード, 10ビット高速PWM
  TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10); // プリスケーラなし
  ICR1 = 1023; // TOP値を1023に設定 (10-bit resolution)
  DDRB |= (1 << PB1); // PB1ピンを出力に設定 (OC1A)
}

void SetBrightness(uint16_t brightness) {
  if (brightness > 1023) {
    brightness = 1023;
  }
  OCR1A = brightness; // OC1Aの出力を設定, LEDの明るさ調整
}

int main(void) {
  PWM_Init(); // PWMの初期化
  while (1) {
    // 明るさを徐々に増加
    for (uint16_t i = 0; i < 1024; i++) {
      SetBrightness(i);
      _delay_ms(2);
    }

    // 明るさを徐々に減少
    for (uint16_t i = 1023; i > 0; i--) {
      SetBrightness(i);
      _delay_ms(2);
    }
  }
}

説明

  • タイマー設定: TCCR1ATCCR1B レジスタを設定して、タイマー1を10ビットの高速PWMモードに設定します。WGM11, WGM12, WGM13 を設定することでフェーズ正弦波PWMを有効にし、COM1A1 でOC1Aピン(PB1)の出力を非反転モードに設定します。
  • プリスケーラ: プリスケーラを無しに設定しています(CS10)。これにより、タイマーのカウント速度が最大になり、より滑らかなPWM波形が得られます。
  • 明るさの設定: SetBrightness 関数では、OCR1Aレジスタに値を設定してPWMのデューティサイクルを制御します。この値を変更することで、接続されたLEDの明るさを変えることができます。
  • ループ動作: メインループではLEDの明るさを徐々に上げた後、下げる動作を繰り返します。これによりLEDが滑らかに明るくなり、暗くなります。

 

タイトルとURLをコピーしました