stm32cubemx+freemodbus通信(RTU)
使用芯片:stm32f103ret
开发环境:cubemx5.3 + keil5
freemodbus版本:V1.6
CUBEMX配置步骤:
- 系统及时钟配置:使用外部时钟


- TIM4作为freemodbus串口定时器:
在RTU模式下,串行链路是以byte为单位进行发送数据的。Modbus-RTU协议中有一个字符时间的概念,Modbus-RTU总线是通过时间间隔来判断一帧数据结束的。波特率小于19200时,3.5个字符时间内没有收到新的数据,则认为这一帧数据结束。将定时器设置为每50us的时长为一个基准,传入的usTim1Timerout50us变量给自动装载即可,prvvTIMERExpiredISR函数需要在定时器中断服务函数中调用,它的作用是用于通知modbus协议栈3.5个字符 的等待时间已经到;波特率大于19200时为固定时长1750us。

图中位置在程序中传入。
- 串口2用作modbus通信接口

- NVIC配置:取消自动生成中断函数选项,最后自己在程序中添加修改
- 串口的中断优先级高于定时器

-
Freemodbus移植
- 下载freemodbus-v1.6解压,
- 需要用到的文件有:modbus文件中的所有文件,port中的文件


第一次编译报错如下(需要删除掉demo.c中的main函数):

其中串口需要修改的文件有portserial.c 定时器需要修改的文件 有porttimer.c
寄存器的读写功能通过新建Modbusdemo.c中实现。
- portserial.c中的函数:保留prvvUARTTxReadyISR,prvvUARTRxISR
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{/* If xRXEnable enable serial receive interrupts. If xTxENable enable* transmitter empty interrupts.*/ if(xRxEnable)//接收使能{ __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); // 使能接收非空中断 //低电平接收 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET); //根据实际使用芯片决定是否有此步骤}else{__HAL_UART_DISABLE_IT(&huart2, UART_IT_RXNE); // 禁能接收非空中断}if(xTxEnable)//发送使能{//高电平发送 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET); //根据实际使用芯片决定是否有此步骤 __HAL_UART_ENABLE_IT(&huart2, UART_IT_TXE); // 使能发送为空中断 }else{__HAL_UART_DISABLE_IT(&huart2, UART_IT_TXE); // 禁能发送为空中断}
}
BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{huart2.Instance = USART2;huart2.Init.BaudRate = ulBaudRate;huart2.Init.StopBits = UART_STOPBITS_1;huart2.Init.Mode = UART_MODE_TX_RX;huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart2.Init.OverSampling = UART_OVERSAMPLING_16;switch(eParity){// 奇校验case MB_PAR_ODD:huart2.Init.Parity = UART_PARITY_ODD;huart2.Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bitsbreak;// 偶校验case MB_PAR_EVEN:huart2.Init.Parity = UART_PARITY_EVEN;huart2.Init.WordLength = UART_WORDLENGTH_9B; // 带奇偶校验数据位为9bitsbreak;// 无校验default:huart2.Init.Parity = UART_PARITY_NONE;huart2.Init.WordLength = UART_WORDLENGTH_8B; // 无奇偶校验数据位为8bitsbreak;}return HAL_UART_Init(&huart2) == HAL_OK ? TRUE : FALSE;
}
BOOL xMBPortSerialPutByte( CHAR ucByte )
{/* Put a byte in the UARTs transmit buffer. This function is called* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been* called. */USART2->DR = ucByte;while(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC)== RESET){}return TRUE;
}
BOOL xMBPortSerialGetByte( CHAR * pucByte )
{/* Return the byte in the UARTs receive buffer. This function is called* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.*/*pucByte = (USART2->DR & (uint16_t)0x00FF);return TRUE;
}
void USART2_IRQHandler(void)
{if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE)) // 接收非空中断标记被置位{__HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_RXNE); // 清除中断标记prvvUARTRxISR(); // 通知modbus有数据到达}if((__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TXE) == SET)&&(__HAL_UART_GET_IT_SOURCE(&huart2, UART_FLAG_TC) == RESET)) // 发送为空中断标记被置位{__HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TXE); // 清除中断标记prvvUARTTxReadyISR(); // 通知modbus数据可以发松 }
}
porttimer.c中的函数如下:保留vMBPortTimersDisable,prvvTIMERExpiredISR
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )
{TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};/* USER CODE BEGIN TIM4_Init 1 *//* USER CODE END TIM4_Init 1 */htim4.Instance = TIM4;htim4.Init.Prescaler = 7199;htim4.Init.CounterMode = TIM_COUNTERMODE_UP;htim4.Init.Period = usTim1Timerout50us-1; //htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim4) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK){Error_Handler();}__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); // 清除一下定时器的中断标记,防止使能中断后直接触发中断__HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); // 使能定时器更新中断return TRUE;
}inline void vMBPortTimersEnable( )
{__HAL_TIM_SET_COUNTER(&htim4, 0); // 清空计数器__HAL_TIM_ENABLE(&htim4); // 使能定时器/* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
}inline void vMBPortTimersDisable( )
{__HAL_TIM_DISABLE(&htim4); // 禁能定时器/* Disable any pending timers. */
}
/// 定时器4中断服务程序
void TIM4_IRQHandler(void)
{if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE)) // 更新中断标记被置位{__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE); // 清除中断标记prvvTIMERExpiredISR(); // 通知modbus3.5个字符等待时间到}
}
文件demo.c中主要实现0X04

以上是移植过程,只实现了04测试。为了防止运行异常,可以加入看门狗定时器
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
