stm32单片机应用非常广泛,官方提供了标准的接口库,用户可以不用直接操作寄存器,只需要调用接口函数就可以了。在官方库中有一个非常重要的函数void systeminit (void),
该函数用户可能不会直接调用,而在启动文件中一定会调用。函数原型如下:
函数原型
void systeminit (void){ /* reset the rcc clock configuration to the default reset state(for debug purpose) */ /* set hsion bit */ rcc->cr |= (uint32_t)0x00000001; /* reset sw, hpre, ppre1, ppre2, adcpre and mco bits */#ifndef stm32f10x_cl rcc->cfgr = (uint32_t)0xf8ff0000;#else rcc->cfgr = (uint32_t)0xf0ff0000;#endif /* stm32f10x_cl */ /* reset hseon, csson and pllon bits */ rcc->cr = (uint32_t)0xfef6ffff; /* reset hsebyp bit */ rcc->cr = (uint32_t)0xfffbffff; /* reset pllsrc, pllxtpre, pllmul and usbpre/otgfspre bits */ rcc->cfgr = (uint32_t)0xff80ffff;#ifdef stm32f10x_cl /* reset pll2on and pll3on bits */ rcc->cr = (uint32_t)0xebffffff; /* disable all interrupts and clear pending bits */ rcc->cir = 0x00ff0000; /* reset cfgr2 register */ rcc->cfgr2 = 0x00000000;#elif defined (stm32f10x_ld_vl) || defined (stm32f10x_md_vl) || (defined stm32f10x_hd_vl) /* disable all interrupts and clear pending bits */ rcc->cir = 0x009f0000; /* reset cfgr2 register */ rcc->cfgr2 = 0x00000000; #else /* disable all interrupts and clear pending bits */ rcc->cir = 0x009f0000;#endif /* stm32f10x_cl */ #if defined (stm32f10x_hd) || (defined stm32f10x_xl) || (defined stm32f10x_hd_vl) #ifdef data_in_extsram systeminit_extmemctl(); #endif /* data_in_extsram */#endif /* configure the system clock frequency, hclk, pclk2 and pclk1 prescalers */ /* configure the flash latency cycles and enable prefetch buffer */ setsysclock();#ifdef vect_tab_sram scb->vtor = sram_base | vect_tab_offset; /* vector table relocation in internal sram. */#else scb->vtor = flash_base | vect_tab_offset; /* vector table relocation in internal flash. */#endif }
可以看到函数体中几乎全是条件编译。
(1)先看第一行代码:rcc->cr |= (uint32_t)0x00000001;显然这是给cr寄存器的最低一位赋值为1.官方寄存器配置详解截图:
编译条件宏定义
#ifndef stm32f10x_cl rcc->cfgr = (uint32_t)0xf8ff0000;#else rcc->cfgr = (uint32_t)0xf0ff0000;#endif /* stm32f10x_cl */
这个条件编译是根据芯片容量不同默认初始化cfgr寄存器(reset sw, hpre, ppre1, ppre2, adcpre and mco bits )。
rcc->cr = (uint32_t)0xfef6ffff; rcc->cr = (uint32_t)0xfffbffff;
显然是把cr寄存器的某些位赋值,其作用为:reset hseon, csson and pllon ,hsebypbits即将hseon,csson,pllon,hsebyp位置为零。
/* reset pllsrc, pllxtpre, pllmul and usbpre/otgfspre bits */rcc->cfgr = (uint32_t)0xff80ffff;
作用为把cfgr寄存器的pllsrc, pllxtpre, pllmul and usbpre/otgfspre位置0。
#ifdef stm32f10x_cl /* reset pll2on and pll3on bits */ rcc->cr = (uint32_t)0xebffffff; /* disable all interrupts and clear pending bits */ rcc->cir = 0x00ff0000; /* reset cfgr2 register */ rcc->cfgr2 = 0x00000000;#elif defined (stm32f10x_ld_vl) || defined (stm32f10x_md_vl) || (defined stm32f10x_hd_vl) /* disable all interrupts and clear pending bits */ rcc->cir = 0x009f0000; /* reset cfgr2 register */ rcc->cfgr2 = 0x00000000; #else /* disable all interrupts and clear pending bits */ rcc->cir = 0x009f0000;#endif /* stm32f10x_cl */
这个条件编译块的作用为根据芯片容量初始化中断位(关闭中断)。
#if defined (stm32f10x_hd) || (defined stm32f10x_xl) || (defined stm32f10x_hd_vl) #ifdef data_in_extsram systeminit_extmemctl(); #endif /* data_in_extsram */#endif
这个条件编译块的作用为初始化memory控制。
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 /* if none of the define above is enabled, the hsi is used as system clock source (default after reset) */ }
我们可以看到该函数就是通过判断定义了哪个宏定义标志符而调用不同的设置sys时钟频率的函数,官方固件库默认定义了sysclk_freq_72mhz,所以会调用setsysclockto72这个函数。
如果要使用其它频率,那就解开相应注释(只保留一个不被注释)。
setsysclockto72()函数如下:
static void setsysclockto72(void){ __io uint32_t startupcounter = 0, hsestatus = 0; /* sysclk, hclk, pclk2 and pclk1 configuration ---------------------------*/ /* enable hse */ rcc->cr |= ((uint32_t)rcc_cr_hseon); /* wait till hse is ready and if time out is reached exit */ do { hsestatus = rcc->cr rcc_cr_hserdy; startupcounter++; } while((hsestatus == 0) (startupcounter != hse_startup_timeout)); if ((rcc->cr rcc_cr_hserdy) != reset) { hsestatus = (uint32_t)0x01; } else { hsestatus = (uint32_t)0x00; } if (hsestatus == (uint32_t)0x01) { /* enable prefetch buffer */ flash->acr |= flash_acr_prftbe; /* flash 2 wait state */ 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 */ rcc->cfgr |= (uint32_t)rcc_cfgr_ppre1_div2;#ifdef stm32f10x_cl /* configure plls ------------------------------------------------------*/ /* pll2 configuration: pll2clk = (hse / 5) * 8 = 40 mhz */ /* prediv1 configuration: prediv1clk = pll2 / 5 = 8 mhz */ rcc->cfgr2 = (uint32_t)~(rcc_cfgr2_prediv2 | rcc_cfgr2_pll2mul | rcc_cfgr2_prediv1 | rcc_cfgr2_prediv1src); rcc->cfgr2 |= (uint32_t)(rcc_cfgr2_prediv2_div5 | rcc_cfgr2_pll2mul8 | rcc_cfgr2_prediv1src_pll2 | rcc_cfgr2_prediv1_div5); /* enable pll2 */ rcc->cr |= rcc_cr_pll2on; /* wait till pll2 is ready */ while((rcc->cr rcc_cr_pll2rdy) == 0) { } /* pll configuration: pllclk = prediv1 * 9 = 72 mhz */ rcc->cfgr = (uint32_t)~(rcc_cfgr_pllxtpre | rcc_cfgr_pllsrc | rcc_cfgr_pllmull); rcc->cfgr |= (uint32_t)(rcc_cfgr_pllxtpre_prediv1 | rcc_cfgr_pllsrc_prediv1 | rcc_cfgr_pllmull9); #else /* pll configuration: pllclk = hse * 9 = 72 mhz */ rcc->cfgr = (uint32_t)((uint32_t)~(rcc_cfgr_pllsrc | rcc_cfgr_pllxtpre | rcc_cfgr_pllmull)); rcc->cfgr |= (uint32_t)(rcc_cfgr_pllsrc_hse | rcc_cfgr_pllmull9);#endif /* stm32f10x_cl */ /* enable pll */ rcc->cr |= rcc_cr_pllon; /* wait till pll is ready */ while((rcc->cr rcc_cr_pllrdy) == 0) { } /* select pll as system clock source */ rcc->cfgr = (uint32_t)((uint32_t)~(rcc_cfgr_sw)); rcc->cfgr |= (uint32_t)rcc_cfgr_sw_pll; /* wait till pll is used as system clock source */ while ((rcc->cfgr (uint32_t)rcc_cfgr_sws) != (uint32_t)0x08) { } } else { /* if hse fails to start-up, the application will have wrong clock configuration. user can add here some code to deal with this error */ }}
这个函数体比较长,但仔细看会发现这个函数就是在配置cr,cfgr,acr(设置flash)寄存器的某些位(使能,判断是否就绪,设置相应位,设置flash,设置ahb,apb预分频系数,设置hclk,pclk等等外设时钟,设置pll锁相环倍频系数最终确定系统时钟),结合官方注释和官方寄存器的说明很容易理解。
至此,systeminit函数就能大概理解了。但是还有一个问题需要注意:那就是虽然我们在main函数中并没有调用systeminit函数,但它在start up启动文件中被调用了:
可以看到systeminit函数是在main函数之前执行的,要是自定义该函数,那这里也要修改名称,建议不要随意修改或者重构该函数。
安科瑞防逆流监测电表在光伏项中的应用
选择这两颗芯片才有“硬核”240W电源适配器方案
Rokid推出全新黑科技AR眼镜Rokid Glass
小米A1的问世对于小米粉丝和小米本身来说都是一个惊喜
物联网具体要实现哪些功能需要遵照什么原则进行搭建
STM32库函数SystemInit()详解
5G终端射频标准的新版本R17 h61又多了什么
莫之比8路360全景环视系统已在智轨上成功应用
IBM宣布在三份关于安全托管服务提供商评估的市场报告中被评为“领导者”
预测2019年及未来网络安全趋势
采用RFID射频识别技术的高速不停车收费系统
小步快走!炬芯科技人工智能早教芯片备受关注
LDO输出噪声对VCO相噪的影响
消除焊接后内应力的方法
“伙伴+华为”体系,数字时代的新航标
开年巨献,UDE2024唤醒半导体显示产业全年活力
不得不知的PCB布局陷阱:您还在浪费时间和金钱吗?
特种设备防误伤安全监测应用案例
曝iPhoneSE2将有两款机型 其中一款支持5G网络
日本NTT Docomo计划明年在关岛建立一个5G测试实验室