1

我遇到了一些麻烦,我不知道这是我对 Atmel 语法、Atmel Studio 6.0 还是程序本身的理解。我似乎无法让中断处理程序接收一个简单的字符串然后做点什么。当 USART 接收到一个字符时,它会打开 LED,然后如果它接收到不同的字符,它会关闭 LED,我成功地实现了单个字符打开 LED。顺便说一句,我有一个设计板,程序在进入接收子例程时遇到了一些麻烦,因为主程序中的发送代码太大,所以建议我利用中断来解决这个问题。顺便说一句,我正在 EVK1100 AVR32 板 MCU:AT32UC3A0512-U 上试用这个程序,不知道你们中是否有人玩过这些,但它们非常棒。不确定我是否喜欢 Atmel 语法。反正,

我对 Atmel 世界的中断还很陌生。

任何帮助将非常感激。我只对内置的 ASF USART 中断“INTC”项目示例进行了一些修改。

谢谢,

#include <string.h>
#include <avr32/io.h>
#include "compiler.h"
#include "board.h"
#include "print_funcs.h"
#include "intc.h"
#if defined (__GNUC__)
#  if   defined (__AVR32_AP7000__)
#    include "pm_at32ap7000.h"
#  else
#    include "power_clocks_lib.h"
#  endif
#elif defined (__ICCAVR32__) || defined (__AAVR32__)
#  if  defined (__AT32AP7000__)
#    include "pm_at32ap7000.h"
#  else
#    include "power_clocks_lib.h"
#  endif
#endif
#include "gpio.h"
#include "usart.h"
//#include "conf_example.h"    
#  define EXAMPLE_TARGET_PBACLK_FREQ_HZ FOSC0  // PBA clock target frequency, in Hz

#if BOARD == EVK1100
#  define EXAMPLE_USART                 (&AVR32_USART1)
#  define EXAMPLE_USART_RX_PIN          AVR32_USART1_RXD_0_0_PIN
#  define EXAMPLE_USART_RX_FUNCTION     AVR32_USART1_RXD_0_0_FUNCTION
#  define EXAMPLE_USART_TX_PIN          AVR32_USART1_TXD_0_0_PIN
#  define EXAMPLE_USART_TX_FUNCTION     AVR32_USART1_TXD_0_0_FUNCTION
#  define EXAMPLE_USART_CLOCK_MASK      AVR32_USART1_CLK_PBA
#  define EXAMPLE_PDCA_CLOCK_HSB        AVR32_PDCA_CLK_HSB
#  define EXAMPLE_PDCA_CLOCK_PB         AVR32_PDCA_CLK_PBA
#  define EXAMPLE_USART_IRQ             AVR32_USART1_IRQ
#  define EXAMPLE_USART_BAUDRATE        57600
#endif
    /**
     * \brief The USART interrupt handler.
     *
     * \note The `__attribute__((__interrupt__))' (under GNU GCC for AVR32) and
     *       `__interrupt' (under IAR Embedded Workbench for Atmel AVR32) C function
 *       attributes are used to manage the `rete' instruction.
 */
#if defined (__GNUC__)
__attribute__((__interrupt__))
#elif defined(__ICCAVR32__)
__interrupt
#endif

static void usart_int_handler(void)
{   
    static char Cmnd[30];
    int index = 0;
    int c;

    usart_read_char(EXAMPLE_USART, &c);
    Cmnd[index++] = c;

if (c = '\r')
{
    Cmnd[index] = '\0';
    usart_write_line(EXAMPLE_USART, Cmnd);
}

}   


/**
 * \brief The main function.
 *
 * It sets up the USART module on EXAMPLE_USART. The terminal settings are 57600
 * 8N1.
 * Then it sets up the interrupt handler and waits for a USART interrupt to
 * trigger.
 */
int main(void)
{
    static const gpio_map_t USART_GPIO_MAP =
    {
        {EXAMPLE_USART_RX_PIN, EXAMPLE_USART_RX_FUNCTION},
        {EXAMPLE_USART_TX_PIN, EXAMPLE_USART_TX_FUNCTION}
    };

    // USART options.
    static const usart_options_t USART_OPTIONS =
    {
        .baudrate     = 57600,
        .charlength   = 8,
        .paritytype   = USART_NO_PARITY,
        .stopbits     = USART_1_STOPBIT,
        .channelmode  = USART_NORMAL_CHMODE
    };

#if BOARD == EVK1100 || BOARD == EVK1101 || BOARD == UC3C_EK \
    || BOARD == EVK1104 || BOARD == EVK1105 || BOARD == STK600_RCUC3L0 \
    || BOARD == STK600_RCUC3D
    /*
     * Configure Osc0 in crystal mode (i.e. use of an external crystal
     * source, with frequency FOSC0) with an appropriate startup time then
     * switch the main clock source to Osc0.
     */
    pcl_switch_to_osc(PCL_OSC0, FOSC0, OSC0_STARTUP);

#elif BOARD == STK1000
    pm_reset();
#elif BOARD == UC3L_EK
    /*
     * Note: on the AT32UC3L-EK board, there is no crystal/external clock
     * connected to the OSC0 pinout XIN0/XOUT0. We shall then program the
     * DFLL and switch the main clock source to the DFLL.
     */
    pcl_configure_clocks(&pcl_dfll_freq_param);
    /*
     * Note: since it is dynamically computing the appropriate field values
     * of the configuration registers from the parameters structure, this
     * function is not optimal in terms of code size. For a code size
     * optimal solution, it is better to create a new function from
     * pcl_configure_clocks_dfll0() and modify it to use preprocessor
     * computation from pre-defined target frequencies.
     */
#end if

    // Assign GPIO to USART.
    gpio_enable_module(USART_GPIO_MAP,
        sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0]));

    // Initialize USART in RS232 mode.
    usart_init_rs232(EXAMPLE_USART, &USART_OPTIONS,
        EXAMPLE_TARGET_PBACLK_FREQ_HZ);
    print(EXAMPLE_USART, ".: Using interrupts with the USART :.\r\n\r\n");

    // Disable all interrupts.
    Disable_global_interrupt();

    // Initialize interrupt vectors.
    INTC_init_interrupts();

    /*
     * Register the USART interrupt handler to the interrupt controller.
     * usart_int_handler is the interrupt handler to register.
     * EXAMPLE_USART_IRQ is the IRQ of the interrupt handler to register.
     * AVR32_INTC_INT0 is the interrupt priority level to assign to the
     * group of this IRQ.
     */
    INTC_register_interrupt(&usart_int_handler, EXAMPLE_USART_IRQ, AVR32_INTC_INT0);

    // Enable USART Rx interrupt.
    EXAMPLE_USART->ier = AVR32_USART_IER_RXRDY_MASK;
    print(EXAMPLE_USART, "Type a character to use the interrupt handler."
        "\r\nIt will show up on your screen.\r\n\r\n");

    // Enable all interrupts.
    Enable_global_interrupt();

    /**
     * We have nothing left to do in the main, so we may switch to a device
     * sleep mode: we just need to be sure that the USART module will be
     * still be active in the chosen sleep mode. The sleep mode to use is
     * the FROZEN sleep mode: in this mode the PB clocks are still active
     * (so the USART module which is on the Peripheral Bus will still be
     * active while the CPU and HSB will be stopped).
     * --
     * Modules communicating with external circuits should normally be
     * disabled before entering a sleep mode that will stop the module
     * operation: this is not the case for the FROZEN sleep mode.
     * --
     * When the USART interrupt occurs, this will wake the CPU up which will
     * then execute the interrupt handler code then come back to the
     * while(1) loop below to execute the sleep instruction again.
     */

    while(1)
    {
        /*
         * If there is a chance that any PB write operations are
         * incomplete, the CPU should perform a read operation from any
         * register on the PB bus before executing the sleep
         * instruction.
         */
        AVR32_INTC.ipr[0];  // Dummy read


        /*
         * When the device wakes up due to an interrupt, once the
         * interrupt has been serviced, go back into FROZEN sleep mode.
         */
    }
}  
4

1 回答 1

1

尽量保持你的中断处理程序简短。中断处理程序或 ISR 通常在禁用中断的情况下执行。他们的目标是进入,做某事,然后迅速离开。如果您有其他正在运行的中断(例如实时时钟),当您在 ISR 中时它们会被阻止,这可能会导致中断丢失等问题。

这里最好的做法是将输入缓冲区声明为全局静态。还要定义一个static uchar_t have_line或类似的,并在 ISR 中保存每个字符,直到缓冲区已满(重要的检查!),或者您收到 CR (\r)。还要检查换行符 (\n)。保存一个零以空终止缓冲区,然后设置have_line = 1.

在您的主循环中,等待have_line非零,然后处理输入缓冲区中的内容。最后,将 have_line 设置回零。

这样一来,您的 ISR 就简短且相当稳健。

在您的示例代码中,该功能是否usart_write_line需要启用中断?

哎呀!抱歉,我刚刚注意到您的索引不是静态变量。这意味着每次调用例程时它将被初始化为零。在int index前面添加一个静态声明符,这应该可以对其进行排序。

于 2013-09-10T16:29:58.473 回答