嵌入式系统开发中,常常使用串口将重要的数据或者字符信息打印到PC,为系统的调试带来了很大的便利。本文简单介绍一下printf在stm32上的实现,当然也不仅限于stm32,只要把串口发送函数稍加改动就可以移植其他任何微控制器环境上。
提到printf,首先简单介绍一下可变参数的实现va函数:
va_list arg_ptr;
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针。然后使用va_start使arg_ptr指针指向prev_param的下一位,然后使用va_args取出从arg_ptr开始的type类型长度的数据,并返回这个数据,最后使用va_end结束可变参数的获取。
代码:
#include <stdarg.h>
#include "Stm32f10x_conf.h"
#include "com.h"
int itoa(int num, char *str, int radix)
{
char string[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char* ptr = str;
int temp;
int i;
int j;
if (num==0)
{
*ptr++ = 0x30;
*ptr = 0;
return 1;
}
if(num < 0)
{
*ptr++ = '-';
num *= -1;
}
while (num)
{
*ptr++ = string[num % radix];
num /= radix;
if (num < radix)
{
*ptr++ = string[num];
*ptr = '\0';
break;
}
}
j = ptr - str - 1;
for (i = 0; i < (ptr - str) / 2; i++)
{
temp = str[i];
str[i] = str[j];
str[j--] = temp;
}
return (int)(ptr - str);
}
void Uart_Config()
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure); //PA9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1 RX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure); //PA10
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
return;
}
void ComPrint(u8 *Data,...)
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap, Data);
while(*Data!=0)
{
if(*Data == '\n')
{
USART_SendData(USART1, 0x0d);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
USART_SendData(USART1, 0x0a);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
Data++;
}
else if(*Data=='%')
{
switch (*++Data){
case 's':
s = va_arg(ap, const char *);
for ( ; *s; s++) {
USART_SendData(USART1,*s);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
}
Data++;
break;
case 'd':
d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++) {
USART_SendData(USART1,*s);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
}
Data++;
break;
case 'x':
d = va_arg(ap, int);
itoa(d, buf, 16);
for (s = buf; *s; s++) {
USART_SendData(USART1,*s);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
}
Data++;
break;
default:
Data++;
break;
}
}
else
{
USART_SendData(USART1, *Data++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
}
}
}
/***************************************************************
*
*
*
***************************************************************/
void assert_debug(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,\ */
ComPrint("Wrong parameters value: file %s on line %d\r\n", file, line);
/* Infinite loop */
while (1)
{
}
}