当前位置:   article > 正文

STM32学习笔记——仿库函数写法点亮LED_uint32_t crl; uint32_t crh; uint32_t idr; uint32_t

uint32_t crl; uint32_t crh; uint32_t idr; uint32_t odr; uint32_t bsrr; uint3

参考海创电子的STM32视频。

1.头文件

头文件作为一种包含功能函数、数据接口声明的载体文件

#include <stm32f10x.h>                #include "stm32f10x.h"
<>:Keil自带的头文件,只要写上能自动去相应的文件夹加载!
“ ”:自定义的头文件,使用的时候一定要指明路径!

 如:

  1. #define PERIPH_BASE 0X4000 0000//总线基地址
  2. #define ABP1PERIPH_BASE PERIPH_BASE
  3. #define ABP2PERIPH_BASE (PERIPH_BASE+0x40010000)
  4. #define AHBPERIPH_BASE (PERIPH_BASE+0x40020000)
  5. #define GPIOC_BASE (ABP2PERIPH_BASE+0X00010000)
  6. #define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0X04)

 2.结构体

 将上面图片用结构体表示:

  1. typedef struct
  2. {
  3. uint32_t CRL;
  4. uint32_t CRH;
  5. uint32_t IDR;
  6. uint32_t ODR;
  7. uint32_t BSRR;
  8. uint32_t BRR;
  9. uint32_t LCKR;
  10. }GPIO_TypeDef;//总名字,上面中括号里是他的“成员”

但结构体只有名字没有地址,需要和第一章结合起来。

(GPIO_TypeDef*)GPIOC_BASE//GPIOC_BASE表示0x4001 1000,加“*”将其转化为地址

 引用结构体中的成员:

  1. ((GPIO_TypeDef*)GPIOC_BASE)->ODR;
  2. //"->"是对结构体指针变量的引用
  3. //由于((GPIO_TypeDef*)GPIOC_BASE)过于长,进行如下定义
  4. #define GPIOC ((GPIO_TypeDef*)GPIOC_BASE)
  5. GPIOC->ODR;

3.模块化

 模块化编程是将大型程序分解为互相独立的小模块,每个模块负责特定的功能,以便更方便地阅读、维护和复用代码,主要分为源文件(*.c)和头文件(*.h)两部分。

源文件(*.c)

  • 各个函数的具体形式

头文件(*.h)

  • 各个函数的声明
  • define函数的定义
  • 结构体

输出高电平用BSRR寄存器。

 输出低电平用BRR寄存器。

输出高、低电平具体函数形式

GPIOC->BSRR =|1<<13

但是还有GPIOA/GPIOB/GPIOD……

希望有个函数能够识别是哪个组哪个引脚! 

  1. void GPIO_SitBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
  2. {
  3. GPIOx->BSRR|=GPIO_Pin;
  4. }
  5. void GPIO_ResitBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
  6. {
  7. GPIOx->BSRR|=(GPIO_Pin+16);
  8. }
  9. void GPIO_ResitBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
  10. {
  11. GPIOx->BRR|=GPIO_Pin;
  12. }

定义引脚:

  1. #define GPIO_Pin_0 ((uint16_t)0x0001)//二进制:0b0000 0001
  2. #define GPIO_Pin_1 ((uint16_t)0x0002)//二进制:0b0000 0010
  3. #define GPIO_Pin_2 ((uint16_t)0x0004)//二进制:0b0000 0100
  4. #define GPIO_Pin_3 ((uint16_t)0x0008)
  5. #define GPIO_Pin_4 ((uint16_t)0x0010)
  6. #define GPIO_Pin_5 ((uint16_t)0x0020)
  7. #define GPIO_Pin_6 ((uint16_t)0x0040)
  8. #define GPIO_Pin_7 ((uint16_t)0x0080)
  9. #define GPIO_Pin_8 ((uint16_t)0x0100)
  10. #define GPIO_Pin_9 ((uint16_t)0x0200)
  11. #define GPIO_Pin_10 ((uint16_t)0x0400)
  12. #define GPIO_Pin_11 ((uint16_t)0x0800)
  13. #define GPIO_Pin_12 ((uint16_t)0x1000)
  14. #define GPIO_Pin_13 ((uint16_t)0x2000)
  15. #define GPIO_Pin_14 ((uint16_t)0x4000)
  16. #define GPIO_Pin_15 ((uint16_t)0x8000)

枚举

  • 变量的值依次增加1,可以将后面具体值省略
  • 若变量增加不是1,需要写出具体值
  • 若未指定值,第一个枚举成员默认值为0,没有指定值的枚举元素,其值为前一元素值加1
  1. typedef enum
  2. {
  3. GPIO_Speed_10MHZ = 1,
  4. GPIO_Speed_2MHZ,
  5. GPIO_Speed_50MHZ
  6. }GPIOSpeed_TypeDef;//枚举类型的别名
  7. typedef enum
  8. {
  9. GPIO_Speed_10MHZ = 1,
  10. GPIO_Speed_2MHZ = 2,
  11. GPIO_Speed_50MHZ = 3
  12. }GPIOSpeed_TypeDef;
  13. //完整写法

 STM32引脚工作模式

  • bit0bit1对应寄存器的MODEy[1:0]位。 
  • bit2bit3对应寄存器的CNFy[1:0]位。 

如下图所示

引脚初始化是由CRL或者CRH寄存器确定的,其中CRL确定低8位,CRH确定高8位。

GPIO_Init函数配置的就是对应引脚的这4个位,再将这4个位写入到对应引脚的寄存器。

GPIO_Init函数

  1. 设置一个存放4个位的变量值,用来配置bit0、bit1、bit2、bit3
  2. 根据bit4,判断输入还是输出:0为输入,1为输出(输出要添加速度值)
  3. 再确定具体引脚:低8位,高8位
  4. 最后写入相应的模式

4. GPIO_Init函数分析

 GPIO_Init函数原型:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

其中,GPIOx是GPIO端口,GPIO_InitTypeDef是GPIO配置结构体,包含了GPIO端口和各个引脚的配置信息。 

1)PA2推挽输出,输出速度50MHZ

  1. //PA2推挽输出,输出速度50MHZ
  2. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  3. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  4. GPIO_InitStructure.PIO_Speed = GPIO_Speed_50MHz;
  5. GPIO_Init(GPIOA,&GPIO_InitStructure);
  6. GPIO_InitStructure.GPIO_Pin = 0b0000 0100;
  7. GPIO_InitStructure.GPIO_Mode = 0x10;
  8. GPIO_InitStructure.GPIO_Speed = 0x03;
  9. 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

 2)PA2上拉输入

  1. //PA2上拉输入
  2. GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;
  3. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  4. GPIO_Init(GPIOA,&GPIO_InitStructure);
  5. GPIO_InitStructure.GPIO_Pin = 0b0000 0100;
  6. GPIO _InitStructure.GPIO_Mode= 0b0100 1000;
  7. 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)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/280985
推荐阅读
相关标签
  

闽ICP备14008679号