软件模拟串口通信

点点圈 提交于 2019-12-12 03:44:48

软件模拟串口通信


上个月入职了一家做消费类电子的公司,做了两个小项目,用的是NY8芯片,资源有限,没有串口和IIC,其中一个项目是做闹钟显示板,只用将主机发过来来命令处理就行,做的是通版,使用串口和IIC两种方式数据。
网上搜寻一边,参考借鉴了整理出一份可行的方案,整理出来供以后工作和有需要的朋友使用。
下面是h文件

#ifndef SoftWareSeries
#define SoftWareSeries

#include "user.h"
#include "display.h"

#define BaudRate 10 //bps9600 10  4800 20 

#define RXDBit Port_B7
#define TXDBit Port_C0

#define IO_RXD PORTBbits.PB7
#define IO_TXD PORTCbits.PC0 

enum {
	COM_START_BIT,
	COM_D0_BIT,
	COM_D1_BIT,
	COM_D2_BIT,
	COM_D3_BIT,
	COM_D4_BIT,
	COM_D5_BIT,
	COM_D6_BIT,
	COM_D7_BIT,
	COM_STOP_BIT,
};

extern U8 RXD_BIT;
extern U8 RXD_DATA;

void SoftWareUartInit(void);
void TXD_OneByte(U8 Data);
void UART_Send(U8 *Buffer,U8 Length);

#endif
U8 RXD_BIT = COM_STOP_BIT;
U8 RXD_DATA = 0;

发送部分

关闭中断使用delay_us模拟uart时序进行发送

void SoftWareUartInit(void)
{
	IOSTB |= RXDBit;   	//置1 输入 
	IOSTC &= ~TXDBit;   //置0 输出
	BPHCON &= ~RXDBit; //置0使能上拉
	IO_TXD = 1; //拉高发送位
}
void TXD_OneByte(U8 Data)
{
	U8 i;	
	IO_TXD = 0;  //拉低发送起位     		
	delay_10us(BaudRate); //100us bps9600
	for(i = 0;i<8;i++)
	{
		if(Data&0x01) IO_TXD = 1;   //发送1bit数据,低位先发
		else 		  IO_TXD = 0; 			
		delay_10us(BaudRate);
		Data = Data>>1;				//右移发送下一bit
	}
	IO_TXD = 1;					   // 拉高发送停止位
	delay_10us(BaudRate);		
}
/*
function  IO模拟串口发送数据包
parameter Buffer 数据包的首地址
		  Length 数据包的长度	
*/
void UART_Send(U8 *Buffer,U8 Length) 
{
	U8 t;
	DISI();//关闭中断,数组处理  
	for(t = 0;t<Length;t++)
	{
		TXD_OneByte(Buffer[t]);
	}
	ENI();//打开中断
}

接收部分

接收采用的是外部中断+定时器中断的方式,UART数据帧起始bit是高电平拉低,触发外部中断之后开启定时器,定时器按bps中断读取IO口电平
外部中断开始一帧数据接收,接收位置赋值起始位,中间delay是为了定时器中断触发时检测的是中间电平而不是边缘电平。

	if(INTFbits.PABIF){	     ///PAB转换中断  
		INTFbits.PABIF = 0;
		if(0==IO_RXD){ //检测引脚高低电平,如果是低电平,则说明检测到下升沿
			if(COM_STOP_BIT == RXD_BIT){	
				flag.RXDStart = 1;
				Count_2ms = 0;  //RXD接收开始 计时清0	
				RXD_BIT = COM_START_BIT;	
				delay_10us(3);			//延时30us时间,每次中断采样到中间的电平,而不是边缘
				TIMER3_CMD(ENABLE);
			}
		}	
	}

定时器中断模拟uart接收时序,定时时长104us(9600bps),项目接收第一个字节的数据是数据长度

	if(INTE2bits.T3IF){
		INTE2bits.T3IF = 0; 
		RXD_BIT++;
		if(COM_STOP_BIT == RXD_BIT){
			TIMER3_CMD(DISABLE); //一byte数据接收完成,关闭定时器
			ReciveData[ProcessTimes]=RXD_DATA;	
			
			if(0==ProcessTimes) DataLength=ReciveData[ProcessTimes]; //数据包长度赋值
			else if(DataLength==ProcessTimes){
				flag.RXDStart = 0; //接收结束 接收标志位置0
				flag.UartRecived = 1; //接收完成标志位,实际多接收了一个byte校验数据
				Count_2ms = 0; //传输完一次数据包 计时清0
			}  
			ProcessTimes++;
			return;
		}
		if(1==IO_RXD) RXD_DATA |= (1 << (RXD_BIT - 1));  //接收一个bit
		else RXD_DATA &= ~(1 << (RXD_BIT - 1));
	}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!