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

📄 comm.c

📁 RS485通讯程序,用于PC与单片机通讯,开发上下位机通讯程序
💻 C
字号:

#include <common.h>
#include <head.h>

BYTE ToHexchar( BYTE a )
{
	a &= 0x0f;
	if ( a < 10 )
		return a + '0';
	
	return a - 10 + 'A';
}

BYTE HexCharToInt( BYTE c )
{
	if ( ((c) >= '0') && ((c) <= '9') )
		return (c) - '0';

	if ( ((c) >= 'A') && ((c) <= 'F') )
		return (c) - 'A' + 10;

	if ( ((c) >= 'a') && ((c) <= 'f') )
		return (c) - 'a' + 10;

	return 0;
}

BYTE TwoHexCharToInt( BYTE c1, BYTE c2 )
{
	return (HexCharToInt( c1 ) << 4) | HexCharToInt( c2 );
}

BYTE CalCheckCode( u_char idata *buf, BYTE len )
{
	BYTE	i, ret;
	
	ret = 0;
	for( i = 0; i < len; i++ )
		ret += buf[i];
	
	return ret;
}

void EnableSerialComm( void )
{
	u_char	tmp;

	// 串行通讯初始化
	SCON = 0x40;  	// 模式1, 允许接收
	T2CON = 0x30;	// RXD TXD 使用T2
	TR2 = 0;

	// 波特率公式:
	// baud = f/2/16/(65536-(RCAP2H,RCAP2L))
	// f = 40M
	// 1200: 0xfbee
	// 2400: 0xfdf7
	// 4800: 0xfefb
	// 9600: 0xff7d

#if (SCH_PCB_VERSION == 1)
	tmp = ((BYTE)BAUD_RATE_H*2) + (BYTE)BAUD_RATE_L;
#endif
#if (SCH_PCB_VERSION == 2)
	tmp = CommBaudRateConst[P1>>6];
#endif

	RCAP2H = CommBaudRateConst[tmp] >> 8;
	RCAP2L = CommBaudRateConst[tmp];

	TH2 = RCAP2H;
	TL2 = RCAP2L;		

	TR2 = 1;

	RE	= RECV;

	REN = 1;		// 启动接收
	ES = 1;			// 允许中断

	EA = 1;
}

void FillHalfByteToCommBuf( BYTE cc )
{
	CommBuf.MsgData[CommBuf.MsgCnt++] = ToHexchar( cc );
}

void FillByteToCommBuf( BYTE cc )
{
	CommBuf.MsgData[CommBuf.MsgCnt++] = ToHexchar( cc >> 4 );
	CommBuf.MsgData[CommBuf.MsgCnt++] = ToHexchar( cc );
}

void CommandProcessExtra( void )
{
	FillByteToCommBuf( CalCheckCode( CommBuf.MsgData, CommBuf.MsgCnt ) );
	CommBuf.MsgData[CommBuf.MsgCnt++] = END_CHAR;
			
	RE = SEND;
	BufUseFlag = 1;
	CommBuf.SendIdx = 0;
	TxdStartFlag = 1;	
	RecvOkFlag = 0;

	TI = 1;
}

void ReadCommand( void )
{
	BYTE 	idx, tmp;
	BYTE	idata	*ptr;
	DWORD	dtmp;

	CommBuf.MsgData[0] = NO_ACK_CHAR;
	CommBuf.MsgCnt = CMD_HEAD_LEN;
	
	idx = CommBuf.MsgData[2] - '1';
	switch ( CommBuf.MsgData[4] )
	{
		case READ_MOTOR_STATUS:	// 读电机状态
			if ( idx >= MAX_MOTOR_NUM )
				break;

			// 正确回答
			CommBuf.MsgData[0] = ACK_CHAR;	

			// 填充电机方向
			FillHalfByteToCommBuf( MotorStatus[idx].Dir & DIR_FLAG_MASK );

			// 填充电机状态
			tmp = MotorStatus[idx].Status & ZERO_RECORD_MASK ? 2 : 0;
			tmp |= MotorStatus[idx].TotalPluseCnt ? 0 : 1;
			FillHalfByteToCommBuf( tmp );

			// 填充电机脉冲计数
			dtmp = MotorStatus[idx].TotalPluseCnt >> 1;

			ptr = (BYTE idata*)&dtmp + MSB;
			if ( *ptr & 0x40 )
				*ptr |= 0x80;
			FillByteToCommBuf( *ptr );
			ptr++;
			FillByteToCommBuf( *ptr );
			ptr++;
			FillByteToCommBuf( *ptr );
			ptr++;
			FillByteToCommBuf( *ptr );
			break;
		
		case READ_VERSION:	// 读软件版本号
			CommBuf.MsgData[0] = ACK_CHAR;	
			FillByteToCommBuf( Version );
			break;
	}
	
	CommandProcessExtra( );
}

void WriteCommand( void )
{
	BYTE 		idx;
	BYTE idata 	*ptr;
	WORD		tmp;

	CommBuf.MsgData[0] = NO_ACK_CHAR;
	CommBuf.MsgCnt = CMD_HEAD_LEN;
	
	idx = CommBuf.MsgData[2] - '1';
	switch ( CommBuf.MsgData[4] )
	{
		case WRITE_MOTOR_DATA:	// 写电机数据
			if ( idx >= MAX_MOTOR_NUM )
				break;
			
			// 已运行
			if ( MotorStatus[idx].Status & MOTOR_RUN_MASK )
				break;

			// 保留零点记录标志,其余清除
			MotorStatus[idx].Status &= ZERO_RECORD_MASK;

			// 方向
			MotorStatus[idx].Dir = HexCharToInt( CommBuf.MsgData[5] ) & DIR_FLAG_MASK;
						
			// 零位检测
			if ( (HexCharToInt( CommBuf.MsgData[6] ) & 0x03) == 0x03 )
				break;
			MotorStatus[idx].Status |= HexCharToInt( CommBuf.MsgData[6] ) & 0x01 ? ZERO_CHECK_MASK : 0;
			MotorStatus[idx].Status |= HexCharToInt( CommBuf.MsgData[6] ) & 0x02 ? WORK_ZERO_CHECK_MASK : 0;

			// 升降频, 转换时将频率计数值放低4位,频率增量放高4位
			MotorStatus[idx].UpDwon = TwoHexCharToInt( CommBuf.MsgData[8], CommBuf.MsgData[7] );
			if ( !(MotorStatus[idx].UpDwon & 0xf0) || !(MotorStatus[idx].UpDwon & 0x0f) )
				MotorStatus[idx].UpDwon = 0;

			// 频率
			MotorStatus[idx].SetFreq = (TwoHexCharToInt( CommBuf.MsgData[9], CommBuf.MsgData[10] )<<8)
										| TwoHexCharToInt( CommBuf.MsgData[11], CommBuf.MsgData[12] );
			if ( MotorStatus[idx].SetFreq > MAX_FREQ_VAL )
				MotorStatus[idx].SetFreq = MAX_FREQ_VAL;
			if ( MotorStatus[idx].SetFreq < START_FREQ )
				MotorStatus[idx].SetFreq = START_FREQ;
	
			// 脉冲数量
			ptr = (BYTE idata*)&MotorStatus[idx].CmdPluseNum + MSB;
			*ptr = TwoHexCharToInt( CommBuf.MsgData[13], CommBuf.MsgData[14] );
			ptr++;
			*ptr = TwoHexCharToInt( CommBuf.MsgData[15], CommBuf.MsgData[16] );
			ptr++;
			*ptr = TwoHexCharToInt( CommBuf.MsgData[17], CommBuf.MsgData[18] );
			ptr++;
			*ptr = TwoHexCharToInt( CommBuf.MsgData[19], CommBuf.MsgData[20] );
					
			// 回零命令
			if ( MotorStatus[idx].Status & ZERO_CHECK_MASK )
			{
				// 已在零点
				if ( (MotorStatus[idx].TotalPluseCnt == 0) && (MotorStatus[idx].Status & ZERO_RECORD_MASK) )
				{
					// 保留零点记录
					MotorStatus[idx].Status &= ZERO_RECORD_MASK;
					MotorStatus[idx].Dir = 0;
				}
			}
			CommBuf.MsgData[0] = ACK_CHAR;
			break;

		case WRITE_MOTOR_FREQ:		// 改变电机频率
			if ( idx >= MAX_MOTOR_NUM )
				break;

			// 已启动
			if ( MotorStatus[idx].Status & MOTOR_RUN_MASK )
			{
				// 不是升降速都可以改变频率
				if ( !MotorStatus[idx].UpDwon )
				{
					tmp = (TwoHexCharToInt( CommBuf.MsgData[5], CommBuf.MsgData[6] ) << 8)
							| TwoHexCharToInt( CommBuf.MsgData[7], CommBuf.MsgData[8] );					
					if ( tmp > MAX_FREQ_VAL )
						tmp = MAX_FREQ_VAL;
					if ( tmp < START_FREQ )
						tmp = START_FREQ;

					MotorStatus[idx].SetFreq = tmp;
					CommBuf.MsgData[0] = ACK_CHAR;	
				}
			}
			break;

		case WRITE_MOTOR_STOP_CMD:	// 电机停止
			// 停止所有电机
			if ( idx == 0xff )				
			{
				if ( Timer[0].MotorIdx )
					MotorStatus[Timer[0].MotorIdx-1].Status |= MOTOR_STOP_CMD_MASK;	
					
				if ( Timer[1].MotorIdx )
					MotorStatus[Timer[1].MotorIdx-1].Status |= MOTOR_STOP_CMD_MASK;	
				
				CommBuf.MsgData[0] = ACK_CHAR;
			}
			else if ( idx < MAX_MOTOR_NUM )
			{
				MotorStatus[idx].Status |= MOTOR_STOP_CMD_MASK;
				CommBuf.MsgData[0] = ACK_CHAR;
			}
			break;

		case WRITE_CLR_PLUSE_CNT:
			// 清除所有电机频率
			if ( idx == 0xff )				
			{
				for( idx = 0; idx < MAX_MOTOR_NUM; idx++ )
				{
					MotorStatus[idx].TotalPluseCnt = 0;
				}
				CommBuf.MsgData[0] = ACK_CHAR;
			}
			else if ( idx < MAX_MOTOR_NUM )
			{
				MotorStatus[idx].TotalPluseCnt = 0;
				CommBuf.MsgData[0] = ACK_CHAR;
			}
			break;
	}
	
	CommandProcessExtra( );
}

void RecvMsgProce( void )
{
	u_char	tmp;

	if ( !RecvOkFlag )
		return;

	// 模块地址
	tmp = HexCharToInt(CommBuf.MsgData[1]);
	if ( tmp && (tmp != (P1 & 0x0f) ) )
		return;

	// 检查校验码
	if ( TwoHexCharToInt( CommBuf.MsgData[CommBuf.MsgCnt-3], CommBuf.MsgData[CommBuf.MsgCnt-2] ) 
			!= CalCheckCode( CommBuf.MsgData, CommBuf.MsgCnt-3 ) )
	{
		CommBuf.MsgData[0] = NO_ACK_CHAR;
		CommBuf.MsgCnt = CMD_HEAD_LEN;
		CommandProcessExtra( );
		return;	
	}	

	switch( CommBuf.MsgData[3] )
	{
		case 'R':
			ReadCommand( );
			return;
		case 'W':
			WriteCommand( );
			return;
		default:	
			CommBuf.MsgData[0] = NO_ACK_CHAR;
			CommBuf.MsgCnt = CMD_HEAD_LEN;
			CommandProcessExtra( );
			break;
 	}
}

// 注意:中断程序中不能调用带参数子程序
void SerialComm( void ) interrupt 4 using 1
{
	if ( RI )
	{
		RI = 0;
		
		CommChar = SBUF;
		if ( (CommChar >= 'a') && (CommChar <= 'z') )
			CommChar = CommChar - 'a' + 'A';

		if ( !RecvOkFlag && !TxdStartFlag )
		{		
			switch( CommBuf.MsgCnt )
			{
				case 0:
					if ( CommChar == START_CHAR )
					{
						CommBuf.MsgData[0] = CommChar;
						CommBuf.MsgCnt = 1;
					}
					break;
				 default:
				 	if ( CommChar == START_CHAR )
					{
						CommBuf.MsgData[0] = CommChar;
						CommBuf.MsgCnt = 1;
						break;
					}
		
					CommBuf.MsgData[CommBuf.MsgCnt] = CommChar;
					CommBuf.MsgCnt++;
					if ( CommBuf.MsgCnt == MAX_COMM_BUF_SIZE )
						CommBuf.MsgCnt = 0;

					if ( CommChar == END_CHAR )
						RecvOkFlag = 1;
					break;
			}
		}
	}

	if ( TI )
	{
		TI = 0;
		if ( (CommBuf.SendIdx < CommBuf.MsgCnt) && TxdStartFlag )
		{
			SBUF = CommBuf.MsgData[CommBuf.SendIdx];
			CommBuf.SendIdx++;
		}
		else
		{
			RE	= RECV;
			CommBuf.MsgCnt = 0;
			CommBuf.SendIdx = 0;
			TxdStartFlag = 0;
		}
	}
}


⌨️ 快捷键说明

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