Printf関数を自作する

出典: SpiralRay_Wiki

ココを参考にして、マイコンに接続したLCDにフォント表示をするためのprintf関数を自作する。

printf関数には、変数の内容などを表示するときに、複数の引数を取ることができる。
C言語での可変長引数の宣言は'...'で表現する。
つまり、

void printf(char * fmt, ...)

このようにする。

以下にprintf関数内の例を示す。
引数の設定以外は簡単なので、下のソースコードから把握してください。

stringsystem.c

#include <stdio.h>
#include "stringsystem.h"

void d_printf(char * fmt, ...) {	//stdio.h内のprintfとの競合は避ける
  char **arg = (char **) &fmt;
  char c;
  arg++;

  while((c = *fmt++) != 0) {
    if(c != '%')
      d_putchar(c);
    else {
      char buf[64];
      char *p;
      c = *fmt++;
      switch(c) {
      case 'd':
		if( 0 > *((int *) arg) ) {
          d_putchar('-');
          *((int *) arg) *= -1;
        }
        p = uint_to_str(buf, *((unsigned *) arg++), 10);
        goto print_s;
      case 'x':
	  	d_printf("0x");
        p = uint_to_str(buf, *((unsigned *) arg++), 16);
        goto print_s;
      case 's':
        p = *arg++;
        print_s:
        d_printf(p);
        break;
      default:
        d_putchar(c);
      }
    }
  }
}
char * uint_to_str(char *buf, unsigned src, int base) {
  char *p = buf;
  char *p1, *p2;

  do {
    *p++ = "0123456789ABCDEF"[src%base];
  } while(src /= base);

  // Terminate BUF
  *p = 0;

  // Reverse BUF
  for(p1=buf, p2=p-1; p1 < p2; p1++, p2--) {
    char tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
  }

  return buf;
}
int nowx = 0;
int line = 0;

unsigned char stringdata[MAX_DISPCHARW][MAX_DISPCHARH];

void initstring(){
	for(int y=0 ; y< MAX_DISPCHARH ; y++){
		for(int x=0 ; x< MAX_DISPCHARW ; x++){
			stringdata[x][y] = 32;
		}
	}
	nowx = 0;
	line = 0;
}

void newline(){
	nowx = 0;
	line = (line+1)%MAX_DISPCHARH;
	for(int i=0 ; i<MAX_DISPCHARW ; i++ ){
		stringdata[i][line]=32;
	}
}

void checkmax_x(){
	//横方向にはみ出なければその行でOK
	if(nowx<MAX_DISPCHARW) return;
	//改行処理
	newline();
}

void d_putchar(char c){
	//\n
	if(c==0x0a){
		newline();
		return;
	}
	//\r
	else if(c==13){
		initstring();
		return;
	}
	//"		"TAB
	else if(c==9){
	
		if(MAX_DISPCHARW-SURPLUSTAB <= nowx){
			newline();
		}
		else{
			nowx += 4-(nowx%4);
		}

		return;
	}
	//それ以外
	else checkmax_x();
	
	stringdata[nowx][line] = c;
	nowx++;
}


stringsystem.h

#define MAX_DISPCHARW	30	//文字数(横方向)の限界
#define MAX_DISPCHARH	20	//文字数(縦方向)の限界

//TABキーの時のスペース数決定(この場合は最大4文字)
#define SURPLUSTAB	MAX_DISPCHARW%4

extern int nowx;	//現在選択されているx(横方向)の番号(左から012...MAX_DISPCHARWまで)
extern int line;	//現在選択されているy(縦方向)の番号(左から012...MAX_DISPCHARHまで)

extern unsigned char stringdata[MAX_DISPCHARW][MAX_DISPCHARH];	//文字列の保存

void initstring();	//文字列を全てフォーマット。行、列ともに0に戻る
void newline();		//改行処理
void checkmax_x();	//列(横方向)がはみ出ないかをチェック

char * uint_to_str(char *buf, unsigned src, int base);

void d_putchar(char c);
void d_printf(char * fmt, ...);


ATmega644PとYHY024006A-PCBを使用した例を公開しておく。
回路図はあげてないのでプログラムから推測してください。(データビット以外はdefineで宣言してあるからわかりやすいかと)
(YHY024006A-PCBは16bitモードで動作させています)
パスワードはspiralray
lcd_with_atmega644p.rar

また、windowsでのコンソールでの例も挙げておく。
パスワードはspiralray
stringtest.rar

個人用ツール