STM32版FX2N源码&原理图&PCB板(可直接移植) FX2N源码V3.8版的使用基本说明...
STM32版FX2N源码&原理图&PCB板(可直接移植) FX2N源码V3.8版的使用基本说明: 编译语言:C语言 FX2N源码V3.8版是根据三菱FX2N的PLC通信协议、通信命令以及基于STM32F103系列单片机上编写运行的程序,可以直接利用三菱编程软件编写梯形图下载运行,无需任何转换。 注:1)目前在STM32F103RD/STM32F103VC/STM32F103VD/STM32F103VE/STM32F103ZE测试通过; 2)本程序不完全支持所有梯形图指令,如果需要其他的功能,需要亲自己修改代码, 编译环境:Keil 4或者Keil5
这年头用STM32复刻PLC的项目不少,但能把三菱FX2N协议跑利索的真不多见。最近搞到个开源的FX2N_V3.8实现,实测确实能用三菱的GX Works2直接下载梯形图,这种无缝对接的骚操作必须得扒开代码看个明白。

先看硬件配置,原理图里STM32F103VE核心板外挂了SRAM和铁电存储器。重点在通信接口这块,源码里用USART1实现了三菱的编程口协议:
void PLC_Comm_Init(void)
{
GPIO_InitTypeDef gpio;
USART_InitTypeDef uart;
// 485方向控制引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
gpio.GPIO_Pin = GPIO_Pin_8;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &gpio);
// 串口配置:9600,8,N,1
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_Init(USART1, &USART_InitStructure);
}
这段配置有个坑点——需要外接MAX485芯片做电平转换,PCB文件里用的是PA8控制收发方向。实际调试时发现三菱编程软件对时序极其敏感,在发送应答帧前必须精准切换方向,否则分分钟握手失败。
指令解析是核心部分,项目里用状态机处理梯形图逻辑。比如处理MOV指令的代码段:
void Handle_MOV(uint16_t operand[])
{
uint16_t src = operand[0]; // 源操作数地址
uint16_t dest = operand[1]; // 目标地址
uint16_t val = GetRegister(src);
if(dest < D_MAX_ADDR) { // 数据寄存器范围检查
SetRegister(dest, val);
UpdateIOFlag(dest); // 触发IO更新标志
} else {
ExceptionHandler(ERR_ADDRESS);
}
}
这里有个取巧的设计——用GetRegister/SetRegister统一管理寄存器访问,不管是X/Y物理IO还是D/M软元件都走这套接口。实测发现处理速度比预期快,毕竟STM32F103的72MHz主频对PLC逻辑来说绰绰有余。

STM32版FX2N源码&原理图&PCB板(可直接移植) FX2N源码V3.8版的使用基本说明: 编译语言:C语言 FX2N源码V3.8版是根据三菱FX2N的PLC通信协议、通信命令以及基于STM32F103系列单片机上编写运行的程序,可以直接利用三菱编程软件编写梯形图下载运行,无需任何转换。 注:1)目前在STM32F103RD/STM32F103VC/STM32F103VD/STM32F103VE/STM32F103ZE测试通过; 2)本程序不完全支持所有梯形图指令,如果需要其他的功能,需要亲自己修改代码, 编译环境:Keil 4或者Keil5
移植时要注意的硬件差异主要集中在IO映射。比如在IO_Config.c里有这么一段:
const X_IO_MAP x_map[16] = {
{GPIOB, GPIO_Pin_0}, // X0
{GPIOB, GPIO_Pin_1}, // X1
//... 省略其他输入点配置
};
const Y_IO_MAP y_map[16] = {
{GPIOC, GPIO_Pin_12}, // Y0
{GPIOC, GPIO_Pin_11}, // Y1
//... 输出点配置
};
如果目标板子的外设引脚不同,改这里比改全局宏定义更安全。之前有个老哥直接把PCB的GPIO定义全改成自己的开发板,结果下载后输出点全乱,排查半天才发现Y7接的引脚被复用成SWD接口了...

项目里最骚的操作是模拟了FX2N的RUN/STOP开关。源码里用按键长按实现模式切换:
void Check_Mode_Switch(void)
{
static uint8_t last_state = 1;
if(KEY_RUNSTOP_GPIO->IDR & KEY_RUNSTOP_PIN) {
if(last_state == 0) { // 释放检测
if(key_press_time > 2000) { // 长按2秒切换模式
plc_mode = (plc_mode==RUN_MODE)?STOP_MODE:RUN_MODE;
SetStatusLED();
}
key_press_time = 0;
}
last_state = 1;
} else {
last_state = 0;
key_press_time += PLC_SCAN_TIME; // 累计按下时间
}
}
这种软硬结合的设计让调试方便不少,实测长按响应比原厂PLC还灵敏,估计是STM32的时钟精度带来的意外收获。
虽然源码已经实现了大部分基础指令,但像PID、高速计数器这些高级功能确实需要自己补全。比如项目里的定时器中断服务函数留了扩展口子:
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
// 基础定时任务
SysTimer++;
// 用户自定义硬件定时任务钩子
if(usr_timer_hook) usr_timer_hook();
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
想加高速脉冲计数的话,可以在这里挂接自己的编码器处理函数。之前见过有人在这个钩子里实现了四路200kHz的AB相计数,STM32的性能果然还是能榨出不少油水。

最后说下移植到其他STM32型号的注意事项。虽然源码支持多个F103型号,但换到F4系列的话要改启动文件和时钟配置。尤其是HSE_VALUE的定义,F103用8MHz外部晶振,而F4开发板常见25MHz,不改的话分频系数算错直接启动失败。
更多推荐

所有评论(0)