⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simulatecomm - 调试成功.cpp

📁 在LPC213X上实现了模拟串口功能
💻 CPP
字号:
#include <stdio.h>
#include <string.h>
#include "..\LIB\ArmOS\ArmLib.h"
#include "..\LIB\ArmOS\ArmOs.h"

#include "HdrIntfc.h"

#include "SimulateComm.h"
/*-------------------------------------------------------------------------------------------------------------
                                      模拟串口说明
占用资源:
1. RCV_CAP   , 用于接收:直接连接到某个引脚,用来接收。检测起始位时配置为下降沿触发,以后配置为跳变触发。
                         如果两次触发的间隔小于1bit时间,则设置错误标志
2. RCV_MAT   , 用于接收:检测到起始位后定时到一个字节时间(1个起始位,8数据位,1校验位,1或者2停止位)
3. SND_MAT   , 用于发送:每个bit时间发生出一个bit。

使用本模块前,必须先设置好引脚的模式:TX在 MATCH 模式,而RX 在 capture 模式
-------------------------------------------------------------------------------------------------------------*/


//-------------------------------------------------------------------------------------------------------------
//             用户定义:数据位、校验位、波特率、硬件时钟、引脚
//-------------------------------------------------------------------------------------------------------------
#define SU_BAUD_RATE         9600
#define SU_DATA_BIT_COUNT    8
#define SU_PARITY_MODE       0   //0-NONE, 1-ODD, 2-EVEN全0填0, 3-MARK总填1, 4-SPACE填0
#define SU_STOP_BIT_COUNT    1

//缓冲区定义
#ifndef SU_XMIT_SIZE
	#define SU_XMIT_SIZE 	128
#endif

#ifndef SU_RCV_SIZE
	#define SU_RCV_SIZE		128
#endif

#define SIMU_COMM_TIMER 0 

//SIMULATED UART, RECEIVE CAPTURE INDEX
#define SU_RCV_CAP 2
//SIMULATED UART, RECEIVE MATCH INDEX
#define SU_RCV_MAT 1
//SIMULATED UART, SEND MATCH INDEX
#define SU_SND_MAT 2
//SIMULATED UART, RECIEVE PIN PORT NUMBER
#define SU_RCV_PIN_X 0
//SIMULATED UART, RECIEVE PIN NUMBER
#define SU_RCV_PIN   16

//-------------------------------------------------------------------------------------------------------------
//             使用用户定义生成对时钟的访问宏
//-------------------------------------------------------------------------------------------------------------

#if SIMU_COMM_TIMER == 0
	#define ISN_TIMERX ISN_TIMER0
	#define TX_SOFT_INT_FLAG 0X10
	#define TXPR       T0PR
	#define TXTCR      T0TCR
	#define TXCCR      T0CCR
	#define TXMCR      T0MCR
	#define TXTC       T0TC
	#define TXIR       T0IR
	#define TXEMR      T0EMR
	#define TXMR      (&T0MR0)
	#define TXCR      (&T0CR0)
#elif SIMU_COMM_TIMER == 1
	#define ISN_TIMERX ISN_TIMER1
	#define TX_SOFT_INT_FLAG 0X20
	#define TXPR       T1PR
	#define TXTCR      T1TCR
	#define TXCCR      T1CCR
	#define TXMCR      T1MCR
	#define TXTC       T1TC
	#define TXIR       T1IR
	#define TXEMR      T1EMR
	#define TXMR      (&T1MR0)
	#define TXCR      (&T1CR0)
#else	
	#error "Simulate UART timer definition missing"
#endif


#if SU_PARITY_MODE == 0
	#define SU_PARITY_BIT_COUNT  0
#else
	#define SU_PARITY_BIT_COUNT  1
#endif

#define RCV_CAP_TM TXCR[SU_RCV_CAP]
#define RCV_MAT_TM TXMR[SU_RCV_MAT]
#define SND_MAT_TM TXMR[SU_SND_MAT]

//-------------------------------------------------------------------------------------------------------------
//             模拟串口有关时间的定义
//-------------------------------------------------------------------------------------------------------------

//Fpclk = 2764800
#define FREQ_T0 (Fpclk/9)
//#define PULSE_WIDTH 	Fpclk / 19200	//052us, FOR 19200 bps
#define PULSE_WIDTH 	Fpclk /(SU_BAUD_RATE) /9	//104us, FOR 9600  bps
//#define PULSE_WIDTH 	Fpclk / 833 	//833us, FOR 1200  bps

#define PULSE_WIDTH_FIRST (PULSE_WIDTH + PULSE_WIDTH / 2)

//-------------------------------------------------------------------------------------------------------------
//             模拟串口接收
//-------------------------------------------------------------------------------------------------------------

class CSimuRcv
{
	static unsigned char simu_rcv_buf[SU_RCV_SIZE];
	enum{RS_WAITING_START, RS_RECEIVING_BITS };
	static uint8 rcv_state ;

	static uint8 bit_pos  ;
	static bool bit_value ;
	static uint32 bit_flag ;
	static uint32 rcv_value;
	static uint32 last_bit_time ;
	//禁止捕获,用于收到非法脉冲时
	static void EnableCaptureFallAndRise()				 
	{
	 	TXCCR |=  (7 << (SU_RCV_CAP * 3));
	}
	static void EnableCaptureFall()				 
	{
	 	TXCCR = (TXCCR & ~(7 << (SU_RCV_CAP * 3))) | (6 << (SU_RCV_CAP * 3));
	}
	//允许捕获,用户当前非法脉冲过去后
	static void DisableCapture()
	{
	 	TXCCR &= ~(7 << (SU_RCV_CAP * 3));
		TXIR = CAP_ISR(SU_RCV_CAP);
	}
	//设置比较时间,就是当前要接收的字节结束的时间
	static void SetMatchTime(uint32 time)
	{
		RCV_MAT_TM = time;
		TXMCR = (TXMCR & ~(7 << (SU_RCV_MAT*3))) | (1 << (SU_RCV_MAT*3));
	}
	static void ClearMatchIsr()
	{
		TXMCR = (TXMCR & ~(7 << (SU_RCV_MAT*3)));
		TXIR = MATCH_ISR(SU_RCV_MAT);
	}
	static void OnCapture(uint32 captured_time, bool pin_changed)
	{
		switch(rcv_state)
		{
		case RS_WAITING_START:
			//仅仅在下降沿才会启动接收
			if(GetPinState(SU_RCV_PIN_X, SU_RCV_PIN) == 0)
			{
				EnableCaptureFallAndRise();
				rcv_state = RS_RECEIVING_BITS;
				bit_pos   = 0;
				bit_value = 0;
				bit_flag  = 1;
				rcv_value = 0;
				last_bit_time  = captured_time;
				//字节结束时间:1起始位,数据位,校验位。停止位不要包括,因为它总是1
				SetMatchTime(captured_time + (1 + SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT) * PULSE_WIDTH);
			}
			break;
		case RS_RECEIVING_BITS:
			//检查接收错误
			if(captured_time - last_bit_time < PULSE_WIDTH * 3 / 4)
			{
				//错误处理有一个目的:如果RX引脚有干扰,那么频繁的中断可能导致CPU总是忙于该中断
				//因此如果检测到错误就放弃接收,等待从定时器中恢复
				DisableCapture();
			}else
			{
				while((last_bit_time + PULSE_WIDTH / 2 < captured_time && bit_pos < SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT))
				{
					if(pin_changed && last_bit_time + PULSE_WIDTH * 3 / 2 > captured_time)
						bit_value = ! bit_value;
					if(bit_value)
						rcv_value |= bit_flag;
					bit_pos ++;
					bit_flag <<= 1;
					last_bit_time += PULSE_WIDTH;	
				}
				//如果接收了足够的bit,添加到接收队列
				if( bit_pos >= SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
				{
					qRcv.Add(rcv_value);
					rcv_state = RS_WAITING_START;	
					EnableCaptureFall();
					TXIR = CAP_ISR(SU_RCV_CAP);   //清除可能的捕获中断
					ClearMatchIsr();              //因为已经接收完成,因此定时器也清除
				}
			}
			break;
		default:
			rcv_state = RS_WAITING_START;
			break;
		}
	}
public:
	static class CQueue qRcv;
	static void Init(void)
	{	  
		rcv_state = RS_WAITING_START;
		EnableCaptureFall();
	}
	static void OnRxCapture()
	{
		OnCapture(RCV_CAP_TM, true);
	}
	static void OnByteTimerExpires()
	{
		OnCapture(RCV_MAT_TM, false); 
		rcv_state = RS_WAITING_START;
		EnableCaptureFall();
		ClearMatchIsr();              //因为已经接收完成,因此定时器也清除
	}
};



unsigned char CSimuRcv::simu_rcv_buf[SU_RCV_SIZE];
class CQueue CSimuRcv::qRcv(simu_rcv_buf,SU_RCV_SIZE) 	;

uint8 CSimuRcv::rcv_state ;
uint8 CSimuRcv::bit_pos  ;
bool CSimuRcv::bit_value ;
uint32 CSimuRcv::bit_flag ;
uint32 CSimuRcv::rcv_value;
uint32 CSimuRcv::last_bit_time ;


//-------------------------------------------------------------------------------------------------------------
//             模拟串口发送
//-------------------------------------------------------------------------------------------------------------
class CSimuSend
{
	static unsigned char buf[SU_XMIT_SIZE];
	static volatile uint8 is_sending, is_end_of_send;

	static uint8 bit_pos  ;
	static bool  bit_value ;
	static uint32 bit_flag ;
	static uint32 send_value, last_bit_time;
	static class CQueue qSend;

	static void SetTimerWithTogglePin(uint32 time)
	{
		TXEMR |= 3 << (4 + SU_SND_MAT * 2);	//比较成功时的引脚反转
		SND_MAT_TM = time;
		TXMCR |= 1 << (SU_SND_MAT * 3);	    //比较成功时触发中断
	}
	static void SetTimerWithSetPin(uint32 time)
	{
		TXEMR = (TXEMR & ~(3 << (4 + SU_SND_MAT * 2))) | (2 << (4 + SU_SND_MAT * 2));	//比较成功时的引脚置位
		SND_MAT_TM = time;
		TXMCR |= 1 << (SU_SND_MAT * 3);	    //比较成功时触发中断
	}
	
/*	static void SetTimer(uint32 time)
	{
		TXEMR &= ~(3 << (4 + SU_SND_MAT * 2)); //不控制引脚引脚
		SND_MAT_TM = time;
		TXMCR |= 1 << (SU_SND_MAT * 3);	    //比较成功时触发中断
	}*/
	
	static void ClearTimer()
	{
		TXEMR &= ~(3 << (4 + SU_SND_MAT * 2)); //不控制引脚引脚
		TXMCR &= ~(7 << (SU_SND_MAT * 3));	   //不触发中断
	}

	static void SetTxPin()
	{
		TXEMR |= 1 << SU_SND_MAT;
	}
	static void ClearTxPin()
	{
		TXEMR &= ~(1 << SU_SND_MAT);
	}

	//发送之前先把 parity 放在 send_value 的第8bit(0-7bit是数据位)
	static void SendByte()
	{
		//如果刚开始发送,则先把TX引脚拉低
		if(bit_pos == 0)
		{
			bit_value = 0;
			bit_flag = 1;
			ClearTxPin();
			last_bit_time = TXTC;
		}
		//如果发送结束,则发送停止位
		if(bit_pos >= 1+SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
		{	
			SetTimerWithSetPin(last_bit_time + SU_STOP_BIT_COUNT * PULSE_WIDTH);
			is_sending = false;
			bit_pos = 0;
		//发送数据位和校奇偶校验
		}else
		{
			bool found =false;
			while(! found && bit_pos < 1+SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
			{
				if(bit_value != ((bit_flag & send_value) != 0))
				{
					bit_value = !bit_value;
					found = true;
				}
				last_bit_time += PULSE_WIDTH;
				bit_pos ++;
				bit_flag <<= 1;
			}
			if(bit_pos >= 1+SU_DATA_BIT_COUNT + SU_PARITY_BIT_COUNT)
			{
				SetTimerWithSetPin(last_bit_time); //最终到停止位,那么就把引脚置位
			}else
			{
				SetTimerWithTogglePin(last_bit_time); //需要反转引脚
			}
		}
	}

	static void FillParityBit()
	{
		uint8 parity = SU_PARITY_MODE;
		if(parity == 0)
			return;
		uint32 bit_count, flag;
		switch(parity)
		{
		case 0:
			break;
		case 1:
		case 2:
			bit_count = 0;
			flag = 1;
			for(int i=0;i<SU_DATA_BIT_COUNT;i++, flag <<= 1)
			{
				if(send_value & flag)
					bit_count = !bit_count;
			}
			if(bit_count == (SU_PARITY_MODE == 2))
				send_value |= (1<<SU_DATA_BIT_COUNT);
			break;
		case 3: //mark
			send_value |= (1<<SU_DATA_BIT_COUNT);
			break;
		case 4: //space
			break;
		}
	}
	static void StartSend()
	{
		soft_start_send = true;
		VICSoftInt |= TX_SOFT_INT_FLAG;
	}
public:
	static bool soft_start_send;
	static bool IsEndOfSend() { return is_end_of_send;};
	static void OnSendBit()
	{
		//SetSysLed(2);	 调试点,看中断时间
		is_end_of_send = false;

		if(is_sending)
		{
			SendByte();//如果发送完毕,将清除is_sending 标志
		}else if( ! qSend.IsEmpty())	
		{
			send_value = qSend.Get();
			FillParityBit();
			SendByte();
			is_sending = true;
		}else
		{
			ClearTimer();
			is_end_of_send = true;
		}

	}
	static void PutCh(char c)
	{
		qSend.Add(c);
		if(IsEndOfSend())
		{
			StartSend();
		}
	}

	static void Init()
	{
		SetTxPin();
		bit_pos = 0;
		is_end_of_send = true;
	}

};

unsigned char CSimuSend::buf[SU_XMIT_SIZE];
volatile uint8 CSimuSend::is_sending;
volatile uint8 CSimuSend::is_end_of_send;

uint8 CSimuSend::bit_pos  ;
bool  CSimuSend::bit_value ;
bool  CSimuSend::soft_start_send ;
uint32 CSimuSend::bit_flag ;
uint32 CSimuSend::send_value, CSimuSend::last_bit_time;
class CQueue CSimuSend::qSend(buf, sizeof(buf));

//-------------------------------------------------------------------------------------------------------------
//             模拟串口中断入口 
//-------------------------------------------------------------------------------------------------------------

//返回发生的中断bit,将被写入 T0IR
//该函数将被多次调用,直到没有中断。
uint8 IsrEntry_ForSimmuComm()
{
	uint8 clear_flag = 0;
	//RXD 捕获
	if(TXIR & CAP_ISR(SU_RCV_CAP))
	{
		clear_flag |= CAP_ISR(SU_RCV_CAP);
		CSimuRcv::OnRxCapture();
	}
	//RXD 匹配
	if(TXIR & MATCH_ISR(SU_RCV_MAT))
	{
		clear_flag |= MATCH_ISR(SU_RCV_MAT);
		CSimuRcv::OnByteTimerExpires();	
	}
	//TXD 匹配
	if((TXIR & MATCH_ISR(SU_SND_MAT)) || CSimuSend::soft_start_send)
	{
		if(CSimuSend::soft_start_send)
		{
			CSimuSend::soft_start_send = false;
			VICSoftIntClear |= TX_SOFT_INT_FLAG;
		}

		CSimuSend::OnSendBit();
		clear_flag |= MATCH_ISR(SU_SND_MAT);
	}

	return clear_flag;
}

//如果使用了T0的其它中断功能,则在此判断
uint8 OSIsrHook()
{
	SetSysLed(1);
	TXIR = IsrEntry_ForSimmuComm();
	SetSysLed(0);
	return 0;
}


/*
void _________task2________()
*/
#include "..\LIB\ArmOS\OSObject.h"


class CTask2 : public CAbsTask
{
	uint32 stack[100];	 //0
	virtual void GetTaskInfo(uint32 *&stack_ptr, int &stack_size, int &task_id)
	{
		stack_ptr = stack;
		stack_size = sizeof(stack);
		task_id = TASK_ID_TEST;
	}
	virtual int Execute();
} task2;


int CTask2::Execute()
{
	SetSysLed(0);
	CSimuRcv::Init();
	CSimuSend::Init();
	while(1)
	{
		OSWDTReset();
		Sleep(100);
		//	CSimuSend::PutCh(0xff);
		while(! CSimuRcv::qRcv.IsEmpty())
		{
			char c = CSimuRcv::qRcv.Get();
		//	printf("%c",c);
			CSimuSend::PutCh(c);
		}
		while(! uart0_rcv_queue.IsEmpty())
		{
			char c = uart0_rcv_queue.Get();
		//	printf("%c",c);
			CSimuSend::PutCh(c);
		}
		//CSimuSend::SetTimerWithTogglePin(TXTC + 50);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -