p.339ff.
今度は、SPIで何かを書き込んでみる / ディジタルポテンショメーターAD8402ARZ50を制御する -(LabVIEW版)で使ったディジタルポテンショメーターAD8402ARZ50をAVRのSPIモジュールで動かしてみる。50 kΩが2個入っている。
チャンネル指定用の2ビットとワイパー位置指定用の8ビットの計10ビットをMSBファーストで送り込めばよいが、8ビット単位でしか転送できないので、まずdon't careの6ビットとチャンネル指定の2ビットとを転送してからワイパー位置指定用の8ビットを転送する。スレーブセレクトが解除されたときの直前の10ビットがスレーブ側で処理される。
#include <avr/io.h> #include <util/delay.h> extern "C" { #include "USART.h" } int main(){ DDRB |= (1 << PB2); // PB2を!SS端子(OUT)として使う。 PORTB |= (1 << PB2); // 最初はスレーブセレクトを解除しておく(Hを出力しておく)。 DDRB |= (1 << PB3); // PB3をMOSI端子(OUT)として使う。 PORTB |= (1 << PB4); // PB4をMISO端子(IN)として使う。内部プルアップしておく。 DDRB |= (1 << PB5); // PB5をSCK端子(OUT)として使う。 //SPCR &= ~(1 << CPOL | 1 << CPHA); // mode(0,0)。デフォルト。CPOL、CPHAのCはclock。 //SPCR &= ~(1 << CPOL); SPCR |= (1 << CPHA); // mode(0,1) //SPCR |= (1 << CPOL); SPCR &= ~(1 << CPHA); // mode(1,0) //SPCR |= (1 << CPOL | 1 << CPHA); // mode(1,1) //SPCR &= ~(1 << DORD); // MSBファーストで転送する。デフォルト。 //SPCR |= (1 << DORD); // LSBファーストで転送する。 SPCR |= (1 << SPR1 | 1 << SPR0); // SPIのクロック周波数。ここでは8MHzを128分周した(62.5kHz)。SPRのRはRate。 SPCR |= (1 << MSTR); // AVRをマスターにする。 SPCR |= (1 << SPE); // SPIを有効化する。 /******************************************************/ /* ためしにチャンネルとワイパーの位置とを指定してみる */ /******************************************************/ initUSART(); uint8_t ch; uint8_t pos; while(1){ printString("Enter a channel, 1 or 2: "); ch = getNumber() - 1; // channel 1: 0b00, channel 2: 0b01 printString("Enter a position of the wiper, 0-255: "); pos = getNumber(); PORTB &= ~(1 << PB2); // スレーブをセレクトして、 SPDR = ch; // (don't careの6ビット)+(チャンネル指定用の2ビット)を送って、 loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、 SPDR = pos; // ワイパー位置指定用の8ビットを送って、 loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、 PORTB |= (1 << PB2); // スレーブセレクトを解除する。 } return 0; }