STM32F系列兼容西门子S7 200PLC源码 CPU:STM32F103RCT6(或其他STM32F103系列大容量芯片) 开发平台:keilMDK5 PLC型号:CPU224XP或226

最近在搞嵌入式PLC开发的朋友肯定对STM32F103系列不陌生,这货简直就是工控领域的万金油。今天咱们就聊聊怎么用这颗芯片跑起西门子S7-200的PLC程序,直接拿STM32硬刚西门子祖传架构,这事儿听着刺激吧?

先扔个硬件配置镇楼:

  • 主控芯片:STM32F103RCT6(Flash容量256K,SRAM 48K,带USB/CAN)
  • 开发环境:Keil MDK5(经典到掉牙的ARM开发环境)
  • 目标型号:CPU224XP(数字量14入/10出,模拟量2入/1出)

!STM32F103RCT6引脚图

重点来了——IO映射这块得玩明白。西门子PLC的IO地址是固定编码的,咱们得在STM32里模拟这套寻址规则。看这段GPIO初始化的骚操作:

// 数字量输入配置
void DI_Config(void) {
    GPIO_InitTypeDef gpio;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    gpio.GPIO_Pin = 0x00FF; // PA0-PA7对应I0.0-I0.7
    gpio.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &gpio);
    
    // 扩展输入用PC0-PC3
    gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_Init(GPIOC, &gpio);
}

这段代码把PA0-PA7映射成PLC的I0.0-I0.7输入点,IPU模式(内部上拉)是重点,工业现场干扰大,上拉比浮空稳定得多。当年在产线调试时发现,不加这个上拉电阻,传感器信号能给你抖出迪斯科节奏...

STM32F系列兼容西门子S7 200PLC源码 CPU:STM32F103RCT6(或其他STM32F103系列大容量芯片) 开发平台:keilMDK5 PLC型号:CPU224XP或226

定时器才是PLC的心脏,西门子那个1ms的扫描周期不是盖的。用STM32的TIM2实现时间基准:

void TIM2_IRQHandler(void) {
    if(TIM_GetITStatus(TIM2, TIM_IT_Update)) {
        static uint16_t scan_cycle = 0;
        scan_cycle++;
        if(scan_cycle >= 1000) { // 1ms*1000=1s
            WatchDog_Feed(); // 喂狗操作
            scan_cycle = 0;
        }
        PLC_Runtime++; // 全局运行时长计数
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}

这个中断服务程序实现了两个关键功能:1ms级别的扫描周期累计和看门狗喂狗。注意那个PLC_Runtime变量,这玩意儿在梯形图程序里对应SM0.4/SM0.5这些特殊寄存器,搞过STEP7的都懂。

说到通讯协议,PPI协议是绕不过的坎。虽然官方没公开协议细节,但咱们可以抓包逆向。关键帧结构解析代码长这样:

uint8_t PPI_Frame_Analysis(uint8_t *buf) {
    if(buf[0] != 0x68) return 0; // 帧头校验
    uint8_t len = buf[1];
    if(len > 240) return 0; // 长度异常
    
    // 校验和计算
    uint8_t checksum = 0;
    for(uint8_t i=0; i<len+2; i++){
        checksum += buf[i];
    }
    if(checksum != buf[len+2]) return 0;
    
    // 提取有效数据
    memcpy(PPI_RxBuffer, &buf[4], len-2);
    return len-2;
}

这个校验算法当年可是用示波器抓了三天三夜的串口波形才摸清楚的。注意那个0x68帧头,西门子的设备在通讯启动时会先发这个魔数,跟TCP三次握手似的。

最后说下抗干扰处理,工业现场没你想的那么干净。在数字量输入部分加个软件滤波:

#define FILTER_DEPTH 5 // 5次采样表决

uint8_t DI_Filter(uint8_t channel) {
    static uint8_t history[8][FILTER_DEPTH] = {0};
    static uint8_t index = 0;
    
    uint8_t current_state = GPIO_ReadInputDataBit(di_port[channel], di_pin[channel]);
    history[channel][index] = current_state;
    
    // 多数表决算法
    uint8_t count = 0;
    for(uint8_t i=0; i<FILTER_DEPTH; i++){
        if(history[channel][i]) count++;
    }
    index = (index+1)%FILTER_DEPTH;
    return (count > FILTER_DEPTH/2) ? 1 : 0;
}

这个滤波算法能有效消除触点抖动,原理类似移动平均滤波。之前在变频器旁边测试时,不加滤波的误动作率高达30%,加上之后直接归零。

移植过程中最坑的是保持寄存器的掉电保存,STM32的Flash写入次数有限,直接照搬西门子的存储策略会快速写废芯片。后来改用EEPROM模拟算法,把写入操作分散到不同扇区,这才解决寿命问题。具体实现有空再展开说。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐