本帖最后由 GCT 于 2022-7-28 16:16 编辑
入门第十四课《位带操作—GPIO输出和输入》 对于“位带操作”的理解 以及七色灯 入门篇 第十四课题目:
经过从寄存器操作到库函数开发的一系列转变,可以很清楚的认识到使用库函数变成的方便直观之处。 在头文件中进行复杂宏定义以后,main函数中的操作可以简化到极致,可读性max
例如LED_Green(OFF),一个不懂程序的人也能明白这个函数作用是关绿色LED灯。
stm32中可以使用BSR、BSRR寄存器,使用例如SetBits()、ResetBits()一类的函数,改变IDR、ODR相应的位的值。但是不能进行“位操作”,即单独对一个位读或写。 据说51单片机中可以实现Px=1、Px=0这样的位操作,但是在stm32里是不合法的,这就需要进行位带操作了。
对于“位带操作”,如果刚接触去看这么大段概念,是很抽象的。我也懵了好久,什么外设位带区、SRAM位带区,位带别名区,比特位膨胀......%¥*@...还是云里雾里的。 直到看到某个网页的博主这样的解读以后,我才基本理解。 一个很形象的比喻:可以把寄存器的每一位看成一户一户人家。“GPIOx”的“x”其实可以看成楼层。比如绿LED的PB0可以看做第B层的0室,按照现实中的门牌号就是2层1室201。 201住着你的好朋友,你要给ta寄东西。但是在他们的社区规定,不能给具体的哪一家送东西,但是可以寄给居委会。那如果要邮寄,写的地址就不能是xxx的201,这样收不到。 要新起一个名字,叫居委xxx,这样你的好朋友就能收到东西了。感觉上好像给了更高一级的单位,但是最终的目标还是每一户。
在STM32中不允许对单一端口进行位操作,不允许PB0=1。给它另外起一个别名,把地址扩展成32位的字地址,再去位操作就可以了。这种对于单一端口进行的操作就是位带操作。
位带地址转换别名地址的公式:
根据参考手册可以算出IDR、ODR的起始地址。根据需要,GPIOA、GPIOC用于按键输入;GPIOB用于LED输出,所以定义三个函数PAin、PCin、PBout。 公式中的 位带地址 替换为 寄存器的起始地址,位带序号 替换为 端口号。 定义如下:
在定义完这个三句后,就可以像51里的那样对一个一个位进行操作了。
题外话:LED灯理论上可以显示255种颜色。如果不用PWM控制,似乎只能通过三原色的合成来实现7种颜色的显示。
为了方便控制,可以把每一种颜色的情况都定义在宏定义 方案一:在LED_TOGGLE后面加了个参数,参数是颜色名。
如果要运用一种颜色的灯,则像这样调用:
方案二:把每一种颜色都定义为单独的宏定义
如要运用,可以直接使用宏定义的标识符。 为方便后续移植,将位带序号也定义为宏。
将三个LED端口进行宏定义并依次初始化
初始化(输出引脚、推挽输出、速度50MHz)
初始化以后要将那一位置1,不然灯会先亮。
键盘的两个端口也同样宏定义并初始化
初始化(输入端口、浮空输入模式)
按键检测部分可以写到主函数里,在头文件里就不写了。
在主函数写入一个while循环,让它一直检测按键。
if的作用是判断按键是否按下,if条件中的while判断按键是否松开,如果松开就跳出循环。 while下面就可以添加按键的功能了。 如果想让左按键实现红灯的亮灭、右按键实现蓝灯的亮灭,就使用LED_XXX_TOGGLE。PA条件下写LED_RED_TOGGLE,PC条件下写LED_BLUE_TOGGLE。 如果想让左按键实现紫灯的点亮、右按键实现青色(靛)灯的亮灭,就使用LED_XXX。PA条件下写LED_PURPLE,PC条件下写LED_CYAN。 在这里已经可以实现七种颜色灯的点亮了。
(在使用LED_XXX的情况下是不能关闭灯的,可以进行灯的切换而颜色不会叠加,关闭灯用LED_OFF)
最终代码: bsp_key.h - #ifndef __BSP_KEY_H
- #define __BSP_KEY_H
- #include "stm32f10x.h"
- #define KEY_ON 1
- #define KEY_OFF 0
- #define KEY1_GPIO_PIN GPIO_Pin_0
- #define KEY1_GPIO_PORT GPIOA
- #define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA
- #define KEY2_GPIO_PIN GPIO_Pin_13
- #define KEY2_GPIO_PORT GPIOC
- #define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC
- void KEY_GPIO_Config(void);
- #endif /*__BSP_KEY_H*/
复制代码
bsp_key.c
- #include "bsp_key.h"
- void KEY_GPIO_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
-
- RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK, ENABLE);
-
- GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
-
- GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);
-
- RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK, ENABLE);
-
- GPIO_InitStruct.GPIO_Pin = KEY2_GPIO_PIN;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
-
- GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStruct);
- }
复制代码
bsp_led.h
- #ifndef __BSP_LED_H
- #define __BSP_LED_H
- #include "stm32f10x.h"
- #define LED_Red_GPIO_PIN GPIO_Pin_5
- #define LED_Red_GPIO_PORT GPIOB
- #define LED_Red_CLK RCC_APB2Periph_GPIOB
- #define LED_Green_GPIO_PIN GPIO_Pin_0
- #define LED_Green_GPIO_PORT GPIOB
- #define LED_Green_CLK RCC_APB2Periph_GPIOB
- #define LED_Blue_GPIO_PIN GPIO_Pin_1
- #define LED_Blue_GPIO_PORT GPIOB
- #define LED_Blue_CLK RCC_APB2Periph_GPIOB
- #define Red 5
- #define Green 0
- #define Blue 1
- #define GPIOB_ODR_Addr (GPIOB_BASE+0x0C)
- #define PBout(n) *(unsigned int*)((GPIOB_ODR_Addr & 0xF0000000)\
- +0x2000000+((GPIOB_ODR_Addr & 0x00FFFFFF)<<5)+(n<<2))
- #define GPIOA_IDR_Addr (GPIOA_BASE+0x08)
- #define PAin(n) *(unsigned int*)((GPIOA_IDR_Addr & 0xF0000000)\
- +0x2000000+((GPIOA_IDR_Addr & 0x00FFFFFF)<<5)+(n<<2))
- #define GPIOC_IDR_Addr (GPIOC_BASE+0x08)
- #define PCin(n) *(unsigned int*)((GPIOC_IDR_Addr & 0xF0000000)\
- +0x2000000+((GPIOC_IDR_Addr & 0x00FFFFFF)<<5)+(n<<2))
- #define LED_RED_TOGGLE {LED_Red_GPIO_PORT->ODR ^=LED_Red_GPIO_PIN;}
- #define LED_GREEN_TOGGLE {LED_Green_GPIO_PORT->ODR ^=LED_Green_GPIO_PIN;}
- #define LED_BLUE_TOGGLE {LED_Blue_GPIO_PORT->ODR ^=LED_Blue_GPIO_PIN;}
- #define LED_WHITE_TOGGLE {LED_Red_GPIO_PORT->ODR ^=LED_Red_GPIO_PIN;\
- LED_Green_GPIO_PORT->ODR ^=LED_Green_GPIO_PIN;\
- LED_Blue_GPIO_PORT->ODR ^=LED_Blue_GPIO_PIN;}
- #define LED_YELLOW_TOGGLE {LED_Red_GPIO_PORT->ODR ^=LED_Red_GPIO_PIN;\
- LED_Green_GPIO_PORT->ODR ^=LED_Green_GPIO_PIN;}
- #define LED_PURPLE_TOGGLE {LED_Red_GPIO_PORT->ODR ^=LED_Red_GPIO_PIN;\
- LED_Blue_GPIO_PORT->ODR ^=LED_Blue_GPIO_PIN;}
- #define LED_CYAN_TOGGLE {LED_Green_GPIO_PORT->ODR ^=LED_Green_GPIO_PIN;\
- LED_Blue_GPIO_PORT->ODR ^=LED_Blue_GPIO_PIN;}
-
- #define LED_RED {PBout(Red)=0;PBout(Green)=1;PBout(Blue)=1;}
- #define LED_GREEN {PBout(Red)=1;PBout(Green)=0;PBout(Blue)=1;}
- #define LED_BLUE {PBout(Red)=1;PBout(Green)=1;PBout(Blue)=0;}
- #define LED_WHITE {PBout(Red)=0;PBout(Green)=0;PBout(Blue)=0;}
- #define LED_YELLOW {PBout(Red)=0;PBout(Green)=0;PBout(Blue)=1;}
- #define LED_PURPLE {PBout(Red)=0;PBout(Green)=1;PBout(Blue)=0;}
- #define LED_CYAN {PBout(Red)=1;PBout(Green)=0;PBout(Blue)=0;}
- #define LED_OFF {PBout(Red)=1;PBout(Green)=1;PBout(Blue)=1;}
- void LED_GPIO_Config(void);
- #endif /*__BSP_LED_H*/
复制代码
bsp_led.c
- #include "bsp_led.h"
- void LED_GPIO_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
-
- RCC_APB2PeriphClockCmd(LED_Red_CLK, ENABLE);
- GPIO_InitStruct.GPIO_Pin = LED_Red_GPIO_PIN;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(LED_Red_GPIO_PORT, &GPIO_InitStruct);
- GPIO_SetBits(LED_Red_GPIO_PORT, LED_Red_GPIO_PIN);
-
- RCC_APB2PeriphClockCmd(LED_Green_CLK, ENABLE);
- GPIO_InitStruct.GPIO_Pin = LED_Green_GPIO_PIN;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(LED_Green_GPIO_PORT, &GPIO_InitStruct);
- GPIO_SetBits(LED_Green_GPIO_PORT, LED_Green_GPIO_PIN);
-
- RCC_APB2PeriphClockCmd(LED_Blue_CLK, ENABLE);
- GPIO_InitStruct.GPIO_Pin = LED_Blue_GPIO_PIN;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(LED_Blue_GPIO_PORT, &GPIO_InitStruct);
- GPIO_SetBits(LED_Blue_GPIO_PORT, LED_Blue_GPIO_PIN);
- }
复制代码
main.c- #include "stm32f10x.h" // 相当于51单片机中的 #include <reg51.h>
- #include "bsp_led.h"
- #include "bsp_key.h"
- int main(void)
- {
- // 来到这里的时候,系统的时钟已经被配置成72M。
- LED_GPIO_Config();
- KEY_GPIO_Config();
-
- while(1)
- {
- if(PAin(0) ==KEY_ON)
- {
- while(PAin(0) ==KEY_ON);
- //LED_PURPLE;
- //LED_RED_TOGGLE;
- }
- if(PCin(13) ==KEY_ON)
- {
- while(PCin(13) ==KEY_ON);
- //LED_CYAN;
- //LED_BLUE_TOGGLE;
- }
- }
- }
复制代码
|