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

📄 meter485_s.c

📁 这是485芯片的USB通信源码
💻 C
字号:
/*
485接口多功能电能表通信程序
依据: DL/T 645-1997 《多功能电能表通信规约》


----------------------------------------------------------------------------------------------

UCFG1 地址:xxxxh	未编程值:63h(看门狗关闭、复位脚使能、掉电检测使能和使用内部RC振荡器)

	7		6		5		4		3		2		1		0
    WDTE	RPE		BOE		WDSE	-		FOSC2	FOSC1	FOSC0


----------------------------------------------------------------------------------------------

WDCON 地址:A7H		不可位寻址	
	7		6		5		4		3		2		1		0
	PRE2	PRE1	PRE0	-		-		WDRUN	WDTOF	WDCLK

复位值:111xx1?1B (注:WDCON.7,6,5,2,0在任何复位时都置1,WDCON.1在上电复位时清零,在看门狗复位时置位,不受其它任何复位影响。)


----------------------------------------------------------------------------------------------

*/

#include <REG932.H>
#include <intrins.H>
#define 	revision	"2006/08/17/01"

//buff格式: 5字节地址 + 1字节命令 + 1字节长度 + ?字节数据		
#define  buffR_size    40
unsigned char xdata buffR[buffR_size];

unsigned char state;					//
unsigned char R_Done;					//一帧完整接收成功标志
unsigned char timeout;				//超时标志
unsigned int  timeout_cnt;		//超时计数器

sbit _RT = P0^7;							//485收发控制线
////////////////////////////////////////////////////
void sendbyte(unsigned char bSend)
{
	ACC  = bSend;
	TB8  = P;

	TI   = 0;
	SBUF = bSend;
 	while(TI==0);
	TI=0;
}
/*
函数名: unsigned char Read485(unsigned char *s)
参数: 	发送缓冲区,	格式: 5字节地址 + 1字节命令 + 1字节长度 + ?字节数据		
返回: 	1: 读取超时; 0: 正常读取, 此时buffR[]中的数据已经被更新
*/
unsigned char Read485(unsigned char *s)
{
	unsigned char i,temp,CS=0x00;					

	for( i=0;i<buffR_size;i++ )
	{
		buffR[i] = 0;
	}
	state       = 0;
	R_Done      = 0;
	timeout			= 0;
	timeout_cnt = 0;

	//使能485发送
	_RT = 1;
	
	//发送两个前导字节
	for(i=0;i<2;i++)
	{
		temp = 0xFE;
		sendbyte(temp);
		
    }

	//发送起始字节
	temp = 0x68;
	CS  += temp;
	sendbyte(temp);

	//发送六个地址字节 	
	for(i=0;i<6;i++)						//i=0,1,2,3,4,5
	{														//结束时i=6
		temp = *(s+i);
		CS  += temp;
		sendbyte(temp);

    }	

	//发送起始字节
	temp = 0x68;
	CS  += temp;
	sendbyte(temp);


	//发送命令字节
	temp = *(s+i);
	CS  += temp;								//i=6
	i++;												//结束时i=7	
	sendbyte(temp);


	//发送长度字节
	temp = *(s+i);							//i=7
	CS  += temp;
	i++;												//结束时i=8		
	sendbyte(temp);


	//发送数据
	for(;i< *(s+7) + 8;i++)			//
	{														//结束时i=len+8
		temp = *(s+i) + 0x33;
		CS  += temp;
		sendbyte(temp);
    }	
	
	//发送校验和
	temp = CS;
	sendbyte(temp);


	//发送结束符
	temp = 0x16;
	sendbyte(temp);

	//使能485接收
	_RT    = 0;

	RTCCON = 0x60;
	RTCCON = 0x63;							//启动实时时钟监控是否超时

	while( !R_Done )
	{
		if( timeout )
		{
			for( i=0;i<buffR_size;i++ )
			{
				buffR[i] = 0;
			}
			state  		 = 0;
			R_Done 		 = 0;
			timeout		 = 0;
			timeout_cnt  = 0;

			return 1;								//一帧未完整接收, 并且已经超时, 返回1
		}	
	}

	return 0;										//一帧完整接收, 返回0


}


void UART_ISR(void) interrupt 4
{
	//i,缓冲区元素索引; j,数据域元素索引; CS,校验和
	static unsigned char i=0,j=0,CS=0;
	unsigned char temp;
		
	if(RI)											//如果是接收中断
	{
		
		RI   = 0;							
		temp = SBUF;	
					
		ACC  = temp;
		if( P!=RB8 ) 		
		{
			goto ERR1;
		}

//		if(	timeout	)	
//		{	
//			state = 0;
//			i = 0;
//			j = 0;
//			CS=0x00;
//		}												//超时之后, 当前接收到的数据被认为是一帧的第一个字节
															//所以仍需要进入下面的分支判断
		switch( state )
		{
			case 0 :
				i  = 0;
				j  = 0;
				CS = 0;

				if( temp != 0xfe )		//如果不是前导字节
				{	
					goto ERR1 ; 		
				}
				else
				{
					state = 1;	
					goto END1;
				}
				break;

			case 1 :
				if( temp == 0xfe )		//如果还是前导字节				
				{	
					goto END1;									
				}
				else
				{
					if( temp == 0x68 )	//如果是帧头
					{
						CS+=0x68;
						state = 2;
						goto END1;
					}
					else								//如果不是帧头
					{
						goto ERR1;
					}	
				}
				break;

			case 2:						
				buffR[i++]=temp;			//接收电表通讯地址 i=0,1,2,3,4,5, 结束时 i=6		
				CS+=temp;				
				if( i==6 )				
				{
					state = 3;
				}
				goto END1;	
				break;

			case 3:
				if( temp != 0x68 )		//如果不是帧头
				{
					goto ERR1;
				}
				CS+=0x68;					
				state = 4;
				goto END1;		
				break;

			case 4:
				buffR[i++]=temp;			//接收通讯命令 i=6, 结束时 i=7
				CS+=temp;
				state = 5;
				goto END1;
				break;
			
			case 5:
				buffR[i++]=temp;			//接收通讯数据长度 i=7, 结束时 i=8
				j=temp;
				CS+=temp; 							
				state = 6;
				goto END1;
				break;

			case 6:
				buffR[i++]=temp-0x33;	//接收 ? 个数据
				CS += temp;						//temp是加了0x33的
				if( i==j+8 )					//结束时 i=j+8
				{
					state = 7;
				}
				goto END1;
				break;
				
			case 7:
				if(CS!=temp) 					//如果校验和不正确 
				{
					goto ERR1;
				}
				state = 8;
				goto END1;
				break;
	
			case 8:
				if( temp != 0x16 )		//如果不是帧尾	
				{
					goto ERR1;
				}
				
				RTCCON 		= 0x60;			//一帧正常结束关闭实时时钟, 取消超时监控

				state 		= 0;
				R_Done 		= 1;
				timeout		= 0;
				timeout_cnt = 0;

				goto END2;
				break;				

		}

ERR1:	
		for( i=0;i<buffR_size;i++ )
		{
			buffR[i] = 0;
		}

		state  		= 0;
		R_Done 		= 0;
		
END1:
		timeout		= 0;
		timeout_cnt = 0;
		RTCCON 		= 0x60;
		RTCCON 		= 0x63;					//启动实时时钟监控是否超时

END2:	
		_nop_();
		

	}														//end of RI;	

	else												//如果是发送中断			
	{
	
	}
}

void CLRWDG()
{
	EA = 0;
	WFEED1 = 0xA5;
	WFEED2 = 0x5A;
	EA = 1;
}

void  RTC_ISR()  interrupt 10
{
	unsigned char temp;
	
	temp = RTCCON & 0x80;		
	if( temp == 0x80 )					//如果是由实时时钟产生的中断
	{
		RTCCON &= 0x7F;						//清除实时时钟中断标志		
				
		timeout_cnt++;
		if(timeout_cnt>500)				
		{
			timeout = 1;	
			RTCCON = 0x60;					//关闭实时时钟, 取消超时监控
		}
	}

	temp = WDCON & 0x02;
	if( temp )									//如果是由看门狗时钟产生的中断
	{
		CLRWDG();
	}

}

void main ()
{
	unsigned char code rev[13]=revision;

	unsigned char i,ERR;
	//buff格式: 5字节地址 + 1字节命令 + 1字节长度 + ?字节数据		
	unsigned char data  buff []={0x99,0x13,0x07,0x00,0x00,0x00,0x01,0x02,0x10,0x90};

	//I/O口配置: 
	P1M1 = 0x00;     
	P1M2 = 0x00;
  P0M2 = 0x00;	
	P0M1 = 0x00;


	//串口配置: 工作模式及波特率
	SCON=0xD0;			//9位UART, 模式3, 波特率由波特率发生器决定				
	SSTAT=0x00;			//
	BRGCON=0x00;    //BRGR1 & BRGR0=(1/9600)/(1/7.3728M)=7.3728M/9600=768=0x0300	
	BRGR0=0xF0;			//0x02F0	9600		
	BRGR1=0x17;			//0x1800	1200	
	BRGCON=0x03;     	
	

	//实时时钟配置: 					
	RTCH = 0x00;		//超时时间计算公式: ( (RTCHL<<7) | 0x7F ) * Tcclk 
	RTCL = 0x3A;		//0X003A 大约1mS; 0x0006 大约0.1mS	
	RTCCON=0x60;				


	//看门狗配置:		  	
	WDL    = 0xFF;
	EA 	   = 0;
	WDCON  = 0xE5;
	WFEED1 = 0xA5;
	WFEED2 = 0x5A;
	EA 	   = 1;


	//中断配置: 
	IP0  = 0X10;		
	IP0H = 0X10;		
	ES   = 1;			//使能串口中断
	EWDRT= 1;			//使能实时时钟及看门狗中断			
	EA   = 1;


	//变量初始化
	state	= 0;
	R_Done  = 0;
	timeout = 0;
	timeout_cnt=0;
	for( i=0;i<buffR_size;i++ )
	{
		buffR[i] = 0;
	}

	
		
    while(1) 
    {
		
		CLRWDG();
		ERR = 2;
		//ERR = Read485(buff);
		if( ERR == 1 )	
		{
			_nop_();
		}

		_nop_();

	}
}


⌨️ 快捷键说明

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