【前言】
在当今科技飞速发展的时代,电子设备之间的通信变得至关重要。无论是智能手机、电脑、还是各种嵌入式系统,它们都需要一种可靠且高效的方式来进行数据交换。而在众多通信技术中,UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)以其独特的优势占据着重要的一席之地。 UART 作为一种古老而又经典的串行通信协议,历经多年的发展与演进,至今仍然广泛应用于各种领域。它的出现,为不同设备之间的数据传输提供了一种简单而有效的解决方案。从早期的计算机外设连接,到如今的物联网设备、工业控制系统等,UART 都发挥着不可或缺的作用。
【软件环境】
e2Studio
【FSP配置】
RA6E2有0-9号UART可供配置使用。从他的用户手册中,Arduino Interfaces接口图上,我选择了P410、P411做为UART0的输出接口。
1、生成一个基础工程,新建一个Stack-》UART
2、进入属性,默认为P411、P410为RX、TX接口,FSP默认生成了115200的波特率配置,我们只需要开启中断,来实现中断接收,同时配置中断回调函数为user_uart0_callback。中断优先级别可根据自己需要修改。
配置如下图所示:
3、为了配合实现接收,我们再配置一个定时器,实现1ms中断,添加一个普通定时器,配置溢出计数为100,000,000即1ms中断。同时实现中断回调函数为timer0_callback。
【代码实现】
1、生成工程后打开hal_entry.c实现用户代码,最先我们要对定时器中断进行实现。
/* Callback function */ void timer0_callback(timer_callback_args_t *p_args) { /* TODO: add your own code here */ if (TIMER_EVENT_CYCLE_END == p_args->event) { if(Rx_flag==1) { printf_usart(); Rx_flag=0; } } }
代码的功能是如果产生空闲中断,则进行串口输出,重置接收标志。
2、定义串口接收数组与标志:
void printf_usart(void); fsp_err_t err = FSP_SUCCESS; volatile bool uart_send_complete_flag = false; uint8_t RxBuff[1]; //进入中断接收数据的数组 uint8_t DataBuff[5000]; //保存接收到的数据的数组 int RxLine=0; //接收到的数据长度 int Rx_flag=0; //接受到数据标志 int Rx_flag_finish=0; //接受完成或者时间溢出
3、实现UART中断接收函数
void user_uart0_callback (uart_callback_args_t * p_args) { if(p_args->event == UART_EVENT_TX_COMPLETE) { uart_send_complete_flag = true; } if(p_args->event == UART_EVENT_RX_CHAR) { RxBuff[0] = (uint8_t )p_args->data; RxLine++; //每接收到一个数据,进入回调数据长度加1 DataBuff[RxLine-1]=RxBuff[0]; //把每次接收到的数据保存到缓存数组 Rx_flag=1; if(RxBuff[0]==0xff) //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff { Rx_flag_finish=1; } RxBuff[0]=0; err = R_GPT_Reset(&g_timer0_ctrl); assert(FSP_SUCCESS == err); } }
4、为了打印方便,实现串口重定向:
#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_uart0_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; } void printf_usart(void) { printf("length=%d\r\n",RxLine); for(int i=0;i<RxLine;i++) printf("data:[%d] = 0x%x\r\n",i,DataBuff[i]); memset(DataBuff,0,sizeof(DataBuff)); //清空缓存数组 //memset()作用:可以方便的清空一个结构类型的变量或数组。 //例句:memset(aTxbuffer,0,sizeof(aTxbuffer)) 用memset清空aTxbuffer。 RxLine=0; //清空接收长度 Rx_flag_finish=0; Rx_flag = 0; }
5、在主函数中添加启动串口与定时器的函数:
/* Open the transfer instance with initial configuration. */ err = R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg); assert(FSP_SUCCESS == err); /* Initializes the module. */ //err = R_GPT_Open(&g_timer0_ctrl, &g_timer0_cfg); err = R_GPT_Open(&g_timer0_ctrl, &g_timer0_cfg); /* Handle any errors. This function should be defined by the user. */ assert(FSP_SUCCESS == err); /* Start the timer. */ (void) R_GPT_Start(&g_timer0_ctrl); while(1) { R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS); // NOLINT100->160 if(Rx_flag_finish==1) { printf_usart(); } }
编译下载后就可以看到如期的结果了。