原理
SysTick 定时器也叫 SysTick 滴答定时器,它是 Cortex-M3 内核的一个外设, 被嵌入在 NVIC 中。它是一个 24 位向下递减的定时器,每计数一次所需时间为 1/SYSTICK,SYSTICK 是系统定时器时钟,它可以直接取自系统时钟,还可以通过系统时钟 8 分频后获取。
当定时器计数到 0 时,将从 LOAD 寄存器中自动重装定时器初值,重新向下递减计数,如此循环往复。如果开启SysTick 中断的话,当定时器计数到 0,将产生一个中断信号。因此只要知道计数的次数就可以准确得到它的延时时间。
在 STM32F1 库函数中,并没有提供相应的 SysTick 定时器配置函数,我们要操作 SysTick 定时器就需要了解它的寄存器功能。CTRL 是 SysTick 定时器的控制及状态寄存器。LOAD 是 SysTick 定时器的重装载数值寄存器。VAL 是 SysTick 定时器的当前数值寄存器。
步骤
- 编写SysTick驱动程序(STM32F1系列通用)
- 将固件库文件misc.c添加至工程,misc.c中包含SysTick寄存器的操作函数
- 编写头文件:函数声明
- 编写驱动文件:初始化函数、延时us函数、延时ms函数
- 对GPIO的IDR和ODR寄存器位操作进行封装(STM32F1系列通用)
- 编写LED驱动程序
- 编写头文件:宏定义连接LED的端口、端口引脚、端口时钟、引脚位带,函数声明
- 编写驱动文件:
- LED初始化函数:开启端口时钟,定义GPIO_InitTypeDef结构体变量并初始化,拉高引脚电平
- 主函数调用延时初始化函数、延时函数
代码
//SysTick.h
#ifndef _SYSTICK_H
#define _SYSTICK_H
#include "system.h"
void SysTick_Init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif
//SysTick.c
#include "SysTick.h"
static u8 fac_us = 0; //保存倍乘数
static u16 fac_ms = 0;
void SysTick_Init(u8 SYSCLK)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //将CTRL寄存器的第二位置0,即用外部时钟源
fac_us = SYSCLK/8; //72/8
fac_ms = (u16)fac_us*1000;
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD = nus*fac_us;//重装载值
SysTick->VAL = 0x00;//当前数值清0
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//使能SysTick
do
{
temp = SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16)));//定时器开启且未倒数到0
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//失能SysTick
SysTick->VAL = 0x00;//当前数值清0
}
/*
注意:nms的值,SysTick->LOAD为24位寄存器,不要大于0xffffff*8*1000/SYSCLK,对72M条件下,nms<=1864ms
*/
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//system.c
#include "system.h" //头文件中把GPIO的IDR和ODR寄存器位操作进行了封装
//system.h
#ifndef _system_H
#define _system_H
#include "stm32f10x.h"
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
#endif
//led.h
#ifndef _led_H
#define _led_H
#include "stm32f10x.h" //定义了各种地址
#include "system.h"
#define LED1_PORT GPIOB
#define LED1_PIN GPIO_Pin_5
#define LED1_PORT_RCC RCC_APB2Periph_GPIOB
#define LED2_PORT GPIOE
#define LED2_PIN GPIO_Pin_5
#define LED2_PORT_RCC RCC_APB2Periph_GPIOE
#define LED1 PBout(5)
#define LED2 PEout(5)
void LED_Init(void);
#endif
//led.c
#include "led.h"
void LED_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(LED1_PORT_RCC|LED2_PORT_RCC, ENABLE);
GPIO_InitStructure.GPIO_Pin = LED1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED1_PORT, &GPIO_InitStructure);
GPIO_SetBits(LED1_PORT, LED1_PIN);
GPIO_InitStructure.GPIO_Pin = LED2_PIN;
GPIO_Init(LED2_PORT, &GPIO_InitStructure);
GPIO_SetBits(LED2_PORT, LED2_PIN);
}
//main.c
#include "system.h"
#include "SysTick.h"
#include "led.h"
int main()
{
LED_Init();
SysTick_Init(72);
while(1)
{
LED1 = 0;
LED2 = 0;
delay_ms(500);
LED1 = 1;
LED2 = 1;
delay_ms(500);
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)