上海万网网站建设,代理网址怎么用,惠州市建设局网站,腾讯官网首页登录入口【STM32笔记】HAL库外部定时器、系统定时器阻塞、非阻塞延时
外部定时器
采用定时器做延时使用时 需要计算好分频和计数 另外还要配置为不进行自动重载
对于50MHz的工作频率 分频为50-1也就是50M/501M 一次计数为1us 分频为50000-1也就是1k 一次计数为1ms 我配置的是TIM6 只…【STM32笔记】HAL库外部定时器、系统定时器阻塞、非阻塞延时
外部定时器
采用定时器做延时使用时 需要计算好分频和计数 另外还要配置为不进行自动重载
对于50MHz的工作频率 分频为50-1也就是50M/501M 一次计数为1us 分频为50000-1也就是1k 一次计数为1ms 我配置的是TIM6 只能下上计数
也就是从0开始计数 计数到counter值为止
所以在while里面要判断计数值不为us
没用到中断 所以不用开启定时器中断
阻塞延时
整体代码如下
void TIM_Delay_us(uint16_t us,TIM_HandleTypeDef* htim)
{TIM_Base_InitTypeDef TIM_Str{0};TIM_Str.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_DISABLE;TIM_Str.Prescaler50-1;TIM_Str.Periodus;TIM_Str.CounterModeTIM_COUNTERMODE_UP; TIM_Base_SetConfig(htim-Instance,TIM_Str);HAL_TIM_Base_Start(htim);while(__HAL_TIM_GET_COUNTER(htim)!us);HAL_TIM_Base_Stop(htim);
}void TIM_Delay_ms(uint16_t ms,TIM_HandleTypeDef* htim)
{TIM_Base_InitTypeDef TIM_Str{0};TIM_Str.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_DISABLE;TIM_Str.Prescaler50000-1;TIM_Str.Periodms;TIM_Str.CounterModeTIM_COUNTERMODE_UP; TIM_Base_SetConfig(htim-Instance,TIM_Str);HAL_TIM_Base_Start(htim);while(__HAL_TIM_GET_COUNTER(htim)!ms);HAL_TIM_Base_Stop(htim);
}尽量不要用tim.h里面的更改分频和更改计数值的函数 改了没用 写结构体更好
另外 还可以通过中断来实现 不过不推荐 因为中断进行不如阻塞来的快
中断就要用
HAL_TIM_Base_Start_IT(htim);但中断可以在回调里面实现其他的功能
非阻塞延时
void TIM_Delay_us(uint16_t us,TIM_HandleTypeDef* htim)
{TIM_Base_InitTypeDef TIM_Str{0};TIM_Str.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_DISABLE;TIM_Str.Prescaler50-1;TIM_Str.Periodus;TIM_Str.CounterModeTIM_COUNTERMODE_UP; TIM_Base_SetConfig(htim-Instance,TIM_Str);HAL_TIM_Base_Start(htim);
// while(__HAL_TIM_GET_COUNTER(htim)!us);
// HAL_TIM_Base_Stop(htim);
}void TIM_Delay_ms(uint16_t ms,TIM_HandleTypeDef* htim)
{TIM_Base_InitTypeDef TIM_Str{0};TIM_Str.AutoReloadPreloadTIM_AUTORELOAD_PRELOAD_DISABLE;TIM_Str.Prescaler50000-1;TIM_Str.Periodms;TIM_Str.CounterModeTIM_COUNTERMODE_UP; TIM_Base_SetConfig(htim-Instance,TIM_Str);HAL_TIM_Base_Start(htim);
// while(__HAL_TIM_GET_COUNTER(htim)!ms);
// HAL_TIM_Base_Stop(htim);
}调用非阻塞后 需要在别的地方调用
while(__HAL_TIM_GET_COUNTER(htim)!ms);
HAL_TIM_Base_Stop(htim);才能实现阻塞延时 如果不调用 则可以自行选择判断时间
系统定时器
Cortex-M架构SysTick系统定时器阻塞和非阻塞延时
阻塞延时
void delay_ms(unsigned int ms)
{SysTick-LOAD 50000000/1000-1; // Count from 255 to 0 (256 cycles) 载入计数值 定时器从这个值开始计数SysTick-VAL 0; // Clear current value as well as count flag 清空计数值到达0后的标记SysTick-CTRL 5; // Enable SysTick timer with processor clock 使能26MHz的系统定时器while(ms--){while ((SysTick-CTRL 0x00010000)0);// Wait until count flag is set 等待}SysTick-CTRL 0; // Disable SysTick 关闭系统定时器
}
void delay_us(unsigned int us)
{SysTick-LOAD 50000000/1000/1000-1; // Count from 255 to 0 (256 cycles) 载入计数值 定时器从这个值开始计数SysTick-VAL 0; // Clear current value as well as count flag 清空计数值到达0后的标记SysTick-CTRL 5; // Enable SysTick timer with processor clock 使能26MHz的系统定时器while(us--){while ((SysTick-CTRL 0x00010000)0);// Wait until count flag is set 等待}SysTick-CTRL 0; // Disable SysTick 关闭系统定时器
}50000000表示工作频率 分频后即可得到不同的延时时间 以此类推
那么 不用两个嵌套while循环 也可以写成
void delay_ms(unsigned int ms)
{SysTick-LOAD 50000000/1000*ms-1; // Count from 255 to 0 (256 cycles) 载入计数值 定时器从这个值开始计数SysTick-VAL 0; // Clear current value as well as count flag 清空计数值到达0后的标记SysTick-CTRL 5; // Enable SysTick timer with processor clock 使能26MHz的系统定时器while ((SysTick-CTRL 0x00010000)0);// Wait until count flag is set 等待SysTick-CTRL 0; // Disable SysTick 关闭系统定时器
}
void delay_us(unsigned int us)
{SysTick-LOAD 50000000/1000/1000*us-1; // Count from 255 to 0 (256 cycles) 载入计数值 定时器从这个值开始计数SysTick-VAL 0; // Clear current value as well as count flag 清空计数值到达0后的标记SysTick-CTRL 5; // Enable SysTick timer with processor clock 使能26MHz的系统定时器while ((SysTick-CTRL 0x00010000)0);// Wait until count flag is set 等待SysTick-CTRL 0; // Disable SysTick 关闭系统定时器
}但是这种写法有个弊端 那就是输入ms后最大定时不得超过计数值也就是不能超过LOAD的最大值否则溢出以后则无法正常工作
而LOAD如果最大是32位 也就是4294967295
晶振为50M的话 50M的计数值为1s 4294967295计数值约为85s
固最大定时时间为85s
但用嵌套while的话 最大可以支持定时4294967295*85s
非阻塞延时
直接改写第二种方法就好了
void delay_ms(unsigned int ms)
{SysTick-LOAD 50000000/1000*ms-1; // Count from 255 to 0 (256 cycles) 载入计数值 定时器从这个值开始计数SysTick-VAL 0; // Clear current value as well as count flag 清空计数值到达0后的标记SysTick-CTRL 5; // Enable SysTick timer with processor clock 使能26MHz的系统定时器//while ((SysTick-CTRL 0x00010000)0);// Wait until count flag is set 等待//SysTick-CTRL 0; // Disable SysTick 关闭系统定时器
}
void delay_us(unsigned int us)
{SysTick-LOAD 50000000/1000/1000*us-1; // Count from 255 to 0 (256 cycles) 载入计数值 定时器从这个值开始计数SysTick-VAL 0; // Clear current value as well as count flag 清空计数值到达0后的标记SysTick-CTRL 5; // Enable SysTick timer with processor clock 使能26MHz的系统定时器//while ((SysTick-CTRL 0x00010000)0);// Wait until count flag is set 等待//SysTick-CTRL 0; // Disable SysTick 关闭系统定时器
}将等待和关闭定时器语句去掉 在使用时加上判断即可变为阻塞
delay_ms(500);
while ((SysTick-CTRL 0x00010000)0);
SysTick-CTRL 0;在非阻塞状态下 可以提交定时器后 去做别的事情 然后再来等待
不过这样又有一个弊端 那就是定时器会自动重载 可能做别的事情以后 定时器跑过了 然后就要等85s才能停下
故可以通过内部定时器来进行非阻塞延时函数的编写
基本上每个mcu的内部定时器都可以配置自动重载等功能 网上资料很多 这里就不再阐述了