stm32互连型系列产品分为两个型号: stm32f105和stm32f107。stm32f105具有usb otg 和can2.0b接口。stm32f107在usb otg 和can2.0b接口基础上增加了以太网10/100 mac模块 。片上集成的以太网mac支持mii和rmii,因此,实现一个完整的以太网收发器只需一个外部phy芯片。只使用一个25mhz晶振即可给整个微控制器提供时钟频率,包括以太网和usb otg外设接口。微控制器还能产生一个25mhz或50mhz的时钟输出,驱动外部以太网phy层芯片,从而为客户节省了一个附加晶振。
音频功能方面,新系列微控制器提供两个i2s音频接口,支持主机和从机两种模式,既用作输入又可用作输出,分辨率为16位或32位。音频采样频率从8khz到96khz。利用新系列微控制器强大的处理性能,开发人员可以用软件实现音频编解码器,从而消除了对外部组件的需求。
把u盘插入微控制器的usb otg接口,可以现场升级软件;也可以通过以太网下载代码进行软件升级。这个功能可简化大型系统网络(如远程控制器或销售终端设备)的管理和维护工作。
一、硬件上的连接问题
如果使用内部rc振荡器而不使用外部晶振,请按照如下方法处理:
1)对于100脚或144脚的产品,osc_in应接地,osc_out应悬空。
2)对于少于100脚的产品,有2种接法:
i)osc_in和osc_out分别通过10k电阻接地。此方法可提高emc性能。
ii)分别重映射osc_in和osc_out至pd0和pd1,再配置pd0和pd1为推挽输出并输出‘0’。此方法可以减小功耗并(相对上面i)节省2个外部电阻。
对上图的分析如下:
重要的时钟:
pllclk,sysclk,hckl,pclk1,pclk2 之间的关系要弄清楚;
1、hsi:高速内部时钟信号 stm32单片机内带的时钟 (8m频率) 精度较差
2、hse:高速外部时钟信号 精度高来源(1)hse外部晶体/陶瓷谐振器(晶振) (2)hse用户外部时钟
3、lse:低速外部晶体 32.768khz主要提供一个精确的时钟源一般作为rtc时钟使用
在stm32中,有五个时钟源,为hsi、hse、lsi、lse、pll。
①、hsi是高速内部时钟,rc振荡器,频率为8mhz。
②、hse是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4mhz~16mhz。
③、lsi是低速内部时钟,rc振荡器,频率为40khz。
④、lse是低速外部时钟,接频率为32.768khz的石英晶体。
⑤、pll为锁相环倍频输出,其时钟输入源可选择为hsi/2、hse或者hse/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72mhz。
其中40khz的lsi供独立看门狗iwdg使用,另外它还可以被选择为实时时钟rtc的时钟源。另外,实时时钟rtc的时钟源还可以选择lse,或者是hse的128分频。rtc的时钟源通过rtcsel[1:0]来选择。
stm32中有一个全速功能的usb模块,其串行接口引擎需要一个频率为48mhz的时钟源。该时钟源只能从pll输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用usb模块时,pll必须使能,并且时钟频率配置为48mhz或72mhz。
另外,stm32还可以选择一个时钟信号输出到mco脚(pa8)上,可以选择为pll输出的2分频、hsi、hse、或者系统时钟。
系统时钟sysclk,它是供stm32中绝大部分部件工作的时钟源。系统时钟可选择为pll输出、hsi或者hse。系统时钟最大频率为72mhz,它通过ahb分频器分频后送给各模块使用,ahb分频器可选择1、2、4、8、16、64、128、256、512分频。其中ahb分频器输出的时钟送给5大模块使用:
①、送给ahb总线、内核、内存和dma使用的hclk时钟。
②、通过8分频后送给cortex的系统定时器时钟。
③、直接送给cortex的空闲运行时钟fclk。
④、送给apb1分频器。apb1分频器可选择1、2、4、8、16分频,其输出一路供apb1外设使用(pclk1,最大频率36mhz),另一路送给定时器(timer)2、3、4倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2、3、4使用。
⑤、送给apb2分频器。apb2分频器可选择1、2、4、8、16分频,其输出一路供apb2外设使用(pclk2,最大频率72mhz),另一路送给定时器(timer)1倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器1使用。另外,apb2分频器还有一路输出供adc分频器使用,分频后送给adc模块使用。adc分频器可选择为2、4、6、8分频。
在以上的时钟输出中,有很多是带使能控制的,例如ahb总线时钟、内核时钟、各种apb1外设、apb2外设等等。当需要使用某模块时,记得一定要先使能对应的时钟。
需要注意的是定时器的倍频器,当apb的分频为1时,它的倍频值为1,否则它的倍频值就为2。
连接在apb1(低速外设)上的设备有:电源接口、备份接口、can、usb、i2c1、i2c2、uart2、uart3、spi2、窗口看门狗、timer2、timer3、timer4。注意usb模块虽然需要一个单独的48mhz时钟信号,但它应该不是供usb模块工作的时钟,而只是提供给串行接口引擎(sie)使用的时钟。usb模块工作的时钟应该是由apb1提供的。
连接在apb2(高速外设)上的设备有:uart1、spi1、timer1、adc1、adc2、所有普通io口(pa~pe)、第二功能io口。
涉及的寄存器:
rcc 寄存器结构,rcc_typedeff,在文件“stm32f10x_map.h”中定义如下:
typedef struct
{
vu32 cr; //hsi,hse,css,pll等的使能
vu32 cfgr; //pll等的时钟源选择以及分频系数设定
vu32 cir; // 清除/使能时钟就绪中断
vu32 apb2rstr; //apb2线上外设复位寄存器
vu32 apb1rstr; //apb1线上外设复位寄存器
vu32 ahbenr; //dma,sdio等时钟使能
vu32 apb2enr; //apb2线上外设时钟使能
vu32 apb1enr; //apb1线上外设时钟使能
vu32 bdcr; //备份域控制寄存器
vu32 csr;
} rcc_typedef;
这些寄存器的具体定义和使用方式参见芯片手册,因为c语言的开发可以不和他们直接打交道,当然如果能够加以理解和记忆,无疑是百利而无一害。
如果外接晶振为8mhz,最高工作频率为72mhz,显然需要用pll倍频9倍,这些设置都需要在初始化阶段完成。为了方便说明,以例程的rcc设置函数,并用中文注释的形式加以说明:
static void rcc_config(void)
{
rcc_deinit();
rcc_hseconfig(rcc_hse_on);
hsestartupstatus = rcc_waitforhsestartup();
if (hsestartupstatus == success)
{
flash_prefetchbuffercmd(flash_prefetchbuffer_enable);
flash_setlatency(flash_latency_2);
rcc_hclkconfig(rcc_sysclk_div1);
rcc_pclk2config(rcc_hclk_div1);
rcc_pclk1config(rcc_hclk_div2);
rcc_adcclkconfig(rcc_pclk2_div6);
//上面这句例程中缺失了,但却很关键
rcc_pllconfig(rcc_pllsource_hse_div1, rcc_pllmul_9);
rcc_pllcmd(enable);
while (rcc_getflagstatus(rcc_flag_pllrdy) == reset)
{}
rcc_sysclkconfig(rcc_sysclksource_pllclk);
while (rcc_getsysclksource() != 0x08)
{}
}
//使能外围接口总线时钟,注意各外设的隶属情况,不同芯片的分配不同,到时候查手册就可以
rcc_ahbperiphclockcmd(rcc_ahbperiph_fsmc, enable);
rcc_apb2periphclockcmd(rcc_apb2periph_gpiod | rcc_apb2periph_gpioe |
rcc_apb2periph_gpiof | rcc_apb2periph_gpiog |
rcc_apb2periph_afio, enable);
}
由上述程序可以看出系统时钟的设定是比较复杂的,外设越多,需要考虑的因素就越多。同时这种设定也是有规律可循的,设定参数也是有顺序规范的,这是应用中应当注意的,例如pll的设定需要在使能之前,一旦pll使能后参数不可更改。
经过此番设置后,对于外置8mhz晶振的情况下,系统时钟为72mhz,高速总线和低速总线2都为72mhz,低速总线1为36mhz,adc时钟为12mhz,usb时钟经过1.5分频设置就可以实现48mhz的数据传输。
一般性的时钟设置需要先考虑系统时钟的来源,是内部rc还是外部晶振还是外部的振荡器,是否需要pll。然后考虑内部总线和外部总线,最后考虑外设的时钟信号。遵从先倍频作为cpu时钟,然后在由内向外分频,下级迁就上级的原则。
时钟控制寄存器(rcc_cr)
eg:rcc-》cr|=0x00010000; //外部高速时钟使能hseon
rcc-》cr|=0x01000000; //使能pllon
rcc-》cr》》25; //等待pll锁定
时钟配置寄存器(rcc_cfgr)
eg: rcc-》cfgr=0x00000400; //apb1=div2;apb2=div1(不分频);ahb=div1(不分频);
根据stm32库函数设置时钟流程:
rcc_deinit(); //设置rcc寄存器重新设置为默认值
rcc_hseconfig(rcc_hse_on); //打开外部高速时钟晶振
hsestartupstatus = rcc_waitforhsestartup(); //等待外部高速时钟晶振工作
if(hsestartupstatus == success) //外部就绪
{
//add here pll ans system clock config
rcc_hclkconfig(rcc_sysclk_div1); //设置ahb时钟不分频
rcc_pclk2config(rcc_hclk_div1); //设置apb2时钟不分频
rcc_pclk1config(rcc_hclk_div2); //设置apb1时钟二分频
rcc_adcclkconfig(rcc_pclk2_div6); //设置adc时钟六分频
//设置pll时钟将8m时钟9倍频到72m
rcc_pllconfig(rcc_pllsource_hse_div1,rcc_pllmul_9);
rcc_pllcmd(enable); //使能pll
flagstatus status;
status = rcc_getflagstatus(rcc_flag_pllrdy);
if(status == reset)
{
……
}
rcc_sysclkconfig(rcc-sysclksource_pllclk); //将pll输出设置为系统时钟
while(rcc_getsysclksource()!=0x08) //测试pll是否被用作系统时钟等待校验完成
{}
}
else
{
//add here some code to deal with this error
}
//使能外围接口总线时钟
rcc_apb2periphclockcmd() / rcc_apb1periphclockcmd()
具体配置过程:
第一步:
复位并配置向量表。
函数myrcc_deinit();
下面对该函数进行分析:
(1) 设置外设复位寄存器:rcc-》apb1rstr = 0x00000000
该寄存器中包含dac,电源复位,定时器等外设复位设置,某位为1表示对相应外设复位。开机启动时将该寄存器数据清空。
(2) 设置外设复位寄存器:rcc-》apb2rstr = 0x00000000
同第一步外设复位寄存器的设置。
解答:
rcc-》apb1rstr = 0x00000000;//复位结束
rcc-》apb2rstr = 0x00000000;
这里的“复位结束”具体是什么意思??我把它注释掉后发现也是可以运行的
1是复位.0当然是不复位了
不复位那就是复位结束了。
(3) 睡眠模式闪存和sram时钟使能,其他关闭。用于使用sram。 sram相当于pc的内存。
stm32有三种启动模式:
1,isp模式。这种模式就是stm32复位后就执行固化在内部的bootloader程序(固化的,我们无法读写。),然后等待串口数据,从而实现串口bootloader功能。
这种模式不会从用户存储区启动(除非用串口控制其从0x08000000启动),所以在更新了代码之后,需要设置为其他模式(flash模式)。
2,flash启动模式。这种模式直接从0x08000000启动,也就是我们自己编写的代码的启动方式了。正常情况都应该用这种。
3,sram启动模式。这种模式我没有用过,是从0x20000000启动的,也就是说在sram模式开始之前,你要确保sram里面已经有代码了,否则就是死机。
rcc-》ahbenr = 0x00000014
(4) 设置外设时钟使能寄存器:
rcc-》apb1enr = 0x00000000;
rcc-》apb2enr = 0x00000000; 将所有外设全部关闭
(5) 使能内部高速hsion。
rcc-》cr |=0x00000001;
stm32的时钟启动过程。
启动过程是:
1,首先使用内部时钟(这也是为什么你不接晶振也可以下载代码了)。
2,尝试开启外部时钟。
3,如果开启成功,则使用外部时钟,否则使用内部。
4,做其他事情。
当然以上代码都需要你自己写代码实现,当然内部时钟是默认的时钟,你不开启也可以。
(6) 复位sw,hpre,ppre1,ppre2,adcpre,mco
rcc-》cfgr &= 0xf8ff0000;
这步有什么意思呢,我的理解是。cfgr寄存器主要用于对时钟分频的控制,见下图:
通过该步的配置:
首先配置mco无输出,mco是什么呢?是指可以将stm32的内部时钟通过io口引脚输出出去,如上图就可以看到,对cfgr的配置,可以有四种mco输出,分别是将pllclk两分频后输出,hsi(片内时钟)输出等。
其次:配置adcpre就是上图中ahb分频器线面的adc
再次:配置ppre2也就是高速外部时钟apb2,这里设成不分频。高速外部时钟主要驱动一些高速外设,这个在apb2enr时钟控制寄存器中有介绍
再次:配置ppre1配置低速外部时钟分频apb1这里也全部设成不分频。
再次:配置hpre。这几个位主要用来配置ahb这个寄存器的分频系数这里也设置成不分频。也就是说上图sysclk经ahb没有分频。
最后:配置sw,以及sws。表示启用his作为系统时钟。
到这一步,经过分析得知,rcc-》cfgr &= 0xf8ff0000;主要是用来配置ahb等各个分频器的设置,以及将片内时钟作为系统内部时钟。
(6) 关闭hseon,csson,pllon
rcc-》cr &= 0xfef6ffff;
通过分析cr寄存器可以看出,该寄存器主要涉及三个时钟pll,css,hse。
(7) 复位hsebyp.
rcc-》cr &= 0xfffbffff;这一步有什么作用呢?查询数据手册57页可知,外部时钟源hse有两种模式,hsebyp设置为0时,是选择外部晶体作为外部时钟源这种时钟更加精准,当然也是和外部电路有关的。当然因为第(6)步已经设置了hseon关闭了,所以这一步才可自由设置hsebyp。
(8) 复位pllsrc,pllxtpre,pllmul and usbpre
rcc-》cfgr &= 0xff80ffff;
注意:在这一部中可能会有这样的疑问:
rcc-》cfgr &= 0xff80ffff;
pllsrc=0 hsi振荡器时钟经2分频后作为pll输入时钟
pllxtpre=0,hse分频器作为pll输入,hse不分频
这样不冲突吗?
答案是:以最后配置为准,就是最后一次配置会改变前一次的配置,所以说以最后一次配置为准。
也就是说后文还有其他代码对其进行定义。那干嘛还要怎么重复配置呢?
有时候是有用的。比如你想让stm32超频一会,然后又恢复正常运行,这就有用了。
(9) 关闭所有中断
rcc-》cir = 0x00000000;
(10) 配置向量表
#ifndef vect_tab_ram
my_nvic_setvectortable(nvic_vecttab_ram,0x0);
#else
my_nvic_setvectortable(nvic_vexttab_flash,0x0);
#endif
下面对该函数分析:
//函数功能:设置向量表偏移地址
//nvic_vecttab:基址
//offset:偏移量
void my_nvic_setvectortable(u32 nvic_vecttab, u32 offset)
{
//检查参数合法性
assert_param(is_nvic_vecttab(nvic_vecttab));
assert_param(is_nvic_offset(offset));
scb-》vtor = nvic_vecttab|(offset & (u32)0x1fffff80);//设置nvic的向量表偏移寄存器
//用于标识向量表是在code区还是在ram区
}
前面两行是用来检查参数合法性,这里不作分析。重点看第三行
配置这个向量表有什么用?相见cortexm3权威指南113页向量表的解释
这里
#define nvic_vecttab_ram ((u32)0x20000000)
#define nvic_vecttab_flash ((u32)0x08000000)
offset的值为0x0,为偏移地址,地址必须能被64 * 4 = 256整除,具体请看权威手册113页
scb-》vtor = nvic_vecttab|(offset & (u32)0x1fffff80);//设置nvic的向量表偏移寄存器的疑问如下:
scb-》vtor = nvic_vecttab|(offset & (u32)0x1fffff80);//设置nvic的向量表偏移寄存器。
既然是设置nvic的向量表偏移量,为什么还要和nvic_vecttab相或呢。只设置offset不就可以了吗,另外vtor设置只有bit【28:7】有作用啊,相或以后也放不下这么多位吧?
这个是基址。
那个7~28的,你能定义一个28位的数据出来嘛?
vtor设置只有bit【28:7】,你把(u32)0x1fffff80二进制看看是不是【28:7】。
然后再看下面一段话:
在《《权威指南》》第一百零四页,有这么一段话:
nvic 中有一个寄存器,称为“向量表偏移量寄存器”(在地址0xe000_ed08处),通过修改它的值就能定位向量表。但必须注意的是:向量表的起始地址是有要求的:必须先求出系统中共有多少个向量,再把这个数字向上增大到是2的整次幂,而起始地址必须对齐到后者的边界上。例如,如果一共有32个中断,则共有32+16(系统异常)=48个向量,向上增大到2的整次幂后值为64,因此地址
地址必须能被64*4=256整除,从而合法的起始地址可以是:0x0, 0x100, 0x200等。
向量表偏移量寄存器,也就是scb-》vtor.它的第29位,用来标识向量表是在code区还是ram区,从而0x1,就是最高3位不去动,这好理解。 但是低位,根据上面这段话的理解,stm32自己有60个中断,加上cm3的16个,总共有76个中断,扩大到2的整次幂,那就是128,然后再乘以4,得到512,也就是0x200.根据这样计算,合法的偏移地址应该是0x0,0x200,0x400,0x600.。。因此,在此处应该&0x1fff fe00.才对。
以上是我的理解。实际上确是&0x1fff ff80;这点,我也有疑问。
答案:cortex-m3权威指南上介绍 bit 28-7为向量表的起始地址。所以低7位没有用到,所以&0x80,为的就是将低七位清零。但这里写&0x1fff fe00,也能达到清零的目的。至于地址必须是512的整数只要offset这个参数注意就可以了。
下面我们回到例说stm32这本书61页的stm32_clock_init()函数:
经过上面配置完毕后,下面开始配置外部时钟。
ministm32开发板目前的实都是采用高速外部时钟作为时钟源,在经过myrcc_deinit()先将外部时钟源关闭,然后在cfgr重新配置之后,下面就准备开启高速外部时钟。
(11) rcc-》cr |= 0x00010000;外部高速时钟使能hseon,前面说过以最后一次设置为准,所以自打这一步开始hse作为了外部时钟。
(12) 等待外部时钟是否就绪
while(!(rcc-》cr》》17)); (其实这一步的作用和while(rcc-》cr&(u32)(1《《17));是一样的,因为在myrcc_deinit()中的18位至31位全为0了,当然在论坛中http://www.openedv.com/posts/list/1943.htm第23楼也承认while(!(rcc-》cr》》17)这样写有点轻率,23楼这样写道
对此,原子哥也说了写成(rcc-cr》》17)&0x01比较合适,但我感觉rcc-cr》》17是不准确的,比方说如果第十八位是1,那么右移17位后不管时钟是否就绪,表达式“rcc-cr》》17”的结果始终为真,这样while(!(rcc-cr》》17))不就没有意义了吗?所以写成(rcc-cr》》17)&0x01才是最准确的
)
(13) 配置apb1/2=div2和ahb = div1
rcc-》cfgr = 0x00000400;
(14) 设置pll分频
pll -=2;
rcc-》cfgr = pll 《《18;
设置pll 9倍频
这里还涉及到了一个问题,如下
其实,这里今天林妹妹问了一个比较专业的问题,那就是pll是一个u8的数据类型,为什么在这里可以右移18位呢?不是早超出了么?其实,我们看看汇编代码就明白了,汇编代码如下: 219: rcc-》cfgr|=pll《《18; //设置pll值 2~16 0x08000618 4608 mov r0,r1 0x0800061a 6840 ldr r0,[r0,#0x04] 0x0800061c ea404084 orr r0,r0,r4,lsl #18 0x08000620 6048 str r0,[r1,#0x04]可以看到,这个移位操作,是在r0和r1里面进行的,r0,r1均是32位的寄存器,所以,这里的移位操作并不会产生错误(结果是赋值给32位的寄存器:rcc-》cfgr)。
(15) flash-》acr |= 0x32 //flash 2个延时周期。flash-》acr|=0x32是为了使频率匹配,
//具体见《stm32闪存编程》
(16) 打开pllon
rcc-》cr|=0x01000000;
(17) 等待pll锁定
while(!((rcc-》cr》》25)&0x01));
(18) pll作为系统时钟
rcc-》cfgr |= 0x00000002;
(19) 等待pll作为系统时钟设置成功
unsigned char temp = 0;
while(temp!=0x02)
{
temp = rcc-》cfgr》》2;
temp &= 0x03;
}
其实这段代码就是判断sws,等待系统时钟成功转为pll时钟。
结合上面的分析已经明了stm32时钟一个始终配置过程,主要流程图如下:
其实个人感觉不用想mini32中自带例程配置有一些没有必要,所以自己改动了一些,发现在跑马灯程序中也能运行,目前只在跑马灯程序中试验过:
第一步:
rcc-》apb1rstr = 0x00000000;//复位结束
rcc-》apb2rstr = 0x00000000;
第二步:
rcc-》ahbenr = 0x00000014; //睡眠模式闪存和sram时钟使能。其他关闭。
第三步:关闭所有外设时钟
rcc-》apb2enr = 0x00000000; //外设时钟关闭。
rcc-》apb1enr = 0x00000000;
为什么要这步因为在配置cfgr以及cr等寄存器时,一些外设时钟要关闭。
第四步:
rcc-》cr &= 0xfef2ffff; //该补的主要作用是开启内部hsion,且关闭hse,css,pllon
第五步:设置分频寄存器,配置分频,使能pllsrc on
rcc-》cfgr=0x00000400; //apb1/2=div2;apb2=div1;ahb=div1;查询中文手册可知,
apb1最大为36mhz所以这里要对其分频,因为经过这番设置pllmul输出后为72mhz所以为,这里要让apb1/2=div2是36mhz。
pll-=2;//抵消2个单位
rcc-》cfgr|=pll《《18; //设置pll值 2~16 设置pll为9倍频
rcc-》cfgr|=1《《16; //pllsrc on设置hse为输入时钟,因为第cfgr的17位也为0,所以hse输入到pllsrc的就是8m
此时hse为8mhz显然经过上面的9倍频,经分析可知输出到ahb的sysclk为72mhz。因为前面设置ahb不分频,所以ahb输出也是72mhz。apb1因为前面分频了所以输出后为36mhz。apb2为72mhz
第七步:
flash-》acr|=0x32; //flash 2个延时周期
第八步:
rcc-》cir = 0x00000000; //关闭所有中断
第九步:
//配置向量表
#ifdef vect_tab_ram
my_nvic_setvectortable(nvic_vecttab_ram, 0x0);
#else
my_nvic_setvectortable(nvic_vecttab_flash, 0x0); //这里用到的就是flash启动
#endif
第十步:
rcc-》cr|=0x00010000; //外部高速时钟使能hseon,注意使能hseon之前外部时钟不能直接或间接的为系统时钟,也就是说cfgr中的sw位先为0,因为在第五步已经设为0了,所以这里无需顾虑。
while(!(rcc-》cr》》17));//等待外部时钟就绪
第十一步:打开pll,
rcc-》cr|=0x01000000; //pllon
while(!(rcc-》cr》》25));//等待pll锁定
第十二步:
rcc-》cfgr|=0x00000002;//pll作为系统时钟
while(temp!=0x02) //等待pll作为系统时钟设置成功
{
temp=rcc-》cfgr》》2;
temp&=0x03;
}
/*上述代码较乱,下面将代码组合一番方便看*/
结合stm32_clock_init()时钟配置过程,我总结时钟配置就是大致如下步骤:
关所有外设时钟,
(1)使能hsi并关闭hse,pll,css,配置分频寄存器,并且在crgr中将系统时钟设为hsi。
(2)关所有中断。
(3)配置向量表。
(4)使能hse,cr中等待设置完毕。
(5)打开pll,cr中等待pll开启。
(6)在cfgr中sws位等待pll成为系统时钟。
结合上述方式,我改写的代码如下:
void stm32_clock_init111(u8 pll)
{
unsigned char temp=0;
rcc-》apb1rstr = 0x00000000;//复位结束
rcc-》apb2rstr = 0x00000000;
rcc-》ahbenr = 0x00000014; //睡眠模式闪存和sram时钟使能。其他关闭。
rcc-》apb2enr = 0x00000000; //外设时钟关闭。
rcc-》apb1enr = 0x00000000;
rcc-》cr &= 0xfef2ffff; //该步的主要作用是开启内部hsion,且关闭hse,css,pllon
rcc-》cfgr=0x00000400; //apb1=div2;apb2=div1;ahb=div1; hse设置为不分频,cfgr的主要作用是配置分频,分频之前当然要把cr中hse时钟全关闭只开启hsi时钟。当然还有一个重要的作用是,设置当前是谁作为系统时钟,就是sw位。
pll-=2;//抵消2个单位
rcc-》cfgr|=pll《《18; //设置pll值 2~16
rcc-》cfgr|=1《《16; //pllsrc on
flash-》acr|=0x32; //flash 2个延时周期
rcc-》cir = 0x00000000; //关闭所有中断
//配置向量表
#ifdef vect_tab_ram
my_nvic_setvectortable(nvic_vecttab_ram, 0x0);
#else
my_nvic_setvectortable(nvic_vecttab_flash, 0x0); //这里用到的就是flash启动
#endif
rcc-》cr|=0x00010000; //外部高速时钟使能hseon
while(!(rcc-》cr》》17));//等待外部时钟就绪
rcc-》cr|=0x01000000; //pllon
while(!(rcc-》cr》》25));//等待pll锁定
rcc-》cfgr|=0x00000002;//pll作为系统时钟
while(temp!=0x02) //等待pll作为系统时钟设置成功
{
temp=rcc-》cfgr》》2;
temp&=0x03;
}
}
5G开始商用 网络安全需要更加受到重视
5.8GHz射频前端芯片GC1125(替代SKY85717)应用在无线门禁系统
LED室内全彩显示屏厂家故障维修的五大问题
专利:魅族背面也有屏幕的手机
618销售额同比增长108% 科大讯飞四大办公系列狂揽四组第一
单片机STM32时钟设计分析
小米6最新消息:小米6为什么至今还没现货?小米6隐藏黑科技曝光!网友直呼买买买!
RJ45网络变压器作用
Transmitting IS Audio Streams
华为麒麟970首次进行爆光,看它如何PK高通骁龙
NB-IoT将是5G时代LPWAN应用的第一选择
采用23mm x 16.5mm封装的170W倍压器
小米6全新武器! 高通835,该说再见了!
小黄蜂智能执法记录仪的功能特点
芬兰总统尼尼斯托表示5G风险的评估将于两周内完成
icmp协议属于哪一层?有些什么特点
盛科迅速拓展海外以太网交换芯片市场
2019年物联网的五大预测公布 智能家居将成为主流
华为智慧屏首款85英寸机型首销 售价21999元更有多重好礼
华为云如何助力行业实现音视频体验升级