3.6 定时器实验
一、实验目的
本节课主要学习K210的定时器功能。
二、实验准备
1.实验元件
独立按键BOOT、RGB灯
2.元件特性
K210芯片定时器总共有3个,每个定时器有4路通道。每个定时器可以设置触发间隔,和定时器中断处理函数。
3.硬件连接
K210开发板出厂默认已经焊接好BOOT按键和RGB灯。按键连接的引脚为IO16。RGB灯R连接的是IO6,G连接的是IO7, B连接的是IO8。
4.SDK中对应API功能
对应的头文件 timer.h
为用户提供以下接口:
• timer_init:初始化定时器。
• timer_set_interval:设置定时间隔。
• timer_set_irq (0.6.0 后不再支持,请使用timer_irq_register)
• timer_set_enable:使能/禁止定时器。
• timer_irq_register:注册定时器中断回调函数。
• timer_irq_deregister:注销定时器中断。
三、实验原理
定时器的核心其实是加1计数器,对机器周期进行计数,每过一个机器周期,计数器自动加1,直到计数器计满溢出。由于计数的周期是固定的,所以根据计数的多少就可以很方便的计算出计数的时间,当符合自己设定的超时时间,则调用中断回调函数,然后重新开始计数。
四、实验过程
1.首先根据上面的硬件连接引脚图,K210的硬件引脚和软件功能使用的是FPIOA映射关系。
这里要注意的是程序里操作的都是软件引脚,所以需要先把硬件引脚映射成软件GPIO功能,操作的时候直接操作软件GPIO即可。由于没有新增加硬件设备,所以初始化与上一节课是一样的。
2.第二步需要初始化外部中断服务,并且使能全局中断。如果没有这一步操作,系统的中断就不会运行,所以也不会调用中断回调函数。
3.在使用RGB灯前需要初始化,也就是把RGB灯的软件GPIO设置为输出模式。
4.然后关闭RGB灯,同样是设置RGB灯的GPIO为高电平则可以让RGB灯熄灭。
5.使用BOOT按键同样需要初始化,设置BOOT键为上拉输入模式,设置按键的GPIO电平触发模式为上升沿和下降沿,也可以设置单上升沿或单下降沿等,设置BOOT按键的中断回调函数为key_irq_cb,参数为空NULL。
6.每次BOOT按下或者松开都会触发中断函数key_irq_cb,在中断里先读取当前按键的状态,保存到key_state中,并且根据key_state的状态设置定时器的状态,当被按下时停止定时器,当被松开时打开定时器。
7.初始化定时器,这里使用的是定时器0通道0,超时时间为500毫秒,定时器中断回调函数为timer_timeout_cb,参数为g_count。
8.定时器中断内的处理,每次中断的时候修改RGB灯的亮灭。此函数相当于定时器打开的情况下,每0.5秒切换一次RGB灯点亮白色或熄灭的状态。
9.点亮RGB灯亮白色的函数为rgb_all_on,即RGB灯内部三种颜色的灯一起亮就变为白色。
10.最后是一个while(1)循环,这个是必须的,否则系统就会退出,不再运行。
11.编译调试,烧录运行
把本课程资料中的timer复制到SDK中的src目录下,
然后进入build目录,运行以下命令编译。
cmake .. -DPROJ=timer -G "MinGW Makefiles"
make
编译完成后,在build文件夹下会生成timer.bin文件。
使用type-C数据线连接电脑与K210开发板,打开kflash,选择对应的设备,再将程序固件烧录到K210开发板上。
五、实验现象
烧录完成固件后,系统会弹出一个终端界面,如果没有弹出终端界面的可以打开串口助手显示调试内容。
RGB灯亮白色,每0.5秒后熄灭再亮白色,一直循环,当按住BOOT键时,定时器停止,RGB灯保存当前的状态,不再切换状态,当松开BOOT键时,定时器恢复启动,RGB灯又开始每0.5秒切换状态。
六、实验总结
1.定时器可以设置纳秒级别的超时时间,并且可以设置中断回调。
2.定时器可以通过控制使能与禁止的方式来暂停和重新启动,而不需要重新配置。
3.K210总共有三个定时器,每个定时器有四个通道。
附:API
对应的头文件 timer.h
初始化定时器。
void timer_init(timer_device_number_t timer_number)
参数名称 | 描述 | 输入输出 |
timer_number | 定时器号 | 输入 |
无。
设置定时间隔。
size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds)
参数名称 | 描述 | 输入输出 |
timer_number | 定时器号 | 输入 |
channel | 定时器通道号 | 输入 |
nanoseconds | 时间间隔(纳秒) | 输入 |
实际的触发间隔(纳秒)。
设置定时器触发中断回调函数,该函数已废弃,替代函数为timer_irq_register。
void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority)
参数名称 | 描述 | 输入输出 |
timer_number | 定时器号 | 输入 |
channel | 定时器通道号 | 输入 |
func | 回调函数 | 输入 |
priority | 中断优先级 | 输入 |
无。
使能禁用定时器。
void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable)
参数名称 | 描述 | 输入输出 |
timer_number | 定时器号 | 输入 |
channel | 定时器通道号 | 输入 |
enable | 使能禁用定时器 | 输入 |
无。
注册定时器触发中断回调函数。
int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx);
参数名称 | 描述 | 输入输出 |
device | 定时器号 | 输入 |
channel | 定时器通道号 | 输入 |
is_single_shot | 是否单次中断 | 输入 |
priority | 中断优先级 | 输入 |
callback | 中断回调函数 | 输入 |
ctx | 回调函数参数 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
注销定时器中断函数。
int timer_irq_deregister(timer_device_number_t device, timer_channel_number_t channel)
参数名称 | 描述 | 输入输出 |
device | 定时器号 | 输入 |
channel | 定时器通道号 | 输入 |
返回值 | 描述 |
0 | 成功 |
非0 | 失败 |
/* 定时器0 通道0 定时1秒打印Time OK! */
void irq_time(void)
{
printf("Time OK!n");
}
plic_init();
timer_init(TIMER_DEVICE_0);
timer_set_interval(TIMER_DEVICE_0, TIMER_CHANNEL_0, 1e9);
timer_set_irq(TIMER_DEVICE_0, TIMER_CHANNEL_0, irq_time, 1);
timer_set_enable(TIMER_DEVICE_0, TIMER_CHANNEL_0, 1);
sysctl_enable_irq();
相关数据类型、数据结构定义如下:
· timer_device_number_t:定时器编号。
· timer_channel_number_t:定时器通道号。
· timer_callback_t:定时器回调函数。
定时器编号
typedef enum _timer_deivce_number
{
TIMER_DEVICE_0,
TIMER_DEVICE_1,
TIMER_DEVICE_2,
TIMER_DEVICE_MAX,
} timer_device_number_t;
成员名称 | 描述 |
TIMER_DEVICE_0 | 定时器 0 |
TIMER_DEVICE_1 | 定时器 1 |
TIMER_DEVICE_2 | 定时器 2 |
定时器通道号。
typedef enum _timer_channel_number
{
TIMER_CHANNEL_0,
TIMER_CHANNEL_1,
TIMER_CHANNEL_2,
TIMER_CHANNEL_3,
TIMER_CHANNEL_MAX,
} timer_channel_number_t;
成员名称 | 描述 |
TIMER_CHANNEL_0 | 定时器通道 0 |
TIMER_CHANNEL_1 | 定时器通道 1 |
TIMER_CHANNEL_2 | 定时器通道 2 |
TIMER_CHANNEL_3 | 定时器通道 3 |
定时器回调函数。
typedef int (*timer_callback_t)(void *ctx);