ATmega168でADコンバータも試した。

CdS(光量センサ)と10kΩの抵抗を使った。

ATmega168 ADC and UART

ADC0でAD変換した値を文字列に変換して、UARTでPCに送る

ADC0の値が700以上の時、LEDを点灯させる。700以下だったら消灯する。

動いているところ

■コード

SourceCode, hex, Makefile(avr-gcc 3.4.6)

AD変換の準備のadc_init()、実際にAD変換を行ない値(int)を取るadc_convert(int pin)、USARTで文字列を送る関数 usart_sendStr()、intをStringに変換するintToStr(int, buf)を作った。

s.h.log: Arduino – UART、LED、AD変換を試したでも書いたが

シリアル通信で送信できるのは8bitまで。AD値は10bit。

なので、そのままSerial.print()してしまうと上位2bitが飛んで変な値になる。

こういう時は

・上位2bit/下位8bitを2回に分けて送信し、PC側で連結する

・マイコン側で、AD値が0~50の時は’a’を送る/51~100の時は’b’を送るの様に、プロトコルを決める

・Stringにして送信して、PC側で数値に直す

・4で割ると、10bitの最大値1023が8bitの最大値255に納まる。ただし精度は4分の1になる

のどれかで対処する。

なので今回は文字列に変換して送ってみた。これが無いとデバッグとかやってられない。



今回のコード。


#include <avr/io.h>
#include <avr/interrupt.h>

#define TRUE 1
#define FALSE 0
#define NULL '\0'
#define sbi(BYTE,BIT) BYTE|=_BV(BIT) // BYTEの指定BITに1をセット
#define cbi(BYTE,BIT) BYTE&=~_BV(BIT) // BYTEの指定BITをクリア

/** 動作設定 **/
#define FOSC 8000000 // 8MHz

/** UART設定 **/
#define BAUD 9600 // 9600bps
#define MYUBRR FOSC/16/BAUD-1 // UART分周率
// #define UCSR0A_U2X0 1 // 倍速フラグ 等速ならコメントアウト
#ifdef UCSR0A_U2X0 // 倍速が定義されているならば
#define MYUBRR FOSC/16/(BAUD/2)-1 // UART分周率(倍速)
#endif
volatile char usart_recvData; // USARTで受信したデータ

#define LED_SET() sbi(PORTB, PB0) // 基盤上の動作確認LED
#define LED_CLR() cbi(PORTB, PB0)


/* PORT設定 */
void port_init(void){
sbi(DDRB, PB0);
}


/* USART設定 */
void usart_init(unsigned int ubrr){
UBRR0H = (unsigned char)(ubrr>>8); // ボーレート上位8bit
UBRR0L = (unsigned char)ubrr; // ボーレート下位8bit
UCSR0A = (0<<U2X0); // 等速
UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); // 送受信許可、受信完了割り込み許可
UCSR0C = (0<<UMSEL00)|(3<<UCSZ00)|(1<<USBS0)|(0<<UPM00);
// フレーム設定 非同期通信 8ビット 1ストップビット パリティ無し
}

/* intの桁数を返す */
char getDigit(int n){
char i;
i = 0;
while(n>0){
n /= 10;
i++;
}
return i;
}

/* int->String変換 */
char *intToStr(int n, char *buf){ // 変換する数、作業領域
int i, digit;
digit = getDigit(n); // 桁数
for(i = digit-1; i >= 0; i--){ // intは最大5桁
buf[i] = n%10+'0';
n /= 10;
}
buf[digit] = '\0'; // 行末改行
return buf;
}

/* UARTで文字列送信 */
void usart_sendStr(char *str){
while(*str != NULL){
loop_until_bit_is_set(UCSR0A,UDRE0); // 送信データレジスタ空きまで待機
UDR0 = *str++; // 1文字送信、1文字進む
}
}

/* ADコンバータ設定 */
void adc_init(void){
ADMUX = (0<<REFS0); // 外部基準電圧
ADCSRA =(1<<ADEN)|(1<<ADSC)|(0<<ADPS0);
// A/D変換許可、1回目変換開始(調整)、分周率2
}

/* ピンを指定してAD変換 return 0-1023 */
int adc_convert(char pin){
int ad;
ADMUX = pin; // AD変換入力ピン
cbi(ADCSRA,ADIF);
sbi(ADCSRA,ADSC); // 変換開始
loop_until_bit_is_set(ADCSRA,ADIF); // 変換完了まで待つ
ad = ADCL; // 下位8bit取得
return ad += (ADCH<<8); // 上位2bit取得
}

int main(void){
port_init(); // PORT設定
usart_init(MYUBRR); // USART設定
adc_init(); // ADConverter設定

LED_SET(); // 起動確認LED

int ad;
char buf[6];

for(;;){
ad = adc_convert(0); // ADC0からAD変換
if(ad > 700) LED_SET();
else LED_CLR();
usart_sendStr(intToStr(ad,buf)); // AD値を文字列にして送信
usart_sendStr("\r\n"); // 改行
}
}