STM32入门精要:从CPU架构到GPIO实战的避坑指南

知识点1【概念补充】

1、CPU概念:中央处理器

中央处理器(central processing unit)作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。

内核

2、MCU概念:微控制单元

微控制单元(Microcontroller Unit),又称单片机微型计算机或者单片机,是将中央处理器(CPU)的频率与规格做适当缩减,并将内存、计数器、USB、A/D转换、USB、A/D转换、UART、PLC、DMA等周边接口,甚至LCD驱动电路都整合在单一芯片上,形成芯片级的计算机,为不同的应用场合做不同组合控制。

MCU—>单片机—>单核的CPU

目前比较新的单片机 中也有多核的

3、嵌入式

嵌入式系统是以应用为中心,以现代计算机技术为基础,能够根据用户需求(功能,可靠性,成本,体积,功耗,环境等)灵活裁剪软硬件模块的专用计算机系统

嵌入式:软硬件结合 软硬件和裁剪

4、物联网

最简洁明了的定义:物联网(Internet of Things)是一个基于互联网,传统电信网等信息承载体,让所有能够单独寻址的普通物理对象实现互通互联的网络。它具有普通对象设备化、自治终端互联化和普适服务智能化3个重要特征。

物联网包括嵌入式。更准确来说,嵌入式是物联网技术的一种具体实践方式。

万物互联

知识点2【MCU的组成】

ARM公司:主要是设计处理器架构的

ST(意法半导体)公司:获取架构的版权后,设计芯片

台积电:生产芯片

知识点3【软件安装】

之前学习单片机使用的VS code,VIM……

编写单片机的代码,需要使用KEIL5工具

我们这里使用的版本是MDK529

注意:安装的过程中,不要包含中文路径

1、安装keil5的步骤

下面这个界面 随便填写

2、破解keil5的步骤

知识点4【STM32F103ZE】

1、STM32 的命名规则

2、GPIO的输入输出模式

忽略我的标注

1、输出模式

**开漏输出:**本身没有驱动能力,无法输出高电平,如果想要输出高电平,需要外界电路。

开漏的好处,本身不驱动,依赖外部电路,当内部电路电压无法满足外界原件的时候,就需要开漏输出借助外部电路来提高驱动能力

**推挽输出:**有一定的驱动能力,内部既可以输出低电平,也可以输出高电平

**复用推挽:**除了通用IO口输出高低电平的第二功能,都是复用推挽

**复用开漏:**除了通用IO口输出低电平的第二功能,都是复用开漏

2、输入模式

模拟输入:主要使用于AD转换中

上拉输入:管脚默认是高电平,电路内部是弱上拉

下拉输入:管教默认是低电平,电路内部是强下拉

浮空输入:管教既不连接上拉电阻,也不连接下拉电阻,状态不确定。但在32中由于强下拉的原因,呈现低电平

3、寄存器控制IO

1、统一步骤

1、配置时钟

2、配置端口输入输出的模式

3、控制端口

2、操作寄存器的方式

改变其中一位,使用

按位与将特定位置0:与1不变,与0为0

按位或将特定位置1:或0不变,或1位1

4、寄存器配置详解

以配置LED0为例,即配置PB5

1、配置时钟

时钟的概念

时钟在我们的单片机中主要起到计数的作用,代表系统运行的速度快慢

强调:每一个PA,PB,PC(每个端口)…….他们都有各自独立的时钟

1、根据上图选时钟源

2、选完时钟后查手册

这里以配置GPIOB 时钟为例

RCC_APB2ENR |= (0x01 << 4);

将IOPB位置1

2、配置端口输出\输入模式

依旧查表

下面介绍一下 上面是如何配置 输出\输入模式的:

根据 MODE配置管脚是输入还是输出

1、输出

MODE ≠ 0,其余三个模式没有什么特别大的区别,我们这里选择01

选择好MODE后,来选择CNF,我们根据需求,可以知道推挽模式更适合我们,因为LED0无外界电路,且 选择的是GPIOB5 的通用端口。

最终确定我们需要将23 - 20 依次配置为 0010

这里我建议的配置步骤是:先将这四位全部清0,清0后再执行特定位置1操作。

GPIOB->CRL &= ~(0x0f << 20);
GPIOB->CRL |= (0x01 << 20);

2、输入

MODE = 0

选好MODE后,来选择CNF。

这里不多讲配置过程,我想说一下 大家可能在配置按键时的疑惑:

可以看到 下拉和下拉模式都是一个CNF,如何区分呢?

这里我给大家提供方案:

GPIOE->CRL &= ~(0x0f << 16);
GPIOE->CRL |= (0x08 << 16);
GPIOE->ODR |= (1 << 4);//上拉
//下拉则是将这个端口置0

3、配置管脚

在这两个文档里,大家自行查看吧,没什么注意事项,认真就好。

while(1)
{
	//LED0 亮
	GPIOB->ODR &= ~(0x01 << 5);
	//LED1 灭
	GPIOE->ODR |= (0x01 << 5);
	Delay_1ms(500);

	//LED0 灭
	GPIOB->ODR |= (0x01 << 5);
	//LED1 亮
	GPIOE->ODR &= ~(0x01 << 5);
	Delay_1ms(500);
}

补充延时函数:

void Delay_1ms(uint32_t ms) {
    SysTick->LOAD = 72000 - 1;      // 72MHz/1000 = 72000 cycles/ms
    SysTick->VAL  = 0;              // 清空计数器
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
    
    while(ms--) {
        while( !(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) ); // 等待计数完成
    }
    
    SysTick->CTRL = 0; // 可选:关闭SysTick
}

4、代码演示

#include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
void Delay_1ms(uint32_t ms);
void LED();
void beep();

int main(void)
{
	//配置按键时钟
	RCC->APB2ENR |= (0x01 << 6);
	
	//配置按键0 输入模式
	GPIOE->CRL &= ~(0x0f << 16);
	GPIOE->CRL |= (0x08 << 16);
	GPIOE->ODR |= (1 << 4);
	
	//配置按键1 输入模式
	GPIOE->CRL &= ~(0x0f << 12);
	GPIOE->CRL |= (0x08 << 12);
	GPIOE->ODR |= (1 << 3);
	
	//配置按键2 输入模式
	GPIOE->CRL &= ~(0x0f << 8);
	GPIOE->CRL |= (0x08 << 8);
	GPIOE->ODR |= (1 << 2);
	
	//配置按键触发功能
	while(1)
	{
		
		if((GPIOE->IDR & (0x01 << 4)) == 0)
		{
			//按键0
			Delay_1ms(20);
			if((GPIOE->IDR & (0x01 << 4)) == 0)
			{
				while((GPIOE->IDR & (0x01 << 4)) == 0);
				LED();
			}
		}
		
		//按键1
		if((GPIOE->IDR & (0x01 << 3)) == 0)
		{
			Delay_1ms(20);
			if((GPIOE->IDR & (0x01 << 3)) == 0)
			{
				while((GPIOE->IDR & (0x01 << 3)) == 0);
				beep();
			}
		}
		
		//按键2
		if((GPIOE->IDR & (0x01 << 2)) == 0)
		{
			Delay_1ms(20);
			if((GPIOE->IDR & (0x01 << 2)) == 0)
			{
				while((GPIOE->IDR & (0x01 << 2)) == 0);
			}
		}
	}
}

//走马灯函数
void beep()
{
	//打开GPIOB的时钟
	RCC->APB2ENR |= (0x01 << 3);
	
	//配置GPIOB8端口输出模式:推挽输出 BEEP
	GPIOB->CRH &= ~(0x0f << 0);
	GPIOB->CRH |= (0x01 << 0);
	
	//配置端口
	GPIOB->ODR |= (0x01 << 8);
	Delay_1ms(1000);
	GPIOB->ODR &= ~(0x01 << 8);
}

void LED()
{
	//配置时钟
	RCC->APB2ENR |= (0x0001 << 3);
	RCC->APB2ENR |= (0x0001 << 6);
	
	//配置GPIOB5端口模式:推挽输出 LED0
	GPIOB->CRL &= ~(0x0f << 20);
	GPIOB->CRL |= (0x01 << 20);
	//配置GPIOE5端口模式:推挽输出 LED1
	GPIOE->CRL &= ~(0x0f << 20);
	GPIOE->CRL |= (0x01 << 20);
	
	//配置端口
	while(1)
	{
		//LED0 亮
		GPIOB->ODR &= ~(0x01 << 5); 
		//LED1 灭
		GPIOE->ODR |= (0x01 << 5);
		Delay_1ms(500);
		
		//LED0 灭
		GPIOB->ODR |= (0x01 << 5);
		//LED1 亮
		GPIOE->ODR &= ~(0x01 << 5);
		Delay_1ms(500);
		
		if((GPIOE->IDR & (0x01 << 4)) == 0)
		{
			//按键0
			Delay_1ms(20);
			if((GPIOE->IDR & (0x01 << 4)) == 0)
			{
				while((GPIOE->IDR & (0x01 << 4)) == 0);
				//LED0 灭
				GPIOB->ODR |= (0x01 << 5);
				//LED1 灭
				GPIOE->ODR |= (0x01 << 5);
				break;
			}
		}
	}
}

void Delay_1ms(uint32_t ms) {
    SysTick->LOAD = 72000 - 1;      // 72MHz/1000 = 72000 cycles/ms
    SysTick->VAL  = 0;              // 清空计数器
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
    
    while(ms--) {
        while( !(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) ); // 等待计数完成
    }
    
    SysTick->CTRL = 0; // 可选:关闭SysTick
}

知识点5【代码中遇到的问题】

1、构建和下载程序中出现的问题

2、检查ST Link驱动是否有效

如果遇到驱动没办法正常连接的可以管我要一下驱动文件。

3、时钟理解错误

代码错误:每一个IO块(A,B,C……)都有自己的时钟,知识点遗忘导致忘记配置GPIOE的时钟

学一下使用VS code 写代码

结束

代码重在练习!

代码重在练习!

代码重在练习!

今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏加关注,谢谢大家!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值