学习笔记(三)

 1.用结构体方式构建库

首先解释一下如何让本指向此寄存器第一位的指针指向全部寄存器 

GPIOB_BASE地址为0x40010C00,和GPIOB_CDL地址是一样的

经过宏定义可知GPIOB_BASE是地址,地址就是指针,所以GPIOB_BASE是一个指针,其内存是32位(在stm32中,外设的寄存器的长度都是32位的,因此指针的类型也是32位),GPIOB也是寄存器,所以内存也是32位,内存大小刚好可以对应起来,那么可以实现通过GPIOB_BASE访问整个GPIOB,而不是其中的CDL,为了达到这个目的,将GPIOB_BASE强制类型转换为GPIO_TypeDef类型。(GPIO_TypeDef*)GPIOB_BASE

建结构体犯得错

结构体里的变量是有数据类型的,别乱写

定义宏的时候写上名儿,不然你定义谁呢,服了

 

 写反了结构体名字 ,导致主函数无法用->方式调用CRL寄存器,依葫芦画瓢还能写反了,6

作业

typedef struct{
	uint32_t CR;
	uint32_t CFGR;
	uint32_t CIR;
	uint32_t APB2RSTR;
	uint32_t APB1RSTR;
	uint32_t AHBENR;
  uint32_t APB2ENR;
	uint32_t APB1ENR;
	uint32_t BDCR;
	uint32_t CSR;
}RCC_Typedef;
#define RCC ((RCC_Typedef*)RCC_BASE)

用函数的方式点灯

新建置位BSRR,清零BRR函数

void   bitset(gpiob,pb0)置一(关灯){

直接让位设置寄存器=pb0(所以要先定义好pb0这块的宏)

}

 2.防止重复定义头文件

解决办法:添加如下代码

每写一个头文件,都记得添加一个宏,一般以文件的名字定义宏

防止重复定义头文件不是让你可以省略#include这一步,别忘了#include “stm32f10x,h”

#ifndef_STM32F10X_GPIO_H
#def_STM32F10X_GPIO_H




#endif/*_STM32F10X_GPIO_H*/

别写错头文件

是if not define,别写丢了

3.另一种方式实现置一操作点亮LED

自己构建库函数

 定义如下宏文件

#define GPIO_PIN_1   ((uint16_t)0x0001)   //00000000 00000001
#define GPIO_PIN_2   ((uint16_t)0x0002)   //00000000 00000010
#define GPIO_PIN_3   ((uint16_t)0x0004)   //00000000 00000100
#define GPIO_PIN_4   ((uint16_t)0x0008)   //00000000 00001000
#define GPIO_PIN_5   ((uint16_t)0x0010)   //00000000 00010000
#define GPIO_PIN_6   ((uint16_t)0x0020)   //00000000 00100000
#define GPIO_PIN_7   ((uint16_t)0x0040)   //00000000 01000000
#define GPIO_PIN_8   ((uint16_t)0x0080)   //00000000 10000000
#define GPIO_PIN_9   ((uint16_t)0x0100)   //00000001 00000000
#define GPIO_PIN_10   ((uint16_t)0x0200)   //00000010 00000000
#define GPIO_PIN_11   ((uint16_t)0x0400)   //00000100 00000000
#define GPIO_PIN_12   ((uint16_t)0x0800   //00001000 00000000
#define GPIO_PIN_13   ((uint16_t)0x1000)   //00010000 00000000
#define GPIO_PIN_14   ((uint16_t)0x2000)   //00100000 00000000
#define GPIO_PIN_15   ((uint16_t)0x4000)   //01000000 00000000
#define GPIO_PIN_16   ((uint16_t)0x8000)   //10000000 00000000

定义的时候别忘了写上数据类型

干嘛呢,这是

 不需要特意指定x是几,所有的GPIO都有这些引脚

新建函数

错误一:函数变量与内部不对应

void GPIO_Setbits(GPIO_TypeDef*GPIOx,uint16_t GPIO_PIN_x)

{
     GPIO->BSRR |=GPIO_PIN;
}

正确的

利用BSR

0:对应ODRy位为0

1:不产生效果

void CPIO_Setbits(GPIO_TypeDef*GPIOx,uint16_t GPIO_PIN)
{
   GPIOB->BSR |=GPIO_PIN; 
}

在.c文件里写的函数,别忘记去对应的.h文件里添加声明

定义初始化寄存器结构体

前面的课程中点亮LED需要先给时钟使能,然后设置输出模式,这两部都需要查询手册才知道,可移植性不高,初始化寄存器结构体的目的就是,将使能和设置输出模式这两部放到初始化中

strucr{
    GPIO_PIN_X//选择设置的引脚(Px0是0x0001,Px1是0x0002,Px5是0x0020)
    GPIO_Speed//CRL中的速度
    GPIO_Mode//输入输出模式
}GBPO_InitTypedef

错误总结:1.定义结构体的名字是typedef struct,不是只有struct

                  2.结构体内部成员变量别忘了写数据类型,此数据类型不需要加括号

                  3.别打错字

正确写法

 Mode和Speed采用enum方式声明,枚举定义enum,enum里面是逗号,配置第一个值后,后面值会自动+1

为什么用枚举?

速度是uint16_t,也就是16位的,取值范围有65536(2^16)这么多,而CRL里的速度只有2,10,50三种,为了防止犯错,又没有必要写成十六进制,枚举就解决了这个问题,只在枚举的范围内取值,并且配置第一个值后,后面值会自动+1。

以下两种命名方式都可以,但是库艰苦采用了右边的方式,为了方便以后使用,所以和固件库同名

 模式

其实没有必要弄明白固件库的每一位是如何对应CNF[1:0]和MODE[1:0],只要会用就行,只要后面弄懂自己写的库的逻辑就好

 bit0和bit1对应速度,速度前面单独定义过了,所以这里不写,到时候会加上速度

bit3,bit2对应了中文参考手册中的MODE位

bit4是输入输出设置位,0输入,1输出

 上拉输入和下拉输入除了要看bit6,bit5,还需要BSRR和BRR寄存器的参与

下拉输是接地,所以BRR中PBx位要置一;上拉是接高电平,所以BSRR中PBx位要置一

 GPIO_Init

这里笔者就分析一下低八位的代码

在分析说一下,GPIO一共有16个io口,CRL控制Px0-Px7,剩下八个由CRH寄存器控制

我们假设选择推挽输出模式,对应的GPIO_MODE就是0x10,速度选择0x01,IO口选择PB1

以下分析的时候,没有0x都是二进制

line 79:currentmode=0001 0000 & 0000 1111=0000 0000;

line 83:if(0001 0000 & 0001 0000) 结果不等于0000 0000,所以到

line 86:选择速度GPIO_Speed=0000 0001;

currentmode |=理解为 currentmode= currentmode |  GPIO_Speed;

也就是currentmode=0000 0000 | 0000 0001=0000 0001;到这里,速度模式就选好了

插一嘴,如果不明白line 86,可以查一下C语言里的这些运算  |= ,*=,+=, &=,都是一个意思,需要我写的话,可以留言 

由于前面我们已经选好了CRL的速度和模式,现在还差PB1没有选,下面就进入IO口的选择

line 93:先将配置好的速度模式存入temreg(temp register)=0001 

这一步需要注意的是,其实CRL寄存器的是没有办法每一位都和GPIO_MODE对应上的,通过上述判断编译器已经确定了是推挽输出,并且速度是10MHz,也就是说,CRL目前的值就是0001

接下来就是判断到底Px几是0001了

line 96: 进入for循环 pinpos起始值是0000 0000,且小于0000 1000

line 99:pos=0000 0001左移pinpos(pinpos此时为零,相当于没有移动)=0000 0001

line 102: currentpin=00000000 00000010 & 00000000 00000001=0x0000

line 105: currentpin是0x0000,pos是0x0001,二者明显不相等,所以不进if,直接到ine 122的else

line 125: 我们选择的GPIO_MODE是0x10,不等于0x48,所以不进line 128的if

直接到line 134,目前CRL寄存器里的值就是temreg,然后再次进入for循环,此时pinpos=0x01

line 99:pos=0000 0001左移0000 0001,也就是pos=00000010;

line102:currentpin=00000000 00000010 & 00000000 00000010=0x0002   

line105: 此时currentpin=pos都为00000000 00000010;进入if

line108:pos=0000 0001<<2=0000 0100(4b,二进制的值是4)

line110: pinmask=0000 1111<<4=1111 0000

对于line111行,PB1的话清空的是CRL里的4,5,6,7四位,手册里有写,复位值是0x4444 4444

也就是复位值是八个0100,所以没有选的引脚都是0100,

如果是PB3的话就是0001 0100 0100 & 0000 1111 1111  

line111: tmpreg & 0000 1111=0001 0100 & 0000 1111=0000 0100

line114:tmpreg=tmpreg | (0000 0001<<4)=tmpreg |  0001 0000

                                                                 =0001 0100 | 0001 0000=0001 0100

line117:我们选择了开漏,肯定不是GPIO_ODE_IPD,所以不近if,直接到134

最终输出模式就是0100 0100 0100 0100 0100 0100 0001 0100,也就是PB1是0001

至此低八位就分析完了,高八位同样,因为我自己分析了第八位,所以高八位我也理解,就不再此分析了,有需要的话留言,我在补上。

再加一句,在看这段代码的时候,低八位IO口由CRL寄存器控制,高八位由CRH控制,可见一共有16个IO,但是我在指南者板子上只看到了12个,这是因为,能够开放给我们使用的是12个,像一些电源比如3V,5V,GND的引脚已经封装好了。

这部分我犯得错误

首先是初始化不写初始化函数、GPIO_Init让你吃了??

 有初始化函数了还需要打开时钟,别忘了

最后就是视频里提到的,定义变量必须在{之后,不然的话会报错

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值