//*****************************************************************************
// 包含文件
//*****************************************************************************
#include <SH79F161A.H> // SFR 声明
#include <intrins.H>
//*****************************************************************************
// 全局常量
//*****************************************************************************
#define UCHAR unsigned char
#define UINT unsigned int
#define ULINT unsigned long int
typedef unsigned char BYTE;
typedef unsigned int WORD;
#define SUCCESS 0
#define FOSC 11059200L //系统频率11.0592MHz
//*****************************************************************************
//定时器0初始化(用于定时)
//*****************************************************************************
void Timer0_Init(void)
{
TCON1=0xF4; //T0使用系统时钟的1/12作为时钟源,T1则使用1T模式
//TL0=0xCD; // //1T时的重装值
//TH0=0xD4;
TL0=0x66; // //12T时的重装值
TH0=0xFC;
TF0=0;
TR0 = 1;
ET0 = 1; //开中断T0
}
//*****************************************************************************
//定时器1初始化{用于波特率)
//*****************************************************************************
void Timer1_Init(void)
{
SCON=0X50; //串口方式1,8位数据,可变波特率,允许串行接收
TMOD = 0x21; //定时器1为模式2(8位自动重载,用于产生波特率)(备注:同时T0则为模式1即:16位不可重载)
TL1 = (256 - (FOSC/32/BaudValue)); //设置波特率重装值
TH1 = (256 - (FOSC/32/BaudValue));
TR1 = 1; //定时器1开始启动
ES0 = 1; //使能串口中断
RS485_CON = 0; //处于接收
}
//-------------------------------定时器0 1ms 中断 -------------------------
void timer0_IntProc() interrupt 1
{
//TL0=0xCD; //1T时的重装值
//TH0=0xD4;
TL0=0x66; // //12T时的重装值
TH0=0xFC;
bt1ms = 1;
}
//--------------------------------串行中断程序---------------------------
void comm_IntProc() interrupt 4
{
if (RI)
{
RI = 0;
receTimeOut = 10; //通讯超时值这个地方很重要 10ms
receBuf[receCount] = SBUF;
receCount++; //接收地址偏移寄存器加1
}
if (TI)
{
TI = 0; //清除TI位
busy = 0; //清忙标志
}
}
//------------------------------------定时处理--------------------------------
void timeProc(void)
{
if(bt1ms)
{
bt1ms = 0;
if(receTimeOut>0)
{
receTimeOut--;
if(receTimeOut==0 && receCount>0) //判断通讯接收是否超时
{
RS485_CON = 0; //将485置为接收状态
receCount = 0; //将接收地址偏移寄存器清零
}
}
}
}
void uartsends(UCHAR buff[],UCHAR len)
{
UCHAR i;
for(i=0;i<len;i++)
{
SBUF=buff[i];
while(!TI);
TI=0;
}
}
/*******************************串口发送函数 ********************************/
void Begin_send(void)
{
RS485_CON = 1; //处于发送
uartsends(sendBuf,sendCount);
RS485_CON = 0; //发送完后将485置于接收状态
receCount = 0; //清接收地址偏移寄存器
}
/*************************查询uart接收的数据包内容函数 **************************/
////函数功能:从机根据串口接收到的数据包receBuf[1]里面的内容,即function code执行相应的命令
/********************************************************************************/
void checkComm0Modbus(void) //10ms内必须响应接收数据
{
UINT crcData;
UINT temp;
if(receCount > 4) //如果接收到数据
{
switch(receBuf[1])//功能代码
{
case 3: //功能码3:读取寄存器(一个或多个)
{
if(receCount >= 8) //从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr) //核对地址
{
crcData = crc16(receBuf,6); //核对校验码,重新计算校验码
temp=receBuf[7];//获取发送来的原校验码
temp=(temp<<8)+receBuf[6];
if(crcData == temp)//与原校验码比较
if(receBuf[1] == 3)//核对功能码
{
readRegisters(); //读取保持寄存器(一个或多个)
}
receCount = 0;
}
}
break;
}
case 6: //功能码6:写寄存器
{
if(receCount >= 8)//从询问数据包格式可知,receCount应该等于8 ,接收完成一组数据应该关闭接收中断
{
if(receBuf[0]==LocalAddr)//核对地址
{
crcData = crc16(receBuf,6);//核对校验码
temp=receBuf[7];
temp=(temp<<8)+receBuf[6];
if(crcData == temp)
if(receBuf[1] == 6)//核对功能码
{
presetSingleRegister(); //预置单个保持寄存器
}
receCount = 0;
}
}
break;
}
default: break;
}
}
}
//*******************************************************************************
//主程序
//*****************************************************************************
void main (void)
{
UCHAR j;
EA=0;
Delay_ms(15);
Timer0_Init();
Timer1_Init();
EA=1;
while(1)
{
WatchDog();
timeProc();
checkComm0Modbus();
}
}
|