4: 2009-08-04 (火) 03:46:21 takaboo | 現: 2013-10-07 (月) 19:00:15 eid7gud | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | TITLE:ATmega32 Sample Code | ||
+ | #norelated | ||
+ | #contents | ||
*ダウンロード[#l493db9b] | *ダウンロード[#l493db9b] | ||
+ | #ref(http://www.besttechnology.co.jp/download/ATMEGA32SMPL1.6.ZIP) | ||
+ | |CENTER:BGCOLOR(red): :idea:|最新のGCCにおいてATmega32Aをターゲットとした場合のDDRのビット定義名が変わってしまったためソース互換性が保てなくなりました。そのため、PORT・DDR・PINの各レジスタのビット定義名は、PORT7~PORT0・DD7~DD0・PIN7~PIN0に変更しました。| | ||
+ | |||
*一覧 [#j8c69fab] | *一覧 [#j8c69fab] | ||
- | **smpl1(USART).c [#y20358e6] | + | **USART1.c [#y20358e6] |
マイコンのUSARTを使ったシリアル通信を行う。シリアル通信はGCC Developer Liteで提供される専用のライブラリを直接使用し、文字及び文字列の送受信や書式化文字列の送信を行う。 | マイコンのUSARTを使ったシリアル通信を行う。シリアル通信はGCC Developer Liteで提供される専用のライブラリを直接使用し、文字及び文字列の送受信や書式化文字列の送信を行う。 | ||
Line 11: | Line 17: | ||
// 通常の使用においては数バイト程度で十分です。またバッファはグローバル変数としてください。 | // 通常の使用においては数バイト程度で十分です。またバッファはグローバル変数としてください。 | ||
static char txb[10], rxb[10]; | static char txb[10], rxb[10]; | ||
+ | |||
// 通信ポートを初期化 ボーレートは115200[bps] | // 通信ポートを初期化 ボーレートは115200[bps] | ||
rs_init (br115200, txb, sizeof(txb), rxb, sizeof(rxb)); | rs_init (br115200, txb, sizeof(txb), rxb, sizeof(rxb)); | ||
Line 22: | Line 28: | ||
・文字列送信 | ・文字列送信 | ||
void rs_puts (char *); | void rs_puts (char *); | ||
- | ・バイナリ列送信 | + | ・指定サイズのバイナリバイト列送信 |
void rs_putb (char *, short); | void rs_putb (char *, short); | ||
・受信バッファデータサイズ取得 | ・受信バッファデータサイズ取得 | ||
Line 28: | Line 34: | ||
・受信バッファクリア | ・受信バッファクリア | ||
void rs_rx_purge (void); | void rs_rx_purge (void); | ||
- | ・1文字受信 | + | ・1文字受信(受信されるまで待つ) |
char rs_getc (void); | char rs_getc (void); | ||
- | ・文字列受信 | + | ・文字列受信(入力時のエコーバックあり,CRで入力完了) |
short rs_gets (char *, short); | short rs_gets (char *, short); | ||
・簡易書式化文字列送信 | ・簡易書式化文字列送信 | ||
short rs_printf (const char *, ...); | short rs_printf (const char *, ...); | ||
- | **smpl2(USART).c [#jbe6dac4] | + | **USART2.c [#jbe6dac4] |
マイコンのUSARTを使ったシリアル通信を行う。avr-libcで提供される標準I/Oルーチンを中継し、シリアル通信はGCC Developer Liteで提供される専用のライブラリを間接的に使用する。 | マイコンのUSARTを使ったシリアル通信を行う。avr-libcで提供される標準I/Oルーチンを中継し、シリアル通信はGCC Developer Liteで提供される専用のライブラリを間接的に使用する。 | ||
- | 初期化まではsmpl1とほぼ同様だが、fdevopenで初期化された以後はC言語でよく使われる標準I/Oルーチン(putcharやprintf等)を使用する事ができる。 | + | 初期化まではUSART1.cとほぼ同様だが、fdevopenで初期化された以後はC言語でよく使われる標準I/Oルーチン(putcharやprintf等)を使用する事ができる。 |
// 通信ポートを初期化 ボーレートは115200[bps] | // 通信ポートを初期化 ボーレートは115200[bps] | ||
rs_init (br115200, txb, sizeof(txb), rxb, sizeof(rxb)); | rs_init (br115200, txb, sizeof(txb), rxb, sizeof(rxb)); | ||
Line 45: | Line 51: | ||
標準I/Oルーチンではまかないきれない機能は、シリアル通信ライブラリで提供されるサブルーチンで補填出来る。 | 標準I/Oルーチンではまかないきれない機能は、シリアル通信ライブラリで提供されるサブルーチンで補填出来る。 | ||
- | **smpl3(LED).c [#d0e3aab7] | + | **LED1.c [#d0e3aab7] |
PC4にソース接続されたLEDを点滅させる。~ | PC4にソース接続されたLEDを点滅させる。~ | ||
#ref(led1234.png) | #ref(led1234.png) | ||
Line 51: | Line 57: | ||
#include <avr/io.h> | #include <avr/io.h> | ||
PC4を出力ポートに設定するにはDDRCの4ビット目を1に設定する。 | PC4を出力ポートに設定するにはDDRCの4ビット目を1に設定する。 | ||
- | DDRC |= _BV(DDC4); // PC4を出力に | + | DDRC |= _BV(DD4); // PC4を出力に |
PC4へ1を書くとLEDは点灯、0を書くと消灯する。ちなみに、_BV() は引数で指定した数値をビットに変換するavr-libcで提供されるマクロである。~ | PC4へ1を書くとLEDは点灯、0を書くと消灯する。ちなみに、_BV() は引数で指定した数値をビットに変換するavr-libcで提供されるマクロである。~ | ||
- | PORTC &= ~_BV(PC4); // 消灯 | + | PORTC &= ~_BV(PORT4); // 消灯 |
- | PORTC |= _BV(PC4); // 点灯 | + | PORTC |= _BV(PORT4); // 点灯 |
点滅の周期は util/delay.h で宣言される _delay_ms 関数を使用し、ミリ秒単位で設定している。 | 点滅の周期は util/delay.h で宣言される _delay_ms 関数を使用し、ミリ秒単位で設定している。 | ||
_delay_ms (500); // 500ms待つ | _delay_ms (500); // 500ms待つ | ||
- | **smpl4(4bitLED).c [#k0566312] | + | **LED2.c [#k0566312] |
PC4~PC7へそれぞれLEDをソース接続し点滅させる。 | PC4~PC7へそれぞれLEDをソース接続し点滅させる。 | ||
出力端子の初期化は以下の通り。 | 出力端子の初期化は以下の通り。 | ||
- | DDRC |= _BV(DDC4) | _BV(DDC5) | _BV(DDC6) | _BV(DDC7); // PC4..7を出力に | + | DDRC |= _BV(DD4) | _BV(DD5) | _BV(DD6) | _BV(DD7); // PC4..7を出力に |
点灯させるビットが増えると一つ一つビットを指定するのが面倒なので、4ビットまとめて点灯ないし消灯させる関数を用意している。 | 点灯させるビットが増えると一つ一つビットを指定するのが面倒なので、4ビットまとめて点灯ないし消灯させる関数を用意している。 | ||
void LED (int d) { | void LED (int d) { | ||
Line 68: | Line 74: | ||
} | } | ||
- | **smpl5(ALLPIO).c [#i281618a] | + | **ALLPIO.c [#i281618a] |
PC2~3にDIPスイッチ、PD2~PD3にプッシュボタンを接続し、逐次それらの状態を取り込んでLED1~4に反映させる。~ | PC2~3にDIPスイッチ、PD2~PD3にプッシュボタンを接続し、逐次それらの状態を取り込んでLED1~4に反映させる。~ | ||
#ref(switch.png) | #ref(switch.png) | ||
入力端子の初期化は以下の通り。 | 入力端子の初期化は以下の通り。 | ||
// DIP1(PC2,3)を構成 | // DIP1(PC2,3)を構成 | ||
- | DDRC &= ~(_BV(DDC2) | _BV(DDC3)); // PC2,3を入力に | + | DDRC &= ~(_BV(DD2) | _BV(DD3)); // PC2,3を入力に |
- | PORTC |= (_BV(PC2) | _BV(PC3)); // PC2,3の内蔵プルアップ抵抗をON | + | PORTC |= (_BV(PORT2) | _BV(PORT3)); // PC2,3の内蔵プルアップ抵抗をON |
+ | |||
// PB1~PB2(PD2,3)を構成 | // PB1~PB2(PD2,3)を構成 | ||
- | DDRD &= ~(_BV(DDD2) | _BV(DDD3)); // PD2,3を入力に | + | DDRD &= ~(_BV(DD2) | _BV(DD3)); // PD2,3を入力に |
- | PORTD |= (_BV(PD2) | _BV(PD3)); // PD2,3の内蔵プルアップ抵抗をON | + | PORTD |= (_BV(PORT2) | _BV(PORT3)); // PD2,3の内蔵プルアップ抵抗をON |
DIPスイッチは2ビットまとめて数値として取り込む関数を用意している。 | DIPスイッチは2ビットまとめて数値として取り込む関数を用意している。 | ||
// DIP1(ディップスイッチ)の状態取り込み | // DIP1(ディップスイッチ)の状態取り込み | ||
Line 87: | Line 93: | ||
// プッシュボタン1の状態取り込み | // プッシュボタン1の状態取り込み | ||
unsigned char PB1_STAT (void) { | unsigned char PB1_STAT (void) { | ||
- | return bit_is_clear (PIND, PIND2); | + | return bit_is_clear (PIND, PIN2); |
} | } | ||
+ | |||
// プッシュボタン2の状態取り込み | // プッシュボタン2の状態取り込み | ||
unsigned char PB2_STAT (void) { | unsigned char PB2_STAT (void) { | ||
- | return bit_is_clear (PIND, PIND3); | + | return bit_is_clear (PIND, PIN3); |
} | } | ||
- | **smpl6(PIOINT).c [#g253e09b] | + | **PIOINT.c [#g253e09b] |
外部割り込みを使ってプッシュボタンの押下を検出し、各々のボタンで異なる機能を持たせる。さらに、割り込みが発生しない間はマイコンをスリープモードにし、低消費電力モードに移行させる。 | 外部割り込みを使ってプッシュボタンの押下を検出し、各々のボタンで異なる機能を持たせる。さらに、割り込みが発生しない間はマイコンをスリープモードにし、低消費電力モードに移行させる。 | ||
Line 102: | Line 108: | ||
MCUCR |= _BV(ISC11) | _BV(ISC01); // ISC11とISC01を1に | MCUCR |= _BV(ISC11) | _BV(ISC01); // ISC11とISC01を1に | ||
MCUCR &= ~(_BV(ISC10) | _BV(ISC00)); // ISC10とISC00を0に | MCUCR &= ~(_BV(ISC10) | _BV(ISC00)); // ISC10とISC00を0に | ||
+ | |||
// INT0/1割り込みを許可 | // INT0/1割り込みを許可 | ||
GICR |= _BV(INT1) | _BV (INT0); | GICR |= _BV(INT1) | _BV (INT0); | ||
+ | |||
// 全割り込み許可 | // 全割り込み許可 | ||
sei (); | sei (); | ||
Line 115: | Line 121: | ||
while (1) { | while (1) { | ||
sleep_mode (); | sleep_mode (); | ||
- | PORTC ^= _BV(PC7); // 起きる度にLED4をブリンク | + | PORTC ^= _BV(PORT7); // 起きる度にLED4をブリンク |
} | } | ||
INT0に対応した割り込みルーチン名は INT0_vect としてavr-libcにて決められているので、その様に記述。処理はcnt変数の値をインクリメントし、その値をLED1~3に表示する。 | INT0に対応した割り込みルーチン名は INT0_vect としてavr-libcにて決められているので、その様に記述。処理はcnt変数の値をインクリメントし、その値をLED1~3に表示する。 | ||
Line 126: | Line 132: | ||
} | } | ||
- | **smpl7(ADC).c [#h9ecd904] | + | **ADC.c [#h9ecd904] |
PA0~PA7の端子に入力されるDC0~5Vの電圧を計測し、シリアル通信で送信する。 | PA0~PA7の端子に入力されるDC0~5Vの電圧を計測し、シリアル通信で送信する。 | ||
Line 151: | Line 157: | ||
ADC=[ 0.57V,0.32V,1.21V,1.18V,1.55V,1.93V,1.82V,1.78V ] | ADC=[ 0.57V,0.32V,1.21V,1.18V,1.55V,1.93V,1.82V,1.78V ] | ||
- | **smpl8(TIMERINT).c [#abc72a43] | + | **TIMERINT.c [#abc72a43] |
タイマ/カウンタ0のオーバーフローを使用して一定間隔で割り込みを励起する。 | タイマ/カウンタ0のオーバーフローを使用して一定間隔で割り込みを励起する。 | ||
Line 165: | Line 171: | ||
if (cnt++ > 31) { // 約0.5秒毎にLEDを反転 | if (cnt++ > 31) { // 約0.5秒毎にLEDを反転 | ||
cnt = 0; | cnt = 0; | ||
- | rbi (PORTC, PORTC4); | + | rbi (PORTC, PORT4); |
} | } | ||
} | } | ||
Line 173: | Line 179: | ||
} | } | ||
- | **smpl9(2chPWM).c [#p286a3ce] | + | **2chPWM.c [#p286a3ce] |
タイマ/カウンタ1の高速PWMモードにてPD4(OC1B)端子とPD5(OC1A)端子から個別のデューティー比でPWM信号を出力できる様に構成し、PWMの1周期(コンペアマッチ)毎に割り込みを発生させてLED1の点滅と周期の更新を行う。~ | タイマ/カウンタ1の高速PWMモードにてPD4(OC1B)端子とPD5(OC1A)端子から個別のデューティー比でPWM信号を出力できる様に構成し、PWMの1周期(コンペアマッチ)毎に割り込みを発生させてLED1の点滅と周期の更新を行う。~ | ||
PWM信号を五感で把握するにはPD4とPD5端子にオシロスコープ等を接続し、オシロスコープのディスプレイ上に表示される波形にて確認する。 | PWM信号を五感で把握するにはPD4とPD5端子にオシロスコープ等を接続し、オシロスコープのディスプレイ上に表示される波形にて確認する。 | ||
Line 179: | Line 185: | ||
LED1が接続されたPC4とPWM信号を出力するPD4とPD5を出力に設定する。 | LED1が接続されたPC4とPWM信号を出力するPD4とPD5を出力に設定する。 | ||
// LED1(PC4)を構成 | // LED1(PC4)を構成 | ||
- | DDRC |= _BV(DDC4); // PC4を出力に | + | DDRC |= _BV(DD4); // PC4を出力に |
- | PORTC &= ~_BV(PC4); // LEDをOFF PC4=0 | + | PORTC &= ~_BV(PORT4); // LEDをOFF PC4=0 |
+ | |||
// PWM出力端子を構成 | // PWM出力端子を構成 | ||
- | DDRD |= _BV(DDB4) | _BV(DDB5); // PD5,PD4を出力に | + | DDRD |= _BV(DD4) | _BV(DD5); // PD5,PD4を出力に |
タイマ/カウンタ1を高速PWMモードに設定する。ICR1がPWMの周期、OCR1AがPD5(OC1A)のデューティー、OCR1BがPD4(OC1B)のデューティーとなり、ここでは周期を8ms(=125Hz=CLK/256 /500)としたので以下の通りに設定する。 | タイマ/カウンタ1を高速PWMモードに設定する。ICR1がPWMの周期、OCR1AがPD5(OC1A)のデューティー、OCR1BがPD4(OC1B)のデューティーとなり、ここでは周期を8ms(=125Hz=CLK/256 /500)としたので以下の通りに設定する。 | ||
// タイマ/カウンタ1を高速PWMモードに設定 (ICR1でTOP) | // タイマ/カウンタ1を高速PWMモードに設定 (ICR1でTOP) | ||
Line 198: | Line 204: | ||
ISR (TIMER1_COMPA_vect) { | ISR (TIMER1_COMPA_vect) { | ||
int i; | int i; | ||
+ | |||
// 1周期毎に比較レジスタ更新 | // 1周期毎に比較レジスタ更新 | ||
for (i = 0; i < 2; i++) if (cnt[i]++ > 500) cnt[i] = 0; | for (i = 0; i < 2; i++) if (cnt[i]++ > 500) cnt[i] = 0; | ||
OCR1A = cnt[0]; | OCR1A = cnt[0]; | ||
OCR1B = cnt[1]; | OCR1B = cnt[1]; | ||
- | + | ||
- | rbi (PORTC, PINC4); // LEDビット反転 | + | rbi (PORTC, PORT4); // LEDビット反転 |
} | } | ||
- | **smpl10(EEPROM).c [#v4acb9af] | + | **EEPROM.c [#v4acb9af] |
マイコンに内蔵されたEEPROMの読み書きを行う。操作及び状況の確認はシリアル通信にて行う。 | マイコンに内蔵されたEEPROMの読み書きを行う。操作及び状況の確認はシリアル通信にて行う。 | ||
- | 内蔵EEPROM関連のサブルーチン等 avr/eeprom.h に定義される。 | + | 内蔵EEPROM関連のサブルーチン等は avr/eeprom.h に定義される。 |
#include <avr/eeprom.h> // EEPROM関連 | #include <avr/eeprom.h> // EEPROM関連 | ||
+ | EEPROMへのアクセスを行う際はそれ以前の内部的なEEPROMへの処理が完了している必要があるため eeprom_busy_wait 関数にて処理完了を待ち、さらにアクセス中は他の処理に影響が及ぶとの事で割り込み等は禁止にする必要がある。 | ||
+ | cli (); | ||
+ | eeprom_busy_wait (); | ||
+ | eeprom_write_byte ((uint8_t *)i, c); | ||
+ | sei (); | ||
+ | **CONSTMEM.c [#gc65cc96] | ||
+ | avr-libcで提供される特殊なメモリアクセス方法の紹介。 | ||
+ | |||
+ | AVRはハーバードアーキテクチャーであるため、プログラムコード領域(フラッシュROM)とワーク領域(SRAM)が分離されている。つまり連続・不連続に関わらず同一のメモリマップ上には配置されないため、一般的なC言語の記述ではフラッシュROM上に置かれたデータ類へのアクセスが出来ない。~ | ||
+ | 例えば | ||
+ | const char hoge[] = "TEST DATA\n"; | ||
+ | といった宣言を行うとフラッシュROM内にhogeのデータが確保され、プログラムの実行が開始される際にhogeをSRAM上にコピーしたものがアクセス対象となる。つまり、ある程度サイズに余裕のあるフラッシュROM上に不変の固定データを置いたつもりでも、それと同等のサイズのデータがSRAM上に別途確保されるので、非常に小さいSRAMを圧迫する結果となる。~ | ||
+ | avr-libcにはSRAMにコピーせずにフラッシュROM上に確保したデータへアクセスするために、宣言時と利用時に特殊な命令が用意されている。 | ||
+ | const char gyao[27000] PROGMEM = {0,0,0,0,0,0,}; | ||
+ | **BUZZER.c [#e8471f5c] | ||
+ | PD7(OC2)端子に接続されたトランジスタを介して他励式のブザーを駆動する。 | ||
+ | #ref(bz.png) | ||
+ | この回路ではPD7端子がHIGHになるとトランジスタがONしてブザーの+/-両端に電圧が加わる。LOWになるとトランジスタがOFFしてブザーの-端子がオープンになる。これをゆっくり繰り返すとブザーがプチプチとなるだけだが、数百~数kHzの周期で繰り返すとぴ~ぷ~といった音として聞こえる様になる。 | ||
+ | |||
+ | 周波数はPA7(ADC7)端子に接続したポテンショメータで分圧された電圧を計測する事で設定するものとしている。 | ||
+ | #ref(vr.png) | ||
+ | |||
+ | PD7はカウンタタイマ2のOC2端子が接続されており、コンペアマッチでトグル動作する様に設定すればOCR2に設定できる範囲の値で周波数が設定出来る。また同時にPD7を出力端子に設定する必要もある。 | ||
+ | void ToneOn (int tone) { | ||
+ | OCR2 = UD_ToneTable[tone]; | ||
+ | TCCR2 = _BV(WGM21) | _BV(COM20) | _BV(CS22) | _BV(CS20); | ||
+ | // PD7(OC2)を出力に | ||
+ | DDRD |= _BV(DD7); | ||
+ | } | ||
+ | 大抵ブザーの類は常時一定の電圧を加えておく事は推奨されていないので、音を出さないときはOFFしておく事で劣化を防ぎつつ無駄に電力を消費する事もなくなる。 | ||
+ | void ToneOff (void) { | ||
+ | // PD7(OC2)を入力(外部のプルダウン抵抗でLOWに) | ||
+ | DDRD &= ~_BV(DD7); | ||
+ | TCCR2 = 0; | ||
+ | } | ||
+ | |||
+ | **SPI_BRIDGE.c [#j47c03d0] | ||
+ | SPIバスで接続されたATA6831(3ch ハーフブリッジドライバ)と通信を行い、任意のパターンで各チャネルのトランジスタをON/OFFさせる。 | ||
+ | #ref(spi.png) | ||
+ | SPIは簡単に言えばクロック同期式の双方向シリアル通信で、MISO・MOSI・SCKとチップセレクトの4本の信号でコミュニケーションする。対象によってタイミング等細かい違いはあるが、AVRの場合は大抵のデバイスとと接続する事ができる。 | ||
+ | |||
+ | ATA6831は3chのハーフブリッジを内蔵した主にリレーやランプを駆動するドライバICである。ここのうちハーフブリッジを2つ使えばモータの正/逆転を行うのに十分なHブリッジが構成できるので、小型モータの駆動程度であれば十分に使える。~ | ||
+ | また3chのハーフブリッジに対してモータをうまくつなげば、動作モードの制限はあるものの2台を個別に駆動する事ができない事も無い。 | ||
+ | |||
+ | **RCSERVO.c [#l9555243] | ||
+ | 1chのPWM信号をマルチプレクサを介して見かけ上8chに分配する。出力端子を変更する毎にPWMのデューティを更新しなくてはならないので少し面倒。 | ||
+ | |||
+ | **ARRAYFUNC.c [#e780cbb7] | ||
+ | C言語の分岐命令等で条件別に関数を呼ぶのではなく、初期化済み配列に関数自体を登録しておき簡便に呼び出すプログラム。 |