初学者对于STM32的GPIO部分理解

2019-07-20 07:40发布

本帖最后由 沓炅 于 2018-6-2 15:56 编辑

#include "stm32f10x.h"   
#include "gpio.h"

//对于STM32  GPIO一般用法配置(这里不包括复用功能),以下的说明可以应用点亮灯多种方式
void GPIO_Configure_GPIOA(void)
{
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//设置时钟,针对GPIOA时钟使能
       /*        为什么要设置时钟呢???
        任何外设都需要时钟,51单片机,stm32,430等等,
        因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。
        stm32之所以是低功耗,他将所有的门都默认设置为disable,在你需要用哪个门的时候,
        开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,
        其他的没用到的可以还是disable,这样耗能就会减少。??
        stm32的时钟是有分工的,并且每类时钟的频率不一样,因为没必要所有的时钟都是最高频率,只要够用就行,
        好比一个门出来水流大小,我只要洗脸,但是出来的是和洪水一样涌出来的水,那就gg了,消耗能源也多,
        所以不同的时钟也会有频率差别,或者在配置的时候可以配置时钟分频。
        */

        
        
        GPIO_InitTypeDef GPIO_InitStructure;//GPIO设备的初始化函数
         //GPIO_InitTypeDef是一个结构体类型同义字,其功能是定义一个结构体,
        //该结构体有三个成员分别是 u16类型的GPIO_Pin、
       // GPIOSpeed_TypeDef 类型的GPIO_Speed  和GPIOMode_TypeDef 类型的GPIO_Mode。即以下三种:

        
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//普通推挽输出
      
        //GPIO有8种工作模式(4种输入模式和4种输出模式):
        /*
       //4种输入模式:
       // 上拉输入模式(GPIO_Mode_IPU)-->在默认状态下(GPIO引脚无输入),读取得的GPIO引脚
      //  数据为1,高电平。
        
       // 而下拉输入模式(GPIO_Mode_IPD)则相反。在默认状态下(GPIO引脚无输入),读取得的GPIO引脚
       // 数据为0,低电平。
        
        浮空输入模式(GPIO_Mode_IN_FLOATING)在芯片内部既没有接上拉,也没有接下拉电阻,
        经由触发器输入。这种模式用于标准的通信协议如I2C、USART的接收端
        
        模拟输入模式(GPIO_Mode_AIN)则关闭了施密特触发器,不接上、下拉电阻,经由另一线路
        把电压信号传送到片上外设模块。如传送至ADC模块,由ADC采集电压信号。所以使用ADC外设时,必须设置为模拟输入模式
        
        4种输出模式:
        普通推挽输出(GPIO_Mode_Out_PP)一般应用在输出电平为0和3.3伏的场合
        
        普通开漏输出(GPIO_Mode_Out_OD)一般在电平不匹配的场合,如需要输出5伏的高电平,就需要在外部接一个
        上拉电阻,电源为5伏,把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5伏的电平
        
        复用推挽输出(GPIO_Mode_AF_PP),是根据GPIO的复用功能来选择的,如GPIO的引脚用作串口的输出,
        则使用复用推挽输出模式。
        
        复用开漏输出(GPIO_Mode_AF_OD),同理,其用在IC、SMBUS这些需要线与功能的复用场合
        在使用任何一种开漏模式时,都需要接上拉电阻。
        */

        
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//针对某组的一个引脚进行初始化

        //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;//针对某组的两个引脚进行初始化
        //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;//针对某组的16个引脚进行初始化


        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        /*
         又称输出驱动电路的响应速度:(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,
         用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,
         达到最佳的噪声控制和降低功耗的目的。)

    可理解为: 输出驱动电路的带宽:即一个驱动电路可以不失真地通过信号的最大频率。

        (如果一个信号的频率超过了驱动电路的响应速度,就有可能信号失真。失真因素?)

        如果信号频率为10MHz,而你配置了2MHz的带宽,则10MHz的方波很可能就变成了正弦波。
        就好比是公路的设计时速,汽车速度低于设计时速时,可以平稳地运行,
        如果超过设计时速就会颠簸,甚至翻车。

        关键是: GPIO的引脚速度跟应用相匹配,速度配置越高,噪声越大,功耗越大。

        带宽速度高的驱动器耗电大、噪声也大,带宽低的驱动器耗电小、噪声也小。
        使用合适的驱动器可以降低功耗和噪声

        比如:高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,
        这样非常有利于提高系统的EMI性能。当然如果要输出较高频率的信号,
        但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。
        关键是GPIO的引脚速度跟应用匹配(推荐10倍以上?)。
        */


        
GPIO_Init(GPIOA,&GPIO_InitStructure);//进行GPIOA初始化
}

void Delay_ms(u16 ms)
{
        int i;
        while(ms--)
        {
                i = 12000;
                while(i--);
        }
               
}

void GPIO_Achieve(u8 n,u16 ms)
{
        u8 Readoutbit;
        u16 Readoutdate;
        if(n == 0)
        {
                GPIO_ResetBits(GPIOA,GPIO_Pin_0);//设置PA0引脚为低电平,清除引脚位
                Delay_ms(ms);//不精准的延时函数,毫秒单位
               
               
                /*这是GPIO_ResetBits(GPIOx,GPIO_Pin)代码
                void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
        {
  //Check the parameters
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  GPIOx->BRR = GPIO_Pin;//位复位寄存器赋值(将某个引脚变为低电平)
        }
                */

               
               
                //Readoutbit = GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0);//将PA0引脚输出的值赋给Readoutbit
                //Readoutdate = GPIO_ReadOutputData(GPIOA);//将PA所有引脚输出的值赋给Readoutdate
               
                //GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);//获取PA0引脚的值
                //GPIO_ReadInputData(GPIOA);//获取PA所有引脚的值
                //GPIO_WriteBit(GPIOA,GPIO_Pin_0,RESET);//将RESET值写入给PA0引脚(其实就是将PA0引脚置0)
                //GPIO_Write(GPIOA,0xffff);//将0xffff值写入PA端口(其实就是将PA所有引脚置1)

        }
        else
        {
                GPIO_SetBits(GPIOA,GPIO_Pin_0);//设置PA0引脚为高电平,置位引脚
                Delay_ms(ms);
                /*
                void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
        {
   //Check the parameters
                assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
                assert_param(IS_GPIO_PIN(GPIO_Pin));
                GPIOx->BSRR = GPIO_Pin;//位置位寄存器赋值(将某个引脚变为高电平)
        }
                */        
                //Readoutbit = GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0);
                //Readoutdate = GPIO_ReadOutputData(GPIOA,GPIO_Pin_0);

        }
}

/*
注释:
GPIOx->BSRR= GPIO_Pin;-----------位置位寄存器---这是单个引脚的
GPIOx->BRR= GPIO_Pin;------------位复位寄存器---这是单个引脚的
GPIOx-ODR= PortVal;--------------端口输出寄存器---这是16个引脚的
GPIOx-IDR= PortVal;--------------端口输入寄存器---这是16个引脚的


对于GPIO来说,还有其他函数

以上,是我对GPIO的部分理解,有些可能理解不到位,请谅解(有些是从网上查找的)
*/
TEXT1.rar (678.13 KB, 下载次数: 83) 2018-6-2 15:51 上传 点击文件名下载附件
点亮灯



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
5条回答
硕果累累
1楼-- · 2019-07-20 09:31
很好
刘书源
2楼-- · 2019-07-20 12:20
对电路上有些疑问,通过什么来判断是应该选择输入还是输出呢?
沓炅
3楼-- · 2019-07-20 12:20
 精彩回答 2  元偷偷看……
刘书源
4楼-- · 2019-07-20 14:33
沓炅 发表于 2018-6-5 19:15
这根据你的需要了

假如,我需要一个SPI的外设,我的GPIO应该怎么选择模式呢?您能帮我分析下吗,万分感谢
沓炅
5楼-- · 2019-07-20 20:08
刘书源 发表于 2018-6-6 10:59
假如,我需要一个SPI的外设,我的GPIO应该怎么选择模式呢?您能帮我分析下吗,万分感谢

你这是需要用GPIO的复用功能了,
而我所写的是一般用法

一周热门 更多>