前言
打印函数对一个程序员是十分重要的,当代码出问题的时候,我们可以通过打印函数实时的跟踪到代码运行到的地方和对应的数值是否符合自己的预期,最近在学习EFM32,发现没有Printf函数,我需要打印的格式数据没办法看到,琢磨了和百度了好久都没有结果,最后在一位大神手上拿到了。
串口初始化
void uartInit (void)
{
CLKINIT(); /* 时钟初始化 */
PININIT(); /* 引脚初始化 */
MISCINIT(); /* 其它项初始化 */
USART_InitAsync_TypeDef tUsartInit = {
.enable = usartEnable, /* 使能USART发送与接收 */
.refFreq = 0, /* 使用当前时钟配置来配置波特率 */
.baudrate = BAUDSET, /* 波特率配置 */
.oversampling = usartOVS16, /* 16x过采样率 */
.databits = DATABIT, /* 8位数据位 */
.parity = PARITY, /* 无校验位 */
.stopbits = STOPBIT, /* 1位停止位 */
.mvdis = false, /* 使能Majority */
.prsRxEnable = false, /* 禁能PRS作为RX输入 */
.prsRxCh = usartPrsRxCh0 /* 选择PRS通道 */
};
USART_InitAsync(UARTPERIPH, &tUsartInit); /* 调用初始化函数 */
/*
* 使能USART1的TX和RX
*/
UARTPERIPH->ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | LOCATION;
USART_IntEnable(UARTPERIPH, USART_IF_RXDATAV);
NVIC_EnableIRQ(USART1_RX_IRQn); /* 使能USART1接收中断 */
}
修改对应的参数
/*********************************************************************************************************
** 宏定义
*********************************************************************************************************/
#define UARTPERIPH USART1
#define LOCATION (2UL << 8)
/*
* 开启与UART驱动相关时钟
*/
#define CLKINIT() do { \
CMU_ClockEnable(cmuClock_HF, true); \
CMU_ClockEnable(cmuClock_GPIO, true); \
CMU_ClockEnable(cmuClock_USART1, true); \
} while(0)
/*
* UART驱动引脚配置
*/
#define PININIT() do { \
GPIO_PinModeSet(gpioPortD, 7, gpioModePushPull, 1); \
GPIO_PinModeSet(gpioPortD, 6, gpioModeInput, 0); \
} while(0)
/*
* 完成其它杂项配置
*/
#define MISCINIT() do { \
} while(0)
#define BAUDSET 115200 /* 波特率配置为115200 */
#define DATABIT usartDatabits8 /* 8位数据位 */
#define STOPBIT usartStopbits1 /* 1位停止位 */
#define PARITY usartNoParity /* 无校验位 */
修改对应参数需要注意的地方:
1、#define LOCATION (2UL << 8)
需要查芯片规格书,LOCATION所对应的寄存器修改。
2、你使用的GPIO口管脚需要对应
3、波特率需要一一对应
串口发送函数
void uartTxByte (INT8U ucData)
{
while (!(UARTPERIPH->STATUS & USART_STATUS_TXBL)); /* 检查发送缓冲区是否为空 */
UARTPERIPH->TXDATA = (unsigned int)ucData;
}
串口接收函数函数
INT8U uartRxByte (void)
{
while (!(UARTPERIPH->STATUS & USART_STATUS_RXDATAV)); /* 查询是否接收到数据 */
return (INT8U)(UARTPERIPH->RXDATA);
}
串口发送字符函数
void uartPrintString (char *pcString)
{
while (*pcString != 0) { /* 查询是否是到字符串的末尾 */
uartTxByte(*pcString++);
}
}
注意:此函数仅仅支持发送字符,不支持格式字符发送。
发送函数改造
1、我们日常使用的STM32芯片中printf函数是需要重写的,EFM32芯片中同样也是需要重写,重写的方式也是不一样,我在网上百度了好久基本没有找到半点可参考的内容,后来在一位牛人手中得到了重写的方式,今天把它发出来,和大家分享,也是一种学习记录,希望对大家也有帮助。
#ifdef _RAISONANCE_
#define PUTCHAR_PROTOTYPE int putchar (char c)
#define GETCHAR_PROTOTYPE int getchar (void)
#elif defined (_COSMIC_)
#define PUTCHAR_PROTOTYPE char putchar (char c)
#define GETCHAR_PROTOTYPE char getchar (void)
#else /* _IAR_ */
#define PUTCHAR_PROTOTYPE int putchar (int c)
#define GETCHAR_PROTOTYPE int getchar (void)
#endif /* _RAISONANCE_ */
PUTCHAR_PROTOTYPE
{
uartTxByte(c);
return c;
}
//将Printf添加到你需要打印的地方即可。
printf("Time_3s = %d\r\n",Time_3s);
将我们发送函数uartTxByte填上去就可以了。然后我们就可以在我们的主程序之中愉快的使用Printf函数了,这样我们就可以实时观测到我们需要查看的数据。
第二种串口打印实现方法
自己通过对函数的改造和重写实现功能
/* 实现itoa函数的源代码 */
char *myitoa(uint32_t num,char *str,uint8_t radix)
{
/* 索引表 */
char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
uint32_t unum; /* 中间变量 */
uint32_t i=0,j,k;
/* 确定unum的值 */
if((radix == 10)&&(num < 0))
{
unum=(uint32_t)-num;
str[i++]='-';
}
else
{
unum=(uint32_t)num; /* 其他情况 */
}
/* 逆序 */
do
{
str[i++]=index[unum%(uint8_t)radix];
unum/=radix;
}while(unum);
str[i]='\0';
/* 转换 */
if(str[0]=='-')
{
k=1; /* 十进制负数 */
}
else
{
k=0;
}
/* 将原来的“/2”改为“/2.0”,保证当num在16~255之间,radix等于16时,也能得到正确结果 */
for(j=k;j<(i-1)/2.0+k;j++)
{
num=str[j];
str[j]=str[i-j-1+k];
str[i-j-1+k]=num;
}
return str;
}
//指定的串口输出
void put_char(char ch)
{
USART_Tx(USART1,ch);
}
#include <stdarg.h>
//打印的函数
void myprintf(const char* fmt,...)
{
const char* s;
uint32_t d;
char buf[16];
va_list ap;
va_start(ap,fmt); // 将ap指向fmt(即可变参数的第一个下一个?)
while (*fmt)
{
if (*fmt != '%')
{
put_char(*fmt++); // 正常发送
continue;
}
switch (*++fmt) // next %
{
case 's':
s = va_arg(ap,const char*); // 将ap指向者转成char*型,并返回之
for (; *s; s++)
put_char(*s);
break;
case 'x':
d = va_arg(ap,uint16_t); // 将ap指向者转成int型,并返回之
myitoa(d,buf,16); // 将整型d以16进制转到buf中
for (s = buf; *s; s++)
put_char(*s);
break;
case 'd':
d = va_arg(ap,uint16_t);
myitoa(d,buf,10); // 将整型d以10进制转到buf中
for (s = buf; *s; s++)
put_char(*s);
break;
case 'u':
d = va_arg(ap,uint32_t);
myitoa(d,buf,10); // 将整型d以10进制转到buf中
for (s = buf; *s; s++)
put_char(*s);
break;
default:
put_char(*fmt);
break;
}
fmt++;
}
va_end(ap);
}
第二种实现的功能和Printf的功能一模一样,格式也按照Printf格式即可。
结束语
本次分享到此为止,欢迎大家一起来探讨更多的学习心得,希望本文章对你有兴趣。