中断和定时器是CPU必不可少的部分,详细的介绍这里不过多赘述,我们直接看一下代码。定时器的代码主要结合C去讲解,这样比较清楚。
中断
from machine import Pin
p2 = Pin(2, Pin.IN, Pin.PULL_UP)
p2.irq(lambda pin: print("IRQ with flags:", pin.irq().flags()),
Pin.IRQ_FALLING)
定时器功能也很基础,而且只有一个,主要功能如下:
- 64位计数器 (频率固定1MHz,所以要好几千年才能溢出)
- 4个闹钟 (闹钟是只匹配低32B,最大间隔4295秒)
- 寄存器自带映射,所以多个处理器同时访问也不用考虑竞争问题(无需考虑竞争问题)
其中ALARM功能只会发起一次中断,中断发生后就会清除ARMED位,所有函数都有他的毫秒版本和微秒版本。
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/util/queue.h"
bool timer_callback(repeating_timer_t *rt);
queue_t sample_fifo;
// using struct as an example, but primitive types can be used too
typedef struct element {
uint value;
} element_t;
const int FIFO_LENGTH = 32;
int main() {
stdio_init_all();
int hz = 25;
queue_init(&sample_fifo, sizeof(element_t), FIFO_LENGTH);
repeating_timer_t timer;
// negative timeout means exact delay (rather than delay between callbacks)
if (!add_repeating_timer_us(-1000000 / hz, timer_callback, NULL, &timer)) {
printf("Failed to add timer\n");
return 1;
}
// read some blocking
for (int i = 0; i < 10; i++) {
element_t element;
queue_remove_blocking(&sample_fifo, &element);
printf("Got %d: %d\n", i, element.value);
}
// now retrieve all that are available periodically (simulate polling)
for (int i = 0; i < 10; i++) {
int count = queue_get_level(&sample_fifo);
if (count) {
printf("Getting %d, %d:\n", i, count);
for (; count > 0; count--) {
element_t element;
queue_remove_blocking(&sample_fifo, &element);
printf(" got %d\n", element.value);
}
}
sleep_us(5000000 / hz); // sleep for 5 times the sampling period
}
cancel_repeating_timer(&timer);
// drain any remaining
element_t element;
while (queue_try_remove(&sample_fifo, &element)) {
printf("Got remaining %d\n", element.value);
}
queue_free(&sample_fifo);
printf("Done\n");
}
bool timer_callback(repeating_timer_t *rt) {
static int v = 100;
element_t element = {
.value = v
};
v += 100;
if (!queue_try_add(&sample_fifo, &element)) {
printf("FIFO was full\n");
}
return true; // keep repeating
}
CMakeLists.txt:
if (NOT PICO_TIME_NO_ALARM_SUPPORT)
add_executable(periodic_sampler
periodic_sampler.c
)
# Pull in our (to be renamed) simple get you started dependencies
target_link_libraries(periodic_sampler pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(periodic_sampler)
# add url via pico_set_program_url
example_auto_set_url(periodic_sampler)
endif()
lowlevel:
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/timer.h"
#include "hardware/irq.h"
/// \tag::get_time[]
// Simplest form of getting 64 bit time from the timer.
// It isn't safe when called from 2 cores because of the latching
// so isn't implemented this way in the sdk
static uint64_t get_time(void) {
// Reading low latches the high value
uint32_t lo = timer_hw->timelr;
uint32_t hi = timer_hw->timehr;
return ((uint64_t) hi << 32u) | lo;
}
/// \end::get_time[]
/// \tag::alarm_standalone[]
// Use alarm 0
#define ALARM_NUM 0
#define ALARM_IRQ TIMER_IRQ_0
// Alarm interrupt handler
static volatile bool alarm_fired;
static void alarm_irq(void) {
// Clear the alarm irq
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
// Assume alarm 0 has fired
printf("Alarm IRQ fired\n");
alarm_fired = true;
}
static void alarm_in_us(uint32_t delay_us) {
// Enable the interrupt for our alarm (the timer outputs 4 alarm irqs)
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
// Set irq handler for alarm irq
irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);
// Enable the alarm irq
irq_set_enabled(ALARM_IRQ, true);
// Enable interrupt in block and at processor
// Alarm is only 32 bits so if trying to delay more
// than that need to be careful and keep track of the upper
// bits
uint64_t target = timer_hw->timerawl + delay_us;
// Write the lower 32 bits of the target time to the alarm which
// will arm it
timer_hw->alarm[ALARM_NUM] = (uint32_t) target;
}
int main() {
stdio_init_all();
printf("Timer lowlevel!\n");
// Set alarm every 2 seconds
while (1) {
alarm_fired = false;
alarm_in_us(1000000 * 2);
// Wait for alarm to fire
while (!alarm_fired);
}
}
CMakeLists.txt:
if (PICO_ON_DEVICE)
add_executable(timer_lowlevel
timer_lowlevel.c)
# Disable SDK alarm support for this lowlevel example
set(PICO_TIME_DEFAULT_ALARM_POOL_DISABLED 1)
target_link_libraries(timer_lowlevel pico_stdlib)
# create map/bin/hex file etc.
pico_add_extra_outputs(timer_lowlevel)
# add url via pico_set_program_url
example_auto_set_url(timer_lowlevel)
endif ()