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;
*/
}
不知道错在哪儿了?请大虾指正,先谢谢了。 你都用了ucos了干吗串口中断还用汇编写啊?中断函数里只要仿照OSTickISR函数的结构来写就行了,处理串口接收或者发送数据用邮箱或队列。 回复【1楼】yangsen
-----------------------------------------------------------------------
我就是仿照OSTickISR写的呀 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要加上保护才行 回复【3楼】yangsen
-----------------------------------------------------------------------
内核已经跑起来了,3个任务都能正常运行,我想在大规模编程之前先把串口调试好。
我刚才按你说的改了下,直接把OSTickISR的拷贝下来再改标号和调用函数,还是不行。
combuffer0这里用只是为了测试,以后肯定是要用邮箱的。 最新进展,我拷贝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 问题解决
我开始对串口的初始化程序InitComm是放在任务中的,后来我把它放在了main函数中,放在任务开始执行之前,就可以了。
谢谢大家! mark一下
页:
[1]