STM32学习心得笔记.docx
- 文档编号:12917392
- 上传时间:2023-06-09
- 格式:DOCX
- 页数:14
- 大小:798.93KB
STM32学习心得笔记.docx
《STM32学习心得笔记.docx》由会员分享,可在线阅读,更多相关《STM32学习心得笔记.docx(14页珍藏版)》请在冰点文库上搜索。
STM32学习心得笔记
窗体顶端
窗体底端
STM32学习心得笔记
时钟篇
在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口。
下图是STM32用户手册中的时钟系统结构图,通过该图可以从总体上掌握STM32的时钟系统。
管脚篇
我们操作STM32过程中对管脚的操作是比较频繁的工作之一,我们一般用提供的封装库来进行操作,因为它直观方便。
我们常用的有:
GPIO_SetBits();GPIO_Writebit();GPIO_ResetBits();GPIO_ReadInputBit();GPIO_ReadOutputBit();等等
它们具体怎么操作的我们是不用管的给我们一个接口就足够了,但是想学好STM32下一步最好使用它的原子操作,下面我们先学习一
下关于管脚端口的一些寄存器。
由于上述命令操作是调用的一些函数故可能在调用的过程中可能被中断所打断产和 想不到的后果
但是如果调用寄存器函可以在一个时钟周期内完成,所以在一些关键的场合要使用对原子的直接访问。
要用到的寄存器有置位复位
寄存器GPIOx_BSRR和复位寄存器GPIOx_BRR,后者是前者的一个子功能,GPIOx_BSRR包括置和复位二功功能高16位是复位功能低16位
是置位功能,高16位中对应位置1表示要复位这一管脚其它写入0的位不改变原有的电平,而低16位置1是真的要使其位输出置1。
对于GPIOx_BRR寄存器写入对应位1时表示要复位输出这一管脚,复位时用哪个寄存器随你便好了,但是要使其置1时只能使用GPIOx_BSRR
了。
说到这里你可能要说了:
GPIOx_ODR不可以嘛?
是真的可以,但是这里的输出0和1都是要反映到管脚是的,对于我们仅需要操作1个
管脚时还要兼顾其它不需要改变的PIN,所以我们最好不要用这个寄存器来进行直接的操作。
常用的几个寄存器:
上面的二个寄存器是设置寄存器的是输入还是输出,输入中包括模拟输入、上拉/下拉输入、还是悬空输入。
输出包括:
推挽输出、开漏输出、复用推挽输出、复用开漏输出。
这个一个在程序初始化时要做的工作,利用封装的函数还是挺好的
这点要是利用寄存器操作就划不来了。
读取端口管脚就是读取 ch = GPIOx->IDR;就是这么简单。
就是把一个16位的管脚值送给这个寄存器如:
GPIOx->ODR=ch ,如果中改变其中一管脚原来的不变,置1时没有问题可以这样做
GPIOx->ODR|=1< 可以这样来做GPIOx->ODR&=`(1< 到目的。 用GPIOx->BRR=0x00008000方便些。 前面的0x00008000只第15脚而已。 下面贴出复位/置位寄存器和复位寄存器来不说了。 下面通过宏定方,使控制GPIO来的更加方便 #defineBITBAND(addrbitnum)((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2)) #defineMEM_ADDR(addr)*((volatileunsignedlong*)(addr)) #defineBIT_ADDR(addrbitnum)MEM_ADDR(BITBAND(addrbitnum)) //IO #defineGPIOA_ODR_Addr(GPIOA_BASE+12)//0x4001080C #defineGPIOB_ODR_Addr(GPIOB_BASE+12)//0x40010C0C #defineGPIOC_ODR_Addr(GPIOC_BASE+12)//0x4001100C #defineGPIOD_ODR_Addr(GPIOD_BASE+12)//0x4001140C #defineGPIOE_ODR_Addr(GPIOE_BASE+12)//0x4001180C #defineGPIOF_ODR_Addr(GPIOF_BASE+12)//0x40011A0C #defineGPIOG_ODR_Addr(GPIOG_BASE+12)//0x40011E0C #defineGPIOA_IDR_Addr(GPIOA_BASE+8)//0x40010808 #defineGPIOB_IDR_Addr(GPIOB_BASE+8)//0x40010C08 #defineGPIOC_IDR_Addr(GPIOC_BASE+8)//0x40011008 #defineGPIOD_IDR_Addr(GPIOD_BASE+8)//0x40011408 #defineGPIOE_IDR_Addr(GPIOE_BASE+8)//0x40011808 #defineGPIOF_IDR_Addr(GPIOF_BASE+8)//0x40011A08 54 #defineGPIOG_IDR_Addr(GPIOG_BASE+8)//0x40011E08 //IOIO! //n16! #definePAout(n)BIT_ADDR(GPIOA_ODR_Addrn)// #definePAin(n)BIT_ADDR(GPIOA_IDR_Addrn)// #definePBout(n)BIT_ADDR(GPIOB_ODR_Addrn)// #definePBin(n)BIT_ADDR(GPIOB_IDR_Addrn)// #definePCout(n)BIT_ADDR(GPIOC_ODR_Addrn)// #definePCin(n)BIT_ADDR(GPIOC_IDR_Addrn)// #definePDout(n)BIT_ADDR(GPIOD_ODR_Addrn)// #definePDin(n)BIT_ADDR(GPIOD_IDR_Addrn)// #definePEout(n)BIT_ADDR(GPIOE_ODR_Addrn)// #definePEin(n)BIT_ADDR(GPIOE_IDR_Addrn)// #definePFout(n)BIT_ADDR(GPIOF_ODR_Addrn)// #definePFin(n)BIT_ADDR(GPIOF_IDR_Addrn)// #definePGout(n)BIT_ADDR(GPIOG_ODR_Addrn)// #definePGin(n)BIT_ADDR(GPIOG_IDR_Addrn)// #defineled0=PAout(8) 使用时可以 led0=0;或者 led0=1;像不像51中的控制。 这样led0就可以像51系统中那样控制某一管脚的高低了,是不是很方便。 这是比前面的应用 的方便性上更加进了一步,只是前面要做一些提前的预备工作了。 中断和核心的系统控制部分 typedefstruct { vuc32CPUID;//CM3 vu32ICSR;// vu32VTOR;// vu32AIRCR;// vu32SCR;// vu32CCR;// vu32SHPR[3];// vu32SHCSR;//Handler vu32CFSR;//MFSR+BFSR+UFSR vu32HFSR;//fault vu32DFSR;//fault vu32MMFAR;// vu32BFAR;//fault vu32AFSR;//fault }SCB_TypeDef; 全局中断禁止和允许 在51系统中都有全局中断允许/禁止位,那在Cortex-M3中这个位在哪呢? 这的水很深,请看在Core_m3.h中有 static__INLINEvoid__enable_irq(){__ASMvolatile("cpsiei");} static__INLINEvoid__disable_irq(){__ASMvolatile("cpsidi");} static__INLINEvoid__enable_fault_irq(){__ASMvolatile("cpsief");} static__INLINEvoid__disable_fault_irq(){__ASMvolatile("cpsidf");} static__INLINEvoid__NOP(){__ASMvolatile("nop");} static__INLINEvoid__WFI(){__ASMvolatile("wfi");} static__INLINEvoid__WFE(){__ASMvolatile("wfe");} static__INLINEvoid__SEV(){__ASMvolatile("sev");} static__INLINEvoid__ISB(){__ASMvolatile("isb");} static__INLINEvoid__DSB(){__ASMvolatile("dsb");} static__INLINEvoid__DMB(){__ASMvolatile("dmb");} static__INLINEvoid__CLREX(){__ASMvolatile("clrex");} 使用前二条__enable_irq();__disable_irq()就可以打开和关闭所有的中断了, 这是在库版本在V3.0以上的情况。 而对于V2.0则要用 NVIC_SETFAULTMASK();//关闭总中断 NVIC_RESETFAULTMASK();//开放总中断 来实现了。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- STM32 学习心得 笔记
![提示](https://static.bingdoc.com/images/bang_tan.gif)