【瑞萨FPB_RA6E2】测评——UART使用printf
[复制链接]
UART使用printf函数
串口作为常用的通讯外设,常用于MCU与上位机通讯调试以及控制外部模组使用。RA6E2提供了两个SCI接口用于实现UART通讯。
通过查看原理图可知,P109/P110(UART9)通过调试器的CDC端口连接。
UART驱动函数
在FSP使用手册中给出了SCI的UART模式的驱动函数。
Printf函数重定向至UART
首先,在FSP Configurator中点击Stack->New Stack->Connectivity->UART(r_sci_uart),添加一个串口模块。
串口模块的参数如下:
保存配置文件并生成相应的代码。
要使用printf函数需要设置堆栈的大小,这是因为printf函数在运行时需要使用栈空间来存储临时变量和函数调用信息。如果堆栈大小不足,可能会导致程序崩溃或不可预期的行为。 printf函数使用了可变参数列表,它会在调用时使用栈来存储参数,在函数调用结束时再清除参数,这需要足够的栈空间。另外printf也会使用一些临时变量,如果栈空间不足,会导致程序崩溃。 因此,为了避免这类问题,应该根据程序的需求来合理设置堆栈大小。在FSP Configurator中的BSP->RA Common Heap size中修改堆的大小。
在e2studio中使用printf打印时,如果在链接器脚本文件中使用了--specs=rdimon.specs参数,则编译器会使用rdimon.specs文件中的系统调用函数来实现printf函数。 在这种情况下,printf函数的输出会被重定向到一个固定的地址(通常是RAM中的一段地址),而不是直接输出到控制台或串口。这样就需要在程序中实现一个驱动程序来读取这些输出并将其输出到控制台或串口。 如果希望printf函数的输出直接输出到控制台或串口,那么需要删除--specs=rdimon.specs参数。这样编译器就会使用标准的printf函数实现,输出就会直接输出到控制台或串口。 菜单栏中的Project->Properties的C++ Build->Setting->Tool Settings->GNU ARM Cross C Linker->Miscellaneous去掉Other linker flags中的 “--specs=rdimon.specs”
在源码中引入头文件<stdio.h>,重新定义__io_putchar函数和_write函数,具体代码如下。
#include <stdio.h>
#ifdef __GNUC__ //串口重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
if(FSP_SUCCESS != err) __BKPT();
while(uart_send_complete_flag == false){}
uart_send_complete_flag = false;
return ch;
}
int _write(int fd,char *pBuffer,int size)
{
for(int i=0;i<size;i++)
{
__io_putchar(*pBuffer++);
}
return size;
}
串口发送数据采用中断的方式,具体的代码如下:
volatile bool uart_send_complete_flag = false;
void user_uart9_callback (uart_callback_args_t * p_args)
{
if(p_args->event == UART_EVENT_TX_COMPLETE)
{
uart_send_complete_flag = true;
}
}
结合之前的PWM波输出工程,在主循环中调用printf发送数据。
printf("The PWM duty count is %d.\r\n",duty_count);
实物接线如图所示,由于Jlink虚拟串口无法通讯,这里使用P109和P110引脚通过串口助手与上位机通讯。
效果如图所示。
总结
在使用Jlink的虚拟串口发送数据时,上位机无法得到数据,不确定是什么原因,不知道哪位大佬知道怎么回事。
|