瑞萨RL78--软件模拟串口

软件模拟UART收发(以瑞萨RL78为示例演示)



前言

最近学习使用瑞萨芯片,遇到了一个问题,使用的串口不够,所以才在网上找资料,使用两个IO口实现模拟串口的收发功能。

我选用的是:
P42—>RX 配置为输入
P43—>TX 配置为输出,默认情况位高电平
配置如下图所示:
在这里插入图片描述


一、串口的定义,波形

1.1 串口的定义

串口的基础定义我在此不做过多赘述,如果大家不懂的话我建议大家去看一文读懂串口,这个博主讲的很详细具体。

1.2 串口的波形

对于正逻辑的TTL电平,线路总是高电平(引用串口波形分析)。我们知道串口报文包含起始位、数据位、奇偶校验位、停止位:
起始位:低电平
数据位:低位优先,高电平代表1,低电平代表0
奇偶校验位:奇偶检验等N、O、E、M、S 五种串口检验位类型
停止位:高电平
下图是无校验位的串口波形图。
无校验位的串口波形图

1.3 波特率及一个bit延时时间

我采用的是9600波特率传输,表示1秒内传输9600个bit位,所以每一个bit位的延时时间为1/9600 = 104(us)

二、串口发送

IO口需要功能:能够正常拉高拉低电平就可以,不要使用开漏输出。

2.1 无校验位

#define BuadRate_9600 104		//104us
/***************************************************************
  *  @brief     发送一个字节
  *  @param     要发送的字节
  *  @return    void
 **************************************************************/
void TX_Data(uint8_t data)
{
	uint8_t i = 0;
	TX_L;
	delay_us(BuadRate_9600);	//延时一个bit位时间
	for(i = 0;i < 8;i++)
	{
		if(data & 0x01)
			TX_H;
		else
			TX_L;
		delay_us(BuadRate_9600);
		data = data>>1;
	}
	TX_H;						//停止位1个比特
	delay_us(BuadRate_9600); 
}
/***************************************************************
  *  @brief     计算字符串长度
  *  @param     传入字符串首地址指针  
  *  @return    字符串长度      
 **************************************************************/
uint16_t countCharacters(uint8_t *str) 
{
    uint16_t count = 0;
    while (*str != '\0') 
	{
        count++;
        str++; 					//指针后移
    }
    return count;
}
/***************************************************************
  *  @brief     串口发送函数
  *  @param     要发送的字符串首地址  
  *  @return    void      
 **************************************************************/
void USART_Send(uint8_t *buf)
{
	uint16_t len = countCharacters(buf);
	uint8_t i = 0;
	for(i = 0;i < len;i++)
		TX_Data(buf[i]);
}

2.2 带奇校验位

/***************************************************************
  *  @brief     带奇校验的字节发送
  *  @param     要发送的数据
  *  @return    void
 **************************************************************/
void TX_Data_Odd(uint8_t data)	
{
	uint8_t i = 0,flag_O = 0;
	TX_L;
	delay_us(BuadRate_9600);	//起始位
	for(i = 0;i < 8;i++)
	{
		if(data & 0x01)
		{
			TX_H;
			flag_O++;
		}
		else
			TX_L;
		delay_us(BuadRate_9600);
		data = data>>1;
	}
	if(flag_O%2 == 0)			//偶数个1  高电平校验位
		TX_H;
	else
		TX_L;
	delay_us(BuadRate_9600);
	TX_H;						//结束位1
	delay_us(BuadRate_9600); 
}
/***************************************************************
  *  @brief     串口发送函数带奇校验
  *  @param     要发送的字符串
  *  @return    void
 **************************************************************/
void USART_Send_Odd(uint8_t *buf)
{
	uint16_t len = countCharacters(buf);
	uint8_t i = 0;
	for(i = 0;i < len;i++)
		TX_Data_Odd(buf[i]);
}

其他的校验方式不做演示。

三、 串口接收

IO口需要带定时器功能,把定时器配置为104us进入中断来检测电平高低。使用间隔定时器(任意哪个通道的间隔定时器都可以),配置如下图所示:
在这里插入图片描述

3.1 头文件

#ifndef __UART_H__
#define __UART_H__

#include "r_cg_macrodriver.h"
#include "iodefine.h"

typedef enum
{
	Uart_Start = 0,        //起始状态
	Uart_transfer,         //传输中
	Uart_Stop,	            //ֹ停止状态
}UartState;

#define BuadRate_9600	104					// 1/9600 = 104us
#define UartLength		100            		//最大接收字节数
extern uint8_t UartCnt;                    	//模拟串口接收的个数
extern uint8_t UartBuff[UartLength];      	//模拟串口缓冲区
#define TX P4_bit.no3						
#define TX_H TX=1						
#define TX_L TX=0
#define RX P4_bit.no2

void TX_Data(uint8_t data);
void USART_Send(uint8_t *buf);
void TX_Data_Odd(uint8_t data);
void USART_Send_Odd(uint8_t *buf);
uint16_t countCharacters(uint8_t *str);
uint8_t USART_Recive(uint8_t *buf);

#endif

3.2 无校验位+1停止位的接收

uint8_t UartCnt = 0;                //模拟串口缓冲区位置
uint8_t UartBuff[UartLength];      //模拟串口缓冲区

/***************************************************************
  *  @brief     定时器通道4的中断函数内接收串口数据
  *  @param     void
  *  @return    void
 **************************************************************/
static void __near r_tau0_channel4_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	static uint8_t value = 0,bit_cnt;
	static UartState state = Uart_Start;
	if(RX == 0 && state == Uart_Start)			//检测到起始位
	{
		state = Uart_transfer;					//变成传输状态
		bit_cnt = 0;							//bit位数清0
	}
	else if(state == Uart_transfer)				//传输状态中
	{
		bit_cnt++;
		if(RX)
		{
			value |= (1<<(bit_cnt-1));
		}
		else
		{
			value &= ~(1<<(bit_cnt-1));
		}

		if(bit_cnt >= 8)						//bit位数大于8,来到了停止位
			state = Uart_Stop;
	}
	else if(RX && state == Uart_Stop)			//判断停止位情况
	{
		bit_cnt = 0;
		if(UartCnt < UartLength)
		{
			UartBuff[UartCnt++] = value;
		}
		else 									//串口接收个数超过最大个数,覆盖之前的内容
			UartCnt = 0;	
		state = Uart_Start;
	}
    /* End user code. Do not edit comment generated here */
}

/***************************************************************
  *  @brief     串口接收函数
  *  @param     要存入的内存地址
  *  @return    返回存入了多少个字节数据
 **************************************************************/
 uint8_t USART_Recive(uint8_t *buf)
{
	uint8_t len = 0;
	if(UartCnt > 0)
	{
		len = UartCnt;
		memcpy( buf, UartBuff, len);
		UartCnt = 0;					//位置清0
	}
	return len;
}

3.3 main函数

/* Start user code for global. Do not edit comment generated here */
uint8_t buff[100];
/* End user code. Do not edit comment generated here */
void main(void)
{
    R_MAIN_UserInit();
    /* Start user code. Do not edit comment generated here */
	R_TAU0_Channel4_Start();			//启动定时器4通道,每104us进入中断监视RX
    while (1U)
    {		
		if(USART_Recive( buff))			//接收串口信息存到buff
		{
			USART_Send(buff);			//发送接收到的信息
		}
    }
    /* End user code. Do not edit comment generated here */
}

四、现象演示

在这里插入图片描述

总结

本篇文章思路适用于各种芯片IO口的软件模拟串口收发,我是以瑞萨芯片为模版写的。此外大家需要自己解决延时函数,如有需要我以后会分享。

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值