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

发布者:之敖赵先生最新更新时间:2022-09-30 来源: csdn关键字: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);       //关闭红灯

    }

}

关键字:stm32f103  GPIO  库函数 引用地址:stm32f103 GPIO—— 一灯大师之库函数版

上一篇:stm32——端口重映射
下一篇:GPIO寄存器的地址怎么寻找

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved