完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、 前提了解
系统时钟systick是STM32内部的硬件资源,我们首先要知道,MCU内部资源应该在Cortex-M3权威指南上查询;而STM32中文参考手册主要是对MCU外部外设资源的描述。 二、 手册查询和分析 如2.1图示,在Cortex-M3权威指南目录找到systick。 内容如下图。 该定时器有4个寄存器控制SysTick定时器,如下图所示。 如寄存器对应位的描述,可以知道这个寄存器是配置时钟源的选择和该systick定时器模块的是使能。 这个是我们配置延时或者定时的值,最大重载值为0xFFFFFF。 这个一般来说是用来获取期值来判断一个周期的计数是否已满。 这个校准寄存器一般我们不会使用,除非是要设置一些额外精准的东西,寄存器下图蓝色框内有相关的解释说明。(红色介绍此寄存器使用案例等) 经过上面的分析我们应该有个大致的配置思维了。 这里还要注明一点,我们使用到的是外部时钟,所以要看看时钟源的配置或者说是时钟源流入的频率是怎么样的,时钟树如下图(在中文参考手册时钟章节) 三、 程序编写 1、.h文件的编写 这一段程序就没什么好说的,清除的,我发布的DMA实验有详细的说明。 2、.c文件 ①用无论是用内部还是外部的时钟,都需要使能使用到的时钟。 然后获取已转换过来的外部时钟频率 ②将获取到的source_clk单位是MHz,将进来的时钟频率f*source_clk=10^-6秒,设置到最基本的每微秒的(source_cl)载值后,在乘我们需要的us数即转化为计数器要计数的载数值,然后清除计数器的值,从(空白页)开始计数,计完数后要关闭计数器并漂白计数器。 ③这个ms级延时函数与us级延时函数是相似的,这里我就不多讲了。 不理解计数的话,看如下: 假设进来分频后的时钟就为9MHz,那么也就是每秒节拍数是9000000次,f=1/9000000,那我需要一个周期为1us,即 f9=1/1000000s = 1us,f是真实的时钟频率,而9是我们让程序在这个时钟频率下计算9次得到软件分频后的1us 那么重载值就是9nus就是需要延时nus微秒,这个重载值不得超过0xFFFFFF值。** 四、 Keil仿真调试 运行delay_ms1(1000);这行程序总共计数72005299-5215=72000084次,(在72MHZ)情况下,所以这可以近似认为1s。至于sec为什么7.2秒,我也不清楚,希望各位大神能告诉我。 五、 程序: test.c: #include "stdio.h" #include "gpio.h" #include "USART1.h" #include "delay_ms.h" #include "clock.h" #include "USART1.h" #include "key.h" #include "DMA.h" int main(void) { RCC_Config(9); //72MHz delay_init1(72); //打开延时 GPIO_Init(); //初始化LED口 while(1) { GPIOB->GPIO_ODR^=1<<5; delay_ms1(1000); GPIOE->GPIO_ODR^=1<<5; } } delay.h: #ifndef __DELAY_MS_H #define __DELAY_MS_H #include "RCC.h" //systick寄存器基地址 #define SYSTICK_BASE (0xE000E010) //systick寄存器结构体 typedef struct { volatile unsigned int CTRL; //SysTick控制及状态寄存器 volatile unsigned int LOAD; //SysTick重装载数值寄存器 volatile unsigned int VAL; //SysTick当前数值寄存器 volatile unsigned int CALIB; //SysTick校准数值寄存器 }SYSTICK_Type; //systick寄存器指针 #define SYSTICK ((SYSTICK_Type *) SYSTICK_BASE) static u16 source_clk; static u16 count_us=0; //us延时最小单位载值->倍乘值 static u16 count_ms=0; //ms延时最小单位载值->倍乘值 void delay_init1(u8 sysclk); void delay_ms1(u16 nms); void delay_us1(u16 nus); #endif delay.c #include "delay_ms.h" //初始化systick作为delay延时函数 void delay_init1(u8 sysclk) { SYSTICK->CALIB&=~(1<<2); //使能外部时钟 source_clk=sysclk/8; //转化为外部时钟源的频率,8分频,历72MHz/8=9MHz(也就是进来一开始的时钟) } //延时最大是有个度的 //假设时钟就为9MHz,那么也就是每秒节拍数是9000000次,f=1/9000000 //那我需要一个周期为1us,f*9=1/1000000 s = 1us //那么以1us,我们可以设置多少微秒呢?f*load_max=1864135us约为1864ms //最大重载值 //微秒延时 void delay_us1(u16 nus) { u32 temp; //保存当前计数器值 count_us=source_clk; //单位频率MHz也就是us级别,10^-6秒 SYSTICK->LOAD=count_us*nus; //将需要的定时转化为时间重载值 SYSTICK->VAL=0x00; //清空计数器 SYSTICK->CTRL=0x01 ; //开始倒数 do { temp=SYSTICK->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SYSTICK->CTRL=0x00; //关闭计数器 SYSTICK->VAL=0X00; //清空计数器 } |
|
|
|
只有小组成员才能发言,加入小组>>
3294 浏览 9 评论
2970 浏览 16 评论
3473 浏览 1 评论
9023 浏览 16 评论
4061 浏览 18 评论
1140浏览 3评论
589浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
579浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2313浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1876浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-4 22:29 , Processed in 0.994296 second(s), Total 46, Slave 37 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号