sx1278组网01——网关

nodebus.h

#ifndef __MODBUS_H
#define __MODBUS_H

/*网络相关宏定义*/
#define NET_ADDR           0xA5    //网络地址
#define SLAVE1_ADDR        0x01    //子设备1地址
#define BROADCAST_ADDR     0xFF    //广播地址

/*操作码相关宏定义*/
#define OP_W_COILS         0x02    //写继电器状态
#define OP_R_SENSOR        0x01    //读传感器数据

/*参数相关宏定义*/
#define PRAM_R_TEMPERATURE 0x01    //只读取温度
#define PRAM_R_HUMIDITY    0x02    //只读取湿度
#define PRAM_R_LUX         0x04    //只读取光线强度
#define PRAM_R_ALL         0x07    //读取所有传感器

#define PRAM_W_RELAY1      0x01    //吸合继电器1,如果想断开按位取反即可
#define PRAM_W_RELAY2      0x02    //吸合继电器2,如果想断开按位取反即可

typedef enum
{
    FRAME_OK = 0x00,               //数据帧正确
    FRAME_NETADDR_ERR = 0x01,      //网络地址错误
    FRAME_SLAVEADDR_ERR = 0x02,    //从机地址错误
    FRAME_CRC_ERR = 0x03,          //CRC校验错误
    FRAME_EMPTY = 0xFF             //数据为空,此时没接到数据
}FrameStatus;

typedef struct 
{
    /**
     * 对于主机端来说,还可以在最前面添加各个从机的运行状态
     * 如:unsigned char SlaveStatus[256];
     * 每个数组成员都对应一个从机的状态,比如电量不足、通信异常等等
     * 这里没有添加
     * */  
    unsigned char Coils;        //线圈状态,Bit0对应继电器1,Bit1对应继电器2
    unsigned char Temperature;  //环境温度
    unsigned char Humidity;     //环境湿度
    unsigned short int Lux;     //环境光照强度
    /*可继续添加其他传感器、被控单元和系统参数*/
}DeviceBlock;

void sendMasterAsk(unsigned char slave_addr,unsigned char op_code,unsigned char pram);
FrameStatus receiveSlaveAck(unsigned char slave_addr,unsigned char op_code,unsigned char pram,DeviceBlock * pdevblock);
FrameStatus processMasterAsk(DeviceBlock * pdevblock);

#endif


nodebus.c

#include "NodeBus.h"
#include "SX1278/SX1278.h"
#include "UART/uart.h"

/**
* 功能:根据ModBus规则计算CRC16
* 参数:
*       _pBuf:待计算数据缓冲区,计算得到的结果存入_pBuf的最后两字节
*       _usLen:待计算数据长度(字节数)
* 返回值:16位校验值
*/
static unsigned short int getModbusCRC16(unsigned char *_pBuf, unsigned short int _usLen)
{
	unsigned short int CRCValue = 0xFFFF;  			//初始化CRC变量各位为1
	unsigned char i,j;

	for(i=0;i<_usLen;++i)
	{
		CRCValue  ^= *(_pBuf+i);       			    //当前数据异或CRC低字节
		for(j=0;j<8;++j)                            //一个字节重复右移8次
		{
			if((CRCValue & 0x01) == 0x01)           //判断右移前最低位是否为1
			{
				 CRCValue = (CRCValue >> 1)^0xA001; //如果为1则右移并异或表达式
			}else 
			{
				CRCValue >>= 1;                     //否则直接右移一位
			}			
		}

	} 

    if(CRCValue&0xFF==0)                            //保证CRC最后一个字节不为零
    {
        CRCValue |= 0xA5;
    }
    return CRCValue;            
} 

/**
* 功能:计算数组中有效数据的长度
* 参数:
*       pbuffer:待计算数据数组
*       buffer_len:该数组的长度
* 返回值:数组buffer中有效数据个数
*/
static unsigned char getFrameLength(unsigned char* pbuffer,unsigned char buffer_len)
{
    unsigned char len = buffer_len-1;   //得到数组最后一个数据的索引

    while(len)                          //向前推算非零数据
    {
        if(*(pbuffer+len)!=0)
        {
            break;
        }
        --len;
    }
    return len+1;                       //有效数据长度
}

/**
* 功能:发送数据指令
* 参数:
*       slave_addr:从机地址
*       op_code:操作码
*       pram:操作码参数
* 返回值:None
*/
void sendMasterAsk(unsigned char slave_addr,unsigned char op_code,unsigned char pram)
{
    /*发送数据缓冲区,其大小根绝实际情况设置,本例程为6*/
    unsigned char sendbuffer[6] = {NET_ADDR,slave_addr,op_code,pram,0,0};
    unsigned short int CRC16 = getModbusCRC16(sendbuffer,4);              //计算CRC值

    sendbuffer[4] = CRC16>>8;                                             //赋值CRC高位
    sendbuffer[5] = CRC16;                                                //赋值CRC低位
    
    transmitPackets(sendbuffer,sizeof(sendbuffer));                       //发送数据缓冲区
}

/**
* 功能:发送数据指令
* 参数:
*       slave_addr:从机地址
*       op_code:操作码
*       pram:操作码参数
*       pdevblock:设备数据块
* 返回值:处理状态
*/
FrameStatus receiveSlaveAck(unsigned char slave_addr,unsigned char op_code,unsigned char pram,DeviceBlock * pdevblock)
{
    /*接收数据缓冲区,其大小根绝实际情况设置,本例程最大值为9*/
    unsigned char receivebuffer[9];
    unsigned char len;
    unsigned char i;

    if(receivePackets(receivebuffer)==1) //收到数据
    {
        if(receivebuffer[0] != NET_ADDR) //不是本网络数据,扔掉
        {
            return FRAME_NETADDR_ERR;
        }

        if(receivebuffer[1] != slave_addr)//不是目标从机发送的数据,扔掉
        {
            return FRAME_SLAVEADDR_ERR;
        }

        len = getFrameLength(receivebuffer,sizeof(receivebuffer));
        if(getModbusCRC16(receivebuffer,len-2) != (receivebuffer[len-2]<<8 | receivebuffer[len-1]))//校验值不对数据无效扔掉
        {
            return FRAME_CRC_ERR;
        }

        /*一切正常开始处理数据*/
        if(op_code==OP_W_COILS)           //此时是写线圈(继电器)操作
        {
            (pdevblock+slave_addr)->Coils = receivebuffer[3];//
        }else if(op_code==OP_R_SENSOR)    //此时是读寄存器操作
        {
            /**
             * 该函数传入的应该是一个DeviceBlock类型的数组,每个从机对应一个DeviceBlock类型的数组元素
             */
            for(i=0;i<8;++i)
            {

                switch(pram & (0x01<<i))
                {
                    case PRAM_R_TEMPERATURE:(pdevblock+slave_addr)->Temperature = receivebuffer[3];                break;
                    case PRAM_R_HUMIDITY   :(pdevblock+slave_addr)->Humidity = receivebuffer[4];                   break;
                    case PRAM_R_LUX        :(pdevblock+slave_addr)->Lux = receivebuffer[5]<<8 | receivebuffer[6];  break;

                    default                :                                                                       break;
                }                           
            }
        }else 
        {
            /*其他操作码可在此扩充*/
        }
        return FRAME_OK;                 //接收数据成功
    }else
    {
        /**
         * 没收到从机发送过来的数据,此时的状态可能是处于等待消息阶段,
         * 当长时间没有收到数据后,可以命令从机重发或者标注该从机出现问题 
         */
        return FRAME_EMPTY;                                         
    }

    return FRAME_EMPTY;                  //不会执行到这里,添加该语句可以避免警告
}

/**
* 功能:子设备处理函数
* 参数:
*       pdevblock:设备数据块
* 返回值:处理状态
*/
FrameStatus processMasterAsk(DeviceBlock * pdevblock)
{
    unsigned char Askbuffer[6];
    unsigned char Ackbuffer[9] = {NET_ADDR,SLAVE1_ADDR};
    unsigned char len;
    unsigned short int CRC16;
    unsigned char i;

    if(receivePackets(Askbuffer)==1) //收到数据
    {
        if(Askbuffer[0] != NET_ADDR) //不是本网络数据,扔掉
        {
            return FRAME_NETADDR_ERR;
        }

        if(Askbuffer[1] != SLAVE1_ADDR)//不是目标从机发送的数据,扔掉
        {
            return FRAME_SLAVEADDR_ERR;
        }

        len = getFrameLength(Askbuffer,sizeof(Askbuffer));
        if(getModbusCRC16(Askbuffer,len-2) != (Askbuffer[len-2]<<8 | Askbuffer[len-1]))//校验值不对数据无效扔掉
        {
            return FRAME_CRC_ERR;
        }

        if(Askbuffer[2]==OP_W_COILS)
        {
            Ackbuffer[2] = OP_W_COILS;
            pdevblock->Coils = Askbuffer[3];
            Ackbuffer[3] = pdevblock->Coils;
            CRC16 = getModbusCRC16(Ackbuffer,4);
            Ackbuffer[4] = CRC16>>8;
            Ackbuffer[5] = CRC16;
        }else if(Askbuffer[2]==OP_R_SENSOR)
        {
            Ackbuffer[2] = OP_R_SENSOR;
            for(i=0;i<8;++i)
            {
                switch(Askbuffer[3] & (0x01<<i))
                {
                    case PRAM_R_TEMPERATURE:Ackbuffer[3] = pdevblock->Temperature;break;
                    case PRAM_R_HUMIDITY   :Ackbuffer[4] = pdevblock->Humidity;   break;
                    case PRAM_R_LUX        :{
                                                Ackbuffer[5] = pdevblock->Lux>>8;
                                                Ackbuffer[6] = pdevblock->Lux;
                                            }                                     break;

                    default                :                                      break;
                }
            }

            CRC16 = getModbusCRC16(Ackbuffer,7);
            Ackbuffer[7] = CRC16>>8;
            Ackbuffer[8] = CRC16;

        }else 
        {
            /*其他操作码可在此扩充*/
        }
		
        transmitPackets(Ackbuffer,sizeof(Ackbuffer));
        return FRAME_OK;
    }else 
    {
        return FRAME_EMPTY; 
    }  

    return  FRAME_EMPTY;    //不会执行到这里,添加该语句可以避免警告
}

main。c

/******************************************************************
 * 文件:main.c
 * 功能:主函数入口
 * 日期:2018-02-16
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 官博:http://fengmeitech.club
 * Copyright (C) 2017 zx. All rights reserved.
*******************************************************************/
#include "DELAY/Delay.h"
#include "ADC/ADC.h"
#include "LED/LED.h"
#include "KEY/key.h"
#include "UART/uart.h"
#include "IIC/IIC.h"
#include "OLED/OLED.h"
#include "SPIx/SPIx.h"
#include "SX1278/SX1278.h"
#include "NodeBus.h"

DeviceBlock DeviceBlock_StructureArray[2];

int main(void)
{
    u8 keyvalue;
    u8 i = 0;
	u8 j = 0;

	/*初始化各外设*/ 
    initSysTick();  
	initADC();
	initLED();
	initUART();
    initKey();
	initIIC();
    initOLED();

    initSPIx(SPI2);
    initSX1278();

	formatScreen(0x00);
    for(i=0;i<=128;i+=2)  //风媒电子LOGO从左向右动态显示
    {
		showImage(0,0,i,8,FM_LOGO_ENUM);
    }
	formatScreen(0x00);

    showCNString(32,0,"风媒电子",FONT_16_CN);
	showString(0,2,"Hum :",FONT_16_EN);
    showString(0,4,"Temp:",FONT_16_EN);
    showString(0,6,"Lux :",FONT_16_EN);

    while (1)
    {
        if(++i==40) //3S采集一次从机数据
        {
			i=0;
			sendMasterAsk(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL);//主机发送指令
			receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray);//接收从机数据			
			Delay_ms(100);
			while(receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray)!=FRAME_OK && ++i<10)//等待从机响应
			{
				Delay_ms(100);
			}
			i = 0;
		}

        keyvalue = getKeyValue(KEY_RELEASE);//获取键值

        /*根据键值做出相应控制动作*/
        if(keyvalue==KEY_UP)
        {
			j=0;
			DeviceBlock_StructureArray[SLAVE1_ADDR].Coils ^= 0x01; 
            sendMasterAsk(SLAVE1_ADDR,OP_W_COILS,DeviceBlock_StructureArray[SLAVE1_ADDR].Coils);
			receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray);		
			Delay_ms(100);
			while(receiveSlaveAck(SLAVE1_ADDR,OP_W_COILS,0,DeviceBlock_StructureArray)!=FRAME_OK && ++j<30)
			{
				Delay_ms(100);
			}
        }else if(keyvalue==KEY_DOWN)
        {
			j=0;
			DeviceBlock_StructureArray[SLAVE1_ADDR].Coils ^= 0x02; 
            sendMasterAsk(SLAVE1_ADDR,OP_W_COILS,DeviceBlock_StructureArray[SLAVE1_ADDR].Coils);
			receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray);
			Delay_ms(100);
			while(receiveSlaveAck(SLAVE1_ADDR,OP_W_COILS,0,DeviceBlock_StructureArray)!=FRAME_OK && ++j<30)
			{
				Delay_ms(100);
			}
        }else if(keyvalue==KEY_ALL)
        {
			j=0;
			DeviceBlock_StructureArray[SLAVE1_ADDR].Coils ^= 0x03; 
            sendMasterAsk(SLAVE1_ADDR,OP_W_COILS,DeviceBlock_StructureArray[SLAVE1_ADDR].Coils);
			receiveSlaveAck(SLAVE1_ADDR,OP_R_SENSOR,PRAM_R_ALL,DeviceBlock_StructureArray);
			Delay_ms(100);
			while(receiveSlaveAck(SLAVE1_ADDR,OP_W_COILS,0,DeviceBlock_StructureArray)!=FRAME_OK && ++j<30)
			{
				Delay_ms(100);
			}
        }else
        {

        }

        /*显示传感器数据*/
        showNumber(40,2,DeviceBlock_StructureArray[SLAVE1_ADDR].Humidity,DEC,3,FONT_16_EN);
        showNumber(40,4,DeviceBlock_StructureArray[SLAVE1_ADDR].Temperature,DEC,3,FONT_16_EN);
        showNumber(40,6,DeviceBlock_StructureArray[SLAVE1_ADDR].Lux,DEC,5,FONT_16_EN);  

        toggleLED();
        Delay_ms(50);
	}
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值