1. STM32复刻西门子PLC双串口方案解析
在工业控制领域,西门子S7-200系列PLC因其稳定性和易用性广受欢迎,但原装设备价格较高。最近开源社区出现了一种基于STM32的复刻方案,特别是支持双串口的224XP版本引起了广泛关注。这个方案的核心价值在于:
- 采用STM32F103RCT6作为主控,成本仅为原装PLC的1/5
- 通过宏定义实现224XP和226型号的灵活切换
- 双RS232串口设计支持编程软件和触摸屏同时在线调试
- DMA驱动的串口通信确保数据传输稳定性
2. 硬件架构设计要点
2.1 核心芯片选型
方案选用STM32F103RCT6作为主控芯片,主要考虑以下特性:
- 72MHz主频满足实时控制需求
- 256KB Flash + 48KB RAM空间充足
- 内置2个DMA控制器共12个通道
- 3个USART接口满足双串口需求
- 51个GPIO可配置为数字输入/输出
实际应用中,VCT6型号也可兼容,两者主要差异在于封装形式(RCT6为LQFP64,VCT6为LQFP100)
2.2 双串口硬件设计
串口配置采用以下方案:
- USART1:连接编程软件(STEP7-MicroWIN)
- USART3:连接HMI触摸屏
- 电平转换芯片使用MAX3232CSE
- 每个串口独立DMA通道:
- USART1_TX → DMA1_Channel4
- USART1_RX → DMA1_Channel5
- USART3_TX → DMA1_Channel2
- USART3_RX → DMA1_Channel3
这种设计避免了传统PLC单串口调试时需要频繁插拔的问题,实测可同时进行:
- 程序下载和在线监控
- 触摸屏数据交互
- Modbus RTU从站通信
3. 软件实现关键技术
3.1 型号切换机制
通过预编译宏实现硬件抽象层:
c复制// 型号选择开关
#define IS_CPU224XP 1 // 1:224XP模式 0:226模式
#if IS_CPU224XP
#define IO_GROUP_NUM 4 // 224XP有4组IO
#define PWM_CHANNELS 2 // 224XP支持2路PWM
#else
#define IO_GROUP_NUM 6 // 226有6组IO
#define PWM_CHANNELS 4 // 226支持4路PWM
#endif
这种设计带来三大优势:
- 无需硬件修改即可切换型号
- 编译时自动优化掉未使用代码
- 避免运行时判断带来的性能损耗
3.2 DMA串口优化实现
3.2.1 发送配置
以USART1发送为例:
c复制void USART1_DMA_Config(void) {
DMA_InitTypeDef dma;
DMA_DeInit(DMA1_Channel4); // USART1_TX
dma.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
dma.DMA_MemoryBaseAddr = (uint32_t)uart1_tx_buffer;
dma.DMA_DIR = DMA_DIR_PeripheralDST; // 内存到外设
dma.DMA_BufferSize = UART_BUF_SIZE;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Normal;
DMA_Init(DMA1_Channel4, &dma);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
}
关键参数说明:
DMA_Mode_Normal:单次传输模式DMA_PeripheralDataSize_Byte:按字节传输USART_DMAReq_Tx:使能发送DMA请求
3.2.2 接收处理
利用IDLE中断实现帧结束检测:
c复制void USART3_IRQHandler(void) {
if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET) {
USART_ReceiveData(USART3); // 清中断
DMA_Cmd(DMA1_Channel2, DISABLE);
uint16_t recv_len = USART3_RX_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel2);
process_data(recv_len); // 协议解析
DMA_SetCurrDataCounter(DMA1_Channel2, USART3_RX_BUF_SIZE);
DMA_Cmd(DMA1_Channel2, ENABLE);
}
}
相比传统超时检测,IDLE中断方案具有:
- 响应速度快(硬件自动检测)
- 不受波特率影响
- 准确判断帧间隔
4. 通信协议实现
4.1 PPI协议解析
与STEP7-MicroWIN通信采用精简PPI协议:
- 波特率:9600bps
- 数据格式:1起始位+8数据位+1停止位
- 帧结构:
字段 长度 说明 起始符 1字节 0x68 长度 1字节 数据区长度 目标地址 1字节 PLC站地址 源地址 1字节 PC站地址(通常为0) 功能码 1字节 操作类型 数据区 N字节 具体参数 FCS 1字节 校验和
4.2 Modbus RTU从站
触摸屏通信采用Modbus RTU协议:
- 波特率:19200bps
- 站地址:1
- 支持功能码:
- 0x03:读保持寄存器
- 0x06:写单个寄存器
- 0x10:写多个寄存器
寄存器映射示例:
| 地址 | 类型 | 说明 |
|---|---|---|
| 0x0000 | WORD | 数字量输入状态 |
| 0x1000 | WORD | 数字量输出状态 |
| 0x4000 | FLOAT | 模拟量输入1 |
| 0x4002 | FLOAT | 模拟量输入2 |
5. 工程实践技巧
5.1 调试注意事项
- 上电顺序:先接PLC电源,再连接编程电缆
- 波特率匹配:确保所有设备波特率设置一致
- 终端电阻:长距离通信时在末端加120Ω电阻
- 接地处理:所有设备共地,避免电势差导致通信异常
5.2 性能优化建议
- 将频繁访问的变量定义为
__IO类型 - 关键代码段使用
__asm volatile("nop")插入空指令保证时序 - 启用编译优化选项-O2提升执行效率
- 定期调用
__DMB()保证内存操作顺序
5.3 常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法连接编程软件 | 波特率不匹配 | 检查PC和PLC波特率设置 |
| 触摸屏通信断续 | 线路干扰 | 使用双绞屏蔽线,缩短通信距离 |
| 数据读写错误 | 寄存器地址偏移 | 检查Modbus地址映射表 |
| 频繁死机 | 堆栈溢出 | 调整启动文件中的堆栈大小 |
6. 扩展功能实现
6.1 内置PID算法应用
源码中集成了位置式PID控制器:
c复制typedef struct {
float Kp, Ki, Kd;
float integral;
float last_error;
} PID_Controller;
float PID_Compute(PID_Controller *pid, float setpoint, float input) {
float error = setpoint - input;
pid->integral += error;
float derivative = error - pid->last_error;
pid->last_error = error;
return pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
}
应用示例 - 温度控制:
- 配置定时器中断(如1ms周期)
- 在中断中读取温度传感器
- 调用PID计算输出值
- 通过PWM驱动加热元件
6.2 自定义功能块开发
通过以下步骤扩展新功能:
- 在
user_fb.c中添加功能实现 - 在
user_fb.h中声明接口函数 - 在
plc_main.c中注册功能块 - 重新编译下载固件
典型功能块模板:
c复制// 功能块数据结构
typedef struct {
BOOL EN; // 使能端
BOOL EN_OUT; // 使能输出
// 添加自定义参数
} FB_Example;
// 功能块执行函数
void FB_Example_Run(FB_Example *fb) {
if(!fb->EN) {
fb->EN_OUT = FALSE;
return;
}
// 功能实现代码
fb->EN_OUT = TRUE;
}
这个方案最实用的地方在于将工业级PLC的功能平民化,实测在以下场景表现优异:
- 小型自动化设备控制
- 教学实验平台
- 传统设备改造
- 原型机快速开发
移植时需要注意硬件IO的兼容性,建议先用开发板验证关键功能再制作定制PCB。源码中的匈牙利命名法确实增加了阅读难度,可以采用以下改进策略:
- 使用typedef定义更有意义的类型名
- 通过宏定义简化长变量名
- 添加详细的注释说明
