目录
- 1. 看原理图
- 2 使能GPIOA+GPIOA时钟模块
- 2.2 设置引脚GPIO输入
- 2.3 读取引脚值
- 3. 关于寄存器操作的思考
写在前面
注意,这篇文章虽然说是用按键控制led亮灭,重点不在代码,而是关键核心的描述。
用寄存器的方式,通过key来控制led的亮灭,在各种封装库存在且算力充沛的情况下,是否还有必要用这么底层的方式来写代码呢?
事实上,实际工作中是不需要的,但是学习中,是一定要的,只有这样我们才能理解真实的代码世界是什么样的。
那么真实的代码是什么样的?其实就是一个个拨码开关,不断的开,关,通,断,如果我们肉眼能看到代码运行的世界,我相信那里一定色彩斑斓!
1. 看原理图
-
我们使用KEY1来控制红色LED:按下KEY1则灯亮,松开后灯灭
-
KEY1用的是PA0引脚
2 使能GPIOA+GPIOA时钟模块
RCC_APB2ENR地址:0x40021000 + 0x18
很明显,要想使能GPIOA,就要把第3和4设置成1,
对应下面的代码:
unsigned int *pReg;
unsigned int *pRegA;
unsigned int *pRegB;/*使能GPIOB, GPIOA */
pReg = (unsigned int *)(0x40021000 + 0x18);//找到对应的寄存器位置
*pReg |= (1<<3) | (1<<2);
//这里的计算分为两步,(1<<3) | (1<<2)计算,使其第三位和第四位都是1的32位数据,然后通过*pReg |,把1并入到第三位第四位寄存器中。
2.2 设置引脚GPIO输入
GPIOA_CRL地址:0x40010800 + 0x00
/* 设置GPIOB为输出引脚 */
pRegB = (unsigned int *)(0x40010C00 + 0x00);
*pRegB |= (1<<0);/*设置GPIOA0Î输入引脚*/
pRegA = (unsigned int *)(0x40010800 + 0x00);
*pRegA &= ~(3); /* mode0 = 0b00 */
*pRegA &= ~(3<<2); /* cnf0 = 0b00 */
*pRegA |= (1<<2); /* cnf0 = 0b01 */
2.3 读取引脚值
GPIOA_IDR 地址:0x40010800 + 0x08
/* GPIOB output data register */
pRegB = (unsigned int *)(0x40010C00 + 0x0C);/* GPIOA input data register */
pRegA = (unsigned int *)(0x40010800 + 0x08);/* 读取GPIOA input data register */*pRegA & (1<<0)) == 0 /* KEY1被按下*/
*pRegB &= ~(1<<0);//设置GPIOB输出0
*pRegB |= (1<<0);//设置GPIOB输出1
3. 关于寄存器操作的思考
*pRegA & (1<<0)) == 0 /* KEY1被按下*/
*pRegB &= ~(1<<0);//设置GPIOB输出0
*pRegB |= (1<<0);//设置GPIOB输出1
逻辑与和逻辑或,其实有点哲学意义上的对立和统一。
逻辑或:非常简单的逻辑。只要双方有一个是1,那么或运算必然是1。
1.逻辑或,1和1之间的相互成就。在逻辑或的世界里,1拥有绝对的power,不论遇见什么都会同化为1。 可以说,人难得糊涂,事业才能越做越大。
逻辑与:只要双方有一个是0,那么结果必然是0,逻辑与就像对0有洁癖的家伙,
2.逻辑与,0和0之间的相互擦除,在逻辑与的世界里,0拥有绝对的power,不论遇见什么都会同化0。 可以说,底层人的相互拉踩,才是真正的阶层固化。
总结起来,我们要是想把1作为抓手,就用或,像用0作为抓手,就用与。
比如:
我们需要让寄存器某些位置1的时候用,我们就用或,不论什么位,碰见1就变1。
我们要把某些位清零的时候用,我们就用与。不论什么位,碰见0就变0.
那么我们把上面的案例拿过来看看。
*检测pRegA & (1<<0)) == 0 // KEY1被按下
我们要检测某些位是不是1,那么就要把其他的位用0干掉,一定是用,那么必然我们要把其他位干掉,要用与。
*pRegB &= ~(1<<0);设置GPIOB输出0:我们要设置对应的位为0,首先确定最终必然要用与。
*pRegB |= (1<<0);//设置GPIOB输出1:我们要设置对应的位为0,首先确定最终必然要用或。