定时器
目录
定时器
回顾GPIO、中断
定时器的分类
一、系统滴答定时器
应用:非阻塞轮询思想
回顾GPIO、中断
- 理论:
GPIO:八种模式概念,能够根据电路的实际情况,去分析该使用哪一种模式。
上拉 下拉 浮空 模拟
推挽 开漏 复用推挽 复用开漏
中断:知道中断的概念、中断的运行流程、中断的优先级、中断在内核和 mcu 如何管理。
目的:提高实时性
流程:中断源发送中断请求,cpu 收到请求后,暂停当前的主流程、进行压栈,去执行中断,执行完毕之后回到刚才的位置、进行出栈,继续执行。
内核: 256 个中断(240+16) 256 个优先级 8 位数
单片机: 84 个中断(68(不同的单片机型号不一样)+16个系统异常)
16 个优先级
4 位数(高四位)
优先级:(数字越小,优先级越高)
抢占:高抢占可以打断低抢占
响应:抢占一致,并且同时发生,谁的响应高,谁就先执行。
优先级分组:决定抢占和响应各自的取值范围
- 代码:
寄存器、库函数的使用
记住代码的框架、流程。
应用函数:每一个模块的应用函数都不一样
- 初始化函数:
时钟 :
IO :
外设:每一个外设,都不一样。
中断:
其他:每一个模块,都不一样。
定时器的分类
-- 软件定时器:不存在硬件,系统模拟的
- Systick:系统滴答定时器
-- 硬件定时器:硬件真实存在,8 个
- 基础定时器:tim2 tim3
- 通用定时器:tim4 tim5 tim6 tim7
- 高级定时器:tim1 tim8
一、系统滴答定时器
Systick:处在内核里面
内核手册 150 页,计数器的计数范围:2 的 24 次方,最大值:2 的 24 次方减 1
-- 组成:
- 计数器: 计数(周期性)
- 时钟频率:计数的频率 如果是 1Mhz/s == 1M/s(1s计数1M次)
- 重装载值:计数的最大值
时钟频率为1MHz/s = 1M/s (1s计数1M,100ms计数100000)(计一次数1/1Ms) 那么要100ms,要计数多少次?是100000
-- 计数方式:
- 向上计数:从 0 计数到重装载值
- 向下计数:从重装载值计数到 0
应用:非阻塞轮询思想
-
采用系统滴答定时器可以达到非阻塞
-
系统滴答函数
//SysTick_Config(72M); //滴答定时器初始化 //()里面写的是重装载值 //时钟频率是72MHz //要想实现1s的定时,写72M
SysTick_Config(72K); //定时1ms
-
该定时器已经被系统初始化,所以不需要再次初始化
-
找到定时器的中断服务函数
- 这里设置的是定时1ms,所以每1ms进入一次中断服务函数,所以这里可以设置一个全局变量,每进入一次中断,该变量加1,这样就可以实现定时1ms。
-- 在.h文件中声明全局变量
- 按键不会影响流水灯
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组(相当于内核的第五组)因为在整个工程里只用分一次,所以写在main函数
led_init();
buzzer_init();
relay_init();
key_init();
// buzzer_on();
// Delay_nms(100);
// buzzer_off();
relay_on();
Delay_nms(100);
relay_off();
uint8_t keyflag = 0;
while(1)
{
SysTick_Config(72000); //定时1ms
while(1)
{
//非阻塞
if(ledtime >= 1000)//1s后执行
{
ledtime = 0;
water_led();
}
if(keytime>=50)//50ms执行一次
{
keytime=0;
keyflag = get_key();
switch(keyflag)
{
case 1: buzzer_on(); break;
case 2: buzzer_off(); break;
}
}
}
}
}
uint8_t waterflag = 0;
void water_led(void)
{
switch(waterflag)
{
case 0:LED1(1);LED2(0);LED3(0);LED4(0);break;
case 1:LED1(0);LED2(1);LED3(0);LED4(0);break;
case 2:LED1(0);LED2(0);LED3(1);LED4(0);break;
case 3:LED1(0);LED2(0);LED3(0);LED4(1);break;
}
waterflag++;
waterflag %= 4;
}