void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
//对IO口模式(输出速度、上下拉)设置
//第一个参数,七个寄存器,选中某一个IO口,GPIOx有效性为GPIOA-GPIOG
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;
//第二个参数,对相关参数初始化
typedef struct
{
uint16_t GPIO_Pin;
//确定是这一组GPIO下哪个IO口,有效性
//GPIO_Pin_0
//GPIO_Pin_1
//GPIO_Pin_2
//...
//GPIO_Pin_15
//GPIO_Pin_All
GPIOSpeed_TypeDef GPIO_Speed;
//确定速度,有效性
//GPIO_Speed_10MHz = 1
//GPIO_Speed_2MHz
//GPIO_Speed_50MHz
GPIOMode_TypeDef GPIO_Mode;
//确定模式,有效性
//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
}GPIO_InitTypeDef;
初始化样例:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
//LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
//根据设定参数初始化GPIOB.5
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
//读取某组GPIO输入电平。实际操作是GPIOx_IDR寄存器
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);
//输出高,操作BSRR寄存器
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//输出低,操作BRR寄存器第十六位
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
//在stm32f10x_rcc.c中,有多个外设时钟使能函数
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
/*RCC_APB2Periph有效性
RCC_APB2Periph_GPIOA
RCC_APB2Periph_GPIOB
RCC_APB2Periph_GPIOC
RCC_APB2Periph_GPIOD
RCC_APB2Periph_GPIOE
RCC_APB2Periph_GPIOF
RCC_APB2Periph_GPIOG
*/
/*NewState有效的
DISABLE和ENABLE
*/
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
GPIO_Init();
GPIO_SetBits();
GPIO_ResetBits();
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
#include "LED.h"
#include "stm32f10x.h"
//使用固件库相关函数都要调用
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//定义结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
//使能GPIOE时钟
//也可将前两句写成
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB||RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
//推挽输出
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//GPIOB初始化
GPIO_SetBits(GPIOB,GPIO_Pin_5);
//一开始输出高电平,灯熄灭
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
//推挽输出
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_InitStructure);
//GPIOE初始化
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
#include "stm32f10x.h" //用到gpio函数操作,所以引用顶层头文件
#include "LED.h"
#include "delay.h"
int main(void)
{
delay_init(); //调用延时函数前先初始化
LED_Init();
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);
}
}
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
#include "LED.h"
#include "stm32f10x.h"
void LED_Init(void)
{
//是能时钟
RCC->APB2ENR|=1<<3; //使能GPIOB,1左移三位,即只使得第三位为1,其他位不变
RCC->APB2ENR|=1<<6; //使能GPIOE
//GPIOB.5 50MHz,推挽输出
GPIOB->CRL&=0xFF0FFFFF; //第六个F配置GPIOB.5,清零对应位
GPIOB->CRL|=0x00300000; //或运算不改变0位,将对应四位设置为0011
GPIOB->ODR|=1<<5; //相当于...100000,第六位变成1
//GPIOE.5
GPIOE->CRL&=0xFF0FFFFF; //第六个F配置GPIOB.5,清零对应位
GPIOE->CRL|=0x00300000; //或运算不改变0位,将对应四位设置为0011
GPIOB->ODR|=1<<5;
}
#include "stm32f10x.h"
#include "delay.h"
#include "LED.h"
int main(void)
{
delay_init();
LED_Init();
while(1)
{
GPIOB->ODR|=1<<5;
GPIOE->ODR|=1<<5;
delay_ms(500);
GPIOB->ODR=~(1<<5); //...11011111
GPIOE->ODR=~(1<<5);
delay_ms(500);
}
}
把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说BSRR寄存器有32个位,那么可以映射到32个地址上,我们去访问(读-改-写)这32个地址就达到访问32个比特的目的。
其中一个是 SRAM 区的最低 1MB 范围,0x20000000 ‐ 0x200FFFFF(SRAM 区中的最低 1MB)
第二个则是片内外设区的最低 1MB范围,0x40000000 ‐ 0x400FFFFF(片上外设区中最低 1MB)
一个bit膨胀为32位的地址,所以1M->32M
// sys.h头文件中包含了位操作的封装
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
PAout()等控制ODR寄存器
PAin()等控制IDR寄存器
main.c
#include "STM32F10x.h"
#include "led.h"
#include "delay.h"
int main(void)
{
delay_init();
LED_Init();
while(1)
{
PBout(5)=1;
PEout(5)=1;
delay_ms(300);
PBout(5)=0;
PEout(5)=0;
delay_ms(300);
}
}