printf.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. int main(void){
  65. pll_start();
  66. init_UART1();
  67. printf_("\nSTM32_Start\n");
  68. int cnt;
  69. for (cnt = 0; cnt < 12; cnt++) // test
  70. printf_("test unsigned negativ: |%u| \n", (unsigned int)(-cnt));
  71. char s[30];
  72. sprintf_(s,"Hallo!\n"); printf_("%s",s);
  73. #ifdef INCLUDE_FLOAT
  74. float f=3.14f;
  75. printf_("test float %3f, negativ: %f \n", f, -f);
  76. #endif
  77. return 1;
  78. }
  79. /*
  80. +=============================================================================+
  81. | STM32 register definition only here and in interrupt handler
  82. +=============================================================================+
  83. */
  84. void init_UART1(void){
  85. RCC->APB2ENR |= ( RCC_APB2ENR_IOPAEN |RCC_APB2ENR_AFIOEN | RCC_APB2ENR_USART1EN); //Clock
  86. AFIO->MAPR &= ~(AFIO_MAPR_USART1_REMAP); //UART1 at the original pins
  87. GPIOA->CRH = 0x0090;
  88. USART1->BRR = (APB2CLK + UART1_BAUDRATE/2)/UART1_BAUDRATE;
  89. //0x008B; Baud=FREQUENCY/(16*8,69)=115107; // BRR simplified thanks to Uwe Hermann
  90. USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); // RX, TX enable
  91. }
  92. void putc_UART1 (char c)
  93. {
  94. if (c == '\n') {
  95. while ((USART1->SR & USART_SR_TXE) == 0); //blocks until previous byte was sent
  96. USART1->DR ='\r';
  97. }
  98. while ((USART1->SR & USART_SR_TXE) == 0); //blocks until previous byte was sent
  99. USART1->DR = c;
  100. }
  101. /*
  102. +=============================================================================+
  103. | end of controller specific stuff - no further controller dependent stuff below
  104. +=============================================================================+
  105. */
  106. /*
  107. +=============================================================================+
  108. | global functions
  109. +=============================================================================+
  110. */
  111. int printf_(const char *format, ...)
  112. {
  113. va_list arg;
  114. va_start(arg, format);
  115. vfprintf_((&putc_UART1), format, arg);
  116. va_end(arg);
  117. return 0;
  118. }
  119. int sprintf_(char *buffer, const char *format, ...)
  120. {
  121. va_list arg;
  122. SPRINTF_buffer=buffer; //Pointer auf einen String in Speicherzelle abspeichern
  123. va_start(arg, format);
  124. vfprintf_((&putc_strg), format, arg);
  125. va_end(arg);
  126. *SPRINTF_buffer ='\0'; // append end of string
  127. return 0;
  128. }
  129. /*
  130. +=============================================================================+
  131. | local functions
  132. +=============================================================================+
  133. */
  134. // putc_strg() is the putc()function for sprintf_()
  135. void putc_strg(char character)
  136. {
  137. *SPRINTF_buffer = (char)character; // just add the character to buffer
  138. SPRINTF_buffer++;
  139. }
  140. /*--------------------------------------------------------------------------------+
  141. * vfprintf_()
  142. * Prints a string to stream. Supports %s, %c, %d, %ld %ul %02d %i %x %lud and %%
  143. * - partly supported: long long, float (%ll %f, %F, %2.2f)
  144. * - not supported: double float and exponent (%e %g %p %o \t)
  145. *--------------------------------------------------------------------------------+
  146. */
  147. static int vfprintf_(void (*putc)(char), const char* str, va_list arp)
  148. {
  149. int d, r, w, s, l; //d=char, r = radix, w = width, s=zeros, l=long
  150. char *c; // for the while loop only
  151. #ifdef INCLUDE_FLOAT
  152. float f;
  153. long int m, mv, p, w2;
  154. #endif
  155. while ((d = *str++) != 0) {
  156. if (d != '%') {
  157. (*putc)(d);
  158. continue;
  159. }
  160. d = *str++;
  161. w = r = s = l = 0;
  162. if (d == '%') {
  163. (*putc)(d);
  164. d = *str++;
  165. }
  166. if (d == '0') {
  167. d = *str++; s = 1; //padd with zeros
  168. }
  169. while ((d >= '0')&&(d <= '9')) {
  170. w += w * 10 + (d - '0');
  171. d = *str++;
  172. }
  173. if (s) w = -w; //padd with zeros if negative
  174. #ifdef INCLUDE_FLOAT
  175. w2 = 2; //default decimal places=2
  176. if (d == '.'){
  177. d = *str++; w2 = 0; }
  178. while ((d >= '0')&&(d <= '9')) {
  179. w2 += w2 * 10 + (d - '0');
  180. d = *str++;
  181. }
  182. #endif
  183. if (d == 's') {
  184. c = va_arg(arp, char*);
  185. while (*c)
  186. (*putc)(*(c++));
  187. continue;
  188. }
  189. if (d == 'c') {
  190. (*putc)((char)va_arg(arp, int));
  191. continue;
  192. }
  193. if (d == 'u') { // %ul
  194. r = 10;
  195. d = *str++;
  196. }
  197. if (d == 'l') { // long =32bit
  198. l = 1;
  199. if (r==0) r = -10;
  200. d = *str++;
  201. }
  202. if (d =='\0') break; //avoid crashing if format string is buggy
  203. if (d == 'u') r = 10;// %lu, %llu
  204. else if (d == 'd' || d == 'i') {if (r==0) r = -10;} //can be 16 or 32bit int
  205. else if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas
  206. else if (d == 'b') r = 2;
  207. #ifdef INCLUDE_FLOAT
  208. else if (d == 'f' || d == 'F') {
  209. f=va_arg(arp, double);
  210. if (f >= 0.0) {
  211. r = 10;
  212. mv = f;
  213. m = mv;
  214. }
  215. else {
  216. r = -10;
  217. mv = f;
  218. f = -f;
  219. m = f; // f and m are always positive
  220. }
  221. long_itoa(mv, r, w, (putc));
  222. if (w2!=0) {
  223. putc('.');
  224. f=f-m;
  225. w=-w2; p=1;
  226. while (w2--) p = p*10;
  227. m=f*p;
  228. long_itoa(m, 10, w, (putc));
  229. }
  230. l=3; //do not continue with long
  231. }
  232. #endif
  233. else str--; // normal character
  234. if (r==0) continue; //
  235. if (l==0) {
  236. if (r > 0){ //unsigned
  237. long_itoa((unsigned long)va_arg(arp, int), r, w, (putc)); //needed for 16bit int, no harm to 32bit int
  238. }
  239. else //signed
  240. long_itoa((long)va_arg(arp, int), r, w, (putc));
  241. } else if (l==1){ // long =32bit
  242. long_itoa((long)va_arg(arp, long), r, w, (putc)); //no matter if signed or unsigned
  243. }
  244. }
  245. return 0;
  246. }
  247. void long_itoa (long val, int radix, int len, void (*putc) (char))
  248. {
  249. char c, sgn = 0, pad = ' ';
  250. char s[20];
  251. int i = 0;
  252. if (radix < 0) {
  253. radix = -radix;
  254. if (val < 0) {
  255. val = -val;
  256. sgn = '-';
  257. }
  258. }
  259. if (len < 0) {
  260. len = -len;
  261. pad = '0';
  262. }
  263. if (len > 20) return;
  264. do {
  265. c = (char)((unsigned long)val % radix); //cast!
  266. if (c >= 10) c += ('A'-10); //ABCDEF
  267. else c += '0'; //0123456789
  268. s[i++] = c;
  269. val = (unsigned long)val /radix; //cast!
  270. } while (val);
  271. if ((sgn!=0) && (pad!='0')) s[i++] = sgn;
  272. while (i < len)
  273. s[i++] = pad;
  274. if ((sgn!=0) && (pad=='0')) s[i++] = sgn;
  275. do
  276. (*putc)(s[--i]);
  277. while (i);
  278. }
  279. /******************************************************************************
  280. * END OF FILE
  281. ******************************************************************************/