3912|8

26

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

stm32f10x库文件的学习 [复制链接]

——————————————————————————————————————————————————————————————————————————
system_stm32f10x.c 文件
——————————————————————————————————————————————————————————————————————————
system_stm32f10x.c文件主要有1个全局变量u32 SystemCoreClock(存放系统主频,以Hz为单位),2个外部函数void SystemInit(void)和void SystemCoreClockUpdate(void);
SystemInit()在启动文件复位服务函数中首先被调用完成系统时钟的初始化,然后跳转到库函数__main()完成堆栈、堆的初始化工作,然后调用main()函数,跳转到用户程序中。
LDR     R0, =SystemInit
BLX     R0
LDR     R0, =__main
BX      R0
现在分析SystemInit()函数:
void SystemInit (void)
{
  /* 首先把RCC寄存器恢复为复位状态 ,省略此处代码,有兴趣的可以自己查看源代码*/
  /* 然后调用SetSysClock()函数配置System clock frequency, HCLK, PCLK2 and PCLK1频率和FLASH有关的一些功能*/
  SetSysClock();
}
接下来分析SetSysClock()函数
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
}可以看出来,根据宏定义配置调用相应的函数,一般都习惯配置为主频72M,那么看看SetSysClockTo72()函数
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  /* 高速外部晶振HSE使能 */   
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);//RCC_CR_HSEON这些常数都定义在stm32f10x.h文件中
  /* 等待HSE稳定,如果在HSEStartUp_TimeOut时间内还没有稳定,那么就退出此函数*/
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut));
/*HSE稳定启动后,HSEStatus置1,否则清零*/
  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
else
{
    HSEStatus = (uint32_t)0x00;
}  
/*如果HSE稳定启动,就配置一系列时钟,否则退出函数*/
  if (HSEStatus == (uint32_t)0x01)
  {
    /* Flash预取指缓冲使能*/
    FLASH->ACR |= FLASH_ACR_PRFTBE;
    /* Flash 2 wait state ,在stm32参考手册中第2章嵌入式闪存一节中有规定*/
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    /* PCLK1 = HCLK/2 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz,外部晶振使用的是8Hhz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL));//先对PLLSRC PLLXTPRE PLLMULL位段清零
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);//HSE不分频,9倍频后作为PLL锁相环的时钟输入
    /* PLL使能 */
    RCC->CR |= RCC_CR_PLLON;
    /* 等待PLL稳定*/
    while((RCC->CR & RCC_CR_PLLRDY) == 0){}
    /* 选择PLL输出作为系统时钟源*/
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   
    /*等待PLL被配置为系统时钟源*/
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
  }
  else
  { /* 此次是HSE起振失败后,需要有相应的处理代码,需要用户根据自己的需要进行代码编写*/
  }
}
到此,SystemInit()函数讲解完毕。
SystemCoreClockUpdate()函数其实就是对全局变量SystemCoreClock进行更新,使SystemCoreClock存储系统现在使用的系统时钟频率。
——————————————————————————————————————————————————————————————
system_stm32f10x.c文件讲解完毕,接下来是内核文件core_cm3.c与core_cm3.h进行讲解。
此帖出自stm32/stm8论坛

最新回复

好的  加油加油   详情 回复 发表于 2015-4-29 17:40

赞赏

2

查看全部赞赏

点赞 关注
个人签名最近研究STM32,会对库函数的源代码进行解读,会陆续更新
 

回复
举报

26

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
现在才看的标题写错了 应该是stm32f10x  多写了个s
此帖出自stm32/stm8论坛

点评

帮你修改啦 ,你可以点击编辑按钮进行编辑的。  详情 回复 发表于 2015-4-15 09:23
 
个人签名最近研究STM32,会对库函数的源代码进行解读,会陆续更新
 

回复

59

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
恩  很清晰
此帖出自stm32/stm8论坛
 
 

回复

2万

帖子

71

TA的资源

管理员

4
 
盛夏之蝉 发表于 2015-4-14 20:59
现在才看的标题写错了 应该是stm32f10x  多写了个s

帮你修改啦 ,你可以点击编辑按钮进行编辑的。

此帖出自stm32/stm8论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

26

帖子

0

TA的资源

一粒金砂(中级)

5
 
谢谢啦
此帖出自stm32/stm8论坛
 
个人签名最近研究STM32,会对库函数的源代码进行解读,会陆续更新
 
 

回复

26

帖子

0

TA的资源

一粒金砂(中级)

6
 
本帖最后由 盛夏之蝉 于 2015-4-29 17:42 编辑

—————————————————————————————————————————————————————————————
core_cm3.h
—————————————————————————————————————————————————————————————
core_cm3.h文件是和内核紧密相关的功能模块类型封装,有NVIC,SYSTICK,SCB,ITM等,这些模块的内容的具体介绍是在Cortex-M3 权威指南(建议看英文的,我最开始看的是宋岩翻译 的中文版,但是有很多错误和模糊的地方,最后还是看的英文的)里.和我们应用紧密相关的是NVIC,SYSTICK,这篇主要讲解NVIC,SYSTICK。
首先 NVIC:
typedef struct
{
  __IO uint32_t ISER[8];                      /*!< Offset: 0x000  中断使能寄存器 ,写1置位,写0无效*/
       uint32_t RESERVED0[24];                                   
  __IO uint32_t ICER[8];                      /*!< Offset: 0x080  中断 清除使能寄存器,写1清0,写0无效 */
       uint32_t RSERVED1[24];                                    
  __IO uint32_t ISPR[8];                      /*!< Offset: 0x100  中断悬起寄存器          */
       uint32_t RESERVED2[24];                                   
  __IO uint32_t ICPR[8];                      /*!< Offset: 0x180  中断解悬寄存器 */
       uint32_t RESERVED3[24];                                   
  __IO uint32_t IABR[8];                      /*!< Offset: 0x200  中断活动状态寄存器,只读类型,与中断嵌套相关  */
       uint32_t RESERVED4[56];                                   
  __IO uint8_t  IP[240];                      /*!< Offset: 0x300    中断优先级寄存器*/
       uint32_t RESERVED5[644];                                 
  __O  uint32_t STIR;                         /*!< Offset: 0xE00     软件触发中断寄存器     */
}  NVIC_Type
与NVIC相关的库函数有 12个:
1)、static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)                //设置优先级组
{
  uint32_t reg_value;
  uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);                         /*  优先级组只有3bit位,故可以用的也就0到7这8个级别*/
  reg_value  =  SCB->AIRCR;                                                   /* 先读出AIRCR的内容*/
  reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk);             /*先清0*/
  reg_value  =  (reg_value |  (0x5FA << SCB_AIRCR_VECTKEY_Pos) | (PriorityGroupTmp << 8));        /* 写入访问钥匙和优先级组内容 */
  SCB->AIRCR =  reg_value;           //重置寄存器
}
2)、static __INLINE uint32_t NVIC_GetPriorityGrouping(void)                 //返回优先级组内容
{
  return ((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos);  
}
3)、static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)                   //设置外部中断使能 ,代码简练,优美
{
  NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /*IRQn先右移5位是完成了      IRQn/32    的工作,得到了所在的寄存器index信息,(IRQn) & 0x1F) 完成了    IRQn%32    的工作,得到了在寄存器中具体的bit位地址*/
}
4)、static __INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)                //外部中断使能
{
  NVIC->ICER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* disable interrupt */
}
5)、static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)    //获得指定中断的悬起状态  巧用 条件三目运算符
{
  return((uint32_t) ((NVIC->ISPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
6)、static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)                 //软件设置 中断悬起
{
  NVIC->ISPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
7)、static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)                 //解悬
{
  NVIC->ICPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */
}
8)、static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)                //获得中断的活动状态
{
  return((uint32_t)((NVIC->IABR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
9)、static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)   //设置中断和系统异常的优先级
{
  if(IRQn < 0) {  //设置系统异常的优先级,要注意异常的优先级是负数
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4 = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /*特别注意粉色的部分,首先IRQn以补码的形式读出,只需要其低4位,在减去4,就可以或得寄存器的index了。例如:systick的优先级在stm32f10x.h中定义为-1,获取补码后就是F(15),在减去4,得11,就是systick所在寄存器的索引标号了 。priority << (8 - __NVIC_PRIO_BITS)) & 0xff)是因为优先级必须MSB对齐,__NVIC_PRIO_BITS定义是4,那么stm32用4bit位来定义优先级,那么最多可以设置16个优先级*/
  else {//设置外部中断的优先级,为非负
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }      
}
10)、static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)       //或得指定中断或系统异常的优先级                 
{

  if(IRQn < 0) { //系统异常
    return((uint32_t)(SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] >> (8 - __NVIC_PRIO_BITS)));  }
  else {//中断
    return((uint32_t)(NVIC->IP[(uint32_t)(IRQn)]           >> (8 - __NVIC_PRIO_BITS)));  }
}
11)、static __INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)     //根据指定的优先级组,对给定的抢占优先级PreemptPriority,子优先级SubPriority 进行编码,组合成一个优先级数字  ,代码很有趣
{
  uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);          /*优先级组只有低3位可用*/
  uint32_t PreemptPriorityBits;
  uint32_t SubPriorityBits;
  PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;
  SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;
  return (
           ((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) |
           ((SubPriority     & ((1 << (SubPriorityBits    )) - 1)))
         );
}
12)、static __INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* pPreemptPriority, uint32_t* pSubPriority) //与上面的函数功能相反,根据指定的优先级组,把Priority拆成抢占优先级和子优先级,最后信息存储在pPreemptPriority,pSubPriority中,注意后面2个参数是指针传递
{
  uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);     
  uint32_t PreemptPriorityBits;
  uint32_t SubPriorityBits;
  PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;
  SubPriorityBits     = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;
  *pPreemptPriority = (Priority >> SubPriorityBits) & ((1 << (PreemptPriorityBits)) - 1);
  *pSubPriority     = (Priority                   ) & ((1 << (SubPriorityBits    )) - 1);
}

到此NVIC的12个功能函数讲解完毕,当然misc.c中也有NVIC的函数,2者都可以使用.

现在开始SYSTICK:systick本质上是一个减法计数器,到0中断。
typedef struct
{
  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick 控制和状态寄存器 */
  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick重载寄存器       */
  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick 当前值寄存器 */
  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick校准寄存器 */
} SysTick_Type;

static __INLINE uint32_t SysTick_Config(uint32_t ticks)         //形参是定时间隔 ,返回值是0,成功;1,失败
{
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /*参数无效,一定要注意tick最大可以使24bit位,超过了这个值就无效了*/
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /*减到0,所以需要减1 */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /*优先级设置为为最低,一定要注意哦*/
  SysTick->VAL   = 0;                                          /* 当前值清0*/
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | //使用FCLOk作为systick的时钟源,,默认是72M
                   SysTick_CTRL_TICKINT_Msk   | //到0产生异常
                   SysTick_CTRL_ENABLE_Msk;                    /*使能*/
  return (0);                                          
}
————————————————————————————————————————————————————————
这些天把st公司给的库源码研究完了,做了相应的笔记,只是有惰性没有写成贴子,以后努力把所有的文件都写成帖子。

此帖出自stm32/stm8论坛
 
个人签名最近研究STM32,会对库函数的源代码进行解读,会陆续更新
 
 

回复

2万

帖子

71

TA的资源

管理员

7
 
加油 期待更多分享 嘿嘿
此帖出自stm32/stm8论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身

点评

最近会整理一下笔记,陆续的把各个文件的分析写出来。谢谢支持!  详情 回复 发表于 2015-4-29 17:39
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

26

帖子

0

TA的资源

一粒金砂(中级)

8
 
soso 发表于 2015-4-29 16:51
加油 期待更多分享 嘿嘿

最近会整理一下笔记,陆续的把各个文件的分析写出来。谢谢支持!
此帖出自stm32/stm8论坛

点评

好的 加油加油  详情 回复 发表于 2015-4-29 17:40
 
个人签名最近研究STM32,会对库函数的源代码进行解读,会陆续更新
 
 

回复

2万

帖子

71

TA的资源

管理员

9
 
盛夏之蝉 发表于 2015-4-29 17:39
最近会整理一下笔记,陆续的把各个文件的分析写出来。谢谢支持!

好的  加油加油

此帖出自stm32/stm8论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表