stm32f10x_gpio.c
//.c文件是用来确定h里面的函数或者数据的具体实现方式的。这样方便模块化
#include "stm32f10x_gpio.h"
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin) //第一个变量是定义一个GPIO_TypeDef类型的指针
{
GPIOx->BSRR |= GPIO_Pin;
}
void GPIO_RestBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BRR&=~GPIO_Pin;
}
void GPIO_Speed(GPIO_TypeDef *GPIOx,uint32_t GPIO_Pin)
{
GPIOx->CRL &=~((0x0f)<<(4*GPIO_Pin));
GPIOB->CRL |= (1<<(4*GPIO_Pin));
}
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin) //第一个变量是定义一个GPIO_TypeDef类型的指针
{
GPIOx->BSRR |= GPIO_Pin;
}
GPIO_SetBits()函数的编写使得main.c中可以直接使用 GPIO_SetBits()函数来控制GPIO引脚输出高电平
void GPIO_RestBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BRR&=~GPIO_Pin;
}
GPIO_RestBits()函数的编写使得main.c中可以直接使用 GPIO_RestBits()函数来控制GPIO引脚输出低电平
void GPIO_Speed(GPIO_TypeDef *GPIOx,uint32_t GPIO_Pin)
{
GPIOx->CRL &=~((0x0f)<<(4*GPIO_Pin));
GPIOB->CRL |= (1<<(4*GPIO_Pin));
}
其中GPIO_Speed()函数的编写使得,main.c中可以直接使用GPIO_Speed()来完成配置输出输入模式以及输出速度。
stm32f10x_gpio.h
#ifndef __STM32F10X_GPIO_H
#define __STM32F10X_GPIO_H
#include "stm32f10x.h"
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< 选择Pin0 */ //(00000000 00000001)b
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< 选择Pin1 */ //(00000000 00000010)b
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< 选择Pin2 */ //(00000000 00000100)b
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< 选择Pin3 */ //(00000000 00001000)b
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< 选择Pin4 */ //(00000000 00010000)b
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< 选择Pin5 */ //(00000000 00100000)b
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< 选择Pin6 */ //(00000000 01000000)b
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< 选择Pin7 */ //(00000000 10000000)b
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< 选择Pin8 */ //(00000001 00000000)b
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< 选择Pin9 */ //(00000010 00000000)b
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< 选择Pin10 */ //(00000100 00000000)b
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< 选择Pin11 */ //(00001000 00000000)b
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< 选择Pin12 */ //(00010000 00000000)b
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< 选择Pin13 */ //(00100000 00000000)b
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< 选择Pin14 */ //(01000000 00000000)b
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< 选择Pin15 */ //(10000000 00000000)b
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< 选择全部引脚*/ //(11111111 11111111)b
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_RestBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_Speed(GPIO_TypeDef *GPIOx,uint32_t GPIO_Pin);
#endif /*__STM32F10X_GPIO_H*/
stm32f10x.h
#ifndef __STM32F10X_H
#define __STM32F10X_H
//用来存放STM32寄存器映射的代码
//外设 perirhral
#define PERIPH_BASE ((unsigned int)0x40000000) //这是一个外设基地址
#define APB1PERIPH_BASE PERIPH_BASE //TIM2定时器开始当作APB1总线基地址
#define APB2PERIPH_BASE (PERIPH_BASE+0x10000) //AFIO开始当作APB2总线基地址
#define AHBPERIPH_BASE (PERIPH_BASE+0x20000) //DMA1开始当作AHB总线基地址
#define RCC_BASE (AHBPERIPH_BASE+0x1000)
#define GPIOB_BASE (APB2PERIPH_BASE+0x0C00)
//#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)//RCC_APB2时钟
//#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE+0x00)//GPIOB端口配置低寄存器 用unsigned int*的原因是因为他是32位寄存器 用32位数据类型刚好
//#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE+0x04)//GPIOB端口配置高寄存器
//#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C)//GPIOB端口输出数据寄存器
//#define GPIOB_BSRR *(unsigned int*)(GPIOB_BASE+0x10)//GPIOB端口位设置/清除寄存器
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE)
typedef struct //根据6.3.11RCC寄存器存储器映像所写的RCC结构体指针
{
uint32_t CR; //由于这些寄存器都是32位的也就是四个字节,所以数据类型用unit32_t
uint32_t CFGR; //由于之前的CR占32位,这里的GFGR也是unit32_t的所以也占32位,刚好在CR的基础上偏移0x04
uint32_t CIR; //剩下的都是这个道理
uint32_t APB2RSTR;
uint32_t APB1RSTR;
uint32_t ABHENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
uint32_t BDCR;
uint32_t CSR;
}RCC_TypeDef;
#define RCC ((RCC_TypeDef*)RCC_BASE) //把RCC_BASE强制类型转换为结构体指针,这样结构体指针的值为RCC_BASE的值
#endif /*__STM32F10X_H*/
main.c
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
int main(void)
{
// //GPIOB起始地址0X40010C00
//
// //1开GPIOB时钟使能 APB2 外设时钟使能寄存器(RCC_APB2ENR)偏移地址0x18
// //起始地址挂载到AHB上0x40021000
// *(unsigned int*)0x40021018 |= 1<<3;
//
//
// //CRL端口配置低寄存器配置 偏移地址0x00
// //配置PB0推挽输出 最大速度10MHz
// *(unsigned int*)0X40010C00 |= 1<<0;
//
// //端口输出数据寄存器(GPIOx_ODR) (x=A..E)偏移地址:0Ch
// //配置PB0输出低电平.所以在GPIOB的起始地址上进行偏移
// //*(unsigned int*)0x40010c0c &=~ (1<<0);
// *(unsigned int*)0x40010c0c |= (1<<0);
//
//
// //输出Blue蓝色 PB1
// *(unsigned int*)0X40010C00 |= 1<<4;
// *(unsigned int*)0x40010c0c &=~ (1<<1);
// //*(unsigned int*)0x40010c0c |= (1<<1);
//
// //配置PB5
// *(unsigned int*)0X40010C00 |= 1<<20;
// *(unsigned int*)0x40010c0c &=~ (1<<5);
//
// //寄存器点灯主要三步 1:打开对应GPIO的时钟,RCC时钟挂载在AHB上
// //2:配置输入还是输出还有输出速度 配置CRL(端口配置低寄存器)或者CRH(端口配置高寄存器)
// //3:控制ODR(端口输出数据寄存器) 输入还是输出 |=置1操作 &=~清0操作
//
//
RCC->APB2ENR |= 1<<3;
#if 0
GPIOB->CRL &= ~( (0x0f) << (4*0) );
GPIOB->CRL |= 1<<0;
GPIOB->ODR &=~ (1<<0);
#endif
#if 0
GPIOB->CRL &=~((0x0f)<<(4*5));
GPIOB->CRL |= 1<<20;
GPIOB->ODR &=~ (1<<5);
#endif
#if 0
GPIOB->CRL &=~((0x0f)<<(4*1));
GPIOB->CRL |= 1<<4;
// GPIOB->ODR &=~ (1<<1);
GPIOB->ODR |= (1<<1);
#endif
#if 0
GPIOB->CRL &= ~( (0x0f) << (4*0) );
GPIOB->CRL |= 1<<0;
GPIO_RestBits(GPIOB,GPIO_Pin_0);
#endif
GPIO_Speed(GPIOB,1);
GPIO_RestBits(GPIOB,GPIO_Pin_1);
}
void SystemInit(void)
{
//函数体为空,目的是为了骗过编译器不报错
}
//当没配置系统时钟的时候 STM32会使用HSI = 8M
//教程顺序 1:选定具体的GPIO
//2:配置GPIO工作模式(CRL和CRH寄存器)
//3:控制GPIO输出高低电平(ODR.BRR和BSRR)