1.为什么需要标准库
1.1、传统单片机软件开发方式
(1)芯片厂商提供数据手册、示例代码、开发环境
(2)单片机软件工程师面向产品功能,查阅数据手册,参考官方示例代码进行开发
(3)硬件操作的方式是用C语言对寄存器进行读写以操作硬件
(4)主要工作量分2块:一是调通各种外设,二是实现产品功能
(5)在简单单片机(如51单片机)上这一套工作的很好,但是随着单片机变复杂就带来一些问题
1.2、外设库有什么价值
(1)外设库其实就是以前芯片公司提供的示例代码的标准化产物
(2)外设库简化了我们开发产品的2大工作量的第一个
(3)外设库以源码方式提供,这个源码本身写的很标准,可以用作学习素材
1.3、学习和使用外设库的难点
(1)要有规范化编程的意识和能力
(2)C语言功底要过关
(3)要有一定的框架和层次认识
(4)要会没有外设库时直接C语言操作寄存器的方式(看原理图、查数据手册、位操作等)
1.4、再次强调
(1)外设库只是帮助我们简化编程,简化的主要是劳动量
(2)外设库一定程度上降低了编程难度,但是只会库、离了库就不会编程、库函数调用出了问题就束手无策这种还是没戏。(难度降低是对所有人的,你并不能从中得到好处)
2.外设库结构介绍
2.1、文件夹结构和主要文件的作用
CMSIS(STM32内部ARM核心相关内容)
CM3(Cortex-M3)
CoreSupport
内核相关的一些设置的寄存器集合及其封装
DeviceSupport
ST
STM32F10x
startup(起始文件)
stm32f10x.h
system_stm32f10x.c
system_stm32f10x.h
STM32F10x_StdPeriph_Driver(外设驱动)
inc(include,头文件,.h)
src(source,源文件, .c)
2.2 、后续的学习方法
(1)先搞清楚库对STM32这个硬件的封装和表达方式
(2)再彻底理解库中使用的结构体式访问硬件寄存器的方式
(3)初步建立起面向对象式编程的概念并且去体会
(4)以模块为单位去研究这个模块的库函数,并且用库函数去编程,并且实验结果,并且分析代码,去体会去熟悉库函数使用的方法
(5)最终达到什么程度?眼里有库心中无库。用人话说就是:思维能够穿透库函数直达内部对寄存器的操作。
2.3、标准库对硬件信息的封装方式
- 寄存器地址的封装
- 寄存器位定义的封装
- 外设操作的封装
2.4、使用结构体方式访问寄存器的原理
(1)C语言访问寄存器的本质是C语言访问内存,本质思路是:定义一个指针(临时变量)指向这块内存,然后*p = xx这种方式去解引用指针从而向目标内存中写入内容。
(2)缺陷:当寄存器多了之后每一个寄存器都要定义一套套路,很麻烦。
(3)解决思路:就是打包,批发式的定义,用结构体(想一下为什么不用数组?数组只能定义一种变量)的方式进行打包。具体做法是:把整个一个模块的所有寄存器(地址是连接的)打包在一个结构体中,每个寄存器对应结构体中的一个元素,然后结构体基地址对应寄存器组的基地址,将来就可以通过结构体的各个元素来访问各个寄存器了。
(4)结构体方式来访问寄存器和指针式访问寄存器,本质上其实是一样的,区别是C语言的封装不同。语法糖~~
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
// GPIOA 指针变量,本身占4个字节,指向一个数据类型是TIM_TypeDef的类型,指向的是一个内存区域
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
//不同端口的寄存器的列表
typedef struct
{
__IO uint32_t CRL; 0
__IO uint32_t CRH; 4
__IO uint32_t IDR; 8
__IO uint32_t ODR; c
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
// 结构体自动计算偏移量
之前就玩儿过
#ifndef H_GPIO_G
#define H_GPIO_G
typedef unsigned int u32;
#define PERIPH_BASE 0x40000000
#define GPIOG_BASE (PERIPH_BASE + 0x12000)
#define RCC_APB2ENR ((unsigned int *)0x40021018)
typedef struct
{
u32 CRL; //*
u32 CRH; //*
u32 IDR; //*
u32 ODR; //*
u32 BSRR;
u32 BRR; //*
}GPIOG_TypeDef;
#define GPIOG ((GPIOG_TypeDef *)GPIOG_BASE)
#endif
3.外设库的使用
3.1了解基本框架
打开工程模板
注意define:这里预先进行了宏定义~~~~
在代码里定义和这里定义功能上是相同的
USE_STDPERIPH_DRIVER, 外设驱动
STM32F10X_HD_VL, 芯片的选择
USE_STM32100E_EVAL 工程实例
如果打开stm3210x.h
这里同上,需要哪个启动代码,打开哪个,也可在工程中配置,如上图。
#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
/* #define STM32F10X_LD */ /*!< STM32F10X_LD: STM32 Low density devices */
/* #define STM32F10X_LD_VL */ /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */
/* #define STM32F10X_MD */ /*!< STM32F10X_MD: STM32 Medium density devices */
/* #define STM32F10X_MD_VL */ /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */
/* #define STM32F10X_HD */ /*!< STM32F10X_HD: STM32 High density devices */
/* #define STM32F10X_HD_VL */ /*!< STM32F10X_HD_VL: STM32 High density value line devices */
/* #define STM32F10X_XL */ /*!< STM32F10X_XL: STM32 XL-density devices */
/* #define STM32F10X_CL */ /*!< STM32F10X_CL: STM32 Connectivity line devices */
#endif
上面两个都可以使用
头文件包含:
因此只要包含了stm3210x.h,就包含了所有的头文件
#ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h" //包含所有外设头文件
#endif
#include "stm32f10x_adc.h"
#include "stm32f10x_bkp.h"
#include "stm32f10x_can.h"
#include "stm32f10x_cec.h"
#include "stm32f10x_crc.h"
#include "stm32f10x_dac.h"
#include "stm32f10x_dbgmcu.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_fsmc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_iwdg.h"
#include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_rtc.h"
#include "stm32f10x_sdio.h"
#include "stm32f10x_spi.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_wwdg.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
断言配置
如果定义了USE_FULL_ASSERT 就会使用
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function which reports
* the name of the source file and the source line number of the call
* that failed. If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
3.2标准库配置
库移植成功后,我们原来的代码也可以直接使用
#include "stm32f10x.h"
void led_init(void);
void Delay(void);
void flash(void);
int main(void)
{
led_init();
while(1)
{
flash();
};
return 0;
}
void led_init(void)
{
RCC->APB2ENR = 0x00000100;
GPIOG->CRL = (0x33 << 24);
}
void Delay(void)
{
unsigned int i = 0, j = 0;
for( i = 0; i < 2000; i++)
{
for( j = 0; j < 2000; j++);
}
}
void flash(void)
{
GPIOG->BSRR = 0x000000080;
Delay();
GPIOG->BSRR = 0x00000040;
Delay();
GPIOG->BSRR = 0x00ff0000;
Delay();
}