Modbus RTU 主机协议栈移植 STM32标准库

 使用的此大佬代码:https://blog.youkuaiyun.com/qq153471503/article/details/124523754

工作中用旧项目用标准库试着修改,记录一下自己踩的坑。

工程需要在 小锤子设置——C/C++中,勾选C99标准,否则编译会报错。

设定了10ms的TIM4,串口2接的485收发芯片,配置代码在这里省略。

仅添加需要修改的芯片库函数。错误的定时器移植会导致ret=-1

/*放入定时器暂停函数*/
static void timerStop(void)
{
	TIM_Cmd(TIM4, DISABLE);
}

/*放入定时器清零函数和启动函数*/
static void timerStart(void)
{
    TIM_SetCounter(TIM4, 0);
	TIM_Cmd(TIM4, ENABLE);	
}

/*放入延时函数*/
static void delayms(uint32_t nms)
{
    delay_ms(nms);
}

/*放入串口发送*/
static uint32_t sendData(const void* buf, uint32_t len)
{
    // if(HAL_UART_Transmit(&huart3, (uint8_t *)buf, len, 100) != HAL_OK)
    // {
    //     len = 0;
    // }
    SendString((uint8_t *)buf,len);
    return len;
}

因为很久没用使用标准库,这里犯过一个错,导致找问题花了一会时间,每次执行串口中断接收都会让程序跑飞,卡死。

定时器开启和关闭要用TIM_Cmd,而不是TIM_ITConfig。最早我写控制定时器开关时候就用的cmd,这次试了一下TIM_ITConfig,虽然也可以实现暂停开启效果。

extern MBRTUMaterTypeDef MBRTUHandle;
uint8_t modbus_rxbuf;

void MODBUS_init()
{
    TIM4_Int_Init();
	USART2_init(9600);
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update); 
}

void USART2_IRQHandler(void)
{
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) // 串口接收中断
    {
        USART_ClearITPendingBit(USART2, USART_IT_RXNE); // 清除标志位

        modbus_rxbuf=USART_ReceiveData(USART2);
       MBRTUMasterRecvByteISRCallback(&MBRTUHandle, modbus_rxbuf);
    }
}

void TIM4_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)  //检查TIM4更新中断发生与否
	{
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update  );  //清除TIMx更新中断标志 
        
	 MBRTUMasterTimerISRCallback(&MBRTUHandle);	
	}
}

int ret; 
void Modbus_Send_example()
{
    // 写单个线圈,从机地址0x01,功能吗05,线圈地址0x02,写状态1
		//01 05 00 02 FF 00 2D FA 
    ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x02, 1, 500);
	// 写单个线圈,从机地址0x01,功能吗05,线圈地址0x00,写状态1
		ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x00, 1, 500);
	
		delay_ms(200);
		ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x02, 0, 500);
		ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x00, 0, 500);
	

}

 

不正确的移植方法,在使用modbus slave时候,发送完就会卡死。

modbus slave遇到不少bug,在用06和03寄存器时,出现软件界面不显示写入的数据(但是发现有返回写入的数据),读寄存器时,从机地址为1时,发送的数据全为0,从机地址改为2和3没有此情况。

modbus sim测试功能正常。

测试完成后,后续再修改成串口DMA发送。裸机测试

其他寄存器测试:

void Modbus_Send_example()
{
    // 写单个线圈,从机地址0x01,功能吗05,线圈地址0x02,写状态1
    // 01 05 00 02 FF 00 2D FA
    // ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x02, 0, 100);
    // // 写单个线圈,从机地址0x01,功能吗05,线圈地址0x00,写状态1
    // ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x00, 1, 100);

    // // delay_ms(200);
    // ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x02, 1, 100);
    // ret = MBRTUMasterWriteSingleCoil(&MBRTUHandle, 0x01, 0x00, 0, 100);

    //读线圈 从机0x01 起始地址0  三个线圈
    // MBRTUMasterReadCoils(&MBRTUHandle, 0x01, 0, 3, 100, CoilsBuf);

    // 读保持寄存器
    // 从机地址0x01,功能码0x03。 保持寄存器起始地址0,数量1
    // 01 03 00 00 00 01 84 0A 
    //ret=MBRTUMasterReadHoldingRegisters(&MBRTUHandle, 0x01, 0, 1, 100,usBuf); // 寄存器数量为10的话,需要10个元素的数组
	  //起始地址0,读寄存器数量4
  	ret=MBRTUMasterReadHoldingRegisters(&MBRTUHandle, 0x01, 0, 4, 100,usBuf);    //使用modbus slave 从机选择01地址,会发送0数据  用modbus sim正常 寄存器地址从0001开始
    delay_ms(100);

    // 写单个寄存器
    // ret = MBRTUMasterWriteSingleRegister(&MBRTUHandle, 1, 0, 120, 100);

}

注:当主站使用0x03、0x06、0x10的三个功能码,软件选择寄存器是03 Holding Register

       当主站使用0x01、0x05、0x0F的三个功能码,软件选择寄存器是01 Coil Status

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随风飘零翼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值