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

📄 wirecomm485.c

📁 原创的msp430单片机的整套编码 包括通信,红外检测,软件计时等多种功能
💻 C
📖 第 1 页 / 共 2 页
字号:
//=========================================================================
//              通信程序(szb 2006/03/13)	v1.0.0
//				
//		
//=========================================================================
#ifndef _COMM485
#define _COMM485
#include	"datastru.h"
#include	"func.h"
#endif

///////////////////////////////////////////////////////////////////////////
//name:RS485comminit()
//function:RS485通信初始化,USART0
//parameter:none
//return:none
//现将波特率设定为9600bps
///////////////////////////////////////////////////////////////////////////
void RS485comminit(void)				  
{										  
	unsigned char i;
	
	UBR00 = 0x55;                         // 409600hz 4800 - 85.33  **                
	UBR10 = 0x00;                         
	UMCTL0 = 0x92;                        
	UCTL0 = CHAR;                         // 8位
	UTCTL0 = SSEL1;						            // UCLK = SMCLK
	ME1 = URXE0 + UTXE0;                  // 允许USART0 TXD/RXD
	IE1 |= URXIE0;						            // 允许接收中断


	
	origRS485 = RqueueRS485;
	headRS485 = RqueueRS485;
	tailRS485 = RqueueRS485;
	hoffsetRS485 = 0;
	toffsetRS485 = 0;
	tlengthRS485 = 0;

  for (i=0;i<RqueueRS485_Length;i++) //每次复位后,清除接收和发送队列
      RqueueRS485[i] = 0;
  for (i=0;i<TqueueRS485_Length;i++)
      TqueueRS485[i] = 0;
  
}


///////////////////////////////////////////////////////////////////////////
//name:RS485offset()
//function:计算循环队列头尾指针偏移量的函数
//parameter:Offset-原偏移量的值,n为移位位数,length为接收队列长度
//return:Offset-新的指针偏移量
//explain:每次在对接收队列进行写入和读出操作时,需要移动头尾指针。我们所
//        设计的接收队列是一个循环队列。为了使头尾指针不超出循环队列规定
//        的范围,我们将接收队列的首地址定位在orig变量中,又分别定义头尾
//        指针的偏移量hoffset以及toffset。每次头尾指针移位的时候,先计算
//        他们的偏移量。最终的头尾指针的位置由偏移量加上orig得到。而偏移
//        量由以下计算函数确定,保证了偏移量的范围在0-(length-1)之间,
//		  从而保证了头尾指针不会超出循环队列的范围。
///////////////////////////////////////////////////////////////////////////
int RS485offset(int Offset, int n, int length)
{
	return Offset = (Offset + n) % length;
} 

///////////////////////////////////////////////////////////////////////////
//name:*RS485voffset()
//function:已知头指针head在循环队列中的指向,求*(headRS485 + n)的值.n可正可负.
//parameter:int n为head前或后偏移量的位数
//return:Pdata = headRS485 + n
//explain:当头指针head比较靠近循环队列的末尾时,(head+n)很可能就指到循环队列外
//		  面去了为了防止这种情况发生,需要根据情况先判断(headRS485 + n)是否会溢出,如果
//		  溢出则将其重新指回循环队列内部的元素,使队列真正成为一个循环队列.
//update:2003.2.20 by wjg
///////////////////////////////////////////////////////////////////////////
unsigned char *RS485voffset(int n)
{
	unsigned char *Pdata;
	
	Pdata = origRS485 + RS485offset(headRS485 - origRS485, n, RqueueRS485_Length);

	return Pdata;
}

///////////////////////////////////////////////////////////////////////////
//name:RS485ally()
//function:将两个单字节数据合成为一个字数据字的函数
//parameter:unsigned int *p-待处理数据首位的地址
//return:b-合成后的字数据
//explain:将接收到的一帧数据中相邻的两个字节组合成一个字数据,由于先接收
//        到的数据是字数据的高字节,后接收到的数据才是该字数据的低字节。
//        所以,需要将相邻的两个字节调换位置,然后再依次写入一个字数据的
//        低8位和高8位,从而得到通信中需要的字数据。该函数就是为了完成这
//        个功能而设计的。
///////////////////////////////////////////////////////////////////////////
unsigned int RS485ally(unsigned char *p)
{
	unsigned int b;
	b = *p;

	b = (b << 8) | (0x00FF & (*(origRS485 + (p + 1 - origRS485) % RqueueRS485_Length)));

	return b;
}

///////////////////////////////////////////////////////////////////////////
//name:RS485crc_count()
//function:CRC校验码计算函数
//parameter:p-需校验数据的头指针
//          length-需校验数据的长度
//return:crcvalue:校验后得到的CRC校验码(16位)
///////////////////////////////////////////////////////////////////////////
unsigned int RS485crc_count(unsigned char *p, unsigned int length, unsigned int Send_Recieve)
{
	unsigned int crcvalue;
	unsigned char AH = 0xFF, AL = 0xFF;
	unsigned char GH = 0xA0, GL = 0x01;
	unsigned char i, j;
	for(i = 0;i < length;i++, p++)
	{
		if (Send_Recieve == 1)// 因接收队列是循环队列,所以其中数据的CRC需要特殊处理
		{
			p = origRS485 + (p - origRS485) % RqueueRS485_Length;
		}
		AL = (*p) ^ AL;
		for(j = 0;j < 8;j++)
		{
			if((AL & 0x01) == 1)	// AL最低位为1
			{
				AL = AL >> 1;
				if((AH & 0x01) == 1)
					AL = AL | 0x80;
				AH = AH >> 1;
				AH = AH ^ GH;
				AL = AL ^ GL;
			}
			else
			{
				AL = AL >> 1;
				if((AH & 0x01) == 1)
					AL = AL | 0x80;
				AH = AH >> 1;
			}
		}
	}
	return crcvalue = (unsigned int)(AL * 0x100 + AH);	//低位在前,高位在后
}

///////////////////////////////////////////////////////////////////////////
//name:RS485crc_check()
//function:接收队列CRC校验码检验函数
//parameter:datahead-所有需校验数据的首地址
//          crcpointer-CRC校验码的首地址
//			Send_Recieve-待检查CRC的	数组是否循环队列
//			CommType-通信类型
//return:0-数据不合法
//       1-数据合法
//update:2003.2.20 by wjg
///////////////////////////////////////////////////////////////////////////
unsigned int RS485crc_check(unsigned char *datahead, unsigned char *crcpointer, unsigned int Send_Recieve)
{
	unsigned int mycrcvalue, tempcrc;
	mycrcvalue = RS485crc_count(datahead, (crcpointer - datahead), Send_Recieve);

    if (crcpointer - origRS485 >= RqueueRS485_Length - 1)
		tempcrc = ((*(origRS485 + (crcpointer - origRS485) % RqueueRS485_Length)) << 8) | (0x00FF & (*(origRS485 + (crcpointer + 1 - origRS485) % RqueueRS485_Length)));
	else
		tempcrc = RS485ally(crcpointer);

	if (mycrcvalue == tempcrc) return 1;
	else return 0;
}

///////////////////////////////////////////////////////////////////////////
//name:RS485MoveHead()
//function:将头指针在循环队列中移动n位
//parameter:int step,头指针要移动的步数;unsigned char *CommType,通信类型
//return:none
//update:2003.2.20 by wjg
///////////////////////////////////////////////////////////////////////////
void RS485MoveHead(int step)
{
	hoffsetRS485 = RS485offset(hoffsetRS485, step, RqueueRS485_Length);
    headRS485 = origRS485 + hoffsetRS485;
				 
}

///////////////////////////////////////////////////////////////////////////
//name:RS485Send_Tqueue()
//function:发送队列中的数据发送过程
//parameter:unsigned int MoveOffset,数据发送后头指针head要移动的步长
//return:none
//update:2006.2.20 szb
///////////////////////////////////////////////////////////////////////////
void RS485Send_Tqueue(unsigned int MoveOffset)
{
	numberRS485 = 0;
	TXBUF0 = TqueueRS485[numberRS485];
	IE1 |= UTXIE0 + URXIE0;

	RS485MoveHead(MoveOffset);
}




///////////////////////////////////////////////////////////////////////////
//name:		operate034()
//function: 功能代码为0x03或0x04时的处理函数
//parameter:unsigned char *CommType,通信类型(RS485或者CAN),现在的写法有丢针隐患,应设立重发机制,注意此处还应补充对FRAM使能标志的操作
//return:	none
///////////////////////////////////////////////////////////////////////////
void RS485operate03(void)
{
	
	unsigned char SOEBYTEnum;//发送记录的条数,最大255字节,也就是说最大一次能发31条记录
	unsigned int crccalculate;
	unsigned int i;
	
  if (RS485crc_check(headRS485, headRS485 + 7, 1) == 0)  //如果是后续查询帧
		{
			RS485MoveHead(1);
			return;
		}

					
					/*应答初始查询帧*/
	if (RS485ally(RS485voffset(3)) == 0xFFFF)
		{
			SOEamount_send = FM_word_read(FRAM_NUM_SOE); //FRAM_NUM_SOE 表示保存在FRAM中的尚未发送过的事件数目
	   
	
			TqueueRS485[0] = *headRS485;// 构造发送队列
			TqueueRS485[1] = 0x03;
			TqueueRS485[2] = 2;  
			TqueueRS485[3] = (unsigned char)(SOEamount_send >> 8);//先发送高字节数据
			TqueueRS485[4] = (unsigned char)SOEamount_send;//发送低字节数据
			tlengthRS485 = 7;
					
		  crccalculate = RS485crc_count(TqueueRS485, tlengthRS485 - 2, 0);
			TqueueRS485[tlengthRS485 - 1] = (unsigned char)crccalculate;
			TqueueRS485[tlengthRS485 - 2] = (unsigned char)(crccalculate >> 8);
			RS485Send_Tqueue(9);  //发送数据,接收队列的头指针后移9位,表示已处理完对该帧的应答
		}
		
	else if (RS485ally(RS485voffset(3)) == 0xAAAA)//对所有数据的接收确认
		{
			SOEPosition = FM_word_read(FRAM_POINT_SOE);
			if (SOEamount_send > SOEamount)
				SOEamount_send = 0;
		  SOEamount = SOEamount - SOEamount_send;
		  FM_word_write(FRAM_NUM_SOE,SOEamount); //这可以防止在通讯过程中有新的记录加入的情况
		       
		        
			if(SOEPosition + SOEamount_send * 8 > 0x7FF8) //当FRAM的空间写完时,重新从首地址开始写
			       FM_word_write(FRAM_POINT_SOE,SOEPosition + SOEamount_send * 8 - 0x7FF8);
        
      else
             FM_word_write(FRAM_POINT_SOE,SOEPosition + SOEamount_send * 8);
                  	
	   SOEamount_send = 0;//必需清除SOEamount_send中的记录数,否则如果多次收到终端的确认帧
                         //SOEamount = SOEamount - SOEamount_send会运算溢出  
					    
			RS485MoveHead(9);  //对于最后的确认帧不再应答         
		}
	else
		{
			 SOEPosition_send = FM_word_read(FRAM_POINT_SOE) + (RS485ally(RS485voffset(3)) - 1) * 8;//FRAM_POINT_SOE 保存SOE记录指针,它指向准备发送的SOE记录
			if (SOEPosition_send > 0x7FF8)//边界判断
					SOEPosition_send = SOEPosition_send - 0x7FF8;
			SOEBYTEnum = (unsigned char)(RS485ally(RS485voffset(5)) - RS485ally(RS485voffset(3)) + 1);//发送记录的条数 = (索要记录终止编号 - 索要记录初始编号 + 1) 

⌨️ 快捷键说明

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