移植Freemodbus到STM32

移植Freemodbus到STM32,第1张

具体Freemodbus移植到STM32步骤参考:
STMC2CubeMX | STM32 HAL库移植FreeModbus详细步骤
基于STM32HAL库移植FreeModbus
FreeModbus+STM32 +HAL库 无 *** 作系统移植 (已在正点原子阿波罗F429开发板上移植成功)

移植过程各路网站上都比较多,具体可参考以上链接内容。


把思路和步骤记录一下:
①下载复制Freemodbus库;
② 使用CubeMX生成工程,需要注意配置串口、timer,NVIC优先级串口高于timer,需要用到中断,但不需要生成IRQHandle(移植中有手动添加)
③添加Freemodbus中相关.c.h文件到工程,设置中配置c++ include目录
④移植的核心在于port.c,portserial.c,porttimer.c,portevent.c 四个文件的修改与配置;其中配置serial与time是关键,需修改portserial.c与porttimer.c, *** 作时,只需要修改为需要的串口和timer即可,其他内容不需要动。



⑤如果用到485收发芯片,需要添加收发控制端代码(具体可以参考下边问题1种内容)
⑥根据需要配置port.c文件,如果初步测试,不用修改
⑦编译下载,然后就可以测试了

整个移植过程其实不是太复杂(站在前人基础上),但还是容易出现一些问题,在此仅个人移植存在的问题,踩过的坑在这里记录一下

(1)Freemodbus移植到TTL的USART1可行,但改为485的USART2不行

具体和端口没关系,主要问题是端口使用到485芯片,需要有收发控制端的配置,并在适当时候打开即可;
这个问题具体 *** 作是修改portserial.c文件中 vMBPortSerialEnable函数内容,添加打开接收或者打开发送控制端,具体需要根据芯片及接法有关。


/* ------------- Start implementation -------------------------*/
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    if(xRxEnable)
    {
        __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);// 使能接收非空中断
		HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_RESET); //MAX485 *** 作 低电平为接收模式
    }
    else
    {
        __HAL_UART_DISABLE_IT(&huart2, UART_IT_RXNE);// 禁能接收非空中断	
    }
    
    if(xTxEnable)
    {
		HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_SET); //MAX485 *** 作 高电平为发送模式
		__HAL_UART_ENABLE_IT(&huart2, UART_IT_TXE);			// 使能发送为空中断	
    }
    else
    {
        __HAL_UART_DISABLE_IT(&huart2, UART_IT_TXE);		// 禁能发送为空中断
    }
}
(2)485-Modbus 通讯 Timeout,数据发送不全或者结尾总是0xFF

这个问题的在不使用485芯片上一般不出现,在使用到485芯片的时候就比较明显,根源在于收发过程切换。


仔细调试发现,MCU已经将数据传输出去,TTL口数据已经正常,但到485芯片后就出错,主要是MCU从发送到接收的转换太快,数据还没发送完全就将485的收发端口从发送转换为接收,造成最后一个字节数据没有从485芯片传输出去,造成出错。


修改也比较简单,在切换之前进行适当延时,确保数据发送完成后在进行切换收发使能端口状态,即可解决。


通过多方测试,感觉加到 cBOOL xMBRTUTransmitFSM( void )比较合适:增加语句【while(i


关于RS485_swtict_delay 设置多大合适呢
经测试的波特率115200时,1000左右即可;波特率9600时,13000左右;这个延时时间与芯片延时有关系,具体以测试为准。


BOOL xMBRTUTransmitFSM( void )
{
    BOOL            xNeedPoll = FALSE;
	uint16_t        i = 0;
    assert( eRcvState == STATE_RX_IDLE );

    switch ( eSndState )
    {
    /* We should not get a transmitter event if the transmitter is in
     * idle state.  */
    case STATE_TX_IDLE:
        /* enable receiver/disable transmitter. */
        vMBPortSerialEnable( TRUE, FALSE );
        break;

    case STATE_TX_XMIT:
        /* check if we are finished. */
        if( usSndBufferCount != 0 )
        {
            xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur );
            pucSndBufferCur++;  /* next byte in sendbuffer. */
            usSndBufferCount--;
        }
        else
        {
            xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
            /* Disable transmitter. This prevents another transmit buffer
             * empty interrupt. */
             * 
			//  ********看这里***** ↓ 边是重点
			
			while(i<RS485_swtict_delay) i++; //补充延时
			
			//  ********看这里***** ↑ 边是重点
			
            vMBPortSerialEnable( TRUE, FALSE );
            eSndState = STATE_TX_IDLE;
        }
        break;
    }

    return xNeedPoll;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563517.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存