day 5 寄存器 时钟 堆栈
一、GPIO寄存器开发流程
对实时性要求比较高的情况下,需要使用寄存器开发。
1.分析原理图,找出外设连接的芯片引脚 PF9
2.分析原理图,理解硬件的控制原理 高亮底灭
3.分析中文参考手册或者芯片数据手册,了解需要使用的寄存器有哪些
4.理解寄存器的工作原理 参考中文参考手册 STM32的寄存器就算32bit
5.找到寄存器的地址,根据地址写入数据(数据手册+中文参考手册)
实操:
所以对GPIOF的MODE寄存器进行操作,只需要0x4002 1400+0x00即可
#define GPIOF_MODER (*(volatile unsigned int*)(0x4002 1400+0x00))
时钟同理
0x4002 3800+0x30
使能GPIOF,查GPIOF挂载在时钟线AHB1的第几位
第五位置1使能
#include "stm32f4xx.h"
#define RCC_AHB1ENR (*(volatile unsigned int*)(0x40023800+0x30))
#define GPIOF_MODER (*(volatile unsigned int*)(0x40021400+0x00))
#define GPIOF_OTYPER (*(volatile unsigned int*)(0x40021400+0x04))
#define GPIOF_OSPEEDR (*(volatile unsigned int*)(0x40021400+0x08))
#define GPIOF_PUPDR (*(volatile unsigned int*)(0x40021400+0x0C))
#define GPIOF_ODR (*(volatile unsigned int *)(0x40021400+0x14))
int main()
{
//1打开时钟
RCC_AHB1ENR |=(1<<5);
//设置端口模式,输出模式,输出速度,初始状态
GPIOF_MODER&=~(1<<19);
GPIOF_MODER|=(1<<18);//01输出模式
GPIOF_OTYPER &=~(1<<9) ;//0推挽,1开漏
GPIOF_OSPEEDR |=(3<<18) ;//3->11,11速度最快100MHZ
GPIOF_PUPDR&=~(1<<19);
GPIOF_PUPDR|=(1<<18);//01弱上拉模式
while(1)
{
GPIOF_ODR&=~(1<<9);//0,低电平点亮
// GPIO_ResetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10); //设置低电平 LED亮
// GPIO_SetBits(GPIOE,GPIO_Pin_13|GPIO_Pin_14);
}
}
6.根据寄存器地址写入数据
6位运算符:| & ~ << >>
&有0为0
|有1为1
~0变1,1变0
^异时取或
<< 左移运算符 高舍低补0,
>>右移,同上移出去的不要,空出来的位置补0
置位:x|=(1<<n)
清零:x&=~(1<<n)
在操作寄存器时应该蒋地址先转换为指针,然后再进行操作,无论如何操作都不会影响该地址下原有的数据。
******这个位置漏晚上看视频补全
二、STM32时钟体系
1.什么是晶振
晶振的全称叫做晶体振荡器,是晶体(石英)和电子元件组成,晶振有一个非常重要的特性:机电效应(压电效应),一般晶振会提供高度稳定的频率(振荡频率是固定的),一般晶振的频率有 8MHZ、12MHZ、25MHZ、11.0592MHZ...... 晶振的单位是 HZ 频率(单位时间振荡的次数)
思考:时钟信号是由什么产生的?时钟信号是由时钟源产生的,比如外部晶振产生的时钟信号就是时钟源的一种,但是有的外设不需要太高的时钟频率,所以 STM32 提供了多种时钟源给用户使用。 参考 STM32 中文参考手册第 6 章 一共有 5 种时钟源
2.什么是时钟
HSE 高速外部时钟,实时性强
HSI 高速内部时钟,16MHZ振荡器,成本低、功耗底、容易受温度影响,常用在小家电中
LSE低速外部时钟,32.768KHZ的时钟源,可以驱动RTC时钟源,功耗低、成本高
LSI低速内部时钟,频率为32KHZ的RC振荡器,可以驱动独立的看门狗和低功耗唤醒功能
PLL: 倍频锁相环,由HSE和HSI振荡器提供时钟信号,一般可以作为系统时钟使用。
3.STM32时钟树
3.2 计算M
中文参考手册知
f(VOC)=F(PCC输入)*(PLLN/PLLM)
最大可以达到168MHZ时钟频率
即8MHZ(输入)/PLLM*PLLN/PLLP≤168MHZ
已知:PLLN=336,PLLP=2(标准库可查)
8/PLLM*336/2≤168
8/PLLM≤1
所以PLLM取8
计算后也可以查看分频系数 AHB /1 APB2 /4
4.PLL参数的修改
标准库中使用25MHZ外部晶振,开发平台实际使用是8MHZ,如果不去修改PLL参数,会导致芯片的运行频率错误,所以需要修改PLL参数,可以去system_stm32f4xx.c和stm32f4xx.h两个文件中修改。
******图片及具体步骤看视频补充
5.STM32与51单片机的时钟对比
锁相环会增加功耗、降低使用寿命,因此在手机锁屏和智能手表中不会使用锁相环。
根据实际的情况来修改 PLL 的参数,这样就可以降低功耗或者提供性能,一般修改 PLL_N 的值(192~432),针对高性能模式、平衡模式、低功耗模式(以手机为例)高性能模式 :如果修改 PLL_N 的值为 432,则主频会达到 216MHZ 最高为多少 MHZ?平衡模式 :如果修改 PLL_N 的值为 336,则主频会达到 168MHZ低功耗模式 :主频可以降到 84MHZ 最低能降到多少 MHZ?
三、STM32的启动过程
现有main后有程序,.s文件更在main前。对于 STM32F407ZET6 来说,汇编文件为 startup_stm32f40_41xxx.s,当然不同的芯片型号所使用的汇编文件是不一样的。
启动文件功能如下
1.配置系统的栈空间
·栈是一种特殊的线性表,特殊在用户只能在栈的一端操作(栈顶),无法在另一端进行操作。如果没有数据进入栈空间,称为空栈;如果写入数据称为入栈;如果读取数据称为出栈。
****图
栈空间是由编译器来自动分配和释放的,栈空间一般存储局部变量、存储函数调用过程中的传递参数、保护现场,对于启动文件中的栈空间,默认是1KB。当写的程序较大,用的局部变量比较多,就必须修改栈空间大小。
如果栈空间大小不修改,就会导致 ”栈溢出“ ,让程序出现未知问题。
”栈空间可以由用户手动调整,但是不能超过SRAM的大小(192KB)
2.配置系统的堆空间
****图
THUMB指令集是ARM以前的指令集,THUMB指令集是16bit,ARM现在的指令集是THUMB-2指令集,是32bit的包含原指令集(THUMB)
对于堆空间是一般是动态分配的,由用户来分配,如linux中的malloc函数,但是对空间在STM32中使用的较少。
3.配置系统的向量表
*****图
向量表其实就是中断源表,向量其实就算内核发生的异常的源头,启动文件中的向量表的地址都是从Flash空间的首地址开始,0x0000 0000存储的是栈顶指针,0x 0000 0004存储的是复位程序地址... ...向量表可以参与STM32F4中文参考手册的第10章
4.复位程序分析
[WEAK]指的是弱声明,如果外部文件中提前定义了该函数,则优先使用外部文件中的。若没有重新定义,则使用则使用启动文件中的,也就是是不是唯一的
思考:是否可以改变函数的入口?答案是可以的,可以修改为自己指定的函数接口中。
5.中断服务函数分析
发生异常时,内核就需要跳转到中断服务函数中去处理异常,需要跳转到对应的中断服务函数中执行功能,中断服务函数是由用户在外部文件中重新定义。如果用户开启某个外设的中断,但是没有编写中断服务函数或者中断服务函数名字写错了,就会导致程序一直运行汇编文件中定义的中断服务函数,但是预定义的中断服务函数内部都是空的,所以就会跳转到无限循环、导致程序卡死。
*****图
注意:用户在使用中断服务函数的时候,中断服务函数必须在汇编文件中查找,不能随意定义。
6.堆栈初始化分析
如果启动MicroLIB库,这个库属于KEIL公司自带的库,会替换标准C库,这个微型库会对代码进行高度优化,所以生成的可执行文件的体积就会减小,但是缺点是微型库的功能没有标准库C库多。