在使用库函数之前,我们先来看GPIO寄存器的结构体
该结构体中的成员,包含了引脚,输出速度,输出模式。我们可以使用这个结构体来对I/O口进行配置。
GPIO_InitTypeDef GPIO_InitStruct; //定义一个结构体,用来需要配置的寄存器信息
void LED_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //配置的引脚为Pin6引脚
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz; //配置输出速度为2Mhz
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //配置输出模式为通用推挽输出
GPIO_Init( GPIOC, &GPIO_InitStruct); //配置的I/O口组为GPIOC组 //只要用到I/O口,就一定会用到GPIO_Init(); 函数
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; /*配置的引脚为Pin7引脚,由于输出速度与输出模式还在结构体里面。所以这里 不用重新在配置一次 输出速度与输出模式 */
GPIO_Init( GPIOC, &GPIO_InitStruct); //配置的I/O口组为GPIOC组
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //配置的引脚为Pin8引脚
GPIO_Init( GPIOC, &GPIO_InitStruct); //配置的I/O口组为GPIOC组
LED_Close();//关灯
}
void LED_Open(void) //开灯
{
GPIO_WriteBit( GPIOC, GPIO_Pin_6, Bit_RESET); //设置GPIOC的Pin_6引脚输出低电平
GPIO_WriteBit( GPIOC, GPIO_Pin_7, Bit_RESET);
GPIO_WriteBit( GPIOC, GPIO_Pin_8, Bit_RESET);
}
void LED_Close(void) //关灯
{
GPIO_WriteBit( GPIOC, GPIO_Pin_6, Bit_SET); //设置GPIOC的Pin_6引脚输出高电平
GPIO_WriteBit( GPIOC, GPIO_Pin_7, Bit_SET);
GPIO_WriteBit( GPIOC, GPIO_Pin_8, Bit_SET);
}
实际上,关于初始化函数,我们还可以写成:
void LED_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8; //这里将各个引脚进行 | 操作,就可以一下配置多个引脚
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init( GPIOC, &GPIO_InitStruct);
GPIO_WriteBit( GPIOC, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 , Bit_SET); //关灯,这里也可以进行多个一起配置
}
为什么多个引脚可以一起配置呢?
我们可以看到16个引脚的宏定义的值是多少,那么这些值是怎么来的呢?
我们用ODR寄存器来举例。如果只想要GPIO_Pin_1置1,那么ODR寄存器的值就是0000 0000 0001(即:0x0001),只想要GPIO_Pin_2置1,那么ODR寄存器的值就是0000 0000 0010(即:0x0002),只想要GPIO_Pin_3置1,那么ODR寄存器的值就是0000 0000 0100(0x0004),只想要GPIO_Pin_4置1,那么ODR寄存器的值就是0000 0000 1000(0x0008)
以此类推,GPIO_Pin_5的ODR寄存器值为0000 0001 0000(0x0010)
GPIO_Pin_6的ODR寄存器值为0000 0010 0000(0x0020)
GPIO_Pin_7的ODR寄存器值为0000 0100 0000(0x0040)
GPIO_Pin_8的ODR寄存器值为0000 1000 0000(0x0080)
所以,我们看到,在寄存器中,每个引脚的设置值的位权分别是8、4、2、1(即BCD码)
我们知道:
8 == 1000
4 == 0100
2 == 0010
1 == 0001
它们相互进行位与操作,并不会影响各自的"1",即:不改变位权。利用这个特性,有如下代码来判断,哪个是哪个引脚:
上图是库函数关于GPIO_CRL寄存器中引脚配置的源码
我们来看Pin6与Pin7引脚,我们都知道Pin6与Pin7的选择都是在GPIO_CRL寄存器中配置
其中这一段代码,一开始pinpos为0,所以0x01<<0,即还是0x01,所以pos == 0x01,然后用前面的
(GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8) & 0x01,如果与下来的结果为1,这样就可以判断是不是GPIO_Pin_1被选择了。
然后,下一次循环,pinpos + 1,则0x01<<1,则变成0x02,(GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8) & 0x02,如果与下来的结果为1,这样就可以判断是不是GPIO_Pin_2被选择了。然后,如此循环,直到0x01<<8。这里只移动8位是因为该寄存器是低位寄存器,只配置Pin0~Pin7引脚。
所以:
我们只要在源码中看到某成员的宏定义数值为8、4、2、1这样的结构,我们就可以写成GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8这样进行赋值。所以,关灯也可以写成:GPIO_WriteBit( GPIOC, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 , Bit_SET);
BCD码(Binary-Coded Decimal),用4位 二进制数 来表示1位 十进制数 中的0~9这10个数码,是一种二进制的数字编码形式,用 二进制编码的十进制 代码。. BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使 二进制 和 十进制 之间的转换得以快捷的进行。. 这种编码技巧最常用于会计系统的设计里,因为会计制度经常需要对很长的数字串作准确的计算。. 相对于一般的 浮点 式 记数法 ,采用BCD码,既可保存数值的精确度,又可免去使计算机作浮点运算时所耗费的时间。. 此外,对于其他需要高精确度的计算,BCD编码亦很常用。
8421 BCD码是最基本和最常用的BCD码,它和四位自然二进制码相似,各位的权值为8、4、2、1,故称为有权BCD码。和四位自然二进制码不同的是,它只选用了四位二进制码中前10组代码,即用0000~1001分别代表它所对应的十进制数,余下的六组代码不用。
三色灯
如果有三色灯,我们还可将灯的颜色和点灯、关灯封装在一个函数内:(这样的话,想要打开某种颜色的灯时,就只调用这个函数就行了)
typedef enum LED_RGB{ //这里使用枚举来代替宏定义,当我们需要多次宏替换时候,就不要使用宏定义了,最好使用枚举
LEDR=0x01,
LEDG,
LEDB
}LED_RGB_T;
typedef enum LED_STATUS{
LED_OPEN=0x01,
LED_CLOSE
}LED_STATUS_T;
void LED_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
GPIO_SetBits(GPIOC,GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);
}
void LED_CTRL(LED_RGB_T LED,LED_STATUS_T LED_status )
{
switch(LED){
case LEDR:
if(LED_status==LED_OPEN){
GPIO_ResetBits(GPIOC,GPIO_Pin_8); //打开红灯
}else{
GPIO_SetBits(GPIOC,GPIO_Pin_8); //关闭红灯
}
break;
case LEDG:
if(LED_status==LED_OPEN){
GPIO_ResetBits(GPIOC,GPIO_Pin_7); //打开绿灯
}else{
GPIO_SetBits(GPIOC,GPIO_Pin_7); //关闭绿灯
}
break;
case LEDB:
if(LED_status==LED_OPEN){
GPIO_ResetBits(GPIOC,GPIO_Pin_6); //打开蓝灯
}else{
GPIO_SetBits(GPIOC,GPIO_Pin_6); //关闭蓝灯
}
break;
default:
break;
}
}
int main(void)
{
LED_Config();
while(1){
LED_CTRL(LEDR,LED_OPEN); //打开红灯
LED_CTRL(LEDR,LED_CLOSE); //关闭红灯
}
}
上一篇:stm32——端口重映射
下一篇:GPIO寄存器的地址怎么寻找
设计资源 培训 开发板 精华推荐
- 使用 Analog Devices 的 LTC1315CG 的参考设计
- 【ART-Pi】art-pi
- 【航顺训练营】HK32F030MF4P6开发板-615259G
- fpga矿机控制TF转接板
- STEVAL-BCN002V1B,BlueTile - 支持蓝牙 LE 的传感器节点开发套件
- 采用陶瓷电容器的 LTC3407EDD-2 低纹波降压稳压器的典型应用电路
- 使用 Microchip Technology 的 MIC24054YJL 的参考设计
- LM2902DTBR2G 高阻抗差分放大器的典型应用
- LTC3407、单电感器、正降压-升压型稳压器和一个降压稳压器
- NSI45030AT1G 恒流 LED 灯串的典型应用