本帖最后由 Mcuzone_TKN 于 2020-5-15 09:06 编辑
关键词:Microchip Atmel SAM4E SAM4E-EK SAM4E16E 芯片 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);
}
}
|