STM32 滴答时钟 SysTick 的使用 STM32F103C8T6
程序完成利用STM32F103C8T6 滴答时钟 SysTick进行定时,每隔1秒输出脚PC13的小灯闪烁一下。
注意,小灯每隔1秒闪烁只是转换状态,可以理解为定时或1个脉冲时间,但并不是频率,频率要2个
脉冲时间2秒,所以要测频率的话是0.5Hz,即频率=1/2秒= 0.5Hz 。
1 使用中断的方法
修改stm32f10x_it.c文件,增加下面内容:
extern void LED_PC13 (); //外部引入函数声明 加在文件首部
void SysTick_Handler(void) //中断入口
{
LED_PC13 (); //亮灯取反灭灯函数
}
下面是main.c
#include "stm32f10x.h"
//**********************************************************************************
void GPIO_CFG() //亮灯引脚配置函数
{
GPIO_InitTypeDef GPIO_InitStructure; //声明GPIO_InitStructure结构变量
// 原版创作,引用请指明出处 https://www.cnblogs.com/beiyhs/p/12438787.html 北有寒山
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能AHB预分频器到端口C的开关
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //指定脚13输出
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设定端口最快输出50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure); //按以上参数设置C口
GPIO_SetBits( GPIOC, GPIO_Pin_13); //置高GPIO_Pin_13,关闭LED
}
//*********************************************************************************
void LED_PC13(void) //亮灯取反灭灯函数
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, //指定修改PC13脚的位
(BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)))); //读PC状态后取反
}
//*********************************************************************************
//*********************************************************************************
int main(void)
{
GPIO_CFG() ; //亮灯脚PC13的设置函数
SysTick_Config(9000000); //重装值设9M,定时1秒
//SysTick_Config(9000); //重装值设9K,定时1毫秒
//SysTick_Config(9); //重装值设9,定时1微秒
//NVIC_SetPriority (SysTick_IRQn, 0); //设SysTick中断优先级最高,不会在中断时被别的中断打断
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //配置SysTick时钟=HCLK时钟/8
//即72M/8=9MHz 即记数9M次耗时1秒
//注意要放在SysTick_Config函数之后
//如果屏蔽此句,默认使用的时钟是72M
//将上面9000000 改为72000000仍可得到
//1秒定时
while (1)
{ }
}
说明:
1.1 systick定时器的内部计数器是24位递减的,最大重装值0xFFFFFF,即16777215,设置时不能超此值。
1.2 使用systick定时器,只需调用SysTick_Config(uint32_t ticks)函数即可,该函数可以自动完成重装载
值的装载、时钟源选择、计数寄存器复位、中断优先级的设置(默认最低)、开中断、开始计数的工作。
一次搞定,是不是很爽。函数是在core_cm3.h头文件中进行定义的。
1.3 要修改时钟源,比如外部时钟,可以修改SysTick_CLKSourceConfig函数内部,也可按照SysTick_Config
中默认设置FCLK不变。
1.4 要修改中断优先级调用 NVIC_SetPriority函数,函数在core_cm3.h
1.5 systick是cortex_m3的标配,不是外设。故不需要在RCC寄存器组打开他的时钟。
1.6 每次systick溢出后会置位计数标志位和中断标志位,计数标志位在计数器重装载后被清除,而中断标志位
也会随着中断服务程序的响应被清除,所以这两个标志位都不需要手动清除。
2 使用延时的方法
下面是下面是main.c
//*********************************************************************************
#include "stm32f10x.h"
//************************************************
void delay_ms(unsigned int ms) //把ms换成us,下面9000换成9,就改成了us定时函数
{
unsigned int tmp = 0;
SysTick->LOAD = ms * 9000; // 重装寄存器 设置 72MHz/9000=9MHz
SysTick->VAL = 0x00; // 当前计数寄存器 清零
SysTick->CTRL = 0x01; // 控制寄存器 使能systick,禁止中断,时钟频率AHB/8
do
{
tmp = SysTick->CTRL; // 读取控制寄存器的值赋给tmp
}
while (!(tmp & (1<<16))); // 就是读取tmp的第16位的值,这一位如果为0就表示计数器的值不是0(即
// 还在计数),如果是1就表示计数器已经自减到0了,计数结束。
//假设该值为0,还在计数,套上外面的!取反为1,继续做do的内容。
SysTick->VAL = 0x00; // 当前计数寄存器 清零
SysTick->CTRL = 0x00; //失能systick
}
//*********************************************************************************
int main(void)
{
GPIO_CFG() ; //亮灯脚PC13 设置 参照上面同名函数,不再贴出
while(1)
{
Delay_ms(1000);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
Delay_ms(1000);
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
}
//*********************************************************************************************************
说明: 上面的定时函数如果用到us级别时,误差还是不能忽视的,尤其是10us级别误差很大的这是因为
程序指令的执行、跳转都是要花费时间的,也是在us级别。如果是us级精确定时输出控制的话,可以考
虑使用PWM方式,毕竟设定一次即可,后面全是硬件自己控制。