STM32核心笔记

STM32核心笔记


1. 下载程序的两种方式

1.1 串口ISP

所需材料:

  1. 开发板需带有串口下载电路
  2. 下载软件:flymcu
  3. 编译好的HEX文件(由keil编译生成)
  4. 电脑安装好CH340驱动(因为开发板上用的电平转换芯片是CH340)

操作步骤如下图:
在这里插入图片描述
注:可以在开发板上通过配置BOTO引脚,会有不同的启动方式。
在这里插入图片描述

1.2 仿真器

首先介绍下常用的仿真器:

1.2.1 J-Link

J-Link是SEGGER公司为支持仿真ARM内核芯片推出的JTAG仿真器。配合IAR EWAR,ADS,KEIL,WINARM,RealView
等集成开发环境支持所有ARM7/ARM9/ARM11,Cortex M0/M1/M3/M4, Cortex A5/A8/A9等内核芯片的仿真,与IAR,Keil
等编译环境无缝连接,操作方便、连接方便、简单易学,是学习开发ARM最好最实用的开发工具。

在这里插入图片描述

在这里插入图片描述

1.2.1 ST-LINK

ST-Link是ST意法半导体为评估、开发STM8/STM32系列MCU而设计的集在线仿真与下载为一体的开发工具,支持JTAG/SWD/SWIM三种模式。
SWIM接口常见于ST的STM8系列单片机,ST-Link2与STM8连接只需要4根线。

在这里插入图片描述
在这里插入图片描述
烧录步骤:

  1. keil设置debug
  2. ST-LINK驱动安装
  3. 连接ST-LINK和开发板
  4. 点击下载

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 认识寄存器

简介:

寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,
但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以
由N个锁存器或触发器可以构成N位寄存器。寄存器是中央处理器内的组成部分。寄存器是有限存储容量的高速存储部件,它们可用来暂存
指令、数据和位址。这里暂且将寄存器理解为一个带存储功能的控制器。

3. 地址总线与外设地址映射关系

先来看看系统结构图
在这里插入图片描述
如何去理解这张图呢?我们从一个GPIO说起:

GPIO_InitTypeDef  GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 
 GPIO_Init(GPIOB, &GPIO_InitStructure);

这是一个GPIO_Pin_8引脚的初始化,就凭这简简单单几行代码怎么完成对GPIO的初始化。
首先配置一个GPIO引脚我们得知道他的地址在哪?他的输入输出模式由什么控制?速率是怎么控制的?
查看STM32手册查看与GPIO配置有关的寄存器:
在这里插入图片描述
???这么多寄存器名字也太复杂了要是我要用二三十个引脚那不得累死。仔细想想每个引脚都有几个相同的属性:输入输出模式,速率,引脚地址。于是我们可以像C++那样把他们的共同属性抽象出来形成一个类,用类来管理不就方便多了。不过这可是C不是C++此时就要用到结构体了于是就有了GPIO_InitTypeDef。

typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

GPIO速率,模式也有那么多于也弄个结构体吧。???但是不好意思GPIO速率和模式已经被限定了就那么几个是常量,结构体主要用于管理变量。枚举刚好解决这个问题于是就有了GPIOSpeed_TypeDef,GPIOMode_TypeDef 。

typedef enum
{ GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

那么GPIO_Pin地址如何确定?别人都给你定义好了不用担心

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

后面的((uint16_t)0x0001)真的就是GPIO_Pin_0 的地址吗?查看STM32的位带示意图(如下图),发现片上外设地址是从0X40000000开始的所以上面定义的 ((uint16_t)0x0001) 肯定不是GPIO_Pin_0的基地址。
在这里插入图片描述
那如何才能将GPIO_Pin_0的地址找到呢?在将这个结构体的成员设置好了后,又该往哪里呢?

GPIO_Init(GPIOB, &GPIO_InitStructure)

此时GPIO_Init站出来了,他将我们对结构体配置好的成员变量实实在在的写入到对应的寄存器中。???第一个GPIOB传入的是神马?为啥要传入呢?作用是啥?我们点进去看下:

#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

???怎么又来个GPIOB_BASE?继续点进去看看

#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)

???APB2PERIPH_BASE 又是啥?为啥要加0x0C00?继续点进去

/*!< Peripheral memory map */
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)

看到注释意思好像是外设内存地址再看看PERIPH_BASE 是啥

#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */

((uint32_t)0x40000000) 这不是前面图上标注的外设地址吗,接着 (PERIPH_BASE + 0x10000)是APB2PERIPH_BASE的地址为啥是APB2呢?从系下图上可以看出所有的GPIO都是挂载到APB2总线上的,且APB2的起始地址为0x40010000所以(PERIPH_BASE + 0x10000)。那(APB2PERIPH_BASE + 0x0C00)为啥是GPIOB_BASE的地址?这个问题看下图一下就明白了。
在这里插入图片描述
所有综上所述GPIO_Init传入的GPIOB就是基地址。

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  
/*---------------------------- GPIO Mode Configuration -----------------------*/
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
  { 
    /* Check the parameters */
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    /* Output mode */
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
/*---------------------------- GPIO CRHConfiguration ------------------------*/
  /* Configure the eight low port pins */
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
  {
    tmpreg = GPIOx->CRL;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = ((uint32_t)0x01) << pinpos;
      /* Get the port pins position */
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding low control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }
        else
        {
          /* Set the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
    GPIOx->CRL = tmpreg;
  }
/*---------------------------- GPIO CRH Configuration ------------------------*/
  /* Configure the eight high port pins */
  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
  {
    tmpreg = GPIOx->CRH;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));
      /* Get the port pins position */
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding high control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        /* Set the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    GPIOx->CRH = tmpreg;
  }
}

其实就是对GPIO的CRH/CRH寄存器配置而寄存器有哪些?别人根据STM32参考手册已经按着相应寄存器的偏移地址定义好了,

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注:结构体的顺序需要和寄存器地址偏移对齐,关于结构体地址对齐可百度查看。

4. GPIO的三种配置

5. 时钟树

6. 常用中断大集合

6.1 外部中断

6.2 定时器中断

6.3 DMA中断

6.4 ADC中断

6.5 IIC中断

6.6 SPI中断

6.7 UART中断

6.8 CAN中断

6.9 SDIO中断

6.10 IWDG、WWDG中断

7. 常用存储器

8. DAC

9. LCD/LED/OLED

10. FSMC(灵活的静态存储控制器)

11. FatFS文件系统移植

12. 固件库文件作用

13. 关于STM32系列之间的兼容性

13. 常见问题

1).Check that your license details are correct in the License Management dialog
问题描述:在系统更新后,可能会出现这种问题,原因是license发生错误。
解决办法:重新破解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值