熊爸的学习时间

STM32一文通(2) 理解库函数原理

2020-07-24  本文已影响0人  熊爸天下_56c7

一. 理解库函数原理

外设寄存器的地址都是基于外设基地址的偏
移地址,都是在外设基地址上逐个连续递增的,每个寄存器占 32 个字节,这种方式跟结构
体里面的成员类似。所以我们可以定义一种外设结构体,结构体的地址等于外设的基地址,
结构体的成员等于寄存器,成员的排列顺序跟寄存器的顺序一样。这样我们操作寄存器的
时候就不用每次都找到绝对地址,只要知道外设的基地址就可以操作外设的全部寄存器,
即操作结构体的成员即可。

以GPIOB为例:
因为GPIO内存结构是这样的 (每个寄存器都是有规律的基地址偏移)

这样当我们想访问某个寄存器时就可以按照操作结构体的方式访问了

然后,我们写一些函数来封装操作和数据位移过程

这里用到的GPIO_Pin都是一些固定值, 直接在头文件里声明好了

二. 初识STM32标准库

1. CMSIS标准

ARM 与芯片厂商建立了 CMSIS 标准(Cortex MicroController Software Interface Standard)。所谓 CMSIS 标准,实际是新建了一个软件抽象层。

CMSIS包含两层:

2. 标准库中都有哪些文件???

3. 库函数目录结构

STMF10X标准库下载地址

可以看到,真正有用的是Libraries文件夹

三. 创建一个库函数版的工程

  1. 先创立一个工程文件夹,并文件夹内创立如下文件夹
  1. 打开keil5 创建新工程(创建到project文件夹下)
  1. 在工程上右键建立工程内映射文件夹

4.把标准库文件拷贝进我们的文件夹

把目录整理成这样:

  1. 在User文件夹中建立main.c文件
  2. 从官方样板例程或模板中拷贝如下文件到User文件夹

7.现在开始往工程中添加文件,首先添加启动文件

启动文件在Libraries\CMSIS\startup\arm\startup_stm32f10x_hd.s

  1. 再添加CMSIS核心层文件 core_cm3.csystem_stm32f10x.c
  1. 再添加FWLIB 外设库(全部添加进来)

所需文件在文件夹\Libraries\STM32F10x_StdPeriph_Driver\src中

  1. 在USER中添加stm32f10x_it.cmain.c

11.指定头文件在工程目录中找

打开魔术棒, 找到如下位置:

添加工程中用到的头文件所在目录

  1. 定义一个工程宏USE_STDPERIPH_DRIVER

因为stm32f10x.h头文件中有这么一句:

意思是如果有这个USE_STDPERIPH_DRIVER宏, 则挂载stm32f10x_conf.h文件

那我们就定义一个这样的宏:

  1. 定义一个宏来指定好自己的芯片类型,如:STM32F10X_HD

不同的宏定义之间用 , 隔开

  1. 在main.h中添加main函数
#include "stm32f10x.h"

int main(void)
{
    
}

此时可以编译啦, 一个工程模板做好了!!!!

  1. 接下来要进行一点工程设置, 首先要使用microLIB以方便串口调试
  1. 编译时输出HEX文件
  1. 最后设置好对应的调试器就行了
  1. 我比较喜欢VSCode, 但VSCode默认采用uft-8 码 , 所以我想设置keil5采用utf-8, 这样不会出现中文乱码.

终于完成了!!!!

四. 创建一个LED亮灯工程

  1. 将上面建立的模板复制一份过来
  2. 在user文件夹建立一个led文件夹存放相关驱动程序
  3. 在文件夹内创建led.cled.h文件
  4. 打开工程将我们刚刚创建的led.c导入进去
  5. 添加头文件所在目录进工程中
  1. 这时main.c中就可以引用这个头文件了
  1. 按我们之前的方法预写头文件
  1. 现在在led.c文件中,引入led.h头文件,然后就可以开始写函数了
  1. led.c
#include "led.h"

void LED_GPIO_Config(void)
{
    
    GPIO_InitTypeDef GPIO_InitStruct_G; //创建一个GPIO_InitTypeDef类型的数据
    GPIO_InitStruct_G.GPIO_Pin = LED_G_Pin;   //给这个数据的参数赋值
    GPIO_InitStruct_G.GPIO_Mode = GPIO_Mode_Out_PP;//给这个数据的参数赋值
    GPIO_InitStruct_G.GPIO_Speed = GPIO_Speed_50MHz;//给这个数据的参数赋值
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启时钟
    GPIO_Init(LED_G_GPIO,&GPIO_InitStruct_G);  //初始化端口     
}
  1. led.h
#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"



#define LED_G_GPIO  GPIOB
#define LED_G_Pin   GPIO_Pin_0

#define ON   1
#define OFF  0

#define LED_G(a) if(a) GPIO_ResetBits(LED_G_GPIO,LED_G_Pin); else GPIO_SetBits(LED_G_GPIO,LED_G_Pin);// 这里用了一个条件定义

void LED_GPIO_Config(void);

#endif /*__LED_H*/

  1. main.c
#include "stm32f10x.h"
#include "led.h"

void delay(u32 count);

int main(void)
{
    LED_GPIO_Config();
    while(1)
    {
        LED_G(ON);
        delay(0XFFFFF);
        LED_G(OFF);
        delay(0XFFFFF);
    }   
}

void delay(u32 count) //延时函数
{
    u32 i;
    for(i = count;i>0 ; i--)
    {
    }
}

上一篇 下一篇

猜你喜欢

热点阅读