瑞萨的RA2E1系列MCU是基于M23内核的,这款芯片是不带FPU浮点运算单元的,使用串口prinf函数打印时是无法打印出浮点数的,只有Cortex-M4/M7这些内核才具备FPU单元,才能进行浮点运算。难道由于硬件不支持FPU, 常用的M0/M0+/M23/M3内核就无缘浮点运算了呢?答案是显然不是的。
我们可以移植使用开源的qfplib库来实现浮点运算,这样在一些不具备FPU的低性能MCU上也能实现接近硬件浮点运算的性能。特别是在一些电机控制领域,随便跑跑FOC算法都需要浮点运算,特别是在一些低成本的园林工具和电动牙刷工具领域,都会使用类似于51
单片机/STM8/
STM32F103等M0/M0+/M3内核的MCU上有提供了一种新的方法来实现浮点运算。
言归正传,下面来介绍一下开源的qfplib浮点库的移植和使用步骤。
首先创建一个串口打印工程。双击
图标,
点击next
点击next
点击finish
弹出如下图片
我们先关闭它,然后打开KEIL
配置好后,连接到jlink
再打开下面
配置串口9,我的配置如下
然后点击生成generate,然后关闭当前IDE打开KEIL
修改代码如下:
#include "hal_data.h"
#include
/********* ²ÎÊýºê¶¨Òå *********/
#define USART_REC_LEN 50 //¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý 50
#define First_String "Receive:" //·µ»Ø¸øPC¶ËµÄÆðʼ×Ö·û´®
#define First_String_num strlen(First_String) //Æðʼ×Ö·û´®³¤¶È
#define g_uartx_ctrl g_uart9_ctrl //Èç¹ûÊÇ´®¿Ú9ÐèÒªprintfÖØÓ³É䣬¾Íдg_uart9_ctrl
/*×÷Ó㺴®¿Ú9³õʼ»¯£¬P109--TXD,P110--RXD
*´«Èë²ÎÊý£ºÎÞ
*·µ»Ø²ÎÊý£ºÎÞ
*/
void UART9_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_UART_Open(&g_uart9_ctrl,&g_uart9_cfg);
assert(err == FSP_SUCCESS);
}
vola
tile bool uart_send_complete_flag = false; // ·¢ËÍÍê³É±êÖ¾
uint8_t USART_RX_BUF[USART_REC_LEN] = First_String; //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.Æðʼ×Ö·û´®ÎªFirst_StringµÄºê¶¨Òå
/*
=============================================================================================================
USART_RX_STA
=============================================================================================================
bit15 | bit14 | bit13--bit0
=============================================================================================================
½ÓÊÕÍê³É±ê־루0x0A,»»Ðмü£© | ½ÓÊÕµ½0x0d£¨»Ø³µ¼ü£© | ½ÓÊÕµ½µÄÓÐЧÊý¾Ý¸öÊý
=============================================================================================================
*/
uint16_t USART_RX_STA = First_String_num; //½ÓÊÕ״̬±ê¼Ç£¬¸ù¾ÝÆðʼ×Ö·û´®À´³õʼ»¯Æðʼ×Ö·ûλÖÃ
void UART_Agreement(uart_callback_args_t * p_args); //´®¿ÚͨѶÐÒé
/*ÓÃÓÚ´®¿Ú9µÄ½ÓÊպͷ¢ËÍÖжÏ
*´«Èë²ÎÊý£º
*p_args£ºÕâ¸ö²»ÐèÒªÎÒÃǹܣ¬ÏµÍ³×Ô¶¯»á½«Êý¾Ý´«Èë
*·µ»Ø²ÎÊý£ºÎÞ
*/
void uart9_callback(uart_callback_args_t * p_args)
{
switch (p_args->event)
{
//Èç¹ûÊÇ´®¿Ú½ÓÊÕÖжÏ
case UART_EVENT_RX_CHAR:
{
UART_Agreement(p_args);//´®¿ÚͨѶÐÒéÅжÏ
if(USART_RX_STA&0x8000)//Èç¹û½ÓÊÕÍê³É
{
USART_RX_BUF[USART_RX_STA&0x3FFF] = 0x0d;//½«×Ö·û´®×Ô¶¯»»ÐÐ
USART_RX_STA++; //ÒòΪÔö¼ÓÁË0x0d£¬ËùÒÔ×Ö·û´®ÊýÁ¿+1
R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t*)USART_RX_BUF, USART_RX_STA&0x3fff);//½«×Ö·û´®Êý¾ÝÊä³ö
USART_RX_STA=First_String_num; //½«USART_RX_STA³õʼ»¯
}
break;
}
//Èç¹ûÊÇ´®¿Ú·¢ËÍÖжÏ
case UART_EVENT_TX_COMPLETE:
{
uart_send_complete_flag = true;
break;
}
default:
break;
}
}
/*ÓÃÓÚ´®¿ÚͨѶÐÒéÅжÏ
*´«Èë²ÎÊý£º
*p_args£ºÕâ¸ö²»ÐèÒªÎÒÃǹܣ¬ÏµÍ³×Ô¶¯»á½«Êý¾Ý´«Èë
*·µ»Ø²ÎÊý£ºÎÞ
*/
void UART_Agreement(uart_callback_args_t * p_args)
{
if((USART_RX_STA&0x8000)==0) //bit15ûÓб»ÖÃΪ1£¬½ÓÊÕδÍê³É
{
if(USART_RX_STA&0x4000) //bit14±»ÖÃΪ1£¬±íʾ½ÓÊÕµ½ÁË'n'£¨0x0d£©
{
if((p_args->data)!=0x0a)USART_RX_STA=0; //Èç¹ûbit14±»ÖÃ1ÁË£¬µ«ÊÇbit15²¢²»ÊÇ»»ÐвÙ×÷£¬±íʾ½ÓÊÕ´íÎó,ÖØпªÊ¼
else USART_RX_STA|=0x8000; //½ÓÊÕÍê³ÉÁË
}
else //»¹Ã»ÊÕµ½'n'£¨0x0d£©
{
if((p_args->data)==0x0d)USART_RX_STA|=0x4000; //Èç¹û½ÓÊÕµ½ÁË'n'£¨0x0d£©£¬bit14±»ÖÃΪ1
else
{
USART_RX_BUF[USART_RX_STA&0x3FFF]=(uint8_t)(p_args->data);//Èç¹ûûÓнÓÊÕµ½½áÊø±êÖ¾£¬¼ÌÐø½«Êý¾ÝдÈëUSART_RX_BUF[]
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; //Èç¹û½ÓÊÕµ½µÄÊý¾Ý´óÓÚ¶¨Òå×î´ó½ÓÊÕ×Ö½ÚÊý£¬±íʾ½ÓÊÕÊý¾Ý´íÎó,ÖØпªÊ¼½ÓÊÕ
}
}
}
}
/* Öض¨Ïò printf Êä³ö */
#if defined __GNUC__ && !defined __clang__
int _write(int fd, char *pBuffer, int size); //·ÀÖ¹±àÒ뾯¸æ
int _write(int fd, char *pBuffer, int size)
{
(void)fd;
R_SCI_UART_Write(&g_uartx_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return size;
}
#else
int fputc(int ch, FILE *f)
{
(void)f;
R_SCI_UART_Write(&g_uartx_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return ch;
}
#endif
FSP_CPP_HEADER
void R_BSP_W
ARMStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
/* TODO: add your own code here */
UART9_Init();
printf("»¶ÓÀ´µ½ÈðÈøµç×ÓRA2E1ÊÔÓÃÖÐÐÄrn");
printf("ÎÒŪºÃÁË´®¿Ú´òÓ¡rn");
printf("ÏÖÔÚÀ´½øÐи¡µãÔËË㣬ÒÆÖ²qfplib¿ârn");
// float fnum = 83.12345;
// printf("fnum = %frn",fnum);
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
串口接收用了原子的接收处理
重定向printf
编译后烧录结果见串口打印如下:
接下来,移植qfplib库,复制下面文件夹到keil工程
就是上面的文件夹,里面一个头文件和一个汇编文件,假如keil工程
添加这两个头文件
下面代码是浮点库测试函数
然后编译keil工程烧录,打开串口查看结果
查看视频效果,使用该软件浮点库,能实现接近硬件FPU的性能,非常强悍
附上github连接
https://github.com/mysterywolf/Qfplib-M3
下面是我的工程代码