GPIO(general purpose input output):通用输入输出端口的简称。可以通过软件控制其输出和输入。stm32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通信,控制以及数据采集的功能。
上拉、下拉都断开,电平忽高忽低不确定,取决于外部电路。用作开关按键的读取。
高电平输入。稳定。
低电平输入。稳定。
用AD采集到IO口上面的真实电压。可以在低功耗模式下运行,实现省电的作用。
只输出低电平,仅低电平有驱动能力,要输出高电平需要外接上拉。可以线与,多用于I2C和SMBUS总线。
可以输出高低电平,都有驱动能力,用于连接数字器件。带载能力强。
输出高电平,电流输出到负载,叫灌电流,推;输出低电平,负载电流流向芯片,叫拉电流,挽。
复用推挽和复用开漏其实很简单,在你理解了开漏和推挽的原理之后,如果你不想用单片机内部来输出,那么你可以进行复用,将输出转移到其他外设上面。
40_41xxx的stm32f4xx_rcc.h中有如下函数声明,AHB和APB各有两个,具体第一个参数的取值范围可以查看*.c文件。
这里只举例AHB1的三个常用函数。
使能/禁用AHB1外设时钟。
(uint32_t RCC_AHB1Periph, FunctionalState NewState)
参数:
强制或释放AHB1外围设备复位。
(uint32_t RCC_AHB1Periph, FunctionalState NewState)
参数与上一个函数一致,第一个取值范围些许不同。
在Low Power (Sleep)模式下使能/关闭AHB1外设时钟。
(uint32_t RCC_AHB1Periph, FunctionalState NewState)
参数与上一个函数一致,第一个取值范围些许不同。
参数:(GPIO_TypeDef* GPIOx)
复位GPIOx(GPIOA到GPIOK)
参数:(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
用一个结构体初始化GPIOx。
结构体的参数如下:
typedef struct
{
uint32_t GPIO_Pin; //需要配置的GPIO引脚,可以用按位或操作符选择多个引脚
GPIOMode_TypeDef GPIO_Mode; //指定所选引脚的工作模式。
GPIOSpeed_TypeDef GPIO_Speed; //指定所选引脚的速度。
GPIOOType_TypeDef GPIO_OType; //指定所选引脚的操作输出类型。
GPIOPuPd_TypeDef GPIO_PuPd; //指定所选引脚的上拉/下拉操作。
}GPIO_InitTypeDef;
typedef enum
{
GPIO_Mode_IN = 0x00, /*输入*/
GPIO_Mode_OUT = 0x01, /*输出*/
GPIO_Mode_AF = 0x02, /*GPIO备用功能模式,复用*/
GPIO_Mode_AN = 0x03 /*GPIO模拟模式*/
}GPIOMode_TypeDef;
typedef enum
{ //这里也是可以使用GPIO_Speed_xxMHz的,xx可取25、50、100
GPIO_Low_Speed = 0x00, /*!< Low speed */
GPIO_Medium_Speed = 0x01, /*!< Medium speed */
GPIO_Fast_Speed = 0x02, /*!< Fast speed */
GPIO_High_Speed = 0x03 /*!< High speed */
}GPIOSpeed_TypeDef;
typedef enum
{
GPIO_OType_PP = 0x00, //推挽 Push Pull
GPIO_OType_OD = 0x01 //开漏 Open Drain
}GPIOOType_TypeDef;
typedef enum
{
GPIO_PuPd_NOPULL = 0x00, //浮空
GPIO_PuPd_UP = 0x01, //上拉
GPIO_PuPd_DOWN = 0x02 //下拉
}GPIOPuPd_TypeDef;
参数:(GPIO_InitTypeDef* GPIO_InitStruct)
将结构体附默认值
参数:(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
切换指定的GPIO引脚。
参数:(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
把一些bits置1
参数:(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
把一些bits置0
参数:(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
将某一位赋指定值
参数:(GPIO_TypeDef* GPIOx, uint16_t PortVal);
直接赋值该GPIO的16位
可知GPIOF的Pin_9和Pin_10分别接LED0和LED1
可知LED0和LED1置高电平时不导通,即灯灭,置低电平时导通,灯亮。
#include "stm32f4xx.h"
int main()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 根据原理图使能GPIOF,选择AHB1外设时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //选择输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //选择推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //根据原理图led的两个引脚为PF9和PF10
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_Init(GPIOF, &GPIO_InitStructure); //初始化GPIOF
GPIO_SetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10); //初始化引脚值为高电平,根据原理图即灯熄灭
while(1)
{
GPIO_ResetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10); //Reset两个引脚(即置0),灯亮
}
}
CM4 内核的处理和CM3 一样 ,内部都包含了一个 SysTick 定时器,SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。我们就是利用STM32的内部SysTick 来实现延时的,这样既不占用中断,也不占用系统定时器。
#ifndef DELAY_H__
#define DELAY_H__
#include "stm32f4xx.h"
void delay_init(u8 SYSCLK); //初始化系统时钟
void delay_ms(u16 xms); //延时xms
void delay_us(u32 xus); //延时xus
#endif
void delay_init(u8 SYSCLK);
参数:(u8 SYSCLK);
SYSCLK就是Systick时钟的频率。
用到misc.h中的一个函数void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);配置系统时钟的来源,有两个参数可供选择:
SysTick_CLKSource_HCLK_Div8: AHB时钟频率除以8作为系统时钟源。
SysTick_CLKSource_HCLK: 直接使用AHB作为系统时钟源。
延时的两个函数操作类似,主要使用了以下几个寄存器:
SysTick是MDK定义了的一个结构体(在core_m4.h里面),里面包含CTRL 、LOAD 、VAL 、
CALIB等4 个寄存器:
CTRL(SysTick control and status register)
LOAD(SysTick reload value register)
重装值寄存器,即当VAL为0时,VAL将被重装的值。
VAL(SysTick current value register)
记录次数的寄存器
CALIB(SysTick calibration value register)
校准用,这里没有用到。
SysTick时钟使能/关闭:
使能滴答定时器:SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
关闭滴答定时器:SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
SysTick_CTRL_ENABLE_Msk宏定义位1<<0,那么CTRL或等于它即把最低位置1,即打开时钟。
主要逻辑:
给LOAD赋值,清空VAL的值。
等待直到当CTRL的0位(使能位)且16位(COUNTFLAG)都为1时才停止时钟。
清空VAL的值。
STM32F4的时钟系统,如图HCLK最高168MHz,若使用HCLK除以8作为SysTick时钟源,则最高21MHz,那么每微妙所需要的时钟数为21M/s x 1us = 21,则根据24位寄存器,取值范围可以给到 (2^24 - 1) / 21 = 798915 us。ms的取值就大概在798ms。
delay_init(168); //初始化延时函数
while(1)
{
GPIO_ResetBits(GPIOF, GPIO_Pin_9); //F9置0,F10置1
GPIO_SetBits(GPIOF, GPIO_Pin_10);
delay_ms(500);
GPIO_ResetBits(GPIOF, GPIO_Pin_10); //F9置1,F10置0
GPIO_SetBits(GPIOF, GPIO_Pin_9);
delay_ms(500);
}
由于蜂鸣器的启动电流较大,因此一般使用三极管驱动,STM32F4的引脚只作为标记使能。开发板使用的引脚为PF8。
如图使用NPN型三极管,BEEP输入高电平时导通,蜂鸣器发声。
则具体代码和控制LED类似,不再赘述。