TOPへ戻る

20070715 WinAVRのprintfを試してみる

WinAVRに用意されているprintfについて、動作の確認をしてみました。
パソコンでしたら、printfの出力先は画面ですが、今回はシリアルに出力させます。
※ATmega168 20MHz にて、確認を行っています。他のシリーズを使用する場合レジスタ等を変更してください。

あきぼうのAVRで遊ぶ日々 さんのウエブページの
stdio.h: 標準入出力(Standard IO fascilities)を参考にしました。

調べてみると printf には、数パターンの使い方があるようなので、以下の組み合わせで確認を行いました。

TYPE

方法

Program

Data

0 fdevopenを使用する方法 2988byte 72byte
1 FDEV_SETUP_STREAMを使用する方法 2268byte 76byte
2 vfprintfを使用する方法 2186byte 80byte
3 vfprintf_Pを使用する方法 2152byte 80byte

このサンプルプログラムのダウンロード

標準入力関数を使用することでかなりプログラム領域を消費してしまうようです。
FDEV_SETUP_STREAM を使用した方法が、fdevopenより、720byte小さくなります。

720Byteのイメージ(^_^;
   +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
02:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
03:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
04:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
05:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
06:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
07:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
08:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
09:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
10:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
11:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
12:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
13:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
14:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
15:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
16:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
17:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
19:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
21:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
22:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
23:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
24:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
25:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
26:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
27:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
28:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
29:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
31:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
32:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
33:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
34:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
35:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
36:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
37:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
38:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
39:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
41:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
42:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
43:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
44:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
45:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

実行すると、以下のような文字が送信されます。
Hello, world!
data=65 41 A
00123
PORTB = ff
PORTB = 00
PORTB = ff
PORTB = 00
PORTB = ff

vfprintf を使うと、このようになります。値が変わってしまうのは謎です。(^_^;
Hello, world!
data=79 4f O
00000
PORTB = d10
PORTB = 00
PORTB = d10
PORTB = 00
PORTB = d10
PORTB = 00

プログラムですが、#define TYPE n の n に0〜3の数字を入れてコンパイルすることで
各パターンを確認できるようになっています。
このprintfが使用できれば、printfを使用したデバックが簡単に作れるようになります。

ソースコード
// ATmega168 20MHz printf サンプル //TYPE 0:fdevopen使用 //TYPE 1:FDEV_SETUP_STREAM使用 //TYPE 2:vfprintf使用 //TYPE 3:vfprintf_P使用 #define TYPE 1 #include <stdio.h> #include <avr/io.h> #include <util/delay.h> /** sio設定 **/ #define FOSC 20000000 // 20MHz #define BAUD 38400 #define MYUBRR FOSC/16/BAUD-1 // sio分周率 static int uart_putchar(char c); // 関数宣言 #if TYPE != 0 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); #endif int uart_putchar(char c ) { loop_until_bit_is_set(UCSR0A, UDRE0); //特定のビットが1になるのを待つ命令 UDR0 = c; return 0; } void sio_init(unsigned int ubrr){ UBRR0H = (unsigned char)(ubrr>>8); // ボーレート上位8bit UBRR0L = (unsigned char)ubrr; // ボーレート下位8bit UCSR0B = (1<<RXEN0)|(1<<TXEN0); // 送受信許可 UCSR0C = (1<<USBS0)|(3<<UCSZ00); } /* TEST用LED PORT設定 */ void port_init(void){ DDRB = 0x01; PORTB = 0x00; } int main(void) { int i; sio_init(MYUBRR); // SIO設定 #if TYPE == 0 // fdevopen( uart_putchar, NULL, 0); // avr-libc 1.2 fdevopen( uart_putchar, NULL); // avr-libc 1.4 printf("\r\n"); printf("Hello, world!\r\n"); printf("data=%d %x %c\r\n", 65, 65, 65); printf("%05d\r\n", 123); #endif #if TYPE == 1 stdout = &mystdout; //※stdoutをオーバーライドできる→printfで望む出力が可能になる printf("\r\n"); printf("Hello, world!\r\n"); printf("data=%d %x %c\r\n", 65, 65, 65); printf("%05d\r\n", 123); #endif #if TYPE == 2 stdout = &mystdout; //※stdoutをオーバーライドできる→printfで望む出力が可能になる vfprintf(stdout, "\r\n",NULL); vfprintf(stdout, "Hello, world!\r\n",NULL); // vfprintf(stdout, "data=%d %x %c\r\n", 65, 65, 65); vfprintf(stdout, "data=%d ",65); vfprintf(stdout, "%x ",65); vfprintf(stdout, "%c\r\n",65); vfprintf(stdout, "%05d\r\n", 123); #endif #if TYPE == 3 stdout = &mystdout; //※stdoutをオーバーライドできる→printfで望む出力が可能になる vfprintf_P(stdout, "\r\n",NULL); vfprintf_P(stdout, "Hello, world!\r\n",NULL); // vfprintf_P(stdout, "data=%d %x %c\r\n", 65, 65, 65); vfprintf_P(stdout, "data=%d ",65); vfprintf_P(stdout, "%x ",65); vfprintf_P(stdout, "%c\r\n",65); vfprintf_P(stdout, "%05d\r\n", 123); #endif for(;;){ for(i = 0; i < 20; i++){ _delay_ms(100); } PORTB = ~PORTB; #if TYPE == 0 | TYPE == 1 printf("PORTB = %02x\r\n",PORTB); #endif #if TYPE == 2 vfprintf(stdout, "PORTB = %02x\r\n",PORTB); #endif #if TYPE == 3 vfprintf_P(stdout, "PORTB = %02x\r\n",PORTB); #endif } return 0; }
2007/07/15 初版

TOPへ戻る