FreeModbus学习——定时器

FreeModbus版本:1.6

协议栈初始化时会初始化定时器:

eMBInit →

eMBRTUInit →

xMBPortTimersInit( ( USHORT ) usTimerT35_50us )

协议栈使能时会使能定时器:

eMBEnable →

pvMBFrameStartCur →

eMBRTUStart →

vMBPortTimersEnable

定时器使能做的操作是:清除中断标志位,清除计数,使能定时器,重新计数

也就是说每次调用vMBPortTimersEnable

都会清除计数并重新计数

那么这个函数除了使能协议栈时调用了,还用在哪里呢

用在接收状态机里

当接收状态机为空闲态STATE_RX_IDLE,接收到第一个数据时作为帧首,然后接收状态机进入接收态STATE_RX_RCV,并且使能定时器(重新计数)。

当接收状态机为接收态STATE_RX_RCV,接收到的数据放入帧中,然后使能定时器(重新计数)。

也就是每接收到一个数据就要重新计数定时器,以防进入中断。

那看中断里实现了什么

定时器中断:

TIM7_IRQHandler →

prvvTIMERExpiredISR →

pxMBPortCBTimerExpired →

xMBRTUTimerT35Expired →

c 复制代码
BOOL
xMBRTUTimerT35Expired( void )
{
    BOOL            xNeedPoll = FALSE;

    switch ( eRcvState )
    {
        /* Timer t35 expired. Startup phase is finished. */
    case STATE_RX_INIT:
        xNeedPoll = xMBPortEventPost( EV_READY );
        break;

        /* A frame was received and t35 expired. Notify the listener that
         * a new frame was received. */
    case STATE_RX_RCV:
        xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
        break;

        /* An error occured while receiving the frame. */
    case STATE_RX_ERROR:
        break;

        /* Function called in an illegal state. */
    default:
        assert( ( eRcvState == STATE_RX_INIT ) ||
                ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
    }

    vMBPortTimersDisable(  );
    eRcvState = STATE_RX_IDLE;

    return xNeedPoll;
}

协议栈使能后会将接收状态机置为初始化态STATE_RX_INIT。

接收状态机为空闲态时STATE_RX_IDLE才开始计数。

当接收状态机 为STATE_RX_INIT,进入定时器溢出中断,会发布就绪事件EV_READY 。

当接收状态机 为STATE_RX_RCV,进入定时器溢出中断,会发布已接收事件EV_FRAME_RECEIVED 。说明一帧已经接收完毕。

并且在定时器溢出中断的最后,会把接收状态机置为STATE_RX_IDLE。

接收状态机为空闲态时,接收到一个字符,会进入串口接收中断,串口接收中断中会将接收到的字符保存作为帧首,并且把接收状态机变为STATE_RX_RCV。 也就是接收状态机为接收态,每接收到一个字符,会进入中断,然后把定时器清0。直到距离下个字符超过定时器溢出时间,进入定时器中断,此时接受状态机为STATE_RX_RCV,这就意味着接受完成了一帧。然后发布事件EV_FRAME_RECEIVED

定时器中断里为什么会有一个STATE_RX_INIT的状态判断呢?

因为协议栈使能后会将接收状态机置为初始化态STATE_RX_INIT。

但是万一这个时候串口接收寄存器已经有数据了咋办,那会进入串口接收中断函数,会调用xMBRTUReceiveFSM,当接收状态机为STATE_RX_INIT时,会清空定时器重新计数。

接收状态机为空闲态时STATE_RX_IDLE才开始读取一帧数据。

所以如果STATE_RX_INIT时有数据了,也不会读的,因为无法判断这个数是不是一帧的第一个字符。

所以STATE_RX_INIT时在xMBRTUReceiveFSM里会清空定时器。

直到定时器溢出。

然后会将接收状态机置为空闲态STATE_RX_IDLE。

这个时候在有数据,就可以作为帧首了。

当接收状态机 为STATE_RX_RCV,进入定时器溢出中断,会发布已接收事件EV_FRAME_RECEIVED 。说明一帧已经接收完毕。

这个时候eMBPoll中接收到事件EV_FRAME_RECEIVED ,就可以处理这一帧数据了。

相关推荐
Slow菜鸟4 小时前
AI学习篇(五) | awesome-design-md 使用说明
人工智能·学习
狐狐生风5 小时前
LangChain 向量存储:Chroma、FAISS
人工智能·python·学习·langchain·faiss·agentai
狐狐生风5 小时前
LangChain RAG 基础
人工智能·python·学习·langchain·rag·agentai
LCG元7 小时前
STM32项目实战:基于STM32F103的智能农业监控系统
stm32·单片机·嵌入式硬件
ACP广源盛139246256737 小时前
IX8024与科学大模型的碰撞@ACP#筑牢科研 AI 算力高速枢纽分享
运维·服务器·网络·数据库·人工智能·嵌入式硬件·电脑
努力努力再努力FFF7 小时前
医生对AI辅助诊断感兴趣,作为临床人员该怎么了解和学习?
人工智能·学习
一起搞IT吧8 小时前
Android性能系列专题理论之十:systrace/perfetto相关指标知识点细节含义总结
android·嵌入式硬件·智能手机·性能优化
sakiko_9 小时前
UIKit学习笔记5-使用UITableView制作聊天页面
笔记·学习·swift·uikit
Truffle7电子9 小时前
STM32CubeIDE/Programmer/Touch GFX 应用
stm32·单片机·嵌入式硬件
Alice-YUE9 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript