本节我们将会对STM32
的硬件资源进行介绍,包括如下内容:
- 点亮
LED
; - 检测按键按下和松开事件;
- 串口;
- 点亮
128*128 TFT_LCD
液晶屏;
一、点亮LED
1.1 电路原理图
LED
电路原理图如下图所示:
其中:
LED1连接到
PA8`引脚,低电平点亮;LED2
连接到PD2
引脚,低电平点亮;
1.2 GPIO
引脚介绍
STM32F103RTC6
共有5组GPIO
,分别为 GPIOA
, GPIOB
, GPIOC
, GPIOD
, 和 GPIOE
。其中,GPIOA
、GPIOB
、GPIOC
、GPIOD
是常用的,GPIOE
只有一部分引脚在某些型号的STM32F103
系列中有效。
每组GPIO
通常包含16
个引脚。但并非所有引脚都在所有STM32F103
型号中都有效,具体取决于具体芯片封装。
GPIOA
:16 个引脚(PA0 - PA15
);GPIOB
:16 个引脚(PB0 - PB15
)GPIOC
:16 个引脚(PC0 - PC15
)GPIOD
:16 个引脚(PD0 - PD15
);GPIOE
(在某些型号上有效):16个引脚(PE0 - PE15
);
1.3 GPIO
寄存器
在STM32F103RTC6
中,GPIO
引脚的配置和控制是通过寄存器来实现的。每个GPIO
端口(如GPIOA
、GPIOB
等)都有一组寄存器来控制引脚的方向、输出类型、上拉/下拉电阻、输入模式等。;
- 两个32位配置寄存器,
GPIOx_CRH
、GPIOx_CRL
; - 两个32位数据寄存器,
GPIOx_IDR
、GPIOx_ODR
; - 一个32位设置/清除寄存器,
GPIOx_BSRR
; - 一个16位复位寄存器,
GPIOx_BRR
; - 一个32位锁定寄存器,
GPIOx_LCKR
;
1.3.1 端口配置低寄存器(GPIOx_CRL
)
GPIOx_CRL
端口配置低8位寄存器(x=A~E
),四位控制1个引脚,共控制8个引脚(0~7引脚);
31:28 | 27:24 | 23:20 | 19:16 | 15:12 | 11:8 | 7:4 | 3:0 |
---|---|---|---|---|---|---|---|
CNF7[1:0] MODE7[1:0] |
... | .... | .... | .... | .... | ..... | CNF0[1:0] MODE0[1:0] |
其中:
MODE[1:0] | CNF[1:0] | |
---|---|---|
输入模式 | 0 0 | 0 0:模拟输入模式 0 1:浮空输入模式 1 0:上拉/下卡输入模式 1 1:保留 |
输出模式 | 0 1:最大速度10MHz 1 0:最大速度2MHz 1 1:最大速度50MHz |
0 0:通用推挽输出模式 0 1:通用开漏输出模式 1 0:复用功能推挽输出模式 1 1:复用功能开漏输出模式 |
1.3.3 端口配置高寄存器(GPIOx_CRH
)
GPIOx_CRH
四位控制1个引脚(x=A~E
),共控制8个引脚(8~15引脚);同上不再重复介绍。
1.3.3 端口输入数据寄存器(GPIOx_IDR
)
GPIOx_IDR
端口输入数据寄存器(x=A~E
);
31~16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
保留 | IDR15 | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | IDR0 |
31~16
位始终读0,低16位为只读,并只能以16位的形式读出。
1.3.4 端口输出数据寄存器(GPIOx_ODR
)
GPIOx_ODR
端口输出数据寄存器(x=A~E
);
31~16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
保留 | ODR15 | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | .. | ODR0 |
31~16
位始终读0,低16位可读可写,并只能以16位的形式操作。
1.3.5 端口设置/清除寄存器(GPIOx_BSRR
)
GPIOx_BSRR
端口设置/清除寄存器(x=A~E
);
31~16 | 15~0 |
---|---|
BR15~BR0 | BS15~BS0 |
0:对对应的ODRy位不产生影响 1:清除对应的ODRy位为0 |
0:对对应的ODRy位不产生影响 1:设置对应的ODRy位为1 |
1.3.6 端口清除寄存器(GPIOx_BRR
)
GPIOx_BRR
端口清除寄存器(x=A~E
);
31~16 | 15~0 |
---|---|
保留 | BR15~BR0 |
0:对对应的ODRy位不产生影响 1:清除对应的ODRy位为1 |
1.4 代码实现
1.4.1 GPIO
初始化函数
/******************************************************** ********************
* File Name : gpio.c
* Author : Zhengyang
* Description : 初始化GPIO口portx:端口号PORTA~Epinx:引脚号PORT0~15gpio_cfg:输入输出模式配置bit:输出电平设置 高:HIGH 低:LOW
********************************************************************************/
void gpio_init(PORTx_PINx portx_pinx,GPIO_CFG gpio_cfg,BIT_ACTION bit)
{GPIO_TypeDef *GPIO;u8 portx = portx_pinx/16; //获取端口号u8 pinx = portx_pinx%16; //获取引脚号if(portx==0)GPIO=GPIOA;else if(portx==1)GPIO=GPIOB;else if(portx==2)GPIO=GPIOC;else if(portx==3)GPIO=GPIOD;elseGPIO=GPIOE;RCC->APB2ENR|=1<<(portx+2); //外设时钟使能if(pinx<8){GPIO->CRL &=~(0x0F<<(pinx*4)); //该引脚模式配置四位清零GPIO->CRL|=gpio_cfg<<(4*pinx); //端口配置寄存器CRL}else if(pinx>=8) {GPIO->CRH &=~(0x0F<<((pinx-8)*4)); //该引脚模式配置四位清零GPIO->CRH|=gpio_cfg<<(4*(pinx-8)); //端口配置寄存器CRH}if((gpio_cfg&0x03)!=0x00) //输出{if(pinx<8)GPIO->ODR|=bit<<pinx; //端口数据输出寄存器ODRelse GPIO->ODR|=bit<<pinx; //端口数据输出寄存器 }
}
这里PORTx_PINx
、GPIO_CFG
、BIT_ACTION
均是枚举类型;
/************************************* 端口配置 ************************************************************/
typedef enum //宏定义端口配置
{//这里的值不能改!!!GPI = 0x00, //定义管脚输入方向 GPO_SpeedMax_10 = 0x01, //定义管脚输出方向 最大速度10MHZGPO_SpeedMax_2 = 0x02, //定义管脚输出方向 最大速度2MHZGPO_SpeedMax_50 = 0x03, //定义管脚输出方向 最大速度50MHZ//输入模式可用GPI_DOWN = 0x08|GPI, //输入下拉 PxODR需配置为0 GPI_UP = 0x08|GPI, //输入上拉 PxODR需配置为1 复用功能时一般采用GPI_ANALOG = 0x00|GPI, //模拟输入GPI_FLOAT = 0x04|GPI , //浮空输入//输出模式不能用GPO_PUSH_PULL = 0x00, //通用推挽输出GPO_OPEN_DRAIN = 0x04, //通用开漏输出GPO_MULPUSH_PULL = 0x08, //复用推挽输出GPO_MULOPEN_DRAIN = 0x0C, //复用开漏输出//输出模式可用GPO_PUSH_PULL_50 = GPO_SpeedMax_50| GPO_PUSH_PULL, //通用推挽输出,最大速度50MHZ 通用输出一般设置GPO_PUSH_PULL_10 = GPO_SpeedMax_10| GPO_PUSH_PULL, //通用推挽输出,最大速度10MHZ GPO_PUSH_PULL_2 = GPO_SpeedMax_2 | GPO_PUSH_PULL, //通用推挽输出,最大速度2MHZGPO_MULPUSH_PULL_2 = GPO_SpeedMax_2| GPO_MULPUSH_PULL, //复用推挽输出,最大速度2MHZGPO_MULPUSH_PULL_10 = GPO_SpeedMax_10| GPO_MULPUSH_PULL, //复用推挽输出,最大速度10MHZGPO_MULPUSH_PULL_50 = GPO_SpeedMax_50| GPO_MULPUSH_PULL //复用推挽输出,最大速度50MHZ 复用功能 输出模式一般采用这样设置
}GPIO_CFG;/***************************************** 宏定义引脚号 *************************************************************/
typedef enum
{PA0=0,PA1=1,PA2=2,PA3=3,PA4=4,PA5=5,......PE13=77,PE14=78,PE15=79} PORTx_PINx;typedef enum //外部端口输出电平
{ LOW = 0,HIGH = 1
} BIT_ACTION;
1.4.2 PXout/PxIn
定义GPIO
输入输出宏:
/********************** 位运算符优先级低于算术运算符 << & | ~ 所以位运算符必须加括号 ***********************/
#define Bit_Band(Addr,Bit_Num) *((volatile unsigned long *)((Addr&0xF0000000)+0x02000000+((Addr&0xfffff)<<5)+(Bit_Num<<2)))/********************************************** I/O 地址映射 **************************************************/
#define GPIOA_IDR (GPIOA_BASE + 0x08) //0x40010808
#define GPIOA_ODR (GPIOA_BASE + 0x0C) //0x4001080C
#define GPIOB_IDR (GPIOB_BASE + 0x08) //0x40010C08
#define GPIOB_ODR (GPIOB_BASE + 0x0C) //0x40010C0C
#define GPIOC_IDR (GPIOC_BASE + 0x08) //0x40011008
#define GPIOC_ODR (GPIOC_BASE + 0x0C) //0x4001100C
#define GPIOD_IDR (GPIOD_BASE + 0x08) //0x40011408
#define GPIOD_ODR (GPIOD_BASE + 0x0C) //0x4001180C
#define GPIOE_IDR (GPIOE_BASE + 0x08) //0x40011808
#define GPIOE_ODR (GPIOE_BASE + 0x0C) //0x4001180C/********************************************** 宏定义输入输出 ************************************************/
#define PAout(Bit_Num) Bit_Band(GPIOA_ODR,Bit_Num) //输出 1位输出
#define PAin(Bit_Num) Bit_Band(GPIOA_IDR,Bit_Num) //输入
#define PBout(Bit_Num) Bit_Band(GPIOB_ODR,Bit_Num)
#define PBin(Bit_Num) Bit_Band(GPIOB_IDR,Bit_Num)
#define PCout(Bit_Num) Bit_Band(GPIOC_ODR,Bit_Num)
#define PCin(Bit_Num) Bit_Band(GPIOC_IDR,Bit_Num)
#define PDout(Bit_Num) Bit_Band(GPIOD_ODR,Bit_Num)
#define PDin(Bit_Num) Bit_Band(GPIOD_IDR,Bit_Num)
#define PEout(Bit_Num) Bit_Band(GPIOE_ODR,Bit_Num)
#define PEout(Bit_Num) Bit_Band(GPIOE_ODR,Bit_Num)
这里利用到了STM32
的位段功能,Cortex-M3
储存器包含两个位段(bit-band
)区,将别名寄存器的每个字映射到位段寄存器的一个位。
映射公式(外设寄存器和SRAM
可被映射):
其中:
bit_word_addr
:别名寄存器中的地址映射到某一个目标位;bit_band_base
:别名区的起始地址;byte_offset
:目标位的字节在位段的序号;bit_number
:目标位所在位置(0~31);
例如:SRAM
中某一变量地址为0x20000300
字节中的位2;
1.4.3 点亮LED
如需点亮LED
,我们只需要在main
函数添加如下代码:
gpio_init(PD2,GPO_SpeedMax_50,HIGH); // PD2接入LED2
gpio_init(PA8,GPO_SpeedMax_50,HIGH); // PA8接入LED1
while(1)
{ PAout(8) = 0;PDout(2) = 1;delay_ms(1500);PAout(8) = 1;PDout(2) = 0;delay_ms(1500);
}
这里我们简单介绍一下PAout
、PDout
宏的实现;
1.4.3 烧录
编译完成后通过ISP
烧录到开发版,我们可以看到LED1
、LED2
交替点亮,时间间隔为1.5s
。
二、检测按键
三、串口
三、点亮TFT
四、源码下载
源码下载路径: