stm32f103 GPIO—— 一灯大师之库函数版

在使用库函数之前,我们先来看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);       //关闭红灯
    }
}

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值