AI单片机做PLC
我是做工控行业的,最初看到 PLC 开帖预告——让你的 32位8051 成为一个合格的潜伏者 FX3U ,PLC-教程已上线! 火... [复制链接] 很激动,一直关注着,后来慢慢凉了。这位版主只是公开了通信的源码部分,赚了一波流量。真正处理PLC指令的核心部分到现在没有发表。后来我看了论坛里面很多关于单片机模拟PLC的帖子。要么是广告要么是引流。么有几个真正的把源码和思路开源的。估计也是因为商业利益的关系。我在网上搜罗了很多关于单片机模拟PLC的资料,选两份靠谱的分享出来,希望改群里面的大神做参考,假以时日我们能看到开源的STC做PLC的成功案例。首先声明,资料来自网络,仅用于参考学习,不可用于商业目的。switch(*PLC_Addr/0x100) // 取高8位的数据
{
case 0x06: operation_T(),PLC_Addr++; break;//operation all timer
case 0x0E: operation_C(),PLC_Addr++; break;//
/* 操作S位元件所有的函数 */
case 0x20: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x30: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x40: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x50: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x60: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x70: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作S位元件所有的函数 */
case 0x21: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x31: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x41: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x51: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x61: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x71: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作S位元件所有的函数 */
case 0x22: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x32: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x42: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x52: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x62: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x72: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作S位元件所有的函数 */
case 0x23: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x33: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x43: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x53: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x63: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x73: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作X位元件所有的函数 */
case 0x24: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x34: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x44: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x54: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x64: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x74: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作Y位元件所有的函数 */
case 0x25: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x35: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x45: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x55: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x65: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x75: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XC5: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XD5: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XE5: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作T位元件所有的函数 */
case 0x26: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x36: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x46: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x56: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x66: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x76: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XC6: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作T位元件所有的函数 */
case 0x27: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x37: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x47: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x57: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x67: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x77: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XC7: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作M0_255位元件所有的函数 */
case 0x28: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x38: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x48: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x58: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x68: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x78: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XC8: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XD8: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XE8: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作M256_511位元件所有的函数 */
case 0x29: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x39: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x49: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x59: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x69: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x79: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XC9: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XD9: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XE9: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作M512_767位元件所有的函数 */
case 0x2A: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x3A: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x4A: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x5A: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x6A: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x7A: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XCA: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XDA: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XEA: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作M768_1023位元件所有的函数 */
case 0x2B: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x3B: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x4B: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x5B: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x6B: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x7B: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XCB: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XDB: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XEB: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作M1024_1279位元件所有的函数 */
case 0x2C: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x3C: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x4C: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x5C: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x6C: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x7C: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XCC: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XDC: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XEC: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作M1280_1535位元件所有的函数 */
case 0x2D: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x3D: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x4D: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x5D: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x6D: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x7D: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XCD: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XDD: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XED: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/* 操作C0-C255位元件所有的函数 */
case 0x2E: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x3E: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x4E: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x5E: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x6E: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x7E: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/*m8000-m8255*/
case 0x2F: LD(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x3F: LDI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x4F: AND(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x5F: ANI(0X0FFF&*PLC_Addr),PLC_Addr++; break;
case 0x6F: OR(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0x7F: ORI(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XCF: OUT(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XDF: BIT_SET(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0XEF: RST(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
/**********************STL步进模式***************************/
case 0xF0: STL(0X0FFF&*PLC_Addr),PLC_Addr++; break;//S
case 0xF1: STL(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0xF2: STL(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
case 0xF3: STL(0X0FFF&*PLC_Addr),PLC_Addr++; break;//
////////////////////////////////////////////////////////
//基本逻辑指令二,如ANB、ORB、MPP、MRD、MPS、INV 等
case 0XFF:
{
other_function(*PLC_Addr);
PLC_Addr++;
break; //MPP,MPS
}
case 0xB0: //指针P标识
{
PLC_Addr++;
break;
}
case 0x00: //遇到0X001C为FEND,0X000F为END指令
{
再次强调,仅供学习,源码不可用于商业目的 关于STC单片机实现PLC功能的开源实践与架构设计探讨
尊敬的工控行业同仁:
针对您在工控领域对STC单片机实现PLC功能的探索诉求,笔者从嵌入式系统架构角度进行专业分析,并提出建设性技术路线建议。
一、PLC仿真系统的技术复杂性分析
1. 指令集解析层
需实现FX3U等主流PLC的113条基本指令及扩展指令,包括:
位操作指令(LD/LDI/OUT等)
定时器/计数器(T/C)的复合运算
数据寄存器(D/V/Z)的32位处理
浮点运算指令(DEADD/DESUB等)
2. 实时调度机制
需构建满足IEC 61131-3标准的任务调度器:
主循环周期控制在1ms级
中断事件响应时间enable && (t->current++ >= t->preset)) {
t->done = 1;
t->enable = 0;
}
}
```
四、工程化实施建议
1. 开发工具链配置
编译器:Keil C51 V9.60及以上
调试器:STC-ISP V6.88支持在线仿真
协议分析:Modbus Poll调试工具
2. 关键性能优化
中断嵌套机制优化:采用优先级分组策略
指令加速技术:对高频指令(如MOV/CMP)使用查表法
内存管理:采用xdata分页访问技术
3. 可靠性保障措施
看门狗电路:配置独立硬件WDT
内存校验:增加FLSRAM的CRC校验
故障安全模式:实现双备份寄存器组
五、开源实践路径建议
1. 分阶段开放架构
第一阶段:开放IO驱动层(BSD协议)
第二阶段:开放指令解析层(LGPL协议)
第三阶段:开放运行时系统(Apache协议)
2. 社区协作机制
建议建立标准化接口:
硬件抽象层(HAL):iohal.h
指令集层(ISA):plcisa.h
应用接口层(API):plclib.h
从技术实现角度,STC32G系列芯片凭借48MHz主频、32位数据处理能力和丰富外设接口,完全具备实现基础PLC功能的条件。建议关注以下技术指标:
单指令周期:83ns@48MHz
中断响应:
[本文内容由国芯人工智能辅助生成,仅供参考] 国芯人工智能 发表于 2025-5-12 14:03
关于STC单片机实现PLC功能的开源实践与架构设计探讨
尊敬的工控行业同仁:
正解 STM32方案很成熟了,直接用就行,没必要死磕STC。。。 {:4_174:} 感谢大佬的分享。不过现在PLC基本上都是CODESYS了,感觉就组态稍微方便一点。感慨一下:电气的拼命往高级语言靠近,电子的拼命往梯形图靠近。 有没有STC 单片机的 方案? 一直在找。
页:
[1]