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

📄 单片机modbusrtu通信协议.txt

📁 51系列单片机的ModbusRTU
💻 TXT
📖 第 1 页 / 共 3 页
字号:
		case 4:
		        *tempData = DA_OUT5;
                        send_back = 1;
				break;
		case 5:
		        *tempData = DA_OUT6;
                        send_back = 1;
				break;
		case 6:
		        *tempData = DA_OUT7;
                        send_back = 1;
				break;
		case 7:
		        *tempData = DA_OUT8;
                        send_back = 1;
				break;
		case 8:
                        *tempData = yinhu_bit ;
                        send_back = 1;
				break;
                case 9:
		        *tempData = one_16 ;
                        send_back = 1;
				break;
		case 10:
		        *tempData = two_16 ;
                        send_back = 1;
				break;
                case 11:
		        *tempData = AD_IN1 ;
                        send_back = 1;
				break;
                case 12:
		        *tempData = AD_IN2 ;
                        send_back = 1;
				break;
                case 13:
		        *tempData = AD_IN3 ;
                        send_back = 1;
				break;
                case 14:
		        *tempData = AD_IN4 ;
                        send_back = 1;
				break;
                case 15:
		        *tempData = AD_IN5 ;
                        send_back = 1;
				break;
                case 16:
		        *tempData = AD_IN6 ;
                        send_back = 1;
				break;
                case 17:
		        *tempData = AD_IN7 ;
                        send_back = 1;
				break;
                case 18:
		        *tempData = AD_IN8 ;
                        send_back = 1;
				break;
		default:
                        *tempData = 0 ;
                        send_back = 1;
				break;
	}
    return result;
}

//设置寄存器值 返回0表示成功
uint setRegisterVal(uint addr,uint tempData)
{
    uint result = 0;
    uint tempAddr;

    tempAddr = addr & 0xfff;

    switch(tempAddr & 0xff)
    {
        case 0:
            DA_OUT1 = tempData;
            send_back = 1;
            break;
        case 1:
            DA_OUT2 = tempData;
            send_back = 1;
            break;
        case 2:
            DA_OUT3 = tempData;
            send_back = 1;
            break;
        case 3:
            DA_OUT4 = tempData;
            send_back = 1;
            break;
        case 4:
            DA_OUT5 = tempData;
            send_back = 1;
            break;
        case 5:
            DA_OUT6 = tempData;
            send_back = 1;
            break;
        case 6:
            DA_OUT7 = tempData;
            send_back = 1;
            break;
        case 7:
            DA_OUT8 = tempData;
            send_back = 1;
            break;
        case 8:
            yinhu_bit = tempData;
            send_back = 1;
            break;
        case 9:
            one_16 = tempData;
            send_back = 1;
            break;
        case 10:
            two_16 = tempData;
            send_back = 1;
            break;
        default:
            send_back = 1;
            break;
	}
    return result;
}

uint crc16(uchar *puchMsg, uint usDataLen)
{
    uchar uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
    uchar uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
    unsigned long uIndex ; /* CRC循环中的索引 */

    while (usDataLen--) /* 传输消息缓冲区 */
    {
        uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */
        uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
        uchCRCLo = auchCRCLo[uIndex] ;
        }
    return (uchCRCHi << 8 | uchCRCLo) ;
}


//开始发送
void beginSend(void)
{

    sendPosi = 0;
    if(sendCount > 1)
        sendCount--;
    ACC = sendBuf[0];
    TB8 = P;
    SBUF = sendBuf[0];

}


//读线圈状态
void readCoil(void)
{
    uchar addr;
    uchar tempAddr;
    uchar byteCount;
    uchar bitCount;
    uchar position;
    uchar i,k;
 //   uchar  result;
    uchar  exit = 0;

    uint tempData;
    uint crcData;

    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    //bitCount = (receBuf[4]<<8) + receBuf[5];	//读取的位个数
    bitCount = receBuf[5];

    byteCount = bitCount / 8;					//字节个数
    if(bitCount%8 != 0)
        byteCount++;

    for(k=0;k<byteCount;k++)
    {//字节位置
        position = k + 3;
        sendBuf[position] = 0;
        for(i=0;i<8;i++)
        {
            getCoilVal(tempAddr,&tempData);

            sendBuf[position] |= tempData << i;
            tempAddr++;
            if(tempAddr >= addr+bitCount)
            {	//读完
                exit = 1;
                break;
            }
        }
        if(exit == 1)
            break;
    }

    sendBuf[0] = localAddr;
    sendBuf[1] = 0x01;
    sendBuf[2] = byteCount;
    byteCount += 3;
    crcData = crc16(sendBuf,byteCount);
    sendBuf[byteCount] = crcData >> 8;
    byteCount++;
    sendBuf[byteCount] = crcData & 0xff;
    sendCount = byteCount + 1;

    if (send_back == 1)
    {
        send_back = 0;
        beginSend();
    }
}

//读寄存器
void readRegisters(void)
{
    uchar addr;
    uchar tempAddr;
    uchar readCount;
    uchar byteCount;
  //  uchar  finsh;	//1完成  0出错

 //   uint result;
    uint crcData;
    uint i;
    uint tempData = 0;



    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    //readCount = (receBuf[4]<<8) + receBuf[5];	//要读的个数
    readCount = receBuf[5];

    byteCount = readCount * 2;

    for(i=0;i<byteCount;i+=2,tempAddr++)
    {
        getRegisterVal(tempAddr,&tempData);
        sendBuf[i+3] = tempData >> 8;
        sendBuf[i+4] = tempData & 0xff;
    }

    sendBuf[0] = localAddr;
    sendBuf[1] = 3;
    sendBuf[2] = byteCount;
    byteCount += 3;
    crcData = crc16(sendBuf,byteCount);
    sendBuf[byteCount] = crcData >> 8;
    byteCount++;
    sendBuf[byteCount] = crcData & 0xff;

    sendCount = byteCount + 1;
    if (send_back == 1)
    {
        send_back = 0;
        beginSend();
    }
}

//写1个寄存器
void presetSingleRegister(void)
{
    uchar addr;
    uchar tempAddr;
    uint crcData;
    uint tempData = 0;

    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    tempData = ( receBuf[4 ] << 8) + receBuf[5];

    setRegisterVal( tempAddr, tempData );

    sendBuf[0] = localAddr;
    sendBuf[1] = 3;
    sendBuf[2] = addr >> 8;
    sendBuf[3] = addr & 0xff;
    crcData = crc16(sendBuf,6);
    sendBuf[4] = crcData >> 8;
    sendBuf[5] = crcData & 0xff;
    sendCount = 6;
    if (send_back == 1)
    {
        send_back = 0;
        beginSend();
    }
}

//强制单个线圈
void forceSingleCoil(void)
{
    uchar addr;
    uchar tempAddr;
    uint tempData;
    uchar  onOff;
    uchar i;

    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    //onOff = (receBuf[4]<<8) + receBuf[5];
    onOff = receBuf[4];

    //if(onOff == 0xff00)
    if(onOff == 0xff)
    {	//设为ON
        tempData = 1;
    }
    //else if(onOff == 0x0000)
    else if(onOff == 0x00)
    {	//设为OFF
        tempData = 0;
    }

    setCoilVal(tempAddr,tempData);

    for(i=0;i<receCount;i++)
    {
        sendBuf[i] = receBuf[i];
    }
    sendCount = receCount;
    if (send_back == 1)
    {
        send_back = 0;
        beginSend();
    }
}


//设置多个寄存器
void presetMultipleRegisters(void)
{
    uchar addr;
    uchar tempAddr;
    uchar byteCount;
    uchar setCount;
//    uchar finsh;	//为1时完成 为0时出错
    uchar i;
    uint crcData;
    uint tempData;

    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr & 0xff;

    //setCount = (receBuf[4]<<8) + receBuf[5];
    setCount = receBuf[5];
    byteCount = receBuf[6];

    for(i=0;i<setCount;i++,tempAddr++)
    {
        tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8];

        setRegisterVal(tempAddr,tempData);
    }

    sendBuf[0] = localAddr;
    sendBuf[1] = 16;
    sendBuf[2] = addr >> 8;
    sendBuf[3] = addr & 0xff;
    sendBuf[4] = setCount >> 8;
    sendBuf[5] = setCount & 0xff;
    crcData = crc16(sendBuf,6);
    sendBuf[6] = crcData >> 8;
    sendBuf[7] = crcData & 0xff;
    sendCount = 8;
    if (send_back == 1)
    {
        send_back = 0;
        beginSend();
    }
}
/***********************************************************************************
* Function: RS485_ZHC;
*
* Description: RS485_ZHC程序;
*
* Input:  none;
*
* Return: none;
*
* Note:   none;
************************************************************************************/
void RS485_ZHC(void)
{
    uint crcData;
    uint tempData;
    if(receCount > 4)
    {
        switch(receBuf[1])
        {
            case 1://读取线圈状态(读取点 16位以内)
            case 3://读取保持寄存器(一个或多个)
            case 5://强制单个线圈
            case 6://设置单个寄存器
                if(receCount >= 8)
                {//接收完成一组数据
                 //应该关闭接收中断
                    add++;
                    if(receBuf[0]==localAddr )
                    {
                        crcData = crc16(receBuf,6);
                        if(crcData == receBuf[7]+(receBuf[6]<<8))
                        {//校验正确
                            if(receBuf[1] == 1)
                            {//读取线圈状态(读取点 16位以内)
                                readCoil();
                            }
                            else if(receBuf[1] == 3)
                            {//读取保持寄存器(一个或多个)
                                readRegisters();
                            }
                            else if(receBuf[1] == 5)
                            {//强制单个线圈
                                forceSingleCoil();
                            }
                            else if(receBuf[1] == 6)
                            {
                                presetSingleRegister();
                            }

                        }
                    }
                    receCount = 0;
                }
            break;

            case 15://设置多个线圈
                tempData = receBuf[6];
                tempData += 9;	//数据个数
                if(receCount >= tempData)
                {
                    if(receBuf[0]==localAddr)
                    {
                        crcData = crc16(receBuf,tempData-2);
                        if(crcData == (receBuf[tempData-2]<<8)+ receBuf[tempData-1])
                        {
                            //forceMultipleCoils();
                        }
                    }
                    receCount = 0;
                }
            break;

            case 16://设置多个寄存器
                tempData = (receBuf[4]<<8) + receBuf[5];
                tempData = tempData * 2;	//数据个数
                tempData += 9;
                if(receCount >= tempData)
                {   add++;
                    if(receBuf[0]==localAddr )
                    {
                        crcData = crc16(receBuf,tempData-2);
                        if(crcData == (receBuf[tempData-2]<<8)+ receBuf[tempData-1])
                        {
                            presetMultipleRegisters();
                        }
                    }
                    receCount = 0;
                }
            break;

            default:
                receCount = 0;
            break;
        }
    }
}
///////////////////////////////////////////
void Correspondence(void) interrupt 4
{
	save_point=xdata_point;
	if(TI)
	{
		TI = 0;
		for(;sendPosi < sendCount;)
		{
			sendPosi++;
		//	ACC = sendBuf[sendPosi];
		//	TB8 = P;	//加上校验位
			SBUF = sendBuf[sendPosi];
                        while(TI == 0)
                        {_nop_();_nop_();}
                        TI = 0;
		}


			receCount = 0;   //清接收地址偏移寄存器
			checkoutError = 0;

	}
	else if(RI)
	{
		RI = 0;
	//	receTimeOut = 10;    //通讯超时值
		receBuf[receCount] = SBUF;
	//	ACC = receBuf[receCount];
	//	if(P != RB8)
	//		checkoutError = 2;	//偶校验出错
                if(receBuf[0]==localAddr )
                {
		    receCount++;          //接收地址偏移寄存器加1
		    receCount &= 0x1f;    //最多一次只能接收48个字节
                    check = 1;
                }
                else
                {
                    receCount = 0;
                }
	}

	xdata_point = save_point;
}
////////////////////////////////////////
void start_adc(void)//启动AD转换
{
    //channel是转换通道
    switch (channel)
    {
        case 1:ADC_CONTR = 0X80;break; //启动通道1转换
        case 2:ADC_CONTR = 0X81;break; //启动通道2转换
        case 3:ADC_CONTR = 0X82;break; //启动通道3转换

⌨️ 快捷键说明

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