用的是51普中开发板
功能主要就是接收串口发送过来的信息,
然后根据接收到的信息执行不同的操作,
上位机部分链接:http://t.csdn.cn/evEle
先附上源码链接:(3条消息) 【免费】c#上位机(温室监控系统源码)资源-CSDN文库
通信协议采用modbusRTU
为了能方便的处理数据,在代码中把用到的管脚全都映射到数组上
本文主要介绍了一个用于温室监控系统的代码。该代码使用了多个库文件,包括"Delay.h"、"UART.h"、"DS18B20.h"、"Tool.h"和"Buzzer.h"等等。在代码中定义了一些函数和变量,用于处理Modbus通信、读写线圈和寄存器等操作。
以下是代码中定义的一些重要函数和变量的解析:
- 函数
crc_cal_value:用于计算CRC校验值。
- 函数
ModbusCpu:用于处理接收到的Modbus报文。
- 函数
CoilMapper:将Coils数组中的数据映射到对应的GPIO口。
- 函数
writeCoils:用于写入线圈状态。
- 函数
readCoilsStatus:读取指定范围内的线圈状态。
- 函数
RegistersMapper:更新寄存器数据,包括读取温度和设置报警功能。
- 函数
TemperatureAlarmSetting:根据温度设置触发报警功能。
- 函数
resultKeepRegister:返回指定范围内的寄存器数据。
- 函数
SetSingleKeepRegister:设置单个寄存器的值。
- 函数
UART_Routine:串口中断处理程序,用于接收数据。
- 变量
SlaveAddr:Modbus从机的地址。
- 变量
Message:用于接收Modbus报文的数组。
- 变量
Coils:存储线圈状态的数组。
- 变量
Registers:存储寄存器数据的数组。
主函数中初始化了串口和温度传感器,并设定了报警温度的上限和下限。然后进入了一个死循环,在循环中调用了CoilMapper和RegistersMapper函数,实现了对线圈和寄存器的处理和更新。
#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
#include "DS18B20.h"
#include "Tool.h"
#include "Buzzer.h"
//*************************************************** 函数
unsigned int crc_cal_value(unsigned char* data_value, unsigned char data_length);
void ModbusCpu();
void CoilMapper();
void writeCoils(int CoilsAddr,int onoff);
void readCoilsStatu(int startAddr,int coilsCount);
void RegistersMapper();
void resultKeepRegister(int StartAddr,int RegisterDataPort);
void TemperatureAlarmSetting(int* T);
void SetSigleKeepRegister(int StartAddr,int Value);
//***************************************************
char SlaveAddr=0x01;
unsigned char Message[8]={0x01,0x03,0x00,0x00,0x00,0x01};//用于接收报文
int mesgIndex=0;
unsigned int CRC;
char Coils[32];//线圈
int Registers[4];//寄存器
void main()
{
DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
Delay(500);
UART_Init(); //串口初始化
Registers[1]=50;//报警温度上限
Registers[2]=-40;//报警温度下限
while(1)
{
CoilMapper();
RegistersMapper();
}
}
void ModbusCpu()//处理接收到的报文
{
CRC=crc_cal_value(Message,sizeof(Message)-2);
if(Message[6]==(unsigned char)CRC && Message[7]==(unsigned char)(CRC>>8))//验证CRC 验证接收到的数据是否正确
{
int Count;
int Addr=(Message[2]<<8);//
Addr|=Message[3];
Count=(Message[4]<<8);
Count|=Message[5];
switch(Message[1])//判断功能码
{
case 0x05:writeCoils(Addr,Message[4]==0xFF?1:0);
break;
case 0x01:readCoilsStatu(Addr,Count);
break;
case 0x03:resultKeepRegister(Addr,Count);
break;
case 0x06:SetSigleKeepRegister(Addr,Count);//this Count is Value
break;
}
}
}
void writeCoils(int CoilsAddr,int onoff)
{
if(CoilsAddr>=sizeof(Coils)||CoilsAddr<0)
return;
Coils[CoilsAddr]=onoff;
}
void readCoilsStatu(int startAddr,int coilsCount)
{
unsigned int crc;
int datalen=((coilsCount/8)+(coilsCount%8>0?1:0));
int retuleMsgLenth=3;
unsigned char retuleMsg[sizeof(Coils)+3];
char i=0;
char temp=0x00;//表示一个字节的数据(表示8个线圈)
char tempIndex=1;
retuleMsg[0]=SlaveAddr;
retuleMsg[1]=0x01;
retuleMsg[2]=(char)datalen;
for(i=startAddr;i<(startAddr+coilsCount);i++)
{
if(i>=sizeof(Coils))break;
temp|=(Coils[i]<<tempIndex++);
if(tempIndex>=9)
{
tempIndex=1;
retuleMsg[retuleMsgLenth++]=temp;
}
}
if(tempIndex!=1 && tempIndex<=8)
{
retuleMsg[retuleMsgLenth++]=temp;
}
crc =crc_cal_value(retuleMsg,retuleMsgLenth);
retuleMsg[retuleMsgLenth++]=(unsigned char)crc;
retuleMsg[retuleMsgLenth++]=(unsigned char)(crc>>8);
SendMessage(retuleMsg,retuleMsgLenth);
}
void RegistersMapper()
{
int T=0;
DS18B20_ConvertT(); //转换温度
T=DS18B20_ReadT(); //读取温度
TemperatureAlarmSetting(&T);
Registers[0]=T;
}
void TemperatureAlarmSetting(int* T)
{
if(*T>Registers[1]||*T<Registers[2])
{
Buzzer_Time(100);
}
}
void resultKeepRegister(int StartAddr,int RegisterDataPort)
{
char i=0;
unsigned int crc;
unsigned char retuleMsg[sizeof(Registers)+3];
char retuleMsgLenth=3;
retuleMsg[0]=SlaveAddr;
retuleMsg[1]=0x03;
retuleMsg[2]=((char)RegisterDataPort)*2;
for(i=StartAddr;i<(StartAddr+RegisterDataPort);i++)
{
if(i<0||i>=sizeof(Registers))break;
retuleMsg[retuleMsgLenth++]=Registers[i]>>8;//高位
retuleMsg[retuleMsgLenth++]=(Registers[i]<<8)>>8;//低位
}
crc =crc_cal_value(retuleMsg,retuleMsgLenth);
retuleMsg[retuleMsgLenth++]=(unsigned char)crc;
retuleMsg[retuleMsgLenth++]=(unsigned char)(crc>>8);
SendMessage(retuleMsg,retuleMsgLenth);
}
void SetSigleKeepRegister(int StartAddr,int Value)
{
if(StartAddr<0||StartAddr>sizeof(Registers))return;
Registers[StartAddr]=Value;
}
void UART_Routine() interrupt 4
{
if(RI==1) //如果接收标志位为1,接收到了数据
{
// P2=~SBUF; //读取数据,取反后输出到LED
if(mesgIndex>=8)return;
Message[mesgIndex]=SBUF;//
mesgIndex++;
if(mesgIndex>=8)
{
mesgIndex=0;
ModbusCpu();
}
RI=0; //接收标志位清0
}
}
void CoilMapper()
{
P0_0=Coils[0];
P0_1=Coils[1];
P0_2=Coils[2];
P0_3=Coils[3];
P0_4=Coils[4];
P0_5=Coils[5];
P0_6=Coils[6];
P0_7=Coils[7];
P1_0=Coils[8];
P1_1=Coils[9];
P1_2=Coils[10];
P1_3=Coils[11];
P1_4=Coils[12];
P1_5=Coils[13];
P1_6=Coils[14];
P1_7=Coils[15];
P2_0=Coils[16]==1?0:1;
P2_1=Coils[17]==1?0:1;
P2_2=Coils[18]==1?0:1;
P2_3=Coils[19]==1?0:1;
P2_4=Coils[20]==1?0:1;
P2_5=Coils[21]==1?0:1;
P2_6=Coils[22]==1?0:1;
P2_7=Coils[23]==1?0:1;
}
该代码实现了一个基本的温室监控系统,使用了Modbus通信协议,并通过GPIO口控制了线圈状态和读取了温度传感器数据。读取的数据进行相应的处理,如报警功能等。在主函数中将不断循环执行这些功能,实现了温室监控系统的基本功能。
以上是对给定代码的简要解析,希望对你有所帮助。如有任何疑问,请随时向我提问。