Mcuzone_TKN 发表于 2020-4-30 17:43:19

SAM4E-EK开发板代码解读01——LED闪烁

本帖最后由 Mcuzone_TKN 于 2020-5-15 09:06 编辑

关键词:Microchip AtmelSAM4E SAM4E-EKSAM4E16E 芯片 LED闪烁 按键

概述:解读通过GPIO控制LED的工作流程,并提供GPIO引脚修改方法。

从原理图可知(图1),LED通过GPIO进行控制,当GPIO引脚为高电平时,LED两端均为高电平,LED不亮;当GPIO引脚为低电平时,LED点亮。

LED的亮灭控制通过按键来实现,当按键按下时,LED灭,按键再次按下,LED亮。

按键采用中断方式,初始化流程为:
分配时钟给指定按键引脚->引脚配置为输入模式->设定下降沿出发->使能中断。


LED的初始化流程为:
分配时钟给指定按键引脚->引脚配置为输出模式->初始化输出为高,此时LED不亮


打开产品光盘SAM4E16E-EK/SAM4E16E-EK中文资料/softpack软件包/Atmel Studio 7,打开01_GETTING-STARTED例子。

//当对应的按钮按下时,就改变LED的状态
//修改LED 可以选择对应的LED闪烁
static void ProcessButtonEvt (uint8_t uc_button)
{

      if (uc_button == 0) {
                g_b_led0_active = !g_b_led0_active;

               //如果LED0激活就用LED0
                if (!g_b_led0_active) {
                        ioport_set_pin_level(LED0_GPIO, IOPORT_PIN_LEVEL_HIGH);
                }
      }

#ifdef LED1_GPIO   
      else {
                g_b_led1_active = !g_b_led1_active;

                // 如果LED1激活的就用LED1
                if (g_b_led1_active) {
                        ioport_set_pin_level(LED1_GPIO, IOPORT_PIN_LEVEL_LOW);
                        tc_start(TC0, 0);
                }
                //否则就关闭LED1
                else {
                        ioport_set_pin_level(LED1_GPIO, IOPORT_PIN_LEVEL_HIGH);
                        tc_stop(TC0, 0);
                }
      }
#endif
}


//处理按键1上升边中断   处理LED1的变化
static void Button1_Handler(uint32_t id, uint32_t mask)
{
      if (PIN_PUSHBUTTON_1_ID == id && PIN_PUSHBUTTON_1_MASK == mask) {
                ProcessButtonEvt(0);
      }
}

#ifndef BOARD_NO_PUSHBUTTON_2
//处理按钮2下降沿中断   处理LED2的变化
static void Button1_Handler (uint32_t id, uint32_t mask)
{
      if (PIN_PUSHBUTTON_2_ID == id && PIN_PUSHBUTTON_2_MASK == mask) {
                ProcessButtonEvt(1);
      }
}
#endif


//配置按钮 将PIO配置为输入 并生成相应的中断 按下或者释放

static void configure_buttons (void)
{
      //配置按钮1
      pmc_enable_periph_clk(PIN_PUSHBUTTON_1_ID);
      pio_set_debounce_filter(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_MASK, 10);
      //上升沿中断
      pio_handler_set(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_ID,
                        PIN_PUSHBUTTON_1_MASK, PIN_PUSHBUTTON_1_ATTR, Button1_Handler);
      NVIC_EnableIRQ((IRQn_Type) PIN_PUSHBUTTON_1_ID);
      pio_handler_set_priority(PIN_PUSHBUTTON_1_PIO,
                        (IRQn_Type) PIN_PUSHBUTTON_1_ID, IRQ_PRIOR_PIO);
      pio_enable_interrupt(PIN_PUSHBUTTON_1_PIO, PIN_PUSHBUTTON_1_MASK);

      #ifndef BOARD_NO_PUSHBUTTON_2
       //配置按钮2
      pmc_enable_periph_clk(PIN_PUSHBUTTON_2_ID);
      pio_set_debounce_filter(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_MASK, 10);
      //下降沿中断
      pio_handler_set(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_ID,
                        PIN_PUSHBUTTON_2_MASK, PIN_PUSHBUTTON_2_ATTR, Button2_Handler);
      NVIC_EnableIRQ((IRQn_Type) PIN_PUSHBUTTON_2_ID);
      pio_handler_set_priority(PIN_PUSHBUTTON_2_PIO,
                        (IRQn_Type) PIN_PUSHBUTTON_2_ID, IRQ_PRIOR_PIO);
      pio_enable_interrupt(PIN_PUSHBUTTON_2_PIO, PIN_PUSHBUTTON_2_MASK);
#endif
}

//用于TC0中断的中断处理程序,切换LED的状态
void TC0_Handler (void)   
{
      volatile uint32_t ul_dummy;

      //清除状态位以确定中断
      ul_dummy = tc_get_status(TC0, 0);

      //避免编译器报警
      UNUSED(ul_dummy);

#ifdef LED1_GPIO
      //切换LED状态
      ioport_toggle_pin_level(LED1_GPIO);
#endif

      printf("2 ");
}



//配置定时器计数器0 每250ms产生一个中断
static void configure_tc(void)
{
      uint32_t ul_div;
      uint32_t ul_tcclks;
      uint32_t ul_sysclk = sysclk_get_cpu_hz();

      //配置PMC
      pmc_enble_periph_clk(ID_TC0);

      //将TC配置成4HZ频率,在RC上比较触发器
      tc_find_mck_divisor(4, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
      tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
      tc_write_rc(TC0, 0, (ul_sysclk / ul_div) / 4);

      //配置RC并且启用中断
      NVIC_EnableIRQ((IRQn_Type) ID_TC0);
      tc_enable_interrupt(TC0, 0, TC_IER_CPCS);

#ifdef LED1_GPIO
      //如果启用LED1就启用计数器
      if (g_b_led1_active) {
                tc_start(TC0, 0);
      }
#else
      tc_start(TC0, 0);
#endif
}


int main(void)
{      
       //初始化SAM系统
      sysclk_init();
      board_init();   

       //初始化uart
      configure_console();


       //输出例子信息
      puts(STRING_HEADER);

       //配置系统时钟为1ms    修改1000可以改变LED闪烁时间   
      puts("Configure system tick to get 1ms tick period.\r");
      if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
                puts("-F- Systick configuration error\r");
                while (1);
      }

      puts("Configure TC.\r");
      configure_tc();

      puts("Configure buttons with debouncing.\r");
      configure_buttons();

      printf("Press %s to Start/Stop the %s blinking.\r\n",
                        PUSHBUTTON_1_NAME, LED_0_NAME); // k3按下 LED0熄灭    按键再次按下 LED0亮

#ifndef BOARD_NO_PUSHBUTTON_2
      printf("Press %s to Start/Stop the %s blinking.\r\n",
                        PUSHBUTTON_2_NAME, LED_1_NAME); //k4按下 LED1熄灭   按键再次按下 LED1亮
#endif

      while (1) {
               //等待LED激活
                while (!g_b_led0_active);
               //如果激活 就切换LED的状态
                if (g_b_led0_active) {
                        ioport_toggle_pin_level(LED0_GPIO);
                        printf("1 ");
                }
               //等待500ms
                mdelay(500);
      }
}




页: [1]
查看完整版本: SAM4E-EK开发板代码解读01——LED闪烁