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中实现。

  1. 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测试。为了防止运行异常,可以加入看门狗定时器


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部