1 新建工程模版
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cBSqllCN-
2 cortex-M3框图
1)Icode总线:从flash中取指令。
2)Dcode总线:从flash中取常量,从SRAM中取变量。
3)System总线:完成对外设的控制。
4)DMA:直接访问存储器,完成内存之间或内存与外设之间的数据搬运工作。
5)FSMC:挂载静态SRAM。
6)AHB总线:挂载时钟复位控制器、SDIO、APB1、APB2总线。
7)APB2总线:72MHz,挂载所有GPIO、高速USART、TIM、USB、AFIO。
3 内存映射
- 将4G的内存按照512KB等分为8个块。
- APB1总线的基地址为0x40000000。
- APB2总线的基地址为0x40010000。
- AHB总线的基地址为0x400180000。
4 GPIO框图
1)保护电路:用两个保护二极管来防止电压过大,接电机还需要接其他驱动。
2)推挽输出:接一个CMOS反相器,使得IO口的高低电平均有驱动能力。
3)开漏输出:将CMOS反相器变为一个OD门,使得高电平没有驱动能力,但是高电平依旧可以写。
4)复用推挽输出、复用开漏输出:通过一个与门,实现复用功能引脚的输出。
5)浮空输入:经过施密特触发器来整型电流,获得高低电平的方波。
7)模拟输入:不经过施密特触发器整型电流,获得模拟输入电流。
8)上拉输入:内部上拉,默认为高电平。
9)下拉输入:内部下拉,默认为低电平。
5 GPIO地址映射
- 7个GPIO,对应的地址如下:
外设名 | 地址 |
---|---|
GPIOA | 0x4001 0800 |
GPIOB | 0x4001 0c00 |
GPIOC | 0x4001 1000 |
GPIOD | 0x4001 1400 |
GPIOE | 0x4001 1800 |
GPIOF | 0x4001 1c00 |
GPIOG | 0x4001 2000 |
6 寄存器介绍
寄存器名 | 寄存器标识符 | 偏移量 | 功能 |
---|---|---|---|
端口配置低寄存器 | GPIOX_CRL | 0x00 | 32位有效,调节ODR低8位的输入输出模式 |
端口配置高寄存器 | GPIOX_CRH | 0x04 | 32位有效,调节ODR高八位的输入输出模式 |
端口输出数据寄存器 | GPIOX_ODR | 0x08 | 低16位为IO口的输出,高16位保留 |
端口输人数据寄存器 | GPIOX_IDR | 0x0c | 低16位为IO口的输入,高16位保留 |
端口位设置/清楚寄存器 | GPIOX_BSRR | 0x10 | 低16位置1,置1,高16位置1,清零 |
端口位清楚寄存器 | GPIOX_BRR | 0x14 | 低16位置1,清零,高16位保留 |
端口配置锁定寄存器 | GPIOX_LCKR | 0x18 | 位16锁键,0~15只能在16位为0时才能 |
7 GPIO模式选择
1)CRL和CRH的每4位来控制GPIO的一位的工作模式。
2)[1:0]位控制速度:00-输入,01-2MHz,10-10MHz、11-50MHz。
3)[5]位控制输入输出:0-输入、1-输出。
4)[3:4]位配合[5]位控制输入输出:000-模拟、001-浮空、010-上拉或下拉、100-推挽、101-开漏、110-复推挽、111-复开漏
5)[6:5]控制上拉还是下拉:01-下拉、10-上拉
8 LED原理图
9 寄存器点亮LED
9.1 stm32f10x.h
#ifndef STM32F10X_H__
#define STM32F10X_H__
typedef unsigned int uint32_t; /*32位整型*/
typedef unsigned short uint16_t; /*16位整型*/
typedef unsigned char uint8_t; /*8位整型*/
#define __IO volatile /*防止编译器优化*/
#define APB1PERIPH_BASE 0x40000000 /*APB1基地址*/
#define APB2PERIPH_BASE 0x40010000 /*APB2基地址*/
#define AHBPERIPH_BASE 0x40020000 /*AHB基地址,绕开SDIO等*/
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) /*GPIOA基地址*/
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) /*GPIOB基地址*/
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) /*GPIOC基地址*/
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) /*GPIOD基地址*/
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) /*GPIOE基地址*/
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00) /*GPIOF基地址*/
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000) /*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; /*GPIO结构体*/
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE) /*GPIOA结构体*/
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE) /*GPIOA结构体*/
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE) /*GPIOA结构体*/
#define GPIOD ((GPIO_TypeDef *)GPIOD_BASE) /*GPIOA结构体*/
#define GPIOE ((GPIO_TypeDef *)GPIOE_BASE) /*GPIOA结构体*/
#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE) /*GPIOA结构体*/
#define GPIOG ((GPIO_TypeDef *)GPIOG_BASE) /*GPIOA结构体*/
#define RCC_BASE (AHBPERIPH_BASE + 0x1000) /*RCC基地址*/
typedef struct {
__IO uint32_t CR; // 时钟控制寄存器
__IO uint32_t CFGR; // 时钟配置寄存器
__IO uint32_t CIR; // 时钟中断寄存器
__IO uint32_t APB2RSTR; // APB2外设复位寄存器
__IO uint32_t APB1RSTR; // APB1外设复位寄存器
__IO uint32_t AHBENR; // AHB外设时钟使能寄存器
__IO uint32_t APB2ENR; // APB2外设时钟使能寄存器
__IO uint32_t APB1ENR; // APB1外设时钟使能寄存器
__IO uint32_t BDCR; // 备份域控制寄存器
__IO uint32_t CSR; //控制/状态寄存器
__IO uint32_t AHBRSTR; // AHB外设时钟复位寄存器
__IO uint32_t CFGR2; // 时钟配置寄存器
}RCC_Typedef; /*RCC结构体*/
#define RCC ((RCC_Typedef *)RCC_BASE) /*RCC结构体*/
#endif
9.2 stm32f10x_gpio.h
#ifndef STM32F10X_GPIO_H__
#define STM32F10X_GPIO_H__
#include "stm32f10x.h"
typedef enum{
GPIO_Speed_10MHz = 1, /*10MHZ*/
GPIO_Speed_2MHz, /*2MHZ*/
GPIO_Speed_50MHz /*50MHZ*/
}GPIOSpeed_TypeDef; /*速度结构体*/
typedef enum{
/*
规则
1. 只考虑前7位。
2. 第4位决定输入还是输出,1输出,0输入。
3. 第5位和第6位共同决定上拉还是下拉,01 下拉,10 上拉。
4. 第2、3位一起决定是模拟、浮空、复用、上拉、下拉等模式。
*/
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 /*复用推挽输入*/
}GPIOMode_TypeDef; /*模式结构体*/
typedef struct
{
uint16_t GPIO_Pin; /*引脚*/
GPIOSpeed_TypeDef GPIO_Speed; /*速度*/
GPIOMode_TypeDef GPIO_Mode; /*模式*/
}GPIO_InitTypeDef; /*GPIO初始化结构体*/
#define SET 1
#define RESET 0
#define GPIO_Pin_0 ((uint16_t)0x0001) /*Pin 0 */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*Pin 1 */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*Pin 2 */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*Pin 3 */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*Pin 4 */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*Pin 5 */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*Pin 6 */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*Pin 7 */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*Pin 8 */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*Pin 9 */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*Pin 10*/
#define GPIO_Pin_11 ((uint16_t)0x0800) /*Pin 11*/
#define GPIO_Pin_12 ((uint16_t)0x1000) /*Pin 12*/
#define GPIO_Pin_13 ((uint16_t)0x2000) /*Pin 13*/
#define GPIO_Pin_14 ((uint16_t)0x4000) /*Pin 14*/
#define GPIO_Pin_15 ((uint16_t)0x8000) /*Pin 15*/
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*ALL */
/*
将GPIO_PIN对应IO口置1,
GPIO_X:GPIOA-G
GPIO_Pin:GPIO_Pin_0-15
*/
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
/*
将GPIO_PIN对应IO口清零,
GPIO_X:GPIOA-G
GPIO_Pin:GPIO_Pin_0-15
*/
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
/*初始化结构体,设置工作模式*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
#endif
9.3 stm32f10x_gpio.c
#include "stm32f10x_gpio.h"
/*
将GPIO_PIN对应IO口置1,
GPIO_X:GPIOA-G
GPIO_Pin:GPIO_Pin_0-15
*/
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin){
GPIOx->BSRR |= GPIO_Pin; /*将对应引脚置1,调用BSRR的低16位,BSRR置1*/
}
/*
将GPIO_PIN对应IO口清零,
GPIO_X:GPIOA-G
GPIO_Pin:GPIO_Pin_0-15
*/
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin){
GPIOx->BRR |= GPIO_Pin; /*将对应引脚清0,调用BRR的低16位,BRR置1*/
}
/*初始化结构体,设置工作模式*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct){
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
/*---------------------- GPIO 模式配置 --------------------------*/
// 把输入参数GPIO_Mode的低四位暂存在currentmode
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
// bit4是1表示输出,bit4是0则是输入
// 判断bit4是1还是0,即首选判断是输入还是输出模式
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
{
// 输出模式则要设置输出速度
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
/*-------------GPIO CRL 寄存器配置 CRL寄存器控制着低8位IO- -------*/
// 配置端口低8位,即Pin0~Pin7
if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
{
// 先备份CRL寄存器的值
tmpreg = GPIOx->CRL;
// 循环,从Pin0开始配对,找出具体的Pin
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
// pos的值为1左移pinpos位
pos = ((uint32_t)0x01) << pinpos;
// 令pos与输入参数GPIO_PIN作位与运算,为下面的判断作准备
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
//若currentpin=pos,则找到使用的引脚
if (currentpin == pos)
{
// pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
pos = pinpos << 2;
//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
// 向寄存器写入将要配置的引脚的模式
tmpreg |= (currentmode << pos);
// 判断是否为下拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
// 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
GPIOx->BRR = (((uint32_t)0x01) << pinpos);
}
else
{
// 判断是否为上拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
}
}
}
}
// 把前面处理后的暂存值写入到CRL寄存器之中
GPIOx->CRL = tmpreg;
}
/*-------------GPIO CRH 寄存器配置 CRH寄存器控制着高8位IO- -----------*/
// 配置端口高8位,即Pin8~Pin15
if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
{
// // 先备份CRH寄存器的值
tmpreg = GPIOx->CRH;
// 循环,从Pin8开始配对,找出具体的Pin
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = (((uint32_t)0x01) << (pinpos + 0x08));
// pos与输入参数GPIO_PIN作位与运算
currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
//若currentpin=pos,则找到使用的引脚
if (currentpin == pos)
{
//pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
pos = pinpos << 2;
//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
// 向寄存器写入将要配置的引脚的模式
tmpreg |= (currentmode << pos);
// 判断是否为下拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
// 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
// 判断是否为上拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
}
}
// 把前面处理后的暂存值写入到CRH寄存器之中
GPIOx->CRH = tmpreg;
}
}
9.4 main.c
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
int main(void){
GPIO_InitTypeDef GPIO_InitStruct;
/*打开时钟*/
RCC->APB2ENR |= (1 << 3); /*使能GPIOB*/
/*初始化GPIO结构体*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_ResetBits(GPIOB,GPIO_Pin_0); /*点灯*/
GPIO_SetBits(GPIOB,GPIO_Pin_0); /*熄灭*/
while(1){
}
}
void SystemInit(void){
}
10 按键原理图
1)指南者开发板按键原理
- 用来RC电路实现硬件消抖,高电平时点亮。
2)常见的LED接线方式:
- 二极管低电平驱动、二极管高电平驱动、三极管低电平驱动、三极管高电平驱动。
11 按键消抖
1)按键抖动:机械开关在按下时由于弹性变形,按下或弹开的瞬间存在电压变化。
2)RC电路消抖:利用电容的充放电来消抖。
3)触发器消抖:将电压值锁存实现消抖,是目前最好的消抖方式。
4)软件消抖:利用延时或者中断来实现消抖。
- 消抖模版:
uint8_t KeyScan(void){
if(IO口的值为1){
延时20ms;
if(IO口的值为1){
return 1;
}else{
return 0;
}
}else{
return 0;
}
}
12 按键检测点亮LED
12.1 bsp_led.h
#ifndef BSP_LED_H__
#define BSP_LED_H__
#include "stm32f10x.h"
/*引脚定义*/
#define LED_Port GPIOB /*对应GPIO口*/
#define LED_Pin_R GPIO_Pin_5 /*红灯对应引脚*/
#define LED_Pin_B GPIO_Pin_1 /*蓝灯对应引脚*/
#define LED_Pin_G GPIO_Pin_0 /*绿灯对应引脚*/
/*
初始化GPIO:
1.打开时钟;
2. 初始化GPIO结构体,设置模式、速度、引脚;
3. 熄灭所有LED
*/
void LED_Init(void);
/*点亮LED*/
void LED_ON(uint16_t LED_Pin);
/*熄灭LED*/
void LED_OFF(uint16_t LED_Pin);
/*翻转LED*/
void LED_Invert(uint16_t LED_Pin);
#endif
12.2 bsp_led.c
#include "bsp_led.h"
void LED_Init(void){
/*声明初始化结构体*/
GPIO_InitTypeDef GPIO_InitStruct;
/*打开RCC时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
/*配置GPIO为:推挽输出、50MHz*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = LED_Pin_B | LED_Pin_G | LED_Pin_R;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_Port,&GPIO_InitStruct);
/*置1所有LED*/
LED_Port->BSRR |= (LED_Pin_B | LED_Pin_G | LED_Pin_R);
}
void LED_ON(uint16_t LED_Pin){
/*置1对应BRR引脚电平*/
LED_Port->BRR |= LED_Pin;
}
void LED_OFF(uint16_t LED_Pin){
/*置1对应BSRR引脚电平*/
LED_Port->BSRR |= LED_Pin;
}
void LED_Invert(uint16_t LED_Pin){
/*将对应位电平值取反*/
LED_Port->ODR ^= LED_Pin;
}
12.3 bsp_key.h
#ifndef BSP_KEY_H__
#define BSP_KEY_H__
#include "stm32f10x.h"
/*按键1和按键2的引脚配置*/
#define KEY1_GPIO_Port GPIOA
#define KEY1_GPIO_Pin GPIO_Pin_0
#define KEY2_GPIO_Port GPIOC
#define KEY2_GPIO_Pin GPIO_Pin_13
/*初始化按键*/
void KEY_Init(void);
/*扫描按键*/
uint32_t KEY_Scan(void);
#endif
12.4 bsp_key.c
#include "bsp_key.h"
void KEY_Init(void){
/*初始化结构体声明*/
GPIO_InitTypeDef GPIO_InitStruct;
/*打开对应时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
/*结构体初始化*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_Pin;
GPIO_Init(KEY1_GPIO_Port,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = KEY2_GPIO_Pin;
GPIO_Init(KEY2_GPIO_Port,&GPIO_InitStruct);
}
uint32_t KEY_Scan(void){
/*检查人对应位是否为1*/
if(GPIO_ReadInputDataBit(KEY1_GPIO_Port,KEY1_GPIO_Pin) == SET){
return 1;
}
if(GPIO_ReadInputDataBit(KEY2_GPIO_Port,KEY2_GPIO_Pin) == SET){
return 2;
}
return 0;
}