ページへ戻る

− Links

 印刷 

ATmega32 Sample Code のバックアップソース(No.3) :: Besttechnology

knowledge:ATmega32 Sample Code のバックアップソース(No.3)

« Prev[4]  Next »[5]
*ダウンロード[#l493db9b]
*一覧 [#j8c69fab]
**smpl1(USART).c [#y20358e6]
マイコンのUSARTを使ったシリアル通信を行う。シリアル通信はGCC Developer Liteで提供される専用のライブラリを直接使用し、文字及び文字列の送受信や書式化文字列の送信を行う。~
シリアル通信ライブラリのプロトタイプ宣言はrs.hとして提供され、ソースにインクルードする事で参照される。~
 #include <rs.h>             // USART通信ライブラリ
また、シリアル通信を行う前には必ず初期化処理を必要とし、実際の通信処理を行う内部のサブルーチンは割り込みを使用しているので、割り込みを許可しておく。~
 // 送受信用バッファ
 // バッファの大きさは任意(2~255の間)ですが、大きすぎるとRAMエリアを圧迫するだけです。
 // 通常の使用においては数バイト程度で十分です。またバッファはグローバル変数としてください。
 static char txb[10], rxb[10];

 // 通信ポートを初期化 ボーレートは115200[bps]
 rs_init (br115200, txb, sizeof(txb), rxb, sizeof(rxb));
 // 通信は割り込みで処理されます
 // 初期化後は必ず割り込みを許可状態にしてください
 sei ();
その他のサブルーチンは以下のものが用意されている。詳細はソースのコメントを参照の事。
 ・1文字送信
  void  rs_putc (char);
 ・文字列送信
  void  rs_puts (char *);
 ・バイナリ列送信
  void  rs_putb (char *, short);
 ・受信バッファデータサイズ取得
  short rs_rx_buff (void);
 ・受信バッファクリア
  void  rs_rx_purge (void);
 ・1文字受信
  char rs_getc (void);
 ・文字列受信
  short rs_gets (char *, short);
 ・簡易書式化文字列送信
  short rs_printf (const char *, ...);

**smpl2(USART).c [#jbe6dac4]
マイコンのUSARTを使ったシリアル通信を行う。avr-libcで提供される標準I/Oルーチンを中継し、シリアル通信はGCC Developer Liteで提供される専用のライブラリを間接的に使用する。~
初期化まではsmpl1とほぼ同様だが、fdevopenで初期化された以後はC言語でよく使われる標準I/Oルーチン(putcharやprintf等)を使用する事ができる。
 // 通信ポートを初期化 ボーレートは115200[bps]
 rs_init (br115200, txb, sizeof(txb), rxb, sizeof(rxb));
 // 標準入出力をlibm32.a内のルーチンに割り当て
 fdevopen(rs_putchar, rs_getchar);
標準I/Oルーチンではまかないきれない機能は、シリアル通信ライブラリで提供されるサブルーチンで補填出来る。

**smpl3(LED).c [#d0e3aab7]
PC4にソース接続されたLEDを点滅させる。~
#ref(led1234.png)
AVRの内部レジスタは avr/io.h をインクルードする事でデータシートに記載されている名称で参照出来る。なお、io.hは複数のデバイスのヘッダを取りまとめており、ATmega32の場合は avr/iom32.h が実体である。
 #include <avr/io.h>
PC4を出力ポートに設定するにはDDRCの4ビット目を1に設定する。
 DDRC |= _BV(DDC4);    // PC4を出力に
PC4へ1を書くとLEDは点灯、0を書くと消灯する。ちなみに、_BV() は引数で指定した数値をビットに変換するavr-libcで提供されるマクロである。~
 PORTC &= ~_BV(PC4); // 消灯
 PORTC |= _BV(PC4);  // 点灯
点滅の周期は util/delay.h で宣言される _delay_ms 関数を使用し、ミリ秒単位で設定している。
 _delay_ms (500);    // 500ms待つ

**smpl4(4bitLED).c [#k0566312]
PC4~PC7へそれぞれLEDをソース接続し点滅させる。~
出力端子の初期化は以下の通り。
 DDRC |= _BV(DDC4) | _BV(DDC5) | _BV(DDC6) | _BV(DDC7);  // PC4..7を出力に
点灯させるビットが増えると一つ一つビットを指定するのが面倒なので、4ビットまとめて点灯ないし消灯させる関数を用意している。
 void LED (int d) {
   PORTC = (PORTC & 0x0f) | ((d << 4) & 0xf0);
 }

**smpl5(ALLPIO).c [#i281618a]
PC2~3にDIPスイッチ、PD2~PD3にプッシュボタンを接続し、逐次それらの状態を取り込んでLED1~4に反映させる。~
#ref(switch.png)
入力端子の初期化は以下の通り。
 // DIP1(PC2,3)を構成
 DDRC &= ~(_BV(DDC2) | _BV(DDC3)); // PC2,3を入力に
 PORTC |= (_BV(PC2) | _BV(PC3));   // PC2,3の内蔵プルアップ抵抗をON

 // PB1~PB2(PD2,3)を構成
 DDRD &= ~(_BV(DDD2) | _BV(DDD3)); // PD2,3を入力に
 PORTD |= (_BV(PD2) | _BV(PD3));   // PD2,3の内蔵プルアップ抵抗をON
DIPスイッチは2ビットまとめて数値として取り込む関数を用意している。
 // DIP1(ディップスイッチ)の状態取り込み
 unsigned char DIP1_STAT (void) {
   return (~(PINC >> 2)) & 0x3;
 }
プッシュボタン1/2の取り込みも同様に各々関数を用意している。
 // プッシュボタン1の状態取り込み
 unsigned char PB1_STAT (void) {
   return bit_is_clear (PIND, PIND2);
 }

 // プッシュボタン2の状態取り込み
 unsigned char PB2_STAT (void) {
   return bit_is_clear (PIND, PIND3);
 }

**smpl6(PIOINT).c [#g253e09b]
外部割り込みを使ってプッシュボタンの押下を検出し、各々のボタンで異なる機能を持たせる。さらに、割り込みが発生しない間はマイコンをスリープモードにし、低消費電力モードに移行させる。~
プッシュボタン1,2はPD2(INT0)とPD3(INT1)に直結しており、押下されて信号が0になった瞬間に割り込みを励起するよう設定する。
 // INT0/1の割り込み条件を立下りエッジに
 MCUCR |= _BV(ISC11) | _BV(ISC01);     // ISC11とISC01を1に
 MCUCR &= ~(_BV(ISC10) | _BV(ISC00));  // ISC10とISC00を0に

 // INT0/1割り込みを許可
 GICR |= _BV(INT1) | _BV (INT0);

 // 全割り込み許可
 sei ();

マイコンの低消費電力モードはINT0/1でスリープから復帰できるモードを選択する。
 set_sleep_mode (SLEEP_MODE_IDLE);
mainの中では sleep_mode () をコールする以外に特に何もしないが、スリープから復帰した事を明示的にわかるようにLED4を点滅する様に仕掛けている。
 // 特に仕事はないのでスリープモードに突入(割り込みにて復帰)
 while (1) {
   sleep_mode ();
   PORTC ^= _BV(PC7);  // 起きる度にLED4をブリンク
 }
INT0に対応した割り込みルーチン名は INT0_vect としてavr-libcにて決められているので、その様に記述。処理はcnt変数の値をインクリメントし、その値をLED1~3に表示する。
 ISR(INT0_vect) {
   LED (++cnt);
 }
INT1に対応した割り込みルーチン名は INT1_vect としてavr-libcにて決められているので、その様に記述。処理はcnt変数の値をデクリメントし、その値をLED1~3に表示する。
 ISR(INT1_vect) {
   LED (--cnt);
 }

**smpl7(ADC).c [#h9ecd904]
PA0~PA7の端子に入力されるDC0~5Vの電圧を計測し、シリアル通信で送信する。~
ここではA/D変換するにあたり基準となる電圧(DC5V)をAVCC端子に接続した。
#ref(cn2_adc.png)
A/D変換器の初期化は以下の通り。変換時間等は変換精度等の必要に応じて設定する事。
 // A/D変換許可, 変換クロックCK/16
 ADCSRA = _BV(ADEN) | _BV(ADPS2);
内部にはA/D変換器は1つしかないため、8つの端子からの入力を同時に行う事はできない。任意のチャネルを選択し、変換を励起し、変換が終了するまでチャネルを切り替える事はできない。~
変換開始から終了の待機及び変換されたデータを取得する関数は以下の通り。
 // 任意CHのA/D変換
 unsigned short a2d (char ch) {
   ADMUX = _BV(REFS0) | (ch & 7);          // リファレンス,CH指定
   ADCSRA |= _BV(ADSC);                    // 変換開始
   loop_until_bit_is_clear (ADCSRA, ADSC); // 変換終了待ち
   return ADC;
 }
DC0~5V入力された電圧に応じて0~1023の10ビットの精度で値が取得される。~

mainのループではプッシュボタン1を押すと0~1023の値として、プッシュボタン2を押すと5.00Vといった電圧値として8ch分の変換値をターミナルに対して文字列として送信する。
 ・PushButton1を押している間
  ADC=[   338,  609,  617,  802,  639,  887,  670,  495 ]
 ・PushButton2を押している間
  ADC=[ 0.57V,0.32V,1.21V,1.18V,1.55V,1.93V,1.82V,1.78V ]
**smpl8(TIMERINT).c [#abc72a43]
タイマ/カウンタ0のオーバーフローを使用して一定間隔で割り込みを励起する。~
タイマ/カウンタ0のオーバーフロー割り込みを許可するのは以下の通り。
 // タイマ/カウンタ0割り込みマスク構成
 TIMSK |= _BV(TOIE0);  // タイマカウンタ0オーバーフロー割り込み許可
タイマ/カウンタ0をCLK/1024(16MHz/1024=15.625kHz)で標準動作をさせるには以下の通り。クロックを選択した瞬間からタイマとして動作を開始する。
 TCCR0 = _BV(CS02) | _BV(CS00);   // 標準動作,CLK/1024
15.625kHz毎にTCNT0の値がインクリメントされ、TOP値の255を超えて0にリセットされるとオーバーフロー割り込みが発生(15.625kHz/256=約61Hz)する。タイマ/カウンタ0のオーバフロー割り込みルーチン名は TIMER0_OVF_vect としてavr-libcにて決められているので、その様に記述。ここでは割り込みが発生したらさらにソフト的に分周し、約0.5秒毎にLED1を点滅させている。
 ISR (TIMER0_OVF_vect) {
   static int cnt = 0;
   // 1/16MHz * 1024 * 256 秒毎に割り込み発生
   if (cnt++ > 31) { // 約0.5秒毎にLEDを反転
     cnt = 0;
     rbi (PORTC, PORTC4);
   }
 }
mainは諸々の初期化を行った後は例のごとくしつこく省電力モードに移行し続ける以外の処理は行っていない。
 while (1) {   // 無限ループ
   sleep_mode ();
 }
**smpl9(2chPWM).c [#p286a3ce]
タイマ/カウンタ1の高速PWMモードにてPD4(OC1B)端子とPD5(OC1A)端子から個別のデューティー比でPWM信号を出力できる様に構成し、PWMの1周期(コンペアマッチ)毎に割り込みを発生させてLED1の点滅と周期の更新を行う。なお、PWM信号を五感で把握するにはPD4とPD5端子にオシロスコープ等を接続し、オシロスコープのディスプレイ上に表示される波形にて確認する。~
まずLED1が接続されたPC4とPWM信号を出力するPD4とPD5を出力に設定する。
 // LED1(PC4)を構成
 DDRC |= _BV(DDC4);    // PC4を出力に
 PORTC &= ~_BV(PC4);    // LEDをOFF PC4=0

 // ポート構成
 DDRD = _BV(DDB4) | _BV(DDB5);   // PD5,PD4を出力に

« Prev[4]  Next »[5]