使用的此大佬代码: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