STM32入门_江协科技_5~6_OB记录的自学笔记_GPIO输出_LED流水灯_蜂鸣器

5. GPIO 输出

5.1. GPIO简介

  • GPIO(General Purpose Input Output)通用输入输出口
  • 可配置为8种输入输出模式
  • 引脚电平:0V~3.3V,部分引脚可容忍5V(端口输入5V的电压,之前引脚定义表格中带FT标识的)
  • 输出模式下可控制端口输出高低电平,用以驱动LED、控制蜂鸣器、模拟通信协议输出时序等
  • 输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等

5.2. GPIO基本结构

  • 所有GPIO挂载在APB2外设总线上面
  • GPIO外设命名GPIOA,GPIOB...,引脚对应PA0,PA1...PA15,PB0,PB1...PB15
  • GPIO模块内包含寄存器和驱动器,寄存器是特殊的存储器,STM32内核可以通过APB2总线对寄存器进行读写以完成输出和输入电平的功能;
  • 寄存器的每一位对应一个引脚,输出寄存器写1为输出高电平,写0为输出低电平,输入寄存器高电平读1,低电平读0;
  • STM32为32位,内部寄存器也为32位,但是GPIO端口只有16位,所以寄存器只有低16位对应有端口,高16位没有用到;
  • 驱动器负责增大驱动能力,如需要GPIO点灯;

5.3. GPIO位结构

  1. 如上图所示,右侧IO引脚旁边的VDD与VSS所接保护二极管,如果IO引脚电压大于3.3V,VDD保护二极管导通,电流不进入芯片内部,如果IO引脚电压小于0V,VSS保护二极管导通,此处电流从IO引脚导出,不必从芯片内部汲取电流;
  2. 虚线框内的VDD加开关和电阻组成上拉电阻,VSS加开关和电阻组成下拉电阻,开关的通断通过程序配置,如果上开关导通,下开关断开,为上拉输入模式,反之为下拉输入模式,如果两个开关都断开,则为浮空输入模式;
  3. 上拉和下拉的作用:给输入提供一个默认的电平,对于一个数字端口,输入不是低电平0就是高电平1,如果处于浮空模式,实际情况是引脚的输入电平易受到外界的干扰而变化,为避免出现这种情况,有必要在输入端口加入上拉和下拉电阻,例如,如果接入上拉电阻成为上拉输入模式,即使引脚悬空,也有上拉电阻保证引脚的高电平,所以上拉输入又称作为高电平的输入模式,同理,下拉为低电平输入模式;
  4. TTL肖特基触发器用于对输入的电压进行整形,如果输入电压大于某个阈值,则触发器瞬间输出高电平,反之输入电压小于某个阈值,则触发器瞬间输出低电平,防止输入的电平信号因为干扰失真而导致的信号误判;
  5. 经过触发器整形的信号直接写入输入数据寄存器;
  6. 输入部分至片上外设有2路,其中模拟输入一路是需要输送至ADC进行信号转换,所以从触发器前接入,另一路复用功能输入连接到其他需要读取端口的外设上,如串口的输入输入引脚等,因为这路是数字量,所以接触发器后端;
  7. 输出部分:输出数据寄存器直接控制16位端口,如果只是需要对其中某一位端口进行控制而不影响其他端口的话,则需要借助位设置清除寄存器来完成,在位设置寄存器对应位直接写1就可以使某一位输出置1;(另一种方式是先读出输出数据寄存器,然后用按位与和按位或的方式更改某一位,最后将更改后的数据写回去,此方法麻烦,效率低,对于IO口操作不太合适)
  8. 输出控制后接的两个MOS管可以想象为2个开关,我们通过信号来控制开关的导通与关闭;
  9. 此处MOS管输出有3种模式,推挽,开漏和关闭
  10. 推挽输出模式下,P-MOS与N-MOS均有效,数据寄存器为1时,P-MOS导通,N-MOS断开,输出直接接到VDD,输出高电平,反之数据寄存器为0时,N-MOS导通,P-MOS断开,输出直接接到VSS,输出低电平,这种模式下高地电平均有较强的驱动能力,所以推挽输出模式也叫强推输出模式;
  11. 在推挽输出模式下,STM32对IO口拥有绝对控制权,高低电平均由STM32说的算。
  12. 在开漏输出模式下,P-MOS是无效的,只有N-MOS工作,数据寄存器为1时,下管断开,输出相当于断开,输出处于高阻模式,数据寄存器为0时,下管导通,输出直接接到VSS,输出低电平,这种模式下只有低电平有驱动能力,高电平没有驱动能力,开漏模式用于通信协议的驱动方式,如I2C通信引脚就是用开漏模式,在多机通信的情况下,这个模式可以避免各个设备的相互干扰,同时开漏模式还可以用于输出5V的电平信号(需要I/O引脚接5V上拉电阻)。
  13. 当I/O引脚配置为输入模式的时候,两个MOS管均无效,也就是输出关闭,端口的电平由外部信号来控制,MOS管处于关闭工作模式;

5.4. GPIO模式

  • 浮空输入,上拉输入,下拉输入三种模式的电路基本相同,区别是上拉电阻和下拉电阻的连接,都属于数字输入口,都可以读取端口的电平高低,当引脚悬空时,上拉输入默认高电平,下拉输入默认低电平,浮空输入的电平不确定,在使用浮空输入时,端口一定要接连续的驱动源,不能有悬空的状态。
  • 浮空/上拉/下拉输入的电路结构:
复制代码
- 如上图所示:浮空/上拉/下拉输入模式下,输出驱动器是断开的,端口只能输入,通过开关的关闭状况选择浮空/上拉/下拉输入模式,信号通过触发器整形输入到数据寄存器。同时注意注释中VDD_FT对5V容忍I/O脚是特殊的,具体特殊情况手册中未描述,笔者猜测是保护二极管的不同;
- 模拟输入的电路结构:
复制代码
- 从上图模拟输入的电路图可以看出,模拟输入下,输出驱动器断开,输入触发器断开,信号直接进入ADC。
- 开漏输出/推挽输出的电路结构:
复制代码
- 如上图可见:开漏输出/推挽输出的电路结构基本相同,区别是开漏输出高电平为高阻态,没有驱动能力,推挽输出高电平接VDD,有驱动能力。输出由输出数据寄存器控制,P-MOS如果无效就是开漏输出,P-MOS / N-MOS都有效则是推挽输出,同时注意在输出模式下,输入也是有效的,但在输入模式下,输出无效,因为一个端口只能有一个输出,但可以有多个输入;
- 复用开漏/推挽输出的电路结构图:
复制代码
- 如上图可见:和普通的开漏输出与推挽输出差不多,区别在于复用的输出,引脚电平由片上外设控制,同时注意这8个模式中,处模拟输入外,其他7个模式输入都有效;

5.5. LED和蜂鸣器介绍

•LED:发光二极管,正向通电点亮,反向通电不亮;

•有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定,低电平触发;

•无源蜂鸣器:内部不带振荡源,需要控制器提供振荡脉冲才可发声,调整提供振荡脉冲的频率,可发出不同频率的声音;

5.6. LED和蜂鸣器的硬件电路

  • 左边两个图LED驱动电路,左上图为低电平驱动模式,低电平LED点亮,高电平LED灭,左下图为高电平驱动模式,STM32推挽输出模式可以驱动LED,高电平LED亮,低电平LED灭;
  • 右侧蜂鸣器电路,接三极管驱动蜂鸣器,避免STM32直驱蜂鸣器导致芯片负担过重,右上图PNP三极管,IO口低电平三极管导通,3.3V电压开始驱动蜂鸣器,右下图为NPN三极管,IO口高电平导通,此时蜂鸣器电路产生电流,蜂鸣器工作;

5.7. 面包板介绍和面包板结构

  • 上图中下面的图是面包板背面撕去双面胶后的情况,可见上下横向标识红蓝线的小孔横向导通(用于供电),中间纵向小孔,5个一组导通,右侧是拆出内部夹片后与LED连接的示意图;

6.LED闪烁&LED流水灯&蜂鸣器

6.1. LED灯闪烁的面包板电路:

  • 此为低电平点亮的操作方式,为方便,没有加限流电阻;

  • 上图为笔者实际搭建的电路视频教程截图,至此硬件电路搭建完成;

6.2. Keil中新建项目 < 3-1 LED闪烁 >

  1. 在项目文件夹下面新建< User > < Library > < Start >三个文件夹,文件夹内需要复制文件参考3~4节中的操作,后续新建项目可能直接复制现有项目,加快项目新建过程;

  2. 相应文件拷贝到项目文件夹后,点击Keil中如下图标,删除原默认的< Group >组,

  3. 新建Start, Library, 和User三个组,

  4. Start中添加文件如下图:

  5. 同理Library中添加所有的Library文件夹中的文件:

  6. 同理将User文件夹中的文件添加进去:

  7. 如下图将C语言搜索路径添加进项目选项中:

  8. 如下图在Define中添加如下字符串:USE_STDPERIPH_DRIVER (使用标准外设驱动)

  9. 如下图在debug中选择ST-Link Debugger,在设置中的Flash Download中勾选Reset and Run;至此工程选项配置完成

  10. 如下图,打开User中的main函数文件,全部清空后如图添加头文件和main函数并编译测试没有错误和警告:

  11. 如下图将笔者源码文件包中的< 1-2 KeilKill批处理 >文件夹复制到项目目录中,将文件夹下面的KeilKill.exe文件复制到项目文件夹中,该程序的主要作用是清楚工程编译过程中的中间文件,双击运行后会删除不必要的文件用以缩减项目文件的容量;

6.3. 开始编程前

  1. 操作STM32的GPIO需要3个步骤:第一步,使用RCC开启GPIO的时钟;第二步,使用GPIO_Init函数初始化GPIO;第三步,使用输入或者输出的函数控制GPIO口,以上总共涉及RCC和GPIO两个外设;

  2. 在Library文件夹中找到stm32f10x_rcc.h文件并打开,在文件末尾位置可以看到很多库函数声明,常用的是如下的三个函数,AHB,APB1,APB2的外设时钟控制,右键函数可以打开相应的函数体做进一步的查看:

    void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);

    void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

    void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

  3. 在Library文件夹中找到stm32f10x_gpio.h的文件并转到文件末尾,可以找到所有GPIO的库函数;

  4. 其中比较重要的是如下的函数,Init初始化函数和4个读取,4个写入函数

    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

    void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

6.4. 开始编程

  1. 因为LED接在A0引脚,对应APB2外设时钟需要初始化;
  2. 将 RCC_APB2PeriphClockCmd 复制到main函数中,右键打开函数定义如下:
  3. 对应函数的参数需要选择如下:

  1. 接着需要调用< GPIO_Init >函数,跳转该函数的定义,第一个参数为GPIOA,第二个参数为结构体指针< GPIO_InitTypeDef >,在main函数最前端声明结构体如下< GPIO_InitTypeDef GPIO_InitStructure; >, 同时接着下面插入结构体的名字并将结构体的成员引出:
    GPIO_InitStructure.GPIO_Mode =
    GPIO_InitStructure.GPIO_Pin =
    GPIO_InitStructure.GPIO_Speed =
  2. 如下图,右键GPIO_Mode打开GPIO_Mode定义,然后找到注释中的 " GPIOMode_TypeDef " 选中并Ctrl+F搜索 " GPIOMode_TypeDef "(右键跳转->查看说明->复制粘贴参数)


复制代码
	 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(复用推挽)
  1. 介绍GPIO的输出函数如下:
    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);(指定端口设置高电平)
    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);(指定端口设置低电平)
    void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);(根据BitVal的值来设置端口)
    void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);(同时对16个端口进行写入操作)

  2. 首先用GPIO_ResetBits程序来点亮LED,程序如下:

    #include "stm32f10x.h" // Device header

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    复制代码
     GPIO_ResetBits(GPIOA, GPIO_Pin_0);
     
     while(1)
     {
     	
     }

    }

Proteus中模拟测试没问题:

  1. 测试GPIO_SetBits函数,参数同GPIO_ResetBits,此时LED灯应熄灭,程序如下:

    #include "stm32f10x.h" // Device header

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    复制代码
     //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
     GPIO_SetBits(GPIOA,GPIO_Pin_0);
     while(1)
     {
     	
     }

    }

Proteus测试LED灯熄灭:

  1. 接着测试GPIO_WriteBit函数点亮LED,此函数的前2个参数与之前相同,第3个参数GPIO_WriteBit可以将对应位置低电平,Bit_SET对应位置高电平,如下图函数说明:

  1. 此时程序写为如下LED灯应该点亮,Proteus中测试通过: GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
  1. 如果改为GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); led熄灭;

6.5. LED灯闪烁效果

  1. 思路是需要延时函数的加入,用函数GPIO_WriteBit 让A0位在SET与RESET中切换;
  2. 延时函数采用作者已经放在示例程序1-3 Delay函数模块中,将此文件夹中的两个文件拷贝到项目文件夹中,项目文件夹中新建System目录,将这2个文件拷贝进去,同时需要在项目选项中添加System目录与搜索路径如下图:


  1. 此时的LED闪烁程序需要修改为如下程序:

    #include "stm32f10x.h" // Device header
    #include "Delay.h"

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    复制代码
     //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
     //GPIO_SetBits(GPIOA,GPIO_Pin_0);
     //GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
     //GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
    
     while(1)
     {
     	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
     	Delay_ms(500);
     	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
     	Delay_ms(500);
     }

    }

  2. 同时需要注意的是Proteus中模拟的时候,需要双击STM32芯片,并将其中的时钟设置为如下形式:


  1. proteus模拟测试通过:

  1. 同时需要注意,如果非要用1代表高电平,0代表低电平,则程序需要修改为如下,在0和1前面加入(BitAction)进行强制类型转换,程序编译通过:

    #include "stm32f10x.h" // Device header
    #include "Delay.h"

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    复制代码
     //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
     //GPIO_SetBits(GPIOA,GPIO_Pin_0);
     //GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
     //GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
    
     while(1)
     {
     	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
     	Delay_ms(500);
     	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
     	Delay_ms(500);
     	GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0);	//(BitAction)强制转换0为枚举类型
     	Delay_ms(500);
     	GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1);	//(BitAction)强制转换1为枚举类型
     	Delay_ms(500);		
     }

    }

  2. 同时,如果将 " GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP " 改为开漏输出模式 " GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ",笔者的视频实际测试, A0接LED正极,LED无法点亮,LED负极接A0,LED可以点亮,说明改为开漏模式的时候,低电平还是有驱动能力的,印证了开漏和推挽输出的特性区别;

6.6. LED流水灯

  1. LED流水灯的接线图如下,对应面包板上面需要接线:

  1. 复制3-1 LED闪烁 项目目录,重命名为 3-2 LED流水灯,双击打开" project.uvprojx "文件,在Keil中直接打开了一个新的项目,修改main文件程序实现LED流水灯;
  2. 需要注意的是,GPIO_Pin_0 需要增加定义到 GPIO_Pin_7,同时打开GPIO_Pin的定义可以看到如下规律,同时需要注意的是每个端口对应一个位,后面的注释中对应的二进制的数字只写了最后4位的,实际(uint16_t)0x0001) 改为2进制表示应该是 0000 0000 0000 0001 , 这个需要注意)
    define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected / (对应二进制1为0001
    define GPIO_Pin_1 ((uint16_t)0x0002) /
    !< Pin 1 selected / (对应二进制2为0010
    define GPIO_Pin_2 ((uint16_t)0x0004) /
    !< Pin 2 selected / (对应二进制4为0100
    define GPIO_Pin_3 ((uint16_t)0x0008) /
    !< Pin 3 selected / (对应二进制8为1000
    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 */...
  3. 基于上述规律,程序可以用如下图所示按位或的方式全部选中所需要的位,最终用GPIO_Pin_All,直接初始化所有端口为推挽输出模式;

  1. 此时LED流水灯的简单程序如下:

    #include "stm32f10x.h" // Device header
    #include "Delay.h"

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    复制代码
     //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
     //GPIO_SetBits(GPIOA,GPIO_Pin_0);
     //GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
     //GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
    
     while(1)
     {
     	GPIO_Write(GPIOA,~0x0001);	//对应二进制0000 0000 0000 0001,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0002);	//对应二进制0000 0000 0000 0010,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0004);	//对应二进制0000 0000 0000 0100,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0008);	//对应二进制0000 0000 0000 1000,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0010);	//对应二进制0000 0000 0001 0000,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0020);	//对应二进制0000 0000 0010 0000,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0040);	//对应二进制0000 0000 0100 0000,0点亮,所以取反
     	Delay_ms(500);
     	GPIO_Write(GPIOA,~0x0080);	//对应二进制0000 0000 1000 0000,0点亮,所以取反
     	Delay_ms(500);
     }

    }

  2. Proteus中仿真测试通过:

6.7. 蜂鸣器

  1. 蜂鸣器STM32面包板接线图如下,蜂鸣器IO接B12;

  2. 如上图接好杜邦线和蜂鸣器模块完成硬件电路,同时需要注意此处笔者接的蜂鸣器是B12输出低电平,蜂鸣器响,输出高电平,蜂鸣器不响;

  3. Keil中复制粘贴3-2项目文件夹并改名为< 3-3 蜂鸣器 >,并在Keil中打开

  4. Keil中建立简单测试程序对蜂鸣器进行测试,程序如下

    #include "stm32f10x.h" // Device header
    #include "Delay.h"

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    复制代码
     while(1)
     {
     	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
     	Delay_ms(500);
     	GPIO_SetBits(GPIOB,GPIO_Pin_12);
     	Delay_ms(500);
     }

    }

  5. 需要注意的是Proteus中进行仿真测试的时候的电路如下,buzz蜂鸣器选用的是DC驱动有源蜂鸣器,标识有Active的可以仿真,NPN的选用如下图,BUZZ的操作电压需要修改为5V电压,编译程序后Proteus仿真没有问题;




  1. 修改程序响100ms,关100ms,响100ms,关700ms,程序如下:

    #include "stm32f10x.h" // Device header
    #include "Delay.h"

    int main(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    复制代码
     while(1)
     {
     	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
     	Delay_ms(100);
     	GPIO_SetBits(GPIOB,GPIO_Pin_12);
     	Delay_ms(100);
     	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
     	Delay_ms(100);
     	GPIO_SetBits(GPIOB,GPIO_Pin_12);
     	Delay_ms(700);
     }

    }

  2. 几种使用库函数的方法:

  • 第一种方法,先打开.h文件,找到文件末尾,看有哪些函数,接着右键打开函数定义,查看函数和参数的用法,
  • 第二种方法打开STM32F103XX固件函数库用户手册,有所有函数介绍和使用方法,可能有用户手册与库函数版本不对应的问题;
  • 第三种方法是上网搜索,参考他人的代码;
相关推荐
LinXunFeng5 天前
Obsidian - 使用 Share Note 分享笔记并自部署
前端·笔记·github
✎ ﹏梦醒͜ღ҉繁华落℘9 天前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
闪闪发亮的小星星9 天前
高斯光以及高斯光公式解释
笔记
CNNACN电商经济9 天前
纸价波动加速中小产能出清,包装印刷板块龙头份额提升与议价能力重估
科技·生活
cqbzcsq9 天前
CellFlow虚拟细胞论文阅读
论文阅读·人工智能·笔记·学习·生物信息
牛根生同志9 天前
SPI数据收发的时候 TXE与RXNE标志位置位的时机
stm32·spi·transfer
绿算技术9 天前
Mooncake 与绿算ForinnBase GroundPool如何联手打破推理僵局?
科技·算法·架构
阿米亚波9 天前
【Windows】QEMU 启动 openEuler aarch64/arm64 架构系统 + 离线软件源
linux·windows·经验分享·笔记·架构·arm
自传.9 天前
尚硅谷 Vibe Coding|第三章(1) Claude Code深度使用与进阶技巧 学习笔记
笔记·学习·尚硅谷·vibecoding
nanoscientific9 天前
在芬顿耦合微纳米气泡系统中最大化利用界面处的Fe²⁺以实现有机污染物降解。
科技·微纳米气泡