赞
踩
参考海创电子的STM32视频。
头文件作为一种包含功能函数、数据接口声明的载体文件。
#include <stm32f10x.h> #include "stm32f10x.h"
<>:Keil自带的头文件,只要写上能自动去相应的文件夹加载!
“ ”:自定义的头文件,使用的时候一定要指明路径!
如:
- #define PERIPH_BASE 0X4000 0000//总线基地址
- #define ABP1PERIPH_BASE PERIPH_BASE
- #define ABP2PERIPH_BASE (PERIPH_BASE+0x40010000)
- #define AHBPERIPH_BASE (PERIPH_BASE+0x40020000)
-
- #define GPIOC_BASE (ABP2PERIPH_BASE+0X00010000)
- #define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0X04)
将上面图片用结构体表示:
- 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;//总名字,上面中括号里是他的“成员”
但结构体只有名字没有地址,需要和第一章结合起来。
(GPIO_TypeDef*)GPIOC_BASE//GPIOC_BASE表示0x4001 1000,加“*”将其转化为地址
引用结构体中的成员:
- ((GPIO_TypeDef*)GPIOC_BASE)->ODR;
- //"->"是对结构体指针变量的引用
- //由于((GPIO_TypeDef*)GPIOC_BASE)过于长,进行如下定义
- #define GPIOC ((GPIO_TypeDef*)GPIOC_BASE)
- GPIOC->ODR;
模块化编程是将大型程序分解为互相独立的小模块,每个模块负责特定的功能,以便更方便地阅读、维护和复用代码,主要分为源文件(*.c)和头文件(*.h)两部分。
源文件(*.c)
- 各个函数的具体形式
头文件(*.h)
- 各个函数的声明
- define函数的定义
- 结构体
输出高电平用BSRR寄存器。
输出低电平用BRR寄存器。
输出高、低电平具体函数形式
GPIOC->BSRR =|1<<13
但是还有GPIOA/GPIOB/GPIOD……
希望有个函数能够识别是哪个组的哪个引脚!
- void GPIO_SitBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
- {
- GPIOx->BSRR|=GPIO_Pin;
- }
-
- void GPIO_ResitBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
- {
- GPIOx->BSRR|=(GPIO_Pin+16);
- }
-
- void GPIO_ResitBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
- {
- GPIOx->BRR|=GPIO_Pin;
- }
定义引脚:
- #define GPIO_Pin_0 ((uint16_t)0x0001)//二进制:0b0000 0001
- #define GPIO_Pin_1 ((uint16_t)0x0002)//二进制:0b0000 0010
- #define GPIO_Pin_2 ((uint16_t)0x0004)//二进制:0b0000 0100
- #define GPIO_Pin_3 ((uint16_t)0x0008)
- #define GPIO_Pin_4 ((uint16_t)0x0010)
- #define GPIO_Pin_5 ((uint16_t)0x0020)
- #define GPIO_Pin_6 ((uint16_t)0x0040)
- #define GPIO_Pin_7 ((uint16_t)0x0080)
- #define GPIO_Pin_8 ((uint16_t)0x0100)
- #define GPIO_Pin_9 ((uint16_t)0x0200)
- #define GPIO_Pin_10 ((uint16_t)0x0400)
- #define GPIO_Pin_11 ((uint16_t)0x0800)
- #define GPIO_Pin_12 ((uint16_t)0x1000)
- #define GPIO_Pin_13 ((uint16_t)0x2000)
- #define GPIO_Pin_14 ((uint16_t)0x4000)
- #define GPIO_Pin_15 ((uint16_t)0x8000)
枚举
- 变量的值依次增加1,可以将后面具体值省略
- 若变量增加不是1,需要写出具体值
- 若未指定值,第一个枚举成员默认值为0,没有指定值的枚举元素,其值为前一元素值加1
- typedef enum
- {
- GPIO_Speed_10MHZ = 1,
- GPIO_Speed_2MHZ,
- GPIO_Speed_50MHZ
- }GPIOSpeed_TypeDef;//枚举类型的别名
-
- typedef enum
- {
- GPIO_Speed_10MHZ = 1,
- GPIO_Speed_2MHZ = 2,
- GPIO_Speed_50MHZ = 3
- }GPIOSpeed_TypeDef;
- //完整写法
STM32引脚工作模式
- bit0和bit1对应寄存器的MODEy[1:0]位。
- bit2和bit3对应寄存器的CNFy[1:0]位。
如下图所示
引脚初始化是由CRL或者CRH寄存器确定的,其中CRL确定低8位,CRH确定高8位。
GPIO_Init函数配置的就是对应引脚的这4个位,再将这4个位写入到对应引脚的寄存器。
GPIO_Init函数
- 设置一个存放4个位的变量值,用来配置bit0、bit1、bit2、bit3
- 根据bit4,判断输入还是输出:0为输入,1为输出(输出要添加速度值)
- 再确定具体引脚:低8位,高8位
- 最后写入相应的模式
GPIO_Init函数原型:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
其中,GPIOx是GPIO端口,GPIO_InitTypeDef是GPIO配置结构体,包含了GPIO端口和各个引脚的配置信息。
- //PA2推挽输出,输出速度50MHZ
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.PIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA,&GPIO_InitStructure);
-
-
- GPIO_InitStructure.GPIO_Pin = 0b0000 0100;
- GPIO_InitStructure.GPIO_Mode = 0x10;
- GPIO_InitStructure.GPIO_Speed = 0x03;
- GPIO_Init(GPIOA,&GPIO_InitStructure);
展开第一个加号:
第一条语句:
将低4位暂存在currentmode中
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode)& ((uint32_t)0x0F);
即 currentmode = 0x10 & 0x0F = 0001 0000 & 0000 1111=0x00(&遇0则0)
第二条if语句:
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode)& ((uint32_t)0x10)) != 0x00)
{
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
bit4为1表示输出,bit4为0表示输入
这样0x10&0x10,即0001 0000&0001 0000,刚好判断第4位的值不等于0,执行if中语句
currentmode |=0x03,即currentmode=currentmode|0x03,即currentmode=0x00&0x03=0x03
注:
a&=b; == a=a&b;a|=b; == a=a|b;
展开第2个加号:
if语句判断GPIO_Pin & 0x00FF是否等于0,不等于则进入if循环语句
进入for语句第1次循环,此时pinpos为0
pos = 0x01<<0,pos = 0x01
currentpin = 0b0000 0100&0x01 = 0
if (currentpin == pos)不成立,跳过if语句
进入for语句第2次循环,此时pinpos为1
pos = 0x01<<1,pos = 0x02(0b0000 0010)
currentpin = 0b0000 0100&0x02 = 0
if (currentpin == pos)不成立,跳过if语句
进入for语句第3次循环,此时pinpos为2
pos = 0x01<<2,pos = 0x04(0b0000 0100)
currentpin = 0b0000 0100&0x04 = 0x04
if (currentpin == pos)成立,进入if语句
pos = pinpos<<2 = 8 //pos的值为具体引脚值*4(左移两位=乘4)
pinmask=0x0F<<8=0b0000 1111<<8=0b0000 1111 0000 0000
tmperg =tmperg&~pinmask=tmperg&1111 0000 1111 1111
tmperg |=currentmode<<pos
即tmperg |=0x03<<8=0b0011<<8 //推挽输出,最大速度50MHZ
- //PA2上拉输入
- GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_Init(GPIOA,&GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = 0b0000 0100;
- GPIO _InitStructure.GPIO_Mode= 0b0100 1000;
- GPIO_Init(GPIOA, &GPIO_Initstructure:
第一条语句:
将低4位暂存在currentmode中
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode)& ((uint32_t)0x0F);
即 currentmode = 0x48 & 0x0F = 0100 1000 & 0000 1111=0x08
第二条if语句:
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode)& ((uint32_t)0x10)) != 0x00)
{
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
bit4为1表示输出,bit4为0表示输入
0100 1000&0001 0000,判断第4位的值等于0,if语句不执行
剩余具体方法参考1)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。