开源PLC学习笔记17(开源PLC与组态软件通讯MODBUS)——2013_12_11
从freemodbus的阴影中逃了出来,现在需要把modbus加入到开源PLC中了。首先,利用笔记13中的方法,逐步添加。但是因为STC12系列无法通过PROTEUS仿真,不过找到了内部含有EEPROM并且可以PROTEUS仿真的51,
《单片机C语言程序设计实训100例——基于8051+Proteus仿真(第2版)》25 单片机内置EEPROM读写测试仿真
这样就可以仿真了,然后把笔记15中的代码加入,过程比想象地要简单很多。
输入的命令是03040415
复习一下,
03040415 会被分解成 0403 和 1504
0403:第一个0是散转函数的下标,表示LD命令,403表示X3,是第4个开关;
1504:第一个1是散转函数的下标,表示OUT命令,504表示Y3,是第5个LED;
即 LD X3
OUT Y4
然后,先利用组态王
设置按照http://www.chinabaike.com/z/gyzd/877961.html
这样组态王的开关就可以控制X3,从而间接控制Y4。
sbit LED0 = P0^0; // 对应线圈0
sbit LED1 = P0^1; // 对应线圈1
sbit LED2 = P0^2; // 对应线圈2
sbit LED3 = P0^3; // 对应线圈3
sbit LED4 = P0^4; // 对应线圈4
sbit LED5 = P0^5; // 对应线圈5
sbit LED6 = P0^6; // 对应线圈6
sbit LED7 = P0^7; // 对应线圈7
sbit KEY0 = P1^0;
sbit KEY1 = P1^1;
sbit KEY2 = P1^2;
sbit KEY3 = P1^3;
sbit KEY4 = P1^4;
sbit KEY5 = P1^5;
sbit KEY6 = P1^6;
sbit KEY7 = P1^7;
并且在设置线圈函数中,主要对KEY进行操作
//设定线圈状态 返回0表示成功
INT16U setCoilVal(INT16U addr, INT16U tempData)
{
INT16U result = 0;
INT16U tempAddr;
tempAddr = addr & 0xfff;
switch(tempAddr) // & 0xff
{
case 0:
if (tempData)
KEY0 = 1;
else
KEY0 = 0;
break;
case 1:
if (tempData)
KEY1 = 1;
else
KEY1 = 0;
break;
case 2:
if (tempData)
KEY2 = 1;
else
KEY2 = 0;
break;
case 3:
if (tempData)
KEY3 = 1;
else
KEY3 = 0;
break;
case 4:
if (tempData)
KEY4 = 1;
else
KEY4 = 0;
break;
case 5:
if (tempData)
KEY5 = 1;
else
KEY5 = 0;
break;
case 6:
if (tempData)
KEY6 = 1;
else
KEY6 = 0;
break;
case 7:
if (tempData)
KEY7 = 1;
else
KEY7 = 0;
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
case 14:
break;
case 15:
break;
case 16:
break;
case 17:
break;
default:
break;
}
return result;
}
进行仿真,
从中可以看出,组态王设置线圈状态是没有问题的,但是查询线圈状态,组态王发出的命令总是01 01 01 00 。。。。不是LED所对应的地址,目前还不知道如何解决。
另外,为了简洁和集中重点,命令输入通讯还没加入。
添加通讯,只添加写命令
void FX1NProcessing(void)
{
unsigned char i;
unsigned char WriteLen=0;
unsigned intWriteAddr=0;
if(UDRFlag) // 有数据来
{
UDRFlag=0;
if(Buffer==ENQ) // 发送请求 ==== 1. 3. 5. 7. 10. 12. 14.(14开始下发数据)
{
UartSendByte(ACK);
}
else if(STXETX) // 可识别的
{
if(E11)
{
// 计算得到写入字节数:
for(i=8;i<10;i++)Buffer=ascto0F(Buffer);
Buffer<<=4;
WriteLen=(Buffer+Buffer);
// 计算得到写入地址:
for(i=4;i<8;i++)Buffer=ascto0F(Buffer);
WriteAddr =Buffer<<12;
WriteAddr+=Buffer<<8;
WriteAddr+=Buffer<<4;
WriteAddr+=Buffer;
// if(WriteAddr==0x8000)ErasurePLC(ErasureCODE); // 擦除PLC程序区
WriteFlash(WriteAddr,(unsigned char *)(Buffer+10),(unsigned char)WriteLen); // 写 flash
step=WriteLen;
UartSendByte(ACK);
}
}
UartReceiveCounter=0;
REN=1;
}
}
省去了和检验,
因为采用串口助手,写入命令02 45 31 31 30 30 30 30 30 34 30 32 30 34 30 32 31 35 03 33 33,最后两个随意
表示STX E 1 1 0 0 0 0 0 4 0 2 0 4 0 2 1 5 ETX 3 3
即在0000地址写入 LD X2
OUT Y2
主函数也更改为
#include "system.h"
unsigned char command[]={'0','3','0','4','0','4','1','5'};
void main(void)
{
SYSTEM_DISABLE_INTERRUPT();
UartInit();
TimerInit();
SYSTEM_ENABLE_INTERRUPT();
WriteFlash(IAP_ADDRESS,(unsigned char*)(command),4);
step=4;
while (1)
{
FX1NProcessing();
//更新IO端口,必须
RefreshIO();
//PLC执行去找二当家的,当老大就是好
main_PLC();
timerProc();
checkComm0Modbus();//检测modbus帧
}
}
mark下!{:lol:}【开源PLC与组态软件通讯MODBUS)】 {:shocked:}不是很明白组态,,,收藏先
页:
[1]