printf.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /** \file printf.c
  2. * Simplified printf() and sprintf() implementation - prints formatted string to
  3. * USART (or whereever). Most common % specifiers are supported. It costs you about
  4. * 3k FLASH memory - without floating point support it uses only 1k ROM!
  5. * \author Freddie Chopin, Martin Thomas, Marten Petschke and many others
  6. * \date 16.2.2012
  7. */
  8. /******************************************************************************
  9. * chip: STM32F10x
  10. * compiler: arm-none-eabi-gcc 4.6.0
  11. *
  12. * global functions:
  13. * int printf_(const char *format, ...)
  14. * int sprintf_(char *buffer, const char *format, ...)
  15. *
  16. * STM32 specific functions:
  17. * init_UART1(void)
  18. * void putc_UART1 (char); // blocking put char, used by printf()
  19. *
  20. * local functions:
  21. * int putc_strg(int character, printf_file_t *stream)
  22. * int vfprintf_(printf_file_t *stream, const char *format, va_list arg)
  23. * void long_itoa (long val, int radix, int len, vfprintf_stream *stream)
  24. *
  25. ******************************************************************************/
  26. /*
  27. +=============================================================================+
  28. | includes
  29. +=============================================================================+
  30. */
  31. //#include <stdarg.h> // (...) parameter handling
  32. //#include "config.h" // select controller type, frequency plan
  33. //#include "stm32f10x.h" // only this STM headerfile is used
  34. /*
  35. +=============================================================================+
  36. | options
  37. +=============================================================================+
  38. */
  39. #define INCLUDE_FLOAT // this enables float in printf() and costs you about 2kByte ROM
  40. //#define UART1_BAUDRATE 115200
  41. /*
  42. +=============================================================================+
  43. | global declarations
  44. +=============================================================================+
  45. */
  46. //int printf_(const char *format, ...);
  47. int sprintf_(char *buffer, const char *format, ...);
  48. /*
  49. +=============================================================================+
  50. | local declarations
  51. +=============================================================================+
  52. */
  53. //void init_UART1(void); // STM32 specific stuff
  54. //void putc_UART1 (char); // blocking put char; used by printf_()
  55. //void putc_strg(char); // the put() function for sprintf()
  56. char *SPRINTF_buffer; //
  57. static int vfprintf_(void (*) (char), const char *format, va_list arg); //generic print
  58. void long_itoa (long, int, int, void (*) (char)); //heavily used by printf_()
  59. /*
  60. +=============================================================================+
  61. | sample main() file
  62. +=============================================================================+
  63. */
  64. /*
  65. int main(void){
  66. pll_start();
  67. init_UART1();
  68. printf_("\nSTM32_Start\n");
  69. int cnt;
  70. for (cnt = 0; cnt < 12; cnt++) // test
  71. printf_("test unsigned negativ: |%u| \n", (unsigned int)(-cnt));
  72. char s[30];
  73. sprintf_(s,"Hallo!\n"); printf_("%s",s);
  74. #ifdef INCLUDE_FLOAT
  75. float f=3.14f;
  76. printf_("test float %3f, negativ: %f \n", f, -f);
  77. #endif
  78. return 1;
  79. }
  80. */
  81. /*
  82. +=============================================================================+
  83. | STM32 register definition only here and in interrupt handler
  84. +=============================================================================+
  85. void init_UART1(void){
  86. RCC->APB2ENR |= ( RCC_APB2ENR_IOPAEN |RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN); //Clock
  87. AFIO->MAPR &= ~(AFIO_MAPR_USART1_REMAP); //UART1 at the original pins
  88. GPIOA->CRH = 0x0090;
  89. USART1->BRR = (APB2CLK + UART1_BAUDRATE/2)/UART1_BAUDRATE;
  90. //0x008B; Baud=FREQUENCY/(16*8,69)=115107; // BRR simplified thanks to Uwe Hermann
  91. USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); // RX, TX enable
  92. }
  93. void putc_UART1 (char c)
  94. {
  95. if (c == '\n') {
  96. while ((USART1->SR & USART_SR_TXE) == 0); //blocks until previous byte was sent
  97. USART1->DR ='\r';
  98. }
  99. while ((USART1->SR & USART_SR_TXE) == 0); //blocks until previous byte was sent
  100. USART1->DR = c;
  101. }
  102. */
  103. /*
  104. +=============================================================================+
  105. | end of controller specific stuff - no further controller dependent stuff below
  106. +=============================================================================+
  107. */
  108. /*
  109. +=============================================================================+
  110. | global functions
  111. +=============================================================================+
  112. int printf_(const char *format, ...)
  113. {
  114. va_list arg;
  115. va_start(arg, format);
  116. vfprintf_((&putc_UART1), format, arg);
  117. va_end(arg);
  118. return 0;
  119. }
  120. */
  121. int sprintf_(char *buffer, const char *format, ...)
  122. {
  123. va_list arg;
  124. SPRINTF_buffer=buffer; //Pointer auf einen String in Speicherzelle abspeichern
  125. va_start(arg, format);
  126. vfprintf_((&putc_strg), format, arg);
  127. va_end(arg);
  128. *SPRINTF_buffer ='\0'; // append end of string
  129. return 0;
  130. }
  131. /*
  132. +=============================================================================+
  133. | local functions
  134. +=============================================================================+
  135. */
  136. // putc_strg() is the putc()function for sprintf_()
  137. void putc_strg(char character)
  138. {
  139. *SPRINTF_buffer = (char)character; // just add the character to buffer
  140. SPRINTF_buffer++;
  141. }
  142. /*--------------------------------------------------------------------------------+
  143. * vfprintf_()
  144. * Prints a string to stream. Supports %s, %c, %d, %ld %ul %02d %i %x %lud and %%
  145. * - partly supported: long long, float (%ll %f, %F, %2.2f)
  146. * - not supported: double float and exponent (%e %g %p %o \t)
  147. *--------------------------------------------------------------------------------+
  148. */
  149. static int vfprintf_(void (*putc)(char), const char* str, va_list arp)
  150. {
  151. int d, r, w, s, l; //d=char, r = radix, w = width, s=zeros, l=long
  152. char *c; // for the while loop only
  153. #ifdef INCLUDE_FLOAT
  154. float f;
  155. long int m, mv, p, w2;
  156. #endif
  157. while ((d = *str++) != 0) {
  158. if (d != '%') {
  159. (*putc)(d);
  160. continue;
  161. }
  162. d = *str++;
  163. w = r = s = l = 0;
  164. if (d == '%') {
  165. (*putc)(d);
  166. d = *str++;
  167. }
  168. if (d == '0') {
  169. d = *str++; s = 1; //padd with zeros
  170. }
  171. while ((d >= '0')&&(d <= '9')) {
  172. w += w * 10 + (d - '0');
  173. d = *str++;
  174. }
  175. if (s) w = -w; //padd with zeros if negative
  176. #ifdef INCLUDE_FLOAT
  177. w2 = 2; //default decimal places=2
  178. if (d == '.'){
  179. d = *str++; w2 = 0; }
  180. while ((d >= '0')&&(d <= '9')) {
  181. w2 += w2 * 10 + (d - '0');
  182. d = *str++;
  183. }
  184. #endif
  185. if (d == 's') {
  186. c = va_arg(arp, char*);
  187. while (*c)
  188. (*putc)(*(c++));
  189. continue;
  190. }
  191. if (d == 'c') {
  192. (*putc)((char)va_arg(arp, int));
  193. continue;
  194. }
  195. if (d == 'u') { // %ul
  196. r = 10;
  197. d = *str++;
  198. }
  199. if (d == 'l') { // long =32bit
  200. l = 1;
  201. if (r==0) r = -10;
  202. d = *str++;
  203. }
  204. if (d =='\0') break; //avoid crashing if format string is buggy
  205. if (d == 'u') r = 10;// %lu, %llu
  206. else if (d == 'd' || d == 'i') {if (r==0) r = -10;} //can be 16 or 32bit int
  207. else if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas
  208. else if (d == 'b') r = 2;
  209. #ifdef INCLUDE_FLOAT
  210. else if (d == 'f' || d == 'F') {
  211. f=va_arg(arp, double);
  212. if (f >= 0.0) {
  213. r = 10;
  214. mv = f;
  215. m = mv;
  216. }
  217. else {
  218. r = -10;
  219. mv = f;
  220. f = -f;
  221. m = f; // f and m are always positive
  222. }
  223. long_itoa(mv, r, w, (putc));
  224. if (w2!=0) {
  225. putc('.');
  226. f=f-m;
  227. w=-w2; p=1;
  228. while (w2--) p = p*10;
  229. m=f*p;
  230. long_itoa(m, 10, w, (putc));
  231. }
  232. l=3; //do not continue with long
  233. }
  234. #endif
  235. else str--; // normal character
  236. if (r==0) continue; //
  237. if (l==0) {
  238. if (r > 0){ //unsigned
  239. long_itoa((unsigned long)va_arg(arp, int), r, w, (putc)); //needed for 16bit int, no harm to 32bit int
  240. }
  241. else //signed
  242. long_itoa((long)va_arg(arp, int), r, w, (putc));
  243. } else if (l==1){ // long =32bit
  244. long_itoa((long)va_arg(arp, long), r, w, (putc)); //no matter if signed or unsigned
  245. }
  246. }
  247. return 0;
  248. }
  249. void long_itoa (long val, int radix, int len, void (*putc) (char))
  250. {
  251. char c, sgn = 0, pad = ' ';
  252. char s[20];
  253. int i = 0;
  254. if (radix < 0) {
  255. radix = -radix;
  256. if (val < 0) {
  257. val = -val;
  258. sgn = '-';
  259. }
  260. }
  261. if (len < 0) {
  262. len = -len;
  263. pad = '0';
  264. }
  265. if (len > 20) return;
  266. do {
  267. c = (char)((unsigned long)val % radix); //cast!
  268. if (c >= 10) c += ('A'-10); //ABCDEF
  269. else c += '0'; //0123456789
  270. s[i++] = c;
  271. val = (unsigned long)val /radix; //cast!
  272. } while (val);
  273. if ((sgn!=0) && (pad!='0')) s[i++] = sgn;
  274. while (i < len)
  275. s[i++] = pad;
  276. if ((sgn!=0) && (pad=='0')) s[i++] = sgn;
  277. do
  278. (*putc)(s[--i]);
  279. while (i);
  280. }
  281. /******************************************************************************
  282. * END OF FILE
  283. ******************************************************************************/