/** \file printf.c * Simplified printf() and sprintf() implementation - prints formatted string to * USART (or whereever). Most common % specifiers are supported. It costs you about * 3k FLASH memory - without floating point support it uses only 1k ROM! * \author Freddie Chopin, Martin Thomas, Marten Petschke and many others * \date 16.2.2012 */ /****************************************************************************** * chip: STM32F10x * compiler: arm-none-eabi-gcc 4.6.0 * * global functions: * int printf_(const char *format, ...) * int sprintf_(char *buffer, const char *format, ...) * * STM32 specific functions: * init_UART1(void) * void putc_UART1 (char); // blocking put char, used by printf() * * local functions: * int putc_strg(int character, printf_file_t *stream) * int vfprintf_(printf_file_t *stream, const char *format, va_list arg) * void long_itoa (long val, int radix, int len, vfprintf_stream *stream) * ******************************************************************************/ /* +=============================================================================+ | includes +=============================================================================+ */ #include // (...) parameter handling #include "config.h" // select controller type, frequency plan #include "stm32f10x.h" // only this STM headerfile is used /* +=============================================================================+ | options +=============================================================================+ */ //#define INCLUDE_FLOAT // this enables float in printf() and costs you about 2kByte ROM #define UART1_BAUDRATE 115200 /* +=============================================================================+ | global declarations +=============================================================================+ */ int printf_(const char *format, ...); int sprintf_(char *buffer, const char *format, ...); /* +=============================================================================+ | local declarations +=============================================================================+ */ void init_UART1(void); // STM32 specific stuff void putc_UART1 (char); // blocking put char; used by printf_() void putc_strg(char); // the put() function for sprintf() char *SPRINTF_buffer; // static int vfprintf_(void (*) (char), const char *format, va_list arg); //generic print void long_itoa (long, int, int, void (*) (char)); //heavily used by printf_() /* +=============================================================================+ | sample main() file +=============================================================================+ */ int main(void){ pll_start(); init_UART1(); printf_("\nSTM32_Start\n"); int cnt; for (cnt = 0; cnt < 12; cnt++) // test printf_("test unsigned negativ: |%u| \n", (unsigned int)(-cnt)); char s[30]; sprintf_(s,"Hallo!\n"); printf_("%s",s); #ifdef INCLUDE_FLOAT float f=3.14f; printf_("test float %3f, negativ: %f \n", f, -f); #endif return 1; } /* +=============================================================================+ | STM32 register definition only here and in interrupt handler +=============================================================================+ */ void init_UART1(void){ RCC->APB2ENR |= ( RCC_APB2ENR_IOPAEN |RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN); //Clock AFIO->MAPR &= ~(AFIO_MAPR_USART1_REMAP); //UART1 at the original pins GPIOA->CRH = 0x0090; USART1->BRR = (APB2CLK + UART1_BAUDRATE/2)/UART1_BAUDRATE; //0x008B; Baud=FREQUENCY/(16*8,69)=115107; // BRR simplified thanks to Uwe Hermann USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); // RX, TX enable } void putc_UART1 (char c) { if (c == '\n') { while ((USART1->SR & USART_SR_TXE) == 0); //blocks until previous byte was sent USART1->DR ='\r'; } while ((USART1->SR & USART_SR_TXE) == 0); //blocks until previous byte was sent USART1->DR = c; } /* +=============================================================================+ | end of controller specific stuff - no further controller dependent stuff below +=============================================================================+ */ /* +=============================================================================+ | global functions +=============================================================================+ */ int printf_(const char *format, ...) { va_list arg; va_start(arg, format); vfprintf_((&putc_UART1), format, arg); va_end(arg); return 0; } int sprintf_(char *buffer, const char *format, ...) { va_list arg; SPRINTF_buffer=buffer; //Pointer auf einen String in Speicherzelle abspeichern va_start(arg, format); vfprintf_((&putc_strg), format, arg); va_end(arg); *SPRINTF_buffer ='\0'; // append end of string return 0; } /* +=============================================================================+ | local functions +=============================================================================+ */ // putc_strg() is the putc()function for sprintf_() void putc_strg(char character) { *SPRINTF_buffer = (char)character; // just add the character to buffer SPRINTF_buffer++; } /*--------------------------------------------------------------------------------+ * vfprintf_() * Prints a string to stream. Supports %s, %c, %d, %ld %ul %02d %i %x %lud and %% * - partly supported: long long, float (%ll %f, %F, %2.2f) * - not supported: double float and exponent (%e %g %p %o \t) *--------------------------------------------------------------------------------+ */ static int vfprintf_(void (*putc)(char), const char* str, va_list arp) { int d, r, w, s, l; //d=char, r = radix, w = width, s=zeros, l=long char *c; // for the while loop only #ifdef INCLUDE_FLOAT float f; long int m, mv, p, w2; #endif while ((d = *str++) != 0) { if (d != '%') { (*putc)(d); continue; } d = *str++; w = r = s = l = 0; if (d == '%') { (*putc)(d); d = *str++; } if (d == '0') { d = *str++; s = 1; //padd with zeros } while ((d >= '0')&&(d <= '9')) { w += w * 10 + (d - '0'); d = *str++; } if (s) w = -w; //padd with zeros if negative #ifdef INCLUDE_FLOAT w2 = 2; //default decimal places=2 if (d == '.'){ d = *str++; w2 = 0; } while ((d >= '0')&&(d <= '9')) { w2 += w2 * 10 + (d - '0'); d = *str++; } #endif if (d == 's') { c = va_arg(arp, char*); while (*c) (*putc)(*(c++)); continue; } if (d == 'c') { (*putc)((char)va_arg(arp, int)); continue; } if (d == 'u') { // %ul r = 10; d = *str++; } if (d == 'l') { // long =32bit l = 1; if (r==0) r = -10; d = *str++; } if (d =='\0') break; //avoid crashing if format string is buggy if (d == 'u') r = 10;// %lu, %llu else if (d == 'd' || d == 'i') {if (r==0) r = -10;} //can be 16 or 32bit int else if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas else if (d == 'b') r = 2; #ifdef INCLUDE_FLOAT else if (d == 'f' || d == 'F') { f=va_arg(arp, double); if (f >= 0.0) { r = 10; mv = f; m = mv; } else { r = -10; mv = f; f = -f; m = f; // f and m are always positive } long_itoa(mv, r, w, (putc)); if (w2!=0) { putc('.'); f=f-m; w=-w2; p=1; while (w2--) p = p*10; m=f*p; long_itoa(m, 10, w, (putc)); } l=3; //do not continue with long } #endif else str--; // normal character if (r==0) continue; // if (l==0) { if (r > 0){ //unsigned long_itoa((unsigned long)va_arg(arp, int), r, w, (putc)); //needed for 16bit int, no harm to 32bit int } else //signed long_itoa((long)va_arg(arp, int), r, w, (putc)); } else if (l==1){ // long =32bit long_itoa((long)va_arg(arp, long), r, w, (putc)); //no matter if signed or unsigned } } return 0; } void long_itoa (long val, int radix, int len, void (*putc) (char)) { char c, sgn = 0, pad = ' '; char s[20]; int i = 0; if (radix < 0) { radix = -radix; if (val < 0) { val = -val; sgn = '-'; } } if (len < 0) { len = -len; pad = '0'; } if (len > 20) return; do { c = (char)((unsigned long)val % radix); //cast! if (c >= 10) c += ('A'-10); //ABCDEF else c += '0'; //0123456789 s[i++] = c; val = (unsigned long)val /radix; //cast! } while (val); if ((sgn!=0) && (pad!='0')) s[i++] = sgn; while (i < len) s[i++] = pad; if ((sgn!=0) && (pad=='0')) s[i++] = sgn; do (*putc)(s[--i]); while (i); } /****************************************************************************** * END OF FILE ******************************************************************************/