Air32F103学习笔记-3.1设置RCC和SysTick系统嘀嗒定时器

上一节我们成功点灯,但是没有细说RCC的配置流程。我们这节详细看下时钟树。

寄存器手册,P46

https://cdn.openluat-luatcommunity.openluat.com/attachment/20230907152950811_Air32F103xx_User_Manual_CN-%E5%B8%A6%E7%9B%AE%E5%BD%95%E4%B9%A6%E7%AD%BE.pdficon-default.png?t=N7T8https://cdn.openluat-luatcommunity.openluat.com/attachment/20230907152950811_Air32F103xx_User_Manual_CN-%E5%B8%A6%E7%9B%AE%E5%BD%95%E4%B9%A6%E7%AD%BE.pdf

一. Air32F103的时钟树

比STM32的简单不少(好多没画),咱们整理下

来几个常用的缩写熟悉下先:

1. 4个时钟源

        a. HSE - 高速外部时钟 - 般选8MHZ

        b. LSE - 外部低速时钟 - 一般选32.768KHZ

        c. HSI - 内部高速时钟 - 8MHZ 听说温漂大,一般不使用

        d. LSI - 内部低速时钟 -40KHZ

2. 内部时钟:

        a.PLL:锁相环,不懂,反正挺牛皮的,能倍频。出来的时钟叫PLLCLK,CLK就是Clock的缩写,时钟。

        b.AHB(Advanced High performance Bus):先进高性能总线

        c.APB(Advanced Peripheral Bus):先进外设总线,也有叫外围的。。。

        d.AMBA:AMBA规范主要包括了AHB(Advanced High performance Bus)和APB(Advanced Peripheral Bus)外围总线。

看着比较多哈,但是只要抓住1条主线就行了

1. 板子使用外部8MHZ的晶振作为HSE(紫色框框)

2. 不分频直接走到选择器那里,然后到达PLL锁相环,经过9倍频,PLLCLK变为8M*9=72MHZ

3. AHB不分频,即HCLK=72MHZ

4. APB1预分频器,2分频,所以APB1是36MHZ

5. APB2预分频器,不分频,所以APB2是72MHZ


系统时钟SysTick是多少呢?其实在core.cm3.h中,已经替我们都配置好了。

注:core.cm3是内核寄存器头文件

/**
  \brief   System Tick Configuration
  \details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
           Counter is in free running mode to generate periodic interrupts.
  \param [in]  ticks  Number of ticks between two interrupts.
  \return          0  Function succeeded.
  \return          1  Function failed.
  \note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
           function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
           must contain a vendor-specific implementation of this function.
 */
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}

#endif

/*@} end of CMSIS_Core_SysTickFunctions */

SysTick->CTRL是用来控制系统时钟源,系统时钟源初始化,以及开启系统时钟的。

#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!< SysTick configuration struct */

这里定义了一个结构体指针SysTick,基于基地址SysTick_BASE

SysTick_BASE    =    SCS_BASE +  0x0010UL    UL是无符号long型变量

#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!< SysTick Base Address */

 SCS_BASE  = 0xE000E000UL

#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */

那我们根据以上计算下SysTick的地址=0xE000E000UL+0x0010UL=0xE000E010UL

因为SysTick属于M3内核寄存器,所以在Air32F103寄存器手册中是看不到描述的,需要查看ARM的【Cortex-M3编程手册-英文版】,在第4章,Core peripherals中,起始有对应的寄存器基地址:

可以看到System timer系统定时器的寄存器地址范围是0xE000E010-0xE000E01F 

那么System timer系统定时器的基地址就是0xE000E010

在转到4.5 System Timer(STK),看下寄存器偏移地址是多少:

偏移是0x00,那么STK_CTRL的地址就是 0xE000E010+0x00,即0xE000E010

这和我们刚刚在core.cm3.h中看到的宏定义一致。

再看下这4位分别是干嘛的:

Bit0: ENABLE, 置1,启动系统定时器

Bit1: SysTick中断请求使能,中断都上来了。

Bit2: CLKSOURCE时钟选择,这里可以为AHB/8(0)或者直接就是AHB(置1)

Bit16:COUNTFLAG,计数中断标志位,如果计数到0了,就自动置1;这个方便我们知道啥时候计数完成了,挺好的。而且读这位时,硬件自动清0,贴心~

在上面我们已经将AHB配置为72MHZ,所以这里就看我们怎么选了。

但是core.cm3.h文件里已经帮我们配置好了,包括之前讲的所有配置(HSE,PLL,APB1,APB2),都是默认配置的,我们只要按照AHB=APB2=72MHZ,APB1=36MHZ使用即可

SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;     

这里我们重点看下SysTick_CTRL_CLKSOURCE_Msk是啥意思

又是宏定义:

#define SysTick_CTRL_CLKSOURCE_Pos          2U           //CLK时钟源(左移)位置                                  /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk         (1UL << SysTick_CTRL_CLKSOURCE_Pos) //时钟源0x01左移2位           /*!< SysTick CTRL: CLKSOURCE Mask */

0x1UL左移两位(2U),那就是Bit2被置1了呗,置1,时钟源是AHB=72MHZ

搞清楚了,系统计数器的频率是AHB=72MHZ,也就是说每秒计数72M次。

回到刚刚的时钟树,这里我有个不明白的地方,我觉得厂商的图上有问题。

Systick=AHB/8=9MHZ?

基于上面对core.cm3.h的研究,发现systick的时钟完全取决于配置,可以直接等于AHB,也可以等于AHB/8。

ST的参考手册里,也写了。改Systick的控制和状态寄存器就可以选择时钟源。

ST的手册里,SYSCLK直接等于从前面的选择器出来的HSE,而下面的8分频是系统定时器。

所以这里的时钟树,我改了下 

/**
  \brief   System Tick Configuration
  \details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
           Counter is in free running mode to generate periodic interrupts.
  \param [in]  ticks  Number of ticks between two interrupts. //计数值
  \return          0  Function succeeded.
  \return          1  Function failed.
  \note    When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
           function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
           must contain a vendor-specific implementation of this function.
 */
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) //ticks换成计数值
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) //这里有个条件判断,计数值,不能大于2的24次方
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}

虽然ticks是无符号32位的数,但是,systicks是一个24位的计数器,也就说他的最大值是16777215 (2^24-1,从0开始)。我们要是想获得1秒延时,直接填72000000会溢出。

咱们测试下,写个Systick的配置函数试试。

因为Systick系统嘀嗒定时器,是内核外设,所以咱们单独给他建一个文件夹就叫System。

在里面创建两个文件,Delay.c和Delay.h

Delay.c用来放延时函数,Delay.h用于声明函数,方便其他文件调用Delay.c里的函数

/* Delay.c code */
#include "air32f10x.h"
#define SYSCLK_FREQ_72MHz 72000000

void Delay_ms(uint32_t ticks)
{
	uint16_t i;
	SysTick_Config((SYSCLK_FREQ_72MHz/1000)); //ms,divided by 1000
	for(i=0;i<ticks;i++)  //loop ticks times
	{
		while((SysTick->CTRL&(0x01<<16))==0); //wait, until countflag=1
	}
	SysTick->CTRL&=~0x01; //stop counting
}

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
void Delay_ms(uint32_t ticks);

#endif

main.c

#include "air32f10x.h"
#include "Delay.h"

int main()
{
	
	
	GPIO_InitTypeDef GPIO_InitiateStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitiateStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitiateStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitiateStructure.GPIO_Speed=GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitiateStructure);

	while(1)
	{
		GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_SET);
		Delay_ms(1000);
		GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_RESET);
		Delay_ms(1000);
	
	}
	
	

}

实验现象:

用示波器看下波形

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值