第三部分 通用 I/O (GPIO)
一、GPIO寄存器
0.问题的引入
LED灯原理:LED0给它一个低电平,灯就可以亮;LED0给它一个高电平,灯就会灭
这些引脚最终是接入到MCU的某个引脚(GPIO)上去,控制LED灯或其他,可以在MCU上面写程序去控制这些引脚。
四个灯如下:
找到对应CPU的引脚:D1-PF9,D2-PF10,D3-PE13,D4-PE14
2.GPIO简介
General Purpose Input/Output 通用功能的输入输出
GPIO 引脚(GPIO pin)从芯片内部引出一根功能复用的口线(电线),可以配置成不同的功能,如:输入功能,输出功能,其他复用功能等。
MCU控制"一切",通过它的引脚(Pins)来实现的。
STM32F4xx共用144个GPIO引脚,分为9组,记为GPIOA,GPIOB, GPIOC,GPIOD,GPIOE,GPIOF,GPIOG,GPIOH,GPIOI.每组管理16个引脚,编号从0~15,如:
GPIOF 这一组的16个引脚,分别记为:GPIOF0,GPIOF1,GPIOF2,…,GPIOF15(其他组类似)
简写方式:GPIOF9 -> PF9 GPIOE10 -> PE10
这些GPIO都是功能复用的,有不同的寄存器组来配置它们。
每组GPIO地址分配如下:(0x3FF~1024KB)
边界地址 | 外设 |
---|---|
0x4002 0000 - 0x4002 03FF | GPIOA |
0x4002 0400 - 0x4002 07FF | GPIOB |
0x4002 0800 - 0x4002 0BFF | GPIOC |
0x4002 0C00 - 0x4002 0FFF | GPIOD |
0x4002 1000 - 0x4002 13FF | GPIOE |
0x4002 1400 - 0x4002 17FF | GPIOF |
0x4002 1800 - 0x4002 1BFF | GPIOG |
0x4002 1C00 - 0x4002 1FFF | GPIOH |
0x4002 2000 - 0x4002 23FF | GPIOI |
2. STM32F4xx GPIO内部结构原理
每个GPIO引脚在芯片内部都可以配置成如下功能:
-
输入功能 Input
CPU可以获取该GPIO引脚的外部输入的一个电平状态。输入功能也有几种模式:
-
模拟输入 Input Analog(GPIO_MODE_AIN)
接收外部模拟信号(如变化的电压值),然后交给片上外设模块(如ADC)模数转换。
-
悬空输入 Input Floating(GPIO_MODE_IN_FLOATING)
内部不接上拉/下拉电阻,输入引脚状态完全由外部电路所决定的。CPU能够通过读取GPIO的状态知道I/O的电平状态。
-
下拉输入 Input Pull-Down(GPIO_MODE_IPD)
内部接一个下拉电阻。
作用:引脚在悬空的状态或外部电路没有输出电平时,CPU读取到的为低电平。
-
上拉输入 Input Pull-Up(GPIO_MODE_IPU)
内部接一个上拉电阻。
作用:引脚在悬空的状态或外部电路没有输出电平时,CPU读取到的为高电平。
-
-
输出功能 Output
CPU往GPIO引脚输出一个电平状态。输出功能也有几种模式:
-
输出开漏 Open-Drain (GPIO_MODE_Out_OD)
不输出电压。输出寄存器中的“0”可激活 N-MOS,而输出寄存器中的“1”会使端 口保持高组态 (Hi-Z)(P-MOS 始终不激活)
CPU write 0,接地引脚,输出就是低电平
CPU write 1,输出电平受上拉下拉电阻决定(悬空的状态)
-
输出推挽 Push-Pull (GPIO_MODE_Out_PP)
输出寄存器中的“0”可激活 N-MOS,而输出寄存器中的“1”可激活 P-MOS
作用:增强驱动力可以输出一个高、低电平,其原理见图
CPU write 0 -> 引脚输出低电平
CPU write 1 -> 引脚输出高电平
-
-
复用功能 Alternate Function GPIO_MODE_AF
复用功能是指GPIO引脚用作其它的功能使用,如: I2C,UART,SPI,CAN等。
每个GPIO口都可以配置成多达16种复用功能,记为AF0,AF1,AF2,…,AF15。
具体哪个GPIO可以配置成哪种复用功能,需要看原理图和datasheet.
3.STM32F4xx GPIO寄存器说明
每个通用 I/O 端口包括 4 个 32 位配置寄存器
(GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR 和 GPIOx_PUPDR)
2 个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR)
1 个 32 位置位/复位寄存器 (GPIOx_BSRR)
1 个 32 位锁定寄存器 (GPIOx_LCKR)
2 个 32 位复用功能选择寄存器(GPIOx_AFRH 和 GPIOx_AFRL)
-
端口模式寄存器 GPIOx_MODER
偏移地址:0x00
复位值:
- 0xA800 0000(端口 A)
- 0x0000 0280(端口 B)
- 0x0000 0000(其它端口)
例:GPIOA_MODER = 0x40020000 + 0x00 GPIOF_MODER = 0x40021400 + 0x00
该寄存器用来控制x(x=A,B,C,…I)组GPIO的16个引脚的模式,每个pin都有4种模式,每个pin需要2bits来配置。编号为y(y=0,1,2,…,15)的GPIO引脚在该寄存器的bit位置为:GPIOx_MODER[2y+1:2y]
具体配置如下:
- 00 通用输入模式 input
- 01 通用输出模式 output
- 10 复用功能模式 Alternate Function
- 11 模拟输入模式 input analog
-
端口输出类型寄存器 GPIOx_OTYPER
偏移地址:0x04
复位值:0x0000 0000
该寄存器用来控制x(x=A,B,C,…I)组的16个GPIO口的输出类型(PP/OD),每个GPIO引脚,占1bit,编号为y(y=0,1,2,…,15)的引脚在该寄存器的bit位置为:GPIOx_OTYPER[y]
具体配置如下:
- 0 输出推挽(PP) PP: 1 -> 输出高电平 0 -> 输出低电平
- 1 输出开漏(OD) OD: 0 -> 引脚内部接地 1 ->输出电平受上拉下拉电阻决定
-
端口输出速度寄存器 GPIOx_OSPEEDR
偏移地址:0x08
复位值:
- 0x0000 00C0(端口 B)
- 0x0000 0000(其它端口)
该寄存器用来控制x(x=A,B,C,…,I)组的16个GPIO的输出速率,每个GPIO口占2bits。编号为y(y=0,1,2,…,15)的GPIO口在该寄存器的bit位为:GPIOx_OSPEEDR[2y+1:2y]
具体输出速率为:
- 00 2 MHz(低速)
- 01 25 MHz(中速)
- 10 50 MHz(快速)
- 11 30 pF 时为 100 MHz(高速)(15 pF 时为 80 MHz 输出(最大速度))
-
端口上拉/下拉寄存器 GPIOx_PUPDR
偏移地址:0x0C
复位值:
- 0x6400 0000(端口 A)
- 0x0000 0100(端口 B)
- 0x0000 0000(其它端口)
该寄存器用来控制x(x=A,B,C,…,I)组的16个GPIO引脚的上下拉电阻选择。每个GPIO引脚占2bits.编号为y(y=0,1,2,…,15)的GPIO口在该寄存器的bit位为:GPIOx_PUPDR[2y+1:2y]
具体上下拉情况为:
- 00 无上拉,无下拉
- 01 上拉
- 10 下拉
- 11 无上拉,无下拉保留
-
端口输入数据寄存器 GPIOx_IDR
偏移地址:0x10
复位值:0x0000 XXXX(其中 X 表示未定义)
当GPIO引脚配置成输入模式时,CPU可以读取这个寄存器的值(来自外部电路的值)
该寄存器用来表示x(x=A,B,C,…,I)组的16个GPIO口的输入值,其中位31:16保留。位IDR[15:0]表示相应的GPIO引脚的输入状态,只读。
0 低电平 1 高电平
-
端口输出数据寄存器 GPIOx_ODR
偏移地址:0x14
复位值:0x0000 0000
当GPIO引脚配置成输出模式时,CPU可以往该寄存器写0引脚输出低电平。写1在推挽方式下是引脚输出是高电平,开漏状态下外部电路决定。
该寄存器用来表示x(x=A,B,C,…,I)组的16个GPIO口的输出值,其中位31:16保留。位ODR[15:0]表示相应的GPIO引脚的输出状态,只写。
0 低电平
1 PP :高电平
OD : 悬空(外部电路决定)
-
端口置位/复位寄存器 GPIOx_BSRR
偏移地址:0x18
复位值:0x0000 0000
BSRR[31:16] 端口复位寄存器 对BSRR[31:16]写1,相应的GPIO引脚输出0
BSRR[15:0] 端口置位寄存器 对BSRR[15:0]写1,相应的GPIO引脚输出1
这个寄存器只写1,写0无效
二、流水灯(直接写寄存器)
1. start.s
stack_size EQU 0x200 ;宏指令,定义了两个宏
vector_size EQU 0x400
;define stack ;名字为mystack,数据,可读可写
AREA mystack,DATA,READWRITE
stack_S ;顶格
SPACE stack_size ;设置空间大小
stack_end ;stack top--SP
;define vector table ;定义向量表,只读
AREA RESET,DATA,READONLY
vector_s
DCD stack_end ;the first must be stack top
DCD code_start ;this must be start code
SPACE vector_size
vector_end
IMPORT main
;define code
AREA mycode,CODE,READONLY,ALIGN=3
PRESERVE8 ;8字节对齐
code_start PROC
BL main
B . ;while(1)
ENDP
END
2. led_reg.h
#ifndef __LED_H__ //avoid duplicate head
#define __LED_H__
//include
//define
#define rRCCAHB1CLKEN *((volatile unsigned long *)0x40023830)
#define GPIOE_BASE_ADDR 0X40021000 //引脚GPIOE的地址
#define GPIOF_BASE_ADDR 0x40021400 //引脚GPIOF的的地址
#define MODER_OFFSET_ADDR 0x00 //对应寄存器的偏移地址
#define OTYPER_OFFSET_ADDR 0x04
#define OSPEEDR_OFFSET_ADDR 0x08
#define PUPDR_OFFSET_ADDR 0x0c
#define BSRR_OFFSET_ADDR 0x18
//各寄存器的地址 = 引脚地址+偏移地址
//volatile:(每次存取都往该的实地址存取最新数据)
#define rGPIOF_MODER (*(volatile unsigned long*)(GPIOF_BASE_ADDR+MODER_OFFSET_ADDR))
#define rGPIOF_OTYPER (*(volatile unsigned long*)(GPIOF_BASE_ADDR+OTYPER_OFFSET_ADDR))
#define rGPIOF_OSPEEDR (*(volatile unsigned long*)(GPIOF_BASE_ADDR+OSPEEDR_OFFSET_ADDR))
#define rGPIOF_PUPDR (*(volatile unsigned long*)(GPIOF_BASE_ADDR+PUPDR_OFFSET_ADDR))
#define rGPIOF_BSRR (*(volatile unsigned long*)(GPIOF_BASE_ADDR+BSRR_OFFSET_ADDR))
#define rGPIOE_MODER (*(volatile unsigned long*)(GPIOE_BASE_ADDR+MODER_OFFSET_ADDR))
#define rGPIOE_OTYPER (*(volatile unsigned long*)(GPIOE_BASE_ADDR+OTYPER_OFFSET_ADDR))
#define rGPIOE_OSPEEDR (*(volatile unsigned long*)(GPIOE_BASE_ADDR+OSPEEDR_OFFSET_ADDR))
#define rGPIOE_PUPDR (*(volatile unsigned long*)(GPIOE_BASE_ADDR+PUPDR_OFFSET_ADDR))
#define rGPIOE_BSRR (*(volatile unsigned long*)(GPIOE_BASE_ADDR+BSRR_OFFSET_ADDR))
enum LED_NUM{LED1,LED2,LED3,LED4};
//func
void led_init(void); //初始化函数申明
void led_ctrl( int led_num); //流水灯控制函数申明
void delay(int num); //延迟时间函数申明
#endif
3. led_reg.c
#include "led_reg.h"
void led_init(void)
{
unsigned long r_value;
//GPIOE GPIOF
//rRCCAHB1CLKEN[4]--GPIOE rRCCAHB1CLKEN[5]--GPIOF
rRCCAHB1CLKEN |= (1<<4)|(1<<5); //时钟
//PF9,PF10-->out 设置为输出模式
//[21:18] 0101
r_value=rGPIOF_MODER;
r_value &=~(0xf<<18);
r_value |=(1<<18)|(1<<20);
rGPIOF_MODER=r_value;
//PE13,PE14-->out
//[29:26] 0101
r_value=rGPIOE_MODER;
r_value &=~(0xf<<26);
r_value |=(1<<26)|(1<<28);
rGPIOE_MODER=r_value;
//PF9,PF10-->pp 0 设置为输出类型为推挽
//[10:9] 00
r_value=rGPIOF_OTYPER;
r_value &=~((1<<9)|(1<<10));
rGPIOF_OTYPER=r_value;
//PE13,PE14-->pp 0
//[14:13] 00
r_value=rGPIOE_OTYPER;
r_value &=~((1<<13)|(1<<14));
rGPIOE_OTYPER=r_value;
//PF9,PF10-->50MHZ 10 设置输出速度为50MHZ
//[21:18] 1010
r_value=rGPIOF_OSPEEDR;
r_value &=~(0xf<<18);//****0000******
r_value |=(1<<19)|(1<<21);
rGPIOF_OSPEEDR=r_value;
//PE13,PE14-->50MHZ 10
//[29:26] 1010
r_value=rGPIOE_OSPEEDR;
r_value &=~(0xf<<26);
r_value |=(1<<29)|(1<<27);
rGPIOE_OSPEEDR=r_value;
//PF9,PF10-->no 00 设置无上拉、无下拉
//[21:18] 0000
r_value=rGPIOF_PUPDR;
r_value &=~(0xf<<18);
rGPIOF_PUPDR=r_value;
//PE13,PE14-->no 00
//[29:26] 0000
r_value=rGPIOE_PUPDR;
r_value &=~(0xf<<26);
rGPIOE_PUPDR=r_value;
//LED1 LED2-->PF9,PF10-->BSRR(1) //设置灯初始状态全灭
//[10:9] 11
r_value=rGPIOF_BSRR;
r_value |=(1<<9)|(1<<10);
rGPIOF_BSRR=r_value;
//LED3 LED4-->PE13,PE14-->BSRR(1)
//[14:13] 11
r_value=rGPIOE_BSRR;
r_value |=(1<<13)|(1<<14);
rGPIOE_BSRR=r_value;
}
void led_ctrl( int led_num) //设置对应灯亮
{
unsigned long r_value;
switch(led_num)
{
case LED1:
{
r_value=rGPIOF_BSRR;
//PF9--0,PF10--1
r_value |=(1<<25)|(1<<10);
rGPIOF_BSRR=r_value;
r_value=rGPIOE_BSRR;
//PE13--1,PE14--1
r_value |=(1<<13)|(1<<14);
rGPIOE_BSRR=r_value;
break;
}
case LED2:
{
r_value=rGPIOF_BSRR;
//PF9--1,PF10--0
r_value |=(1<<9)|(1<<26);
rGPIOF_BSRR=r_value;
r_value=rGPIOE_BSRR;
//PE13--1,PE14--1
r_value |=(1<<13)|(1<<14);
rGPIOE_BSRR=r_value;
break;
}
case LED3:
{
r_value=rGPIOF_BSRR;
//PF9--1,PF10--1
r_value |=(1<<9)|(1<<10);
rGPIOF_BSRR=r_value;
r_value=rGPIOE_BSRR;
//PE13--0,PE14--1
r_value |=(1<<29)|(1<<14);
rGPIOE_BSRR=r_value;
break;
}
case LED4:
{
r_value=rGPIOF_BSRR;
//PF9--1,PF10--1
r_value |=(1<<9)|(1<<10);
rGPIOF_BSRR=r_value;
r_value=rGPIOE_BSRR;
//PE13--1,PE14--0
r_value |=(1<<13)|(1<<30);
rGPIOE_BSRR=r_value;
break;
}
default:
break;
}
}
void delay(int num)
{
while(num--);
}
int main()
{
led_init();
while(1)
{
for(int led_n=LED1;led_n<=LED4;led_n++) //循环点亮各个灯
{
led_ctrl(led_n);
delay(0x100000);
}
}
}
三、STM32官方固件库
总线APB/AHB 不同外设连接不同总线(AHB1,AHB2,AHB3,APB1,APB2),GPIO—>AHB1
1. 使能GPIO分组的时钟
RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState)
-
uint32_t RCC_AHB1Periph: 连接到AHB1上的外设编号
-
FunctionalState NewState: ENABLE or DISABLE
例:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOE,ENABLE);
注意:RCC_总线名一定要和外设编号要对应
2. GPIO初始化
GPIO_Init(GPIO_TypeDef * GPIOx, GPIO_InitTypeDef * GPIO_InitStruct)
-
GPIO_TypeDef * GPIOx: 分组的寄存器地址 如:GPIOF
-
GPIO_InitTypeDef * GPIO_InitStruct: 结构体指针
/** * @brief GPIO Init structure definition */ typedef struct { uint32_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIOMode_TypeDef */ GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIOSpeed_TypeDef */ GPIOOType_TypeDef GPIO_OType; /*!< Specifies the operating output type for the selected pins. This parameter can be a value of @ref GPIOOType_TypeDef */ GPIOPuPd_TypeDef GPIO_PuPd; /*!< Specifies the operating Pull-up/Pull down for the selected pins. This parameter can be a value of @ref GPIOPuPd_TypeDef */ }GPIO_InitTypeDef;
/** * @brief GPIO Configuration Mode enumeration */ typedef enum { GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */ GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */ GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */ GPIO_Mode_AN = 0x03 /*!< GPIO Analog Mode */ }GPIOMode_TypeDef;
/** * @brief GPIO Output type enumeration */ typedef enum { GPIO_OType_PP = 0x00, GPIO_OType_OD = 0x01 }GPIOOType_TypeDef;
/** * @brief GPIO Output Maximum frequency enumeration */ typedef enum { 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; /* Add legacy definition */ #define GPIO_Speed_2MHz GPIO_Low_Speed #define GPIO_Speed_25MHz GPIO_Medium_Speed #define GPIO_Speed_50MHz GPIO_Fast_Speed #define GPIO_Speed_100MHz GPIO_High_Speed
/** * @brief GPIO Configuration PullUp PullDown enumeration */ typedef enum { GPIO_PuPd_NOPULL = 0x00, GPIO_PuPd_UP = 0x01, GPIO_PuPd_DOWN = 0x02 }GPIOPuPd_TypeDef;
3. 置位/复位/取反函数
置位:
void GPIO_SetBits(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
-
GPIO_TypeDef * GPIOx: 指定GPIO分组 如:GPIOF
-
uint16_t GPIO_Pin: 引脚号
例:
GPIO_SetBits(GPIOF, GPIO_Pin_9|GPIO_Pin_10)
函数内部执行:GPIOx->BSRRL = GPIO_Pin;
复位:
void GPIO_ResetBits(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
取反:
void GPIO_ToggleBits(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
函数内部执行:GPIOx->ODR ^= GPIO_Pin;
例:GPIO_ToggleBits(GPIOF, GPIO_Pin_9)
4. GPIO引脚的读写
READ:
-
读一个分组的所有引脚的电平状态:
uint16_t GPIO_ReadInputData(GPIO_TypeDef * GPIOx)
返回值:所有引脚的电平状态
- 读一个分组的指定引脚的电平状态:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
WRITE:
-
MCU给指定GPIO分组(GPIOx)的所有引脚(16个)输出一个电平状态
void GPIO_Write(GPIO_TypeDef * GPIOx, uint16_t PortVal)
例子:led0点灯 PF9
uint16_t value=GPIO_ReadInputData(GPIOF); value &= ~(1<<9); GPIO_Write(GPIOF,value);
-
MCU给指定GPIO分组(GPIOx)的指定引脚(16个)输出一个电平状态
void GPIO_WriteBit(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
BitAction BitVal: Bit_Reset 0 Bit_Set 1
例子:
case 1: GPIO_ResetBits(GPIOF, GPIO_Pin_9); GPIO_SetBits(GPIOF, GPIO_Pin_10); GPIO_SetBits(GPIOE, GPIO_Pin_13|GPIO_Pin_14);
四、流水灯(基于固件库)
1. rj_reg.h
#ifndef _LED_H_
#define _LED_H_
#include "stm32f4xx.h"
enum LED_NUM{LED1,LED2,LED3,LED4};
//函数申明
void led_init(void);
void led_ctrl(int led_n);
void delay(int cnt);
void led_loop(void);
#endif
2.rj_reg.c
#include "rj_led.h"
void led_init()
{
//clk enable GPIOE GPIOF --AHB1
//设置连接到AHB1上GPIOE和GPIOF的外设可用
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOF, ENABLE);
//MODE-OUT,OTYPE-PP,OSPEED-50M,NO UPDN
GPIO_InitTypeDef P;
P.GPIO_Mode =GPIO_Mode_OUT; //设置为输出模式
P.GPIO_OType =GPIO_OType_PP; //设置输出类型为推挽
P.GPIO_Pin =GPIO_Pin_9|GPIO_Pin_10; //设置引脚为9和10
P.GPIO_PuPd =GPIO_PuPd_NOPULL; //设置无上拉、无下拉
P.GPIO_Speed =GPIO_Speed_50MHz; //设置输出速率为50MHz
GPIO_Init(GPIOF, &P); //调用初始化函数
P.GPIO_Pin =GPIO_Pin_13|GPIO_Pin_14;
GPIO_Init(GPIOE, &P);
}
void led_loop() //流水灯循环实现
{
for(int led_n=LED1;led_n<=LED4;led_n++)
{
led_ctrl(led_n);
delay(0x100000);
}
}
void led_ctrl( int led_num) //利用置位和复位设置对应的灯的明灭
{
unsigned long r_value;
switch(led_num)
{
case LED1:
{
GPIO_ResetBits(GPIOF, GPIO_Pin_9);
GPIO_SetBits(GPIOF, GPIO_Pin_10);
GPIO_SetBits(GPIOE, GPIO_Pin_13);
GPIO_SetBits(GPIOE, GPIO_Pin_14);
break;
}
case LED2:
{
GPIO_ResetBits(GPIOF, GPIO_Pin_10);
GPIO_SetBits(GPIOF, GPIO_Pin_9);
GPIO_SetBits(GPIOE, GPIO_Pin_13);
GPIO_SetBits(GPIOE, GPIO_Pin_14);
break;
}
case LED3:
{
GPIO_ResetBits(GPIOE, GPIO_Pin_13);
GPIO_SetBits(GPIOE, GPIO_Pin_14);
GPIO_SetBits(GPIOF, GPIO_Pin_9);
GPIO_SetBits(GPIOF, GPIO_Pin_10);
break;
}
case LED4:
{
GPIO_ResetBits(GPIOE, GPIO_Pin_14);
GPIO_SetBits(GPIOE, GPIO_Pin_13);
GPIO_SetBits(GPIOF, GPIO_Pin_9);
GPIO_SetBits(GPIOF, GPIO_Pin_10);
break;
}
default:
break;
}
}
void delay(int num)
{
while(num--);
}
第一部分 嵌入式系统概述
第二部分 ARM指令系统
第三部分 通用 I/O (GPIO)
第四部分 中断机制
第五部分 时钟定时器