This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

怎样编写高效的串口命令处理函数,在中断内部,还是在外部调用。



收串口的指令,都是在串口接收中断中一个字符一个字符的接收的么,一个完整指令的结束肯定也是在串口接收中断中判断出来的(比如说判断出“终止字符”)。
那么现在就有一个问题,当接收完这一个完整的串口指令后,就应该马上调用该指令的处理函数,如果在接收中断中直接调用,有可能这个处理函数耗时较长,这样程序就会处在串口中断中好长时间出不来,影响后面指令的接收;另外还有可能就是这个处理函数中含有串口发送的功能,这样就有可能造成串口中断函数的递归调用,单片机无法实现。

我在编写其他单片机程序的时候,没有考虑低功耗的问题,都是这样做的:主程序始终轮询一个任务变量A,使用switch,不同的任务变量值,就处理不同的任务。串口接收到指令后,对指令进行简单的处理判断,找到对应的任务,将任务变量A的值改为该处理函数对应的任务值,然后中断处理函数结束了。在主程序中进行处理函数的调用。
但是现在msp430,主程序应该长时间休眠,不能始终轮询。

大家在处理串口发过来的指令的时候,都是怎么做的?谢谢大家啦!
  • 楼主你好!

    接收终端中应当这样处理,参考下面伪代码:

    Uart_ISR() {

         接受字符任务;

         if (终止字符){

                     任务变量A = 任务代码;

                     退出低功耗模式;// 操作堆栈中保存的 特殊功能寄存器中功耗模式 

         } else {

                     (进入低功耗模式;)//如果进入中断前是低功耗则不需要此操作;

         }

    }

  • “Billy”,感谢您。

    我有这样的疑问,不知道对不对。这样的话,主程序需要一直轮询“任务变量A”是吧。

    main() {

        ...

        while(1){

            switch(任务变量A) {

                case 任务代码1: 任务1处理函数;

                case 任务代码2: 任务2处理函数;

                ...

            }

        }

    }

    我通常的msp430单片机程序都是这样的:

    main() {

        初始化单片机;

        初始化串口;

        ...

        进入低功耗模式;

    }

    外部函数1(){

    }

    串口中断函数(){

    }

    进入低功耗模式后,主程序就终止了。串口数据过来的时候,单片机被唤醒进入中断函数,中断函数return后,就马上进入低功耗模式了。主程序无法一直轮询的。

    不知道我说的对不对,还是我对430的低功耗理解有误。

  • 不知道我上面的说法对不对。

    main(){

        。。。

        进入低功耗模式3

    }

    串口中断函数(){

        _NOP(); // 中断函数中,没有任何功耗模式切换的操作。

    }

    主程序运行后,进入低功耗模式3,串口数据到来的时候,自动进入串口中断处理函数,函数中没有任何功耗切换的操作,函数完成后单片机仍然返回到低功耗模式3。我这种理解对吗?

  • 楼主你好!


    进入低功耗模式后,主程序就终止了。串口数据过来的时候,单片机被唤醒进入中断函数,中断函数return后,就马上进入低功耗模式了。主程序无法一直轮询的。

    是的。

    还有一个问题要注意,就是要设置互锁的信号量。就是主程序在轮训以及执行任务的时候,如果新的一帧串口数据来了,应当能够通过任务信号量来判断不进入低功耗模式,而是返回主程序的任务。然后,让任务完成后,自己进入低功耗模式。

  • 感谢您,我彻底明白了!

    msp430的程序是不是这样的:

    main() {

        ...

        LPM3;  // 位置1,进入低功耗模式3

        ...          // 位置2

        LPM3;  // 位置3,进入低功耗模式3

        ....          // 位置4

    }

    串口中断函数() {

        ...

       LPM3_EXIT;

    }

    ================================

    像上面的程序,主程序运行之后,到达“位置1”后,会进入低功耗模式,停在那里;而后如果产生了串口中断,进入了一次串口中断函数就会退出低功耗模式,从而“位置2”处的程序得以执行,到达“位置3”后,会再次进入低功耗模式,停在那里?

    我这样理解对吗?

  • 是的。另外需要注意的是,中断中         LPM3_EXIT;            操作的是堆栈中保存的CPU特殊功能寄存器。

  • 现在任务的调度仍然是一个问题,就像您说的,我试想了一下,总体任务执行结构可以使用下面的方法实现:

    int Task_Id = 无任务;

    main() {

        ...

        while (1) {

            switch (Task_Id) {

            case 任务1:...; LPM3;

            case 任务2:...; LPM3;

            case 任务3:...; LPM3;

            case 无任务: LPM3;

             }

        }

    }

    串口接收中断() {

        if (收到终止符) {

            ...

            Task_Id = 任务2;

            LPM3_EXIT;

        }

        else {

            Uart_Buffer[Index++] = received_char;

        }

    }

    这样还是会产生一个问题,就是在处理任务的时候,比如任务1的过程中,接收到串口完整的指令,串口中断,将下一次的Task_Id变为任务2,退出PLM3,然后函数返回,主程序继续执行任务1未完成的部分,当执行到任务1最后PLM3语句后,进入低功耗模式。这样的话任务2并没有得到执行。

    即使我设计一个任务序列(数组),当一个任务没有执行完的时候,新的任务到来,可以预存在任务序列里面,主程序会依次执行任务序列里面的任务,直到所有的任务都被执行完,然后进入LPM3。这样看似可以。但是同样存在问题,比如主程序总要判断序列里面是否还有剩余的任务,当发现没有剩余任务的时候,理应跳转到“进行善后工作并进入LPM3模式”的语句,但是这个时候,触发了接收中断,并且中断函数中恰好产生了新的任务,当中断函数执行完之后,主程序继续进行后面未完成的任务:“进行善后工作并进入LPM3模式”。这样新加入的任务就没有得到执行。

    我的想法可能很不成熟,应该怎样做呢?或者您有什么更好的任务调度的方法(在保证低功耗性能的前提下)?谢谢了!!

  • 哦,我忘记在每条case语句后面加“break;”了。

  • 1)两个概念不应混淆了。任务调度和低功耗模式没有任何联系。

    总体而言,低功耗模式是让操作系统或者任务调度系统在无任务时候进入的状态。

    2)MSP430 在进入中断前会自动将低功耗模式保存到堆栈中,中断执行完后自动进入之前的低功耗模式。所以,基于楼主的应用,终端中不需要处理低功耗模式。让任务调度系统决定低功耗模式即可。