第三篇,芯片启动和时钟系统

芯片启动和时钟系统

1.芯片启动

首先stm32会根据启动方式(参考手册2.4节)从启动位置加载启动代码到内存中,之后开始执行启动代码,一般启动代码使用官方提供的即可 ---------- xxx.s

启动代码的工作:

初始化堆栈空间,定义异常向量表 调用SystemInit ----------- 系统初始化时钟,调整异常向量表 执行main ---------- 主函数

芯片要开始工作,必须初始化时钟和内存,stm32的内存使用片内SRAM,可以直接使用,时钟需要初始化,ARM芯片需要定义异常向量表,执行C语言代码必须初始化堆栈。

stm32f407推荐的主时钟频率 168MHz

2.产生原始频率的硬件

(1)晶振

(2)RC(LC)振荡电路

原始频率不会很高,使用前必须升频,升频使用PLL(升频)电路

CPU时钟系统的大体结构

3.stm32f407的原始时钟

HSI RC -------------- 高速内部振荡时钟 16M

HSE OSC ------------- 高速外部晶振 4~26M(8M) //以上两个时钟源可以直接作为系统主时钟,也可以通过PLL升频后作为主时钟

LSI RC --------------- 低速内部振荡时钟 32K ----- 看门狗 LSE OSC -------------- 低速外部晶振 32.768K ----- RTC

stm32f407的时钟树

PLL的输出时钟 = PLL输入时钟 X PLLN / PLLM / PLLP

168M = 8M X 336 / 8 / 2

4.将keil5的工程的系统时钟配置为168MHz

(1)修改system_stm32f4xx.c的254行

#define PLL_M 8

(2)修改stm32f4xx.h的127行

//该文件是只读属性文件,要去文件系统中找到该文件,去掉只读属性

#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */

练习:

将系统主频配置为168M

修改PLL,调节系统主频

#define PLL_N 336//168M

#define PLL_N 432//216M 超频

#define PLL_N 168//84M 降频

系统总线时钟频率:

SYSCLK时钟 ------------ 168MHz

HCLK/AHB总线 ---------- 168MHz

APB1时钟 -------------- 42MHz

APB2时钟 -------------- 84MHz

__________________________________________________________________________________________________________________________________________________________

按键驱动

1.看原理图

从原理图可知:

按键松开 -------- 引脚高电平

按键按下 -------- 引脚低电平

按键对应的引脚:

S1 ----- PA0

S2 ----- PE2

S3 ----- PE3

S4 ----- PE4

如何读取输入引脚的电平

(1)读取输入数据寄存器(IDR)对应位的值 1 ----- 输入高电平 0 ----- 输入低电平

(2)位段操作 PAin(0)==0 ----- 输入低电平 PAin(0)==1 ----- 输入高电平

(3)库函数 uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //传入哪一组哪个脚,返回该引脚的电平

——————————————————————————————————————————————————————————————————————————————————————

练习:

完成其他三个按键的检测程序,分别使用 寄存器 位段 库函数判断

实现一下功能:

按下S2,D2亮 按下S3,D3亮 按下S4,D4亮

//key.c

#include <stm32f4xx.h>
#include <key.h>
void key_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
    //1.开启GPIOA的时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE,ENABLE);
    
    //2.GPIO初始化 PA0
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;//输入模式
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;//PA0
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//PE2 PE3 PE4
    GPIO_Init(GPIOE,&GPIO_InitStruct);

//main.c

#include <stm32f4xx.h>
#include <led.h>
#include <sys.h>
#include <key.h>

int main()
{
	int key_flag = 0;
	
	//初始化
	led_init();
	key_init();
	
	while(1){
		if(S1==0){
			//延时消抖10ms
			delay(100);
			if(S1==0){
				//真实按键事件
				if(key_flag==0){//按下没有松开
					D1 = ~D1;//取反
					key_flag = 1;
				}
			}
		}
		else{
			//延时消抖10ms
			delay(100);
			if(S1){
				key_flag = 0;
			}
		}
	}

}

//lcd.c

include <stm32f4xx.h>
#include <led.h>

void delay(unsigned int ms)
{
	int i,j;
	
	for(i=0;i<ms;i++)
		for(j=0;j<5000;j++);
}

void led_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//1.开启GPIOE GPIOF的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOF,ENABLE);
	
	//2.GPIO初始化 PF9 PF10 PE13 PE14
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//输出模式
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//高速
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;//PF9 PF10
	GPIO_Init(GPIOF,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14;//PE13 PE14
	GPIO_Init(GPIOE,&GPIO_InitStruct);
	
	//3.LED默认关闭
	GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
	GPIO_SetBits(GPIOE,GPIO_Pin_13|GPIO_Pin_14);
}

//lcd.h

#ifndef _LED_H_
#define _LED_H_

#define D1 PFout(9)
#define D2 PFout(10)
#define D3 PEout(13)
#define D4 PEout(14)

void delay(unsigned int ms);
void led_init(void);

#endif

//key.h

#ifndef _KEY_H_
#define _KEY_H_

#define S1 PAin(0)
#define S2 PEin(2)
#define S3 PEin(3)
#define S4 PEin(4)

void key_init(void);

#endif

 //sys.h                                                该文件由系统定义

#ifndef __SYS_H_
#define __SYS_H_ 
#include "stm32f4xx.h" 

//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    20 = 0x14
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010    16 = 0x10
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入


#endif


3.按键消抖————延时消抖

以上按键程序不管是否有按键事件发生,都会占用CPU来进行判断,这种方式叫做轮询,效率比较低,CPU提供了效率更高的方式 --------- 中断。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
SOC(System on Chip,即片上系统芯片软件启动过程是指从硬件初始状态开始,通过一系列的过程,将SOC芯片软件逐步启动并运行起来的过程。简单来说,软件启动是通过硬件初始化,引导,加载和运行等步骤实现的。 1. 硬件初始化:SOC芯片启动过程的第一步是对硬件进行初始化。此时,芯片会读取系统中的配置信息,例如芯片型号、时钟频率、内存容量等信息,并将其保存在相应的寄存器中。 2. 引导:在硬件初始化完成后,芯片需要读取引导程序。引导程序是硬件上电后自动运行的第一个程序,用于初始化系统并加载操作系统和应用程序等。 3. 加载:引导程序完成启动后,需要将操作系统从外部介质(例如SD卡)中读取到内存中,并将其加载到RAM中。此时,SOC芯片也会执行一些初始化操作,包括设置堆栈、清空缓存、启动时钟等。 4. 运行:当操作系统被加载到内存中后,SOC芯片软件启动过程进入了最后一步——运行。此时,操作系统会开始运行,并管理系统中的资源和服务。应用程序也会随着操作系统启动而开始运行。 在以上过程中,软件启动的过程中需要注意一些问题,例如启动程序的选择、引导程序的优化等。此外,不同的SOC芯片通过相应的引导程序和操作系统等软件来实现相应的功能。因此,在进行SOC芯片软件启动时,需要根据具体情况进行相应的配置和调整。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖爱Kun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值