欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPTX文档下载  

    第4章STM32最小系统与嵌入式C语言课件.pptx

    • 资源ID:1488726       资源大小:1,002.58KB        全文页数:80页
    • 资源格式: PPTX        下载积分:16金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要16金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    第4章STM32最小系统与嵌入式C语言课件.pptx

    ,第4章,STM32最小系统 与嵌入式C语言,STM32,本章知识与能力要求,掌握STM32最小系统设计;理解和掌握嵌入式C语言的程序结构;掌握嵌入式C语言的数据类型、const、volatile和extern等关键字的使用;掌握嵌入式C语言的条件编译;掌握嵌入式C语言指针的应用;学会分析HAL库文件源码。,第4章 STM32最小系统与嵌入式C语言,4.1 STM32最小系统,4.1.1 电源电路,4.1.2 时钟电路(晶振电路),4.1.3 复位电路,4.1.4 调试和下载电路,03,04,01,02,用最少的元件组成单片机可以工作的系统,4.1.1 电源电路,微控制器工作电压,3.4V5.5V或2.7V3.6V,为系统提供稳定可靠的供电,STM32F103系列:2.0V3.6V,电源电压,5V,AMS1117系列芯片,1.5V1.8V2.5V2.85V3.0V3.3V5.0V,供电,4.1.1 电源电路,C1、C3为输入电容,作用是防止断电后出现电压倒置C2、C4为输出滤波电容,作用是抑制自激振荡和稳定输出电压,AMS1117-3.3v降压电路图,电压转换电路提供3.3V电压供STM32主电源VDD使用,4.1.1 电源电路,STM32内部包含一个电压调节器,将外部3.3V电压转换为1.8V提供给Cortex-M3内核、内存以及外设使用。,STM32内部电源框图,内部有两个可选电源选项:ADC模块所需的参考电压VREF+和VREF-。常采用独立的供电电源。备用电池电源VBAT。当主电源VDD掉电后,通过VBAT引脚为实时时钟和备份寄存器提供电源。通常选择备用电池作为该电源,电压范围为1.83.6V。若不使用备用电池供电,则VBAT引脚必须与主电源引脚VDD连接。,4.1.2 时钟电路(晶振电路),时钟系统产生供系统正常工作的稳定的脉冲信号.,单片机的一切指令的执行都依赖于晶振提供的时钟频率,时钟频率越高,单片机运行速度越快,功耗也就越大。,4.1.2 时钟电路(晶振电路),晶振,有源晶振(振荡器),无源晶振(晶体),内部包含晶体管和阻容元件一个完整的谐振振荡器只需要给它供电不需要外接其他元件通常有四个引脚:VCC、GND、晶振输出引脚和一个悬空的引脚。,只有2个引脚的无极性元件需要借助外部电路起振精度上差一些价格便宜,4.1.2 时钟电路(晶振电路),使用低速晶振电路作为系统低速外部时钟源,频率为32.768kHz,主要用作RTC的时钟源,用于精准计时定时电路、万年历等。,使用外部高速晶振电路作为系统时钟源,一般称为高速外部时钟信号(HSE)。一般选择8MHz,方便倍频。,01,02,4.1.3 复位电路,复位电路将系统进行复位,STM32内部复位电路,STM32芯片复位管脚持续为低电平时复位,STM32的NRST引脚在内部已经连接了一个上拉电阻,数据手册建议复位电路需外接一个对地电容,如果认为这个上拉电阻较小,用户也可以在复位电路中外接一个上拉电阻,4.1.3 复位电路,按键S1按下时,RESET和地连通,产生低电平,实现复位。,上电复位:,在上电瞬间,由于电容来两端电压不能突变,RESET出现短暂低电平,芯片自动复位,之后电容充电,充电时间由电阻和电容共同决定:,上电后约1ms左右系统完成复位,之后,单片机开始正常工作。,手动复位:,4.1.4 调试和下载电路,将编译好的程序下载到单片机中运行以及进行在线调试,STM32F103系列微控制器内核集成了SWD/JTAG调试端口(缩写为SWJ-DP)JTAG调试接口(5引脚的JTAG-DP)SWD(Serial Wire Debug,串行单总线调试)( 2引脚的SW-DP),作用,STM32调试端口引脚功能,4.1.4 调试和下载电路,Cortex-M3内核有三种启动方式,可以通过BOOT0和BOOT1的电平组合进行选择。,内核的启动模式,在STM32F103系列微控制器中通过设置BOOT1:0引脚电平的高低选择三种不同启动模式,从而将STM32F103微控制器的存储空间起始地址0 x00000000映射到不同存储区域的起始地址。,4.1.4 调试和下载电路,保持BOOT1为“0”,当BOOT0=1时,STM32F103系列微控制器从系统存储器的起始地址0 x1FFFF000开始启动;当BOOT0=0时,STM32F103系列微控制器从用户Flash的起始地址0 x80000000开始启动运行代码,这是STM32最常用的启动方式。若要从片内SRAM起始地址0 x20000000启动,则BOOT0、BOOT1均设为“1” 。,内核的启动模式,4.2 嵌入式C语言,4.2.1 STM32的数据类型,4.2.2 const 关键字,4.2.3 static 关键字,4.2.4 volatile 关键字,4.2.5 extern 关键字,4.2.8 typedef,4.2.9 #define,4.2.10 #ifdef、#if条件编译,4.2.11 指针,4.2.12 回调函数,4.2.7 enum,4.2.6 struct结构体,4.2 嵌入式C语言,嵌入式开发中既有底层硬件的开发又涉及上层应用的开发,即涉及系统的硬件和软件,C语言既具有汇编语言操作底层的优势,又具有高级语言功能性强的特点。,1,程序总是从main函数开始执行;,2,3,4,5,函数是C语言的基本结构;,函数由两部分组成:函数说明部分和函数体。,一个C语言程序包含若干个源程序文件(.c文件)和头文件(.h文件)。,采用外设功能模块化设计方法,一个外设功能模块包括一个源文件(.c文件)和一个头文件(.h文件)。,4.2 嵌入式C语言,嵌入式系统开发多采用模块化、层次化的设计思想,系统层次架构清晰,便于协同开发。,嵌入式系统软件结构框图,4.2.1 STM32的数据类型,数据是嵌入式C语言的基本操作对象。,数据类型是指数据在计算机内存中的存储方式。,嵌入式C语言的数据类型,4.2.1 STM32的数据类型,不同CPU所定义的数据类型的长度不一致,ST公司为开发人员提供了基于C语言的标准外设库,标准外设库中定义的数据类型的长度如下表所示。,4.2.1 STM32的数据类型,v3.5.0版本已不再使用旧的数据类型,为了兼容以前的版本,stm32f10 x.h头文件还对标准外设库之前版本所使用的数据类型进行了说明。,STM32开发中同一数据类型有多种表示方式。,无符号8位整型数据有unsigned char,uint8_t,u8三种表示方式。,例,最新的v3.5.0版本采用标准的C99标准,即uint8_t方式。,4.2.1 STM32的数据类型,_I、_O以及_IO为IO类型限定词,内核头文件core_cm3.h定义了标准外设库所使用的IO类型限定词。,数据类型和IO类型限定词结合在一起,在标准外设库中常用来定义寄存器和结构体变量:,4.2.1 STM32的数据类型,stm32f10 x.h头文件中常用的布尔类型的变量的定义,typedef enum DISABLE = 0, ENABLE = !DISABLE FunctionalState;,typedef enum RESET = 0, SET = !RESET FlagStatus, ITStatus;,typedef enum ERROR = 0, SUCCESS = !ERROR ErrorStatus;,RESET与SET,DISABLE与ENABLE,ERROR与SUCCESS,#define IS_FUNCTIONAL_STATE(STATE) (STATE) = DISABLE) | (STATE) = ENABLE),4.2.2 const关键字,作用,用于定义只读的变量,其值在编译时不能被改变,const 常量类型 常量名=常量表达式;,格式,为了在编译时防止变量的值被误修改,提高程序的安全性和可靠性。,目的,要求,属性,const关键词修饰的变量在声明时必须初始化,在C标准中,const定义的变量是全局的。,4.2.3 static关键词,修饰变量或函数。修饰后的变量称为静态变量。,作用,在全局变量之前加上关键字static,则该全局变量被定义成为一个静态全局变量。,作用范围只在定义该变量的源文件内有效,其他源文件不能引用该全局变量,避免了在其他源文件中因引用相同名字的变量而引发错误,有利于模块化程序设计。,操作,目的,4.2.3 static关键词,#include stm32f1xx_hal.hstatic void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength); HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) HAL_StatusTypeDef status = HAL_OK; if(HAL_DMA_STATE_READY = hdma-State) DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength); ,static编程要点1: 模块化的程序设计中,用static声明一个函数,则该函数只能被该模块内的其它函数调用。,解析:DMA_SetConfig()函数只能被stm32f1xx_hal_dma.c的其它函数调用,不能被其它模块的文件使用。,4.2.3 static关键词,void fun_count( ) static count_num = 0; / 声明一个静态局部变量,count_num用作计数器,初值为0。 count_num +; printf(%dn, count_num);int main(void) int i=0; for (i = 0;i = 5;i+) fun_count( ); return 0;,static编程要点2: static除了用于静态全局变量,还用于定义静态局部变量,保证静态局部变量在调用过程中不被重新初始化。,解析:在main函数中每调用一次fun_count( )函数,则静态局部变量count_num加1,而不是每次都被初始化为初值0。,4.2.4 volatile关键字,一个类型修饰符,“易变的”。 volatile char i; 使用volatile关键字定义了一个字符型的变量i,指出i是随时可能发生变化的,每次使用的时候都必须从i的地址中读取。,使用volatile就是不让编译器进行优化,即每次读取或者修改值的时候,都必须重新从内存中读取或者修改,而不是使用保存在寄存器里的备份。,中断服务程序中修改的供其他程序检测的变量需要使用volatile;多任务环境下各任务间共享的标志应添加volatile;存储器映射的硬件寄存器通常也要加volatile进行说明。,作用,使用方式,应用场合,4.2.5 extern关键词,extern int a;,指明此函数或变量的定义在别的文件中,提示编译器遇到此函数或变量时去其他模块中寻找其定义。,作用,使用extern是一个声明而不是重新定义,声明变量a,而不是在定义变量a,并未为a分配内存空间,声明函数funA( ),此函数已在其他文件中定义。,extern C进行链接指定,告知编译器这是采用C语言定义的函数,extern int funA( );,4.2.5 extern关键词,#ifdef _cplusplusextern C#endif#ifdef _cplusplus#endif,解析:如果定义了_cplusplus(C+编译器中自定义的宏),则执行extern“C”语句。C+支持函数重载,而C语言不支持函数重载,在C+环境下使用C函数会出现链接时找不到对应函数的情况,这时需要使用extern “C”进行链接指定,告知编译器使用C语言的命名规则来处理函数。,#ifdef _cplusplusextern C#endif/函数声明#ifdef _cplusplus#endif,当函数有可能被C语言或C+使用时,将函数声明放在extern “C”中以免出现编译错误。,4.2.5 extern关键词,为保证全局变量和功能函数的使用,extern一般用在.h头文件中对某个模块提供给其它模块调用的外部函数及变量进行声明,实际编程中只需要将该.h头文件包含进该模块对应的.c文件,即在该模块的.c文件中加入代码#include xxx.h。,4.2.6 struct结构体,举例,作用,格式,struct用于定义结构体类型,其作用是将不同数据类型的数据组合在一起,构造出一个新的数据类型。,struct一般用法为:struct 结构体名 类型标识符 成员名1; 类型标识符 成员名2; 结构体变量;,struct person char name8; int age; char sex8; char address20;person_liu;,4.2.6 struct结构体,struct person char name8; int age; char sex8; char address20;struct person person_liu,person_zhang;,结构体变量(如上例中的person_liu)可以不在定义结构体时定义,后续需要时再进行定义。,使用这种定义方式可以很方便地同时定义多个结构体变量。,结构体变量的使用采用如下形式: 结构体变量名. 成员名如:person_liu.age=35;,struct 结构体名 结构体变量;,定义格式,4.2.7 enum关键词,enum Weekdays Monday = 1,Tuesday, Wednesday, Thursday, Friday,Saturday,Sunday Mydays,Olddays;,enum 枚举名 枚举成员1, 枚举成员2, 枚举变量;,用来将一个变量或对象的所有可能的值一一列出,变量取值只限于列举出来的值。,enum枚举类型的用法:,枚举成员的值是常量,不是变量,不能被赋值,但可以将枚举值赋给枚举变量。,枚举类型具有自动编号的功能,第一个枚举成员其默认值为整型的0,后续枚举成员的值在前一个成员上加1。,可以自定义枚举成员的值,如果把第一个枚举元素的值定义为1,那么第二枚举成员的值就为2,以此类推,如上述例子中Friday的值为5。,4.2.8 typedef,给变量起一个容易记且意义明确的新名字;简化一些比较复杂的类型声明。,目的:,用来为复杂的声明定义一个简单的别名,方便记忆,作用:,不是一个真正意义上的新类型,用法一:typedef的基本应用,typedef 类型名 自定义的别名;,格式:,typedef signed char int8_t; /给数据类型signed char起个别名int8_t typedef signed int int32_t; /给数据类型signed int起个别名int32_t,举例:,为已知的数据类型起一个简单的别名,4.2.8 typedef,typedef struct uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; GPIO_InitTypeDef;,STM32标准外设库中stm32f10 x_gpio.h头文件中利用结构体别名GPIO_InitTypeDef,使用typedef为这个新建的结构体起了一个新的名字叫GPIO_InitTypeDef,则可以使用GPIO_InitTypeDef定义一个变量GPIO_InitStructure,从而调用GPIO_Mode。,GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;,用法二:与结构体struct结合使用,4.2.8 typedef,stm32f10 x_gpio.h头文件中的代码。typedef enum GPIO_Speed_10MHz = 1,GPIO_Speed_2MHz, GPIO_Speed_50MHzGPIOSpeed_TypeDef;,解析1:利用typedef关键字将此枚举类型定义一个别名GPIOSpeed_TypeDef,这里省略了枚举类型的枚举名,只用typedef起了个别名。,用法三:与enum结合使用,解析2: enum枚举类型共三个成员,并将第一个枚举成员GPIO_Speed_10MHz赋值为1,enum枚举类型会将枚举成员的赋值在第一个枚举成员赋值的基础上加1,因此,GPIO_Speed_2MHz默认值为2。,4.2.9 #define,#define是C语言中的预处理命令,它用于宏定义,用来将一个标识符定义为一个字符串,该标识符称为宏名,被定义的字符串称为替换文本。,所谓预处理是指在编译之前所做的工作,由预处理程序负责完成,编译时,系统将自动引用预处理程序对源程序中的预处理部分进行处理。,采用宏定义的目的主要是方便程序编写,一般放在源文件的前面,称为预处理部分。,typedef与#define的区别:typedef是在编译阶段处理的;#define是在预处理阶段处理的。,4.2.9 #define,用法一:无参数宏定义,例1:#define UINT8_MAX 255解析:定义宏名UINT8_MAX,代表255。例2:#define _ _IO volatile;解析:定义宏名_ _IO,表示volatile,以后程序中再需要用到volatile,就可以使用_ _IO。例3:#define RCC_AHBPeriph_DMA1 (uint32_t)0 x00000001)解析:定义RCC_AHBPeriph_DMA1宏名,代表32位的无符号数据0 x00000001。,定义格式: #define ,所定义的宏名,可以是常数、字符串、表达式等,4.2.9 #define,用法一:无参数宏定义,标准外设库v3.5.0的stm32f10 x_rcc.h文件中APB2_peripheral外设基地址的定义,APB2_peripheral各外设基地址的定义,4.2.9 #define,用法二:带参数的宏定义,例4:#define SUM(x,y) (x+y) a = SUM(2,2);解析:将SUM(x,y)定义为x+y,预编译时会将SUM(x,y)替换为x+y,a的结果是4例5:#define IS_GPIO_SPEED(SPEED) (SPEED) = GPIO_Speed_10MHz) | (SPEED)= GPIO_Speed_2MHz) | (SPEED) = GPIO_Speed_50MHz)解析:使用宏定义#define将IS_GPIO_SPEED(SPEED)替换为GPIO_Speed_10MHz或者GPIO_Speed_2MHz或者GPIO_Speed_50MHz。,定义格式: #define(参数1,参数2,参数n),4.2.9 #define,用法二:带参数的宏定义,void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) /* Check the parameters */ assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph); assert_param(IS_FUNCTIONAL_STATE(NewState);if (NewState != DISABLE) RCC-APB2ENR |= RCC_APB2Periph; else RCC-APB2ENR ,STM32标准外设库stm32f10 x.h头文件中的代码:,解析:该函数为外设时钟使能函数,第一个参数为要使能的外设,第二个参数为是否使能。,#define IS_FUNCTIONAL_STATE(STATE) (STATE) = DISABLE) | (STATE) = ENABLE),在stm32f10 x_rcc.c源文件中函数RCC_APB2PeriphClockCmd()使用了IS_FUNCTIONAL_STATE(STATE)这个宏 RCC_APB2PeriphClockCm()源码如下:,4.2.10 #ifdef、#ifndef、#else、#if条件编译,只有满足一定条件才进行编译,一般用在头文件或文件开头部分,嵌入式C语言常使用条件编译,通过条件判断来确定是否对某段源程序进行编译。 条件编译的用途:可以用源程序产生不同版本。,嵌入式C语言常用的条件编译命令,4.2.10 #ifdef、#ifndef、#else、#if条件编译,形式一:,#ifdef 标识符 程序段1#else 程序段2#endif,功能:当指定的标识符已被#define定义过,则只编译程序段1,否则编译程序段2。,#ifdef IN_XXX #define XXX_EXT#else #define XXX_EXT extern #endif.XXX_EXT volatile u16 Name;,如果定义了IN_XXX,则定义XXX_EXT,否则定义XXX_EXT为extern。,4.2.10 #ifdef、#ifndef、#else、#if条件编译,形式二:,#ifndef 标识符 程序段1#else 程序段2#endif,功能:当指定的标识符没有被#define定义过,则编译程序段1,否则编译程序段2。,#ifndef STM32F10X_CL#define RCC_USBCLKSource_PLLCLK_1Div5 (uint8_t)0 x00)#define RCC_USBCLKSource_PLLCLK_Div1 (uint8_t)0 x01)#define IS_RCC_USBCLK_SOURCE(SOURCE) (SOURCE) = RCC_USBCLKSource_PLLCLK_1Div5) |(SOURCE) = RCC_USBCLKSource_PLLCLK_Div1)#else#define RCC_OTGFSCLKSource_PLLVCO_Div3 (uint8_t)0 x00)#define RCC_OTGFSCLKSource_PLLVCO_Div2 (uint8_t)0 x01)#define IS_RCC_OTGFSCLK_SOURCE(SOURCE) (SOURCE) = RCC_OTGFSCLKSource_PLLVCO_Div3)|(SOURCE) = RCC_OTGFSCLKSource_PLLVCO_Div2)#endif,标准外设库v3.5.0版本中的stm32f10 x_rcc.h头文件中的源码,4.2.10 #ifdef、#ifndef、#else、#if条件编译,形式三:,#ifdef 标识符1(或表达式1) 程序段1#elif 标识符2(或表达式2) 程序段2#endif,功能:当定义了标识符1或表达式1,则编译程序段1;否则,如果定义了标识符2或表达式2,则编译程序段2。,#ifdef STM32F10X_CL /* PREDIV1 clock source (for STM32 connectivity line devices) */#define RCC_PREDIV1_Source_HSE (uint32_t)0 x00000000) #define RCC_PREDIV1_Source_PLL2 (uint32_t)0 x00010000) #define IS_RCC_PREDIV1_SOURCE(SOURCE) (SOURCE)=RCC_PREDIV1_Source_HSE) | (SOURCE) = RCC_PREDIV1_Source_PLL2) #elif defined (STM32F10X_LD_VL) | defined (STM32F10X_MD_VL) |defined (STM32F10X_HD_VL)#define RCC_PREDIV1_Source_HSE (uint32_t)0 x00000000) #define IS_RCC_PREDIV1_SOURCE(SOURCE) (SOURCE) = RCC_PREDIV1_Source_HSE) #endif,标准外设库v3.5.0版本中的stm32f10 x_rcc.h头文件中的源码。,4.2.11 指针,指针 用于存放地址的变量,两个要素:值:指的是某个对象的位置(即内存地址);类型:是指对象所在位置上所存储数据的类型。,有确定的数据类型 数据类型 *变量名; 如 int *p ;,特殊的:void * 类型代表通用指针,取地址运算符 /将int类型的指针p指向变量i的地址,4.2.11 指针,取值运算符*访问指针变量所指向地址单元的内容;int i = 0;int *p;p = /输入i 的值,i=200,指针和数组在数组中使用指针,可以通过移动指针,对数组中的元素进行搜索。 int Data_Array = 1,2,3,4,5,6; /定义一个数组 int *pr; /定义一个指针pr pr = /用指针给数组的第三个元素赋值,4.2.11 指针,将指针从一种类型强制转换成另外一种类型。 pr=(int *)0 x42210188;解析:0 x42210188是一个32位的数据,表示的是存储空间中的一个地址,但是在程序中如果写成 pr=0 x42210188;只是将0 x42210188这个32位的数据赋给pr,而使用强制类型转换(int *),则是告知编译器这是一个整型数据所占内存空间的首地址,如果没有这个类型转换,则编译器会报错。*pr表示取这个指针所指向内存空间中存储的数据,如图,*pr=0 x0055。,32位微处理器中int类型的变量占4个字节的空间。,在此输入您的标题在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,在此输入您的文字,4.2.11 指针,编译器会为函数分配一段连续的存储空间,其首地址就是这个函数名所定义的变量的地址,定义一个指针变量来存放该地址,这个指针变量就叫作函数指针变量,简称函数指针。,在程序中可以通过这个函数指针变量调用这个函数。,函数指针的定义方式为: 函数返回值类型 (*指针变量名) (函数参数列表);,例如:int f(int x, int *p);/函数int (* fp) (int, int *); /声明一个指针fp fp = f; /将函数f赋给该指针int y = 1;int result = fp(3, /用指针来调用f函数,4.2.11 指针,STM32标准外设库中,指针的类型为32位整型数据,STM32中片上外设都是挂接在不同的总线上的,stm32f10 x.h文件中利用C语言的宏定义和指针来一步步地封装总线和外设的基地址。,通过宏定义为外设基地址0 x40000000取一个宏名PERIPH_BASE,方便使用,stm32f10 x.h中FLASH、SRAM和PERIPH(外设)的基地址定义如下: #define FLASH_BASE (uint32_t)0 x08000000) #define SRAM_BASE (uint32_t)0 x20000000) #define PERIPH_BASE (uint32_t)0 x40000000),STM32的总线有APB1、APB2和AHB总线组成,各自的总线基地址定义如下: #define APB1PERIPH_BASE PERIPH_BASE #define APB2PERIPH_BASE (PERIPH_BASE + 0 x10000) #define AHBPERIPH_BASE (PERIPH_BASE + 0 x20000),STM32标准外设库中的指针应用,4.2.11 指针,stm32f10 x.h文件中定义了这7组GPIO端口的基地址的宏。#define GPIOA_BASE (APB2PERIPH_BASE + 0 x0800)#define GPIOB_BASE (APB2PERIPH_BASE + 0 x0C00)#define GPIOC_BASE (APB2PERIPH_BASE + 0 x1000)#define GPIOD_BASE (APB2PERIPH_BASE + 0 x1400)#define GPIOE_BASE (APB2PERIPH_BASE + 0 x1800)#define GPIOF_BASE (APB2PERIPH_BASE + 0 x1C00)#define GPIOG_BASE (APB2PERIPH_BASE + 0 x2000),ST公司的工程师采用了C语言结构体的形式封装了这些寄存器组:#define GPIOA (GPIO_TypeDef *) GPIOA_BASE)#define GPIOB (GPIO_TypeDef *) GPIOB_BASE)#define GPIOC (GPIO_TypeDef *) GPIOC_BASE)#define GPIOD (GPIO_TypeDef *) GPIOD_BASE)#define GPIOE (GPIO_TypeDef *) GPIOE_BASE)#define GPIOF (GPIO_TypeDef *) GPIOF_BASE)#define GPIOG (GPIO_TypeDef *) GPIOG_BASE),结构体类型后面加上“*”号,表示是结构体类型的指针,(GPIO_TypeDef *)则是把GPIOA_BASE等的地址强制转换为GPIO_TypeDef结构体类型的指针,实际编程时可以直接用该宏名访问寄存器。,4.2.11 指针,GPIO_TypeDef的相关定义: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;,声明了名为GPIO_TypeDef的结构体类型,C语言中struct结构体中成员在内存中是按顺序存储的。,ST工程师把对底层寄存器的操作进行了封装,以API的形式供开发人员调用,如STM32提供的库函数GPIO_SetBits(),用于设置某位引脚为高电平:void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) GPIOx-BSRR = GPIO_Pin; 库函数GPIO_SetBits()实质上还是对寄存器BSRR进行读写操作,只是进行了封装,开发人员只需调用此函数就可以实现对BSRR寄存器的操作。,有了寄存器的地址,就可以使用指针进行读写操作了。,GPIOA_BSRR | = (1 ODR =0 xFF; /等同于 *(int *) (0 x 0 x4001 080C) ) = 0 xFF;,4.2.12 回调函数,通过函数指针调用的函数。操作系统中的某些函数常需要调用用户定义的函数来实现其功能,由于与常用的用户程序调用系统函数的调用方向相反,因此将这种调用称为“回调”(Callback),而被系统函数调用的函数称为“回调函数”。回调函数是指通过调用其他函数反过来调用某个函数。,void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) if (_HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) _HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin); _weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) UNUSED(GPIO_Pin);,STM32的HAL库中GPIO引脚触发中断后的回调函数,GPIO中断处理函数,STM32的HAL库stm32f1xx_hal_gpio.c源码,调用回调函数,STM32的HAL库的回调函数的函数体需要用户自己编写,其实质是通过中断处理函数调用回调函数来实现中断服务功能,4.3 HAL库文件源码分析,4.3.1 stm32f1xx.h源码分析,stm32f1xx.h是HAL库中非常重要的头文件,是STM32F1xx系列MCU的顶层头文件,意味着凡是使用STM32F1xx系列的芯片,其应用程序都需要包含这个头文件。,4.3.1 stm32f1xx.h源码分析,#ifndef _STM32F1XX_H#define _STM32F1XX_H#ifdef _cplusplusextern C #if !defined (STM32F1)#define STM32F1#endif /* STM32F1 */,解析:如果没有定义宏_STM32F1XX_H,则定义宏_STM32F1XX_H。这是个条件编译,目的是防止头文件被重复包含。,解析:这是一个条件编译,_cplusplus是C+中自定义的一个宏,plus是“+”的意思。这段代码的作用是如果定义了C+,则用externC 和 来告诉编译器:这是一个用C语言写成的库函数,请用C语言的方式来链接编译它们。主要是因为c+中存在重载,c+编译时会把函数参数一起编译,而c语言只编译函数名。,解析:如果没定义STM32F1,则定义STM32F1。,4.3.1 stm32f1xx.h源码分析,#if !defined (STM32F100 xB) & !defined (STM32F100 xE) & !defined (STM32F101x6) & !defined (STM32F101xB) & !defined (STM32F101xE) & !defined (STM32F101xG) & !defined (STM32F102x6) & !defined (STM32F102xB) & !defined (STM32F103x6) & !defined (STM32F103xB) & !defined (STM32F103xE) & !defined (STM32F103xG) & !defined (STM32F105xC) & !defined (STM32F107xC) /* #define STM32F100 xB */ /* #define STM32F100 xE */ /* #define STM32F101x6 */ /* #define STM32F101xB */ /* #define STM32F101xE */ /* #define STM32F101xG */ /* #define STM32F102x6 */ /* #define STM32F102xB */ /* #define STM32F103x6 */ /* #define STM32F103xB */ /* #define STM32F103xE */ /* #define STM32F103xG */ /* #define STM

    注意事项

    本文(第4章STM32最小系统与嵌入式C语言课件.pptx)为本站会员(小飞机)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开