hagx 发表于 2011-2-11 23:36:05

Atmega128+GCC+ucos的串口中断程序如何编写

我用的本网站移植的一个范本,但是没有串口中断的部分,我依葫芦画写了一段,但是一给串口发数据系统就死机了,后来我参照ucos官网的例子改了下,也是不能用。
附程序代码:

;********************************************************************************************************
;                                             uC/OS-II
;                                       The Real-Time Kernel
;
;                                          ATmega128 Specific code for V2.8x
;                                           (AVR-GCC 4.1.1)
;
;
; File         : OS_CPU_A.ASM
; By         : Xiawei   <xiawei0311@gmail.com>
; AVR-GCCversion : 4.1.1 , WinAVR 20070122
; Date       : September 9th,2007
;
;********************************************************************************************************
#include <avr/io.h>
#define OS_CPU_A
#include "../Config/OS_CFG.h"
#include "OS_CPU.h"

;********************************************************************************************************
;                                           I/O PORT ADDRESSES
;********************************************************************************************************




;********************************************************************************************************
;                                          PUBLIC DECLARATIONS
;********************************************************************************************************

                .global OSStartHighRdy
                .global OSCtxSw
                .global OSIntCtxSw
                .global TIMER0_COMP_vect
                .global OSTickISR
                .global OSTickISR2
                                .global SIG_UART0_RECV
                                .global OSUART0ISR
                .global OS_CPU_SR_Save
                .global OS_CPU_SR_Restore

;********************************************************************************************************
;                                       EXTERNAL DECLARATIONS
;********************************************************************************************************

                .extern OSIntExit
                .extern OSIntNesting
                .extern OSPrioCur
                .extern OSPrioHighRdy
                .extern OSRunning
                .extern OSTaskSwHook
                .extern OSTCBCur
                .extern OSTCBHighRdy
                .extern OSTimeTick
                                .extern OSUart0Rec

;********************************************************************************************************
;                                       MACROS
;********************************************************************************************************

; Push all registers and the status register       
.macro        PUSHRS
                push        r0
                push        r1
                push        r2
                push        r3
                push        r4
                push        r5
                push        r6
                push        r7
                push        r8
                push        r9
                push        r10
                push        r11
                push        r12
                push        r13
                push        r14
                push        r15
                push        r16
                push        r17
                push        r18
                push        r19
                push        r20
                push        r21
                push        r22
                push        r23
                push        r24
                push        r25
                push        r26
                push        r27
                push        r28
                push        r29
                push        r30
                push        r31
                in                r16,_SFR_IO_ADDR(SREG)
                push        r16

.endm

; Pop all registers and the status registers
.macro        POPRS

                pop                r16
                out                _SFR_IO_ADDR(SREG),r16
                pop                r31
                pop                r30
                pop                r29
                pop                r28
                pop                r27
                pop                r26
                pop                r25
                pop                r24
                pop                r23
                pop                r22
                pop                r21
                pop                r20
                pop                r19
                pop                r18
                pop                r17
                pop                r16
                pop                r15
                pop                r14
                pop                r13
                pop                r12
                pop                r11
                pop                r10
                pop                r9
                pop                r8
                pop                r7
                pop                r6
                pop                r5
                pop                r4
                pop                r3
                pop                r2
                pop                r1
                pop                r0

.endm

.macro PUSH_ALL
                ST      -Y,R0
                ST      -Y,R1
                ST      -Y,R2
                ST      -Y,R3
                ST      -Y,R4
                ST      -Y,R5
                ST      -Y,R6
                ST      -Y,R7
                ST      -Y,R8
                ST      -Y,R9
                ST      -Y,R10
                ST      -Y,R11
                ST      -Y,R12
                ST      -Y,R13
                ST      -Y,R14
                ST      -Y,R15
                ST      -Y,R16
                ST      -Y,R17
                ST      -Y,R18
                ST      -Y,R19
                ST      -Y,R20
                ST      -Y,R21
                ST      -Y,R22
                ST      -Y,R23
                ST      -Y,R24
                ST      -Y,R25
                ST      -Y,R26
                ST      -Y,R27
                ST      -Y,R30
                ST      -Y,R31
                IN      R16,_SFR_IO_ADDR(RAMPZ)
                ST      -Y,R16
.ENDM

.macro POP_ALL
                LD      R16,Y+
                OUT   _SFR_IO_ADDR(RAMPZ),R16
                LD      R31,Y+
                LD      R30,Y+
                LD      R27,Y+
                LD      R26,Y+
                LD      R25,Y+
                LD      R24,Y+
                LD      R23,Y+
                LD      R22,Y+
                LD      R21,Y+
                LD      R20,Y+
                LD      R19,Y+
                LD      R18,Y+
                LD      R17,Y+
                LD      R16,Y+
                LD      R15,Y+
                LD      R14,Y+
                LD      R13,Y+
                LD      R12,Y+
                LD      R11,Y+
                LD      R10,Y+
                LD      R9,Y+
                LD      R8,Y+
                LD      R7,Y+
                LD      R6,Y+
                LD      R5,Y+
                LD      R4,Y+
                LD      R3,Y+
                LD      R2,Y+
                LD      R1,Y+
                LD      R0,Y+
.ENDM

.macro        PUSH_SREG
                in r16 _SFR_IO_ADDR(SREG)
                st -Y,r16
.endm


.macro        PUSH_SP
                in r16, _SFR_IO_ADDR(SPH)
                st -Y,r16
                in r16, _SFR_IO_ADDR(SPL)
                st -Y,r16
.endm


.macro POP_SP
                LD      R16,Y+
                OUT   _SFR_IO_ADDR(SPL),R16
                LD      R16,Y+
                OUT   _SFR_IO_ADDR(SPH),R16
.endm

.macro POP_SREG_INT
                LD      R16,Y+
                CBR   R16,128
                OUT   _SFR_IO_ADDR(SREG),R16
.endm


                        .text
                        .section        .text
                       

;********************************************************************************************************
;                               START HIGHEST PRIORITY TASK READY-TO-RUN
;
; Description : This function is called by OSStart() to start the highest priority task that was created
;               by your application before calling OSStart().
;
; Note(s)   : 1) The (data)stack frame is assumed to look as follows:
;
;                  OSTCBHighRdy->OSTCBStkPtr --> LSB of (return) stack pointer         (Low memory)
;                                                SPH of (return) stack pointer
;                                                Flags to load in status register
;                                                R31
;                                                R30
;                                                R7
;                                                .
;                                                .
;                                                .
;                                                R0                                    (High memory)
;
;                  where the stack pointer points to the task start address.
;
;
;               2) OSStartHighRdy() MUST:
;                      a) Call OSTaskSwHook() then,
;                      b) Set OSRunning to TRUE,
;                      c) Switch to the highest priority task.
;********************************************************************************************************

OSStartHighRdy:
   #if OS_CPU_HOOKS_EN > 0
                CALL   OSTaskSwHook                ; Invoke user defined context switch hook
   #endif
                LDS   R16,OSRunning               ; Indicate that we are multitasking
                INC   R16                         ;
                STS   OSRunning,R16               ;

                LDS   R30,OSTCBHighRdy            ; Let Z point to TCB of highest priority task
                LDS   R31,OSTCBHighRdy+1          ; ready to run

                LD      R28,Z+                      ; Load stack L pointer
                OUT   _SFR_IO_ADDR(SPL),R28
                LD      R29,Z+                      ;
                OUT   _SFR_IO_ADDR(SPH),R29

                POPRS                               ; Pop all registers and status register
                RET                                 ; Start task

;********************************************************************************************************
;                                       TASK LEVEL CONTEXT SWITCH
;
; Description : This function is called when a task makes a higher priority task ready-to-run.
;
; Note(s)   : 1) Upon entry,
;                  OSTCBCur   points to the OS_TCB of the task to suspend
;                  OSTCBHighRdy points to the OS_TCB of the task to resume
;
;               2) The stack frame of the task to suspend looks as follows:
;
;                                       SP+0 --> LSB of task code address
;                                       +1   MSB of task code address                (High memory)
;
;               3) The saved context of the task to resume looks as follows:
;
;                  OSTCBHighRdy->OSTCBStkPtr --> LSB of (return) stack pointer         (Low memory)
;                                                SPH of (return) stack pointer
;                                                Flags to load in status register
;                                                R31
;                                                R30
;                                                R7
;                                                .
;                                                .
;                                                .
;                                                R0                                    (High memory)
;********************************************************************************************************

OSCtxSw:
                PUSHRS                              ; Save current tasks context

                LDS   R30,OSTCBCur                ; Z = OSTCBCur->OSTCBStkPtr
                LDS   R31,OSTCBCur+1            ;

                IN      r28,_SFR_IO_ADDR(SPL)
                ST      Z+,R28                      ; Save Y (R29:R28) pointer
                IN      r29,_SFR_IO_ADDR(SPH)
                ST      Z+,R29                      ;
#if OS_CPU_HOOKS_EN > 0
                CALL   OSTaskSwHook                ; Call user defined task switch hook
#endif
                LDS   R16,OSPrioHighRdy         ; OSPrioCur = OSPrioHighRdy
                STS   OSPrioCur,R16

                LDS   R30,OSTCBHighRdy            ; Let Z point to TCB of highest priority task
                LDS   R31,OSTCBHighRdy+1          ; ready to run
                STS   OSTCBCur,R30                ; OSTCBCur = OSTCBHighRdy
                STS   OSTCBCur+1,R31            ;

                LD      R28,Z+                      ; Restore Y pointer
                OUT   _SFR_IO_ADDR(SPL),R28
                LD      R29,Z+                      ;
                OUT   _SFR_IO_ADDR(SPH),R29

                POPRS                               ; Restore all registers and the status register
                RETI


;*********************************************************************************************************
;                              INTERRUPT LEVEL CONTEXT SWITCH
;
; Description : This function is called by OSIntExit() to perform a context switch to a task that has
;               been made ready-to-run by an ISR.
;
; Note(s)   : 1) Upon entry,
;                  OSTCBCur   points to the OS_TCB of the task to suspend
;                  OSTCBHighRdy points to the OS_TCB of the task to resume
;
;               2) The stack frame of the task to suspend looks as follows:
;
;                                       SP+0 --> LSB of return address of OSIntCtxSw()   (Low memory)
;                                       +1   MSB of return address of OSIntCtxSw()
;                                       +2   LSB of return address of OSIntExit()
;                                       +3   MSB of return address of OSIntExit()
;                                                                               possible SREG save       
;                                       +4   LSB of task code address
;                                       +5   MSB of task code address                (High memory)
;
;               3) The saved context of the task to resume looks as follows:
;
;                  OSTCBHighRdy->OSTCBStkPtr --> Flags to load in status register         (Low memory)
;                                                R31
;                                                R30
;                                                R7
;                                                .
;                                                .
;                                                .
;                                                R0                                    (High memory)
;*********************************************************************************************************

OSIntCtxSw:
#if OS_CPU_HOOKS_EN > 0
                CALL   OSTaskSwHook                ; Call user defined task switch hook
#endif
                LDS   R16,OSPrioHighRdy         ; OSPrioCur = OSPrioHighRdy
                STS   OSPrioCur,R16               ;

                LDS   R30,OSTCBHighRdy            ; Z = OSTCBHighRdy->OSTCBStkPtr
                LDS   R31,OSTCBHighRdy+1          ;
                STS   OSTCBCur,R30                ; OSTCBCur = OSTCBHighRdy
                STS   OSTCBCur+1,R31            ;

                LD      R28,Z+                      ; Restore Y pointer
                OUT   _SFR_IO_ADDR(SPL),R28
                LD      R29,Z+                      ;
                OUT   _SFR_IO_ADDR(SPH),R29

                POPRS                               ; Restore all registers and status register
                RET

;********************************************************************************************************
;                                           SYSTEM TICK ISR
;
; Description : This function is the ISR used to notify uC/OS-II that a system tick has occurred.
;
;
;********************************************************************************************************
TIMER0_COMP_vect:
OSTickISR:
                PUSHRS                              ; Save all registers and status register

                LDS   R16,OSIntNesting            ; Notify uC/OS-II of ISR
                INC   R16                         ;
                STS   OSIntNesting,R16            ;
               
                CLZ                                 ;清零Z标志位,为下面的比较做好准备
                CPI   R16,1                     ;比较OSIntNesting是否为1
                BREQ    OSTickISR2                  ;如果是1,则跳转至OSTickISR2
               
                SEI                                 ; Enable interrupts
               
                CALL   OSTimeTick                   ; Call uC/OS-IIs tick updating function

                CALL   OSIntExit                   ; Notify uC/OS-II about end of ISR

                POPRS                               ; Restore all registers and status register
                RET                                 ; Note: RET instead of RETI

OSTickISR2:
                LDS   R30,OSTCBCur                ; Z = OSTCBCur->OSTCBStkPtr
                LDS   R31,OSTCBCur+1            ;

                IN      r28,_SFR_IO_ADDR(SPL)
                ST      Z+,R28                      ; Save Y (R29:R28) pointer
                IN      r29,_SFR_IO_ADDR(SPH)
                ST      Z+,R29                      ;OSTCBCur->OSTCBStkPtr=SP

                SEI                                 ; 使能中断,继续执行OSTickISR中被打断的指令(可选用)
                CALL   OSTimeTick                  ; Call uC/OS-IIs tick updating function

                CALL   OSIntExit                   ; Notify uC/OS-II about end of ISR

                POPRS                               ; Restore all registers and status register
                RET                                 ;

;******************************下面开始是我加的                           
SIG_UART0_RECV:
                PUSH_ALL                              ; Save all registers and status register
                IN      R16,_SFR_IO_ADDR(SREG)      ; Save the SREG but with interrupts enabled
                SBR   R16,128
                ST      -Y,R16
                PUSH_SP                           ; Save the task's hardware stack pointer onto task's stack

                LDS   R16,OSIntNesting            ; Notify uC/OS-II of ISR
                INC   R16                         ;
                STS   OSIntNesting,R16            ;

                CPI   R16,1                     ; if (OSIntNesting == 1) {
                BRNE    OSUART0ISR

                LDS   R30,OSTCBCur                ;   OSTCBCur->OSTCBStkPtr = Y
                LDS   R31,OSTCBCur+1
                ST      Z+,R28
                ST      Z+,R29                      ; }

OSUART0ISR:                       
                CALL    OSUart0Rec          ; Call tick Handler written in C

                CALL    OSIntExit                   ; Notify uC/OS-II about end of ISR

                POP_SP                              ; Restore the hardware stack pointer from task's stack
                POP_SREG_INT
                POP_ALL                           ; Restore all registers
                RETI
;********************我加的到此结束

;********************************************************************************************************
;                            DISABLE/ENABLE INTERRUPTS USING OS_CRITICAL_METHOD #3
;
; Description : These functions are used to disable and enable interrupts using OS_CRITICAL_METHOD #3.
;
;               OS_CPU_SROSCPUSaveSR (void)
;                     Get current value of SREG
;                     Disable interrupts
;                     Return original value of SREG
;
;               voidOSCPURestoreSR (OS_CPU_SR cpu_sr)
;                     Set SREG to cpu_sr
;                     Return
;********************************************************************************************************

OS_CPU_SR_Save:
                IN      R16,_SFR_IO_ADDR(SREG)      ; Get current state of interrupts disable flag
                CLI                                 ; Disable interrupts
                RET                                 ; Return original SREG value in R16


OS_CPU_SR_Restore:
                OUT   _SFR_IO_ADDR(SREG),R16      ; Restore SREG
                RET                                 ; Return



说明:
1)PUSH_ALL和PUSHRS的功能是一样的,一个是ucos官网的例子,一个本网大虾移植的。
2)串口例程SIG_UART0_RECV是我加的,这个标号也是Atmega128的串口0的中断标识,我是参照TIMER0_COMP_vect的模式,不知道能否被识别
3)OSUart0Rec串口接收例程,在另外的主程序中
void OSUart0Rec(void)
{
    if(UCSR0A & (1<<RXC0))
    {
         OS_ENTER_CRITICAL();
         combuffer0=UDR0;               
         OS_EXIT_CRITICAL();       
    }
}

4)串口初始化代码
void InitComm()
{
    // init usrt0
    UCSR0A &=~(1<<U2X0);
    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
    UBRR0H= 0;
    UBRR0L= 51;

/*               
    // init usrt1
    UCSR1B = (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1);
    UCSR1C = (1<<UCSZ11)|(1<<UCSZ10);
    UBRR1H= 0;
    UBRR1L= 51;
*/
}

不知道错在哪儿了?请大虾指正,先谢谢了。

yangsen 发表于 2011-2-12 08:33:08

你都用了ucos了干吗串口中断还用汇编写啊?中断函数里只要仿照OSTickISR函数的结构来写就行了,处理串口接收或者发送数据用邮箱或队列。

hagx 发表于 2011-2-12 09:23:05

回复【1楼】yangsen
-----------------------------------------------------------------------

我就是仿照OSTickISR写的呀

yangsen 发表于 2011-2-12 10:45:03

IN      R16,_SFR_IO_ADDR(SREG)      ; Save the SREG but with interrupts enabled
                SBR   R16,128
                ST      -Y,R16
                PUSH_SP                           ; Save the task's hardware stack pointer onto task's stack
这里为什么又压一次栈?这样在修改任务控制块恢复任务时有可能造成堆栈不平衡,任务不能正常运行。
你可以吧OSTickISR函数直接拷贝下来,把其中的OSTimeTick换成OSUart0Rec,标号改改应该就能正常工作了。当然前提是你的内核已经能够转起来了。
再有,OSUart0Rec函数中最好是用邮箱,队列来处理接收数据,你这样处理的话在任务里处理combuffer0要加上保护才行

hagx 发表于 2011-2-12 11:17:07

回复【3楼】yangsen
-----------------------------------------------------------------------

内核已经跑起来了,3个任务都能正常运行,我想在大规模编程之前先把串口调试好。
我刚才按你说的改了下,直接把OSTickISR的拷贝下来再改标号和调用函数,还是不行。
combuffer0这里用只是为了测试,以后肯定是要用邮箱的。

hagx 发表于 2011-2-12 12:52:25

最新进展,我拷贝TIMER0_COMP_vect后,将SEI的位置挪了下,可以运行,并且可以进入中断,我怀疑是timer0的中断优先级高于uart0,因此当在uart0时引起了中断嵌套。
但是现在从UDR0读的数据确是错的,每次都是0xFE,我确信串口是好的,因为我用正常的(非ucos状态)查询接收可以接收到正确的数据。



SIG_UART0_RECV:
                PUSHRS                              ; Save all registers and status register

                LDS   R16,OSIntNesting            ; Notify uC/OS-II of ISR
                INC   R16                         ;
                STS   OSIntNesting,R16            ;
               
                CLZ                                 ;清零Z标志位,为下面的比较做好准备
                CPI   R16,1                     ;比较OSIntNesting是否为1
                BREQ    OSUART0ISR                  ;如果是1,则跳转至OSTickISR2
               
                ;SEI                                 ; Enable interrupts
               
                CALL   OSUart0Rec                   ; Call uC/OS-IIs tick updating function
                SEI ;开中断挪到这儿***********************************************
                CALL   OSIntExit                   ; Notify uC/OS-II about end of ISR

                POPRS                               ; Restore all registers and status register
                RET                                 ; Note: RET instead of RETI

OSUART0ISR:
                LDS   R30,OSTCBCur                ; Z = OSTCBCur->OSTCBStkPtr
                LDS   R31,OSTCBCur+1            ;

                IN      r28,_SFR_IO_ADDR(SPL)
                ST      Z+,R28                      ; Save Y (R29:R28) pointer
                IN      r29,_SFR_IO_ADDR(SPH)
                ST      Z+,R29                      ;OSTCBCur->OSTCBStkPtr=SP

                ;SEI                                 ; 使能中断,继续执行OSTickISR中被打断的指令(可选用)
                CALL   OSUart0Rec                  ; Call uC/OS-IIs tick updating function
                SEI                              ; 开中断挪到这儿****************************************
                CALL   OSIntExit                   ; Notify uC/OS-II about end of ISR

                POPRS                               ; Restore all registers and status register
                RET

hagx 发表于 2011-2-14 12:53:53

问题解决
我开始对串口的初始化程序InitComm是放在任务中的,后来我把它放在了main函数中,放在任务开始执行之前,就可以了。
谢谢大家!

tuohezhuo 发表于 2012-4-30 22:41:55

mark一下
页: [1]
查看完整版本: Atmega128+GCC+ucos的串口中断程序如何编写