你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 6228|回复: 6

STM32 GPIO 入门学习

[复制链接]

6

主题

5

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-3-14 22:03:38 | 显示全部楼层 |阅读模式
接触了STM32的开发板快一周了,拿到板子厂商提供了些DEMO程序,其他想自己学习,看了ST的资料手册,感觉看下来,一个工具还是不知道怎么用,还好现在网络强大,在论坛上可以去找自己需要的资料.我把搜集的资料整理了一下,以及自己加了一些自己的,方便自己以后再用到,方便查找,同时和网友们一起分享,希望你们有什么新的想法也提出来,一起分享.
开始吧!嘿嘿
 
简述
 
1STM32的输入输出管脚有下面8种可能的配置:(4输入+2输出+2复用输出)
① 浮空输入_IN_FLOATING
② 带上拉输入_IPU  
③ 带下拉输入_IPD 
(所谓上拉就是接一电阻到电源;下拉就是接一电阻到地。也就是说带上拉就是口初始的时候是高电平,下拉就是低电平。)         
④ 模拟输入_AIN
⑤ 开漏输出_OUT_OD     
⑥ 推挽输出_OUT_PP
⑦ 复用功能的推挽输出_AF_PP
⑧ 复用功能的开漏输出_AF_OD
1.1         I/O口的输出模式下,有3种输出速度可选(2MHz、10MHz和50MHz),这个速度是指I/O口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能。当然如果要输出较高频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。关键是GPIO的引脚速度跟应用匹配(推荐10倍以上?)。比如:
1.1.1       对于串口,假如最大波特率只需115.2k,那么用2M的GPIO的引脚速度就够了,既省电也噪声小。
1.1.2       对于I2C接口,假如使用400k波特率,若想把余量留大些,那么用2M的GPIO的引脚速度或许不够,这时可以选用10M的GPIO引脚速度。
1.1.3       对于SPI接口,假如使用18M或9M波特率,用10M的GPIO的引脚速度显然不够了,需要选用50M的GPIO的引脚速度。输入模式。
1.4         所有端口都有外部中断能力。为了使用外部中断线,端口必须配置成输入模式。
1.5         GPIO口的配置具有上锁功能,当配置好GPIO口后,可以通过程序锁住配置组合,直到下次芯片复位才能解锁。
2           在STM32中如何配置片内外设使用的IO端口
首先,一个外设经过 ①配置输入的时钟和 ②初始化后即被激活(开启);③如果使用该外设的输入输出管脚,则需要配置相应的GPIO端口(否则该外设对应的输入输出管脚可以做普通GPIO管脚使用);④再对外设进行详细配置。
对应到外设的输入输出功能有下述三种情况:
一、外设对应的管脚为输出:需要根据外围电路的配置选择对应的管脚为复用功能的推挽输出或复用功能的开漏输出。
二、外设对应的管脚为输入:则根据外围电路的配置可以选择浮空输入、带上拉输入或带下拉输入。
三、ADC对应的管脚:配置管脚为模拟输入。
如果把端口配置成复用输出功能,则引脚和输出寄存器断开,并和片上外设的输出信号连接。将管脚配置成复用输出功能后,如果外设没有被激活,那么它的输出将不确定。
3           通用IO端口(GPIO)初始化:
3.1            GPIO初始化
3.1.1       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | B | C, ENABLE):使能APB2总线外设时钟
3.1.2       RCC_ APB2PeriphResetCmd (RCC_APB2Periph_GPIOA | B | C,
DISABLE):释放GPIO复位
3.2            配置各个PIN端口(模拟输入_AIN、输入浮空_IN_FLOATING、输入上拉_IPU、输入下拉_IPD、开漏输出_OUT_OD、推挽式输出_OUT_PP、推挽式复用输出_AF_PP、开漏复用输出_AF_OD)
3.3            GPIO初始化完成
=======================================================================
最近刚开始学习STM32,所以从最基本的GPIO开始学起;首先看看STM32的datasheet上对GPIO口的简单介绍:每个GPI/O 端口有两个32 位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个32位数据寄存器(GPIOx_IDR,GPIOx_ODR),一个32 位置位/复位寄存器(GPIOx_BSRR),一个16 位复位寄存器(GPIOx_BRR)和一个32 位锁定寄存器(GPIOx_LCKR)。
   GPIO 端口的每个位可以由软件分别配置成多种模式。每个I/O 端口位可以自由编程,然而I/0 端口寄存器必须按32 位字被访问(不允许半字或字节访问)。GPIOx_BSRR 和GPIOx_BRR 寄存器允许对任何GPIO 寄存器的读/更改的独立访问;这样,在读和更改访问之间产生IRQ 时不会发生危险。
端口位配置 CNFx[1:0]=xxb,MODEx[1:0]=xxb
再看GPIO功能很强大:
1.通用I/O(GPIO):最最基本的功能,可以驱动LED、可以产生PWM、可以驱动蜂鸣器等等;
2.单独的位设置或位清除:方便软体作业,程序简单。端口配置好以后只需GPIO_SetBits(GPIOx, GPIO_Pin_x)就可以实现对GPIOx的pinx位为高电平;
3.外部中断/唤醒线:端口必须配置成输入模式时,所有端口都有外部中断能力;
4.复用功能(AF):复用功能的端口兼有IO功能等。复位期间和刚复位后,复用功能未开启,I/O 端口被配置成浮空输入模式:(CNFx[1:0]=01b,
MODEx[1:0]=00b)。
5.软件重新映射I/O复用功能:为了使不同器件封装的外设I/O 功能的数量达到最优,可以把一些复用功能重新映射到其他一些脚上。这可以通过软件配置相应的寄存器来完成。这时,复用功能就不再映射到它们的原始引脚上了

6.GPIO锁定机制:当在一个端口位上执行了所定(LOCK)程序,在下一次复位之前,将不能再更改端口位的配置。
GPIO基本设置
GPIOMode_TypeDef GPIO mode    定义及偏移地址
GPIO_Mode_AIN = 0x0,     //模拟输入
GPIO_Mode_IN_FLOATING = 0x04, //悬空输入
GPIO_Mode_IPD = 0x28,    //下拉输入
GPIO_Mode_IPU = 0x48,    //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //推挽输出
GPIO_Mode_AF_OD = 0x1C,   //开漏复用
GPIO_Mode_AF_PP = 0x18    //推挽复用
GPIO输入输出速度选择:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}
GPIOSpeed_TypeDef;
#define IS_GPIO_SPEED(SPEED) ((SPEED == GPIO_Speed_10MHz) ||
(SPEED == GPIO_Speed_2MHz) || (SPEED == GPIO_Speed_50MHz))
做一个GPIO输出的试验
当I/O 端口被配置为推挽模式输出时:输出寄存器上的0 激活N-MOS,而输
出寄存器上的1 将激活P-MOS。
用这段程序实现:GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
int main(void)
{
#ifdef DEBUG
debug();
#endif
/* 设置系统时钟 */
RCC_Configuration();
   
/* 嵌套中断设置*/
NVIC_Configuration();
/* 激活GPIOC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
/* Configure PC.04, PC.05, PC.06 and PC.07 as Output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 |
GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
while (1)
{
    /*本试验仅能实现LED1亮、熄功能*/
    GPIO_SetBits(GPIOC, GPIO_Pin_4); //设置PC.04 pin为高电平,点亮
LED1
    Delay();
    GPIO_ResetBits(GPIOC, GPIO_Pin_4); //设置PC.04 pin为低电平,熄灭
LED1
    Delay();
}
}
 
 
 
再来一个网上的DEMO:
 

硬件电路

本章实验硬件电路如图11-1所示,LED0和LED1分别通过一个1K限流电阻连接在STM32的GPIOA.2和GPIO.3上,另一端接GND(注意是GND)。
 
 
 

实验设计
 

本章的实验主要为了学习如何对STM32的GPIO口进行操作。根据图11-1所示硬件资源,我们可以做一个很简单的实验设计:将这两个LED点亮,隔一段时间后熄灭。
 

程序设计
 

该实验非常的简单,实现过程如下
 

● 配置RCC寄存器组,使用PLL输出72MHz时钟;
● 配置GPIOA.2和GPIOA.3为推挽输出,最大翻转频率为50MHz;
● 点亮与熄灭LED;
 

程序组里面一共包含以下文件:
 

boot文件组:cortexm3_macro.s和stm32f10x_vector.s文件;
library文件组:stm32f10x_rcc.c、stm32f10x_flash.c、stm32_gpio.c、stm32f10x_lib.c文件;
interrupt文件组:stm32f10x_it.c文件;
src文件组:main.c文件;
其中boot文件组放置的是STM32的启动文件,读者暂时不必深究,引用即可;Library文件组中,stm32f10x_rcc.c、stm32f10x_flash.c包含着配置RCC的底层函数,stm32_gpio.c包含配置GPIO的底层函数;stm32f10x_lib.c则负责对整个库进行集中管辖,在任何一个基于固件库函数的STM32应用函数里,stm32f10x_lib.c都是不可或缺的;interrupt文件组的stm32f10x_it.c包含STM32的中断服务子程序,虽本实验尚未启用中断,但为了保持工程的完整性还是将其添加进来。
 

程序流程图如下:
 
 
程序启动之后,我们应该看到如下现象:LED0和LED1被点亮,但在隔一小段时间后熄灭。
 

程序清单如下:
 

/*******************************************************************************
* 文件名          : main.c
* 作者            : Losingamong
* 时间     : 08/08/2008
* 文件描述        : 主函数
********************************************************************************/
/* 头文件    ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"
/* 自定义同义关键字    --------------------------------------------------------*/
/* 自定义参数宏        --------------------------------------------------------*/
#define Delay(n) while((n)--)
/* 自定义函数宏        --------------------------------------------------------*/
/* 自定义变量          --------------------------------------------------------*/
/* 自定义函数声明      --------------------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
 
/*******************************************************************************
* 函数名   : main
* 函数描述       : Main 函数
* 输入参数       : 无
* 输出结果       : 无
* 返回值         : 无
******************************************************************************/
int main(void)
{
 vu32 n = 2000000;       //定义延时参数
   /* 设置系统时钟 */
   RCC_Configuration();  
   /* 设置GPIO端口 */
   GPIO_Configuration();
   
 /* PA.2 , PA.3输出高电平 */
 GPIO_SetBits(GPIOA , GPIO_Pin_2);         
 GPIO_SetBits(GPIOA , GPIO_Pin_3);  
 Delay(n);
   
 /* PA.2 , PA.3输出低电平 */
 GPIO_ResetBits(GPIOA , GPIO_Pin_2);   
 GPIO_ResetBits(GPIOA , GPIO_Pin_3);
 while(1);
}
 
/*******************************************************************************
* 函数名 : RCC_Configuration
* 函数描述  : 设置系统各部分时钟
* 输入参数  : 无
* 输出结果  : 无
* 返回值    : 无
******************************************************************************/
void RCC_Configuration(void)
{
 /* 定义枚举类型变量 HSEStartUpStatus */
 ErrorStatus HSEStartUpStatus;
   /* 复位系统时钟设置 */
   RCC_DeInit();
   /* 开启HSE */
   RCC_HSEConfig(RCC_HSE_ON);
   /* 等待HSE起振并稳定 */
   HSEStartUpStatus = RCC_WaitForHSEStartUp();
 
 /* 判断HSE起是否振成功,是则进入if()内部 */
   if(HSEStartUpStatus == SUCCESS)
   {
     /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
     RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
     /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
     RCC_PCLK2Config(RCC_HCLK_Div1);
     /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
     RCC_PCLK1Config(RCC_HCLK_Div2);
     /* 设置FLASH延时周期数为2 */
     FLASH_SetLatency(FLASH_Latency_2);
     /* 使能FLASH预取缓存 */
     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
     /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
     /* 使能PLL */
     RCC_PLLCmd(ENABLE);
     /* 等待PLL输出稳定 */
     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
     /* 选择SYSCLK时钟源为PLL */
     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
     /* 等待PLL成为SYSCLK时钟源 */
     while(RCC_GetSYSCLKSource() != 0x08);
   }
  
   /* 打开APB2总线上的GPIOA时钟 */
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
}
 
/*******************************************************************************
* 函数名    : GPIO_Configuration
* 函数描述     : 设置各GPIO端口功能
* 输入参数      : 无
* 输出结果      : 无
* 返回值        : 无
******************************************************************************/
void GPIO_Configuration(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
 
   /* 设置PA.2,PA.3为推挽输出,最大翻转频率为50MHz */
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_Init(GPIOA , &GPIO_InitStructure);  
}
 

注意事项:
 

● 配置RCC之前,建议先调用RCC_DeInit()函数复位RCC设置,否则可能会在调试过程中遇到不易预期到的初始化问题;
● APB1总线最大速率是36MHz,请读者注意RCC_PCLK1Config()的参数;
● FLASH延时周期数在本书xxx页有详细说明;
● GPIO配置为输出方向时,其最大翻转频率的设置语句是不可缺少的;
● 有兴趣且未曾了解过带参数宏的读者可以研究一下本程序中带参数的宏的用法;
● 本程序只使用了一种方法操作GPIO,前文已经讲述到STM32 GPIO操作的灵活与多样性, 建议读者自行发掘多种操作方法。
● 前文强调了两个LED为共阴接法,表示使用STM32的IO口输出电流来驱动LED。鉴于STM32的IO强大的驱动能力,这样做完全是可以的。但仍然建议在允许的情况下尽量使用共阳接法,使用外部电源驱动,以减轻主控芯片的负担。
 
实验结果
 
工程建立好之后…
按下F7编译,无错误与警告…
按下ctrl+F5进入仿真…
载入完毕,按下F5全速运行…
可以看到两个LED在点亮一小段时间之后熄灭,符合程序设计的预期。
 
 
再加点GPIO的应用:
 
GPIO_WriteBit(GPIOX, GPIO_Pin_X, Bit_RESET);//重置
GPIO_WriteBit(GPIOX, GPIO_Pin_X, (BitAction)0x01);//写入1
GPIO_WriteBit(GPIOX, GPIO_Pin_X, (BitAction)0x00);//写入0
GPIO_ReadInputDataBit(GPIOX, GPIO_Pin_X) ;//读入IO
 
注释: GPIOX 可选择GPIOA,GPIOB,...GPIOE
     GPIO_Pin_X 可以选择GPIO_Pin_0,GPIO_Pin_1....
这个最好看下STM32的手册,以及自己的硬件电路.
 
 

常用的GPIO操作函数 :
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 读GPIO某一位的输入
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); 读GPIO的输入
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 读GPIO某一位的输出
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); 读GPIO的输出
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 将GPIO的某个位置位
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 将GPIO的某个位复位
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); 写GPIO的某个位
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); 写GPIO
 
再来谈谈一些遇到的小tip

在单片机中,可以通过P0=~P0来进行位取反,但是stm32中却没有单独的位操作,所以我们可以通过如下代码达到取反目的:
GPIOx->ODR ^= GPIO_Pin;
 
可以将其写成库函数格式:
void GPIO_PinReverse(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->ODR ^= GPIO_Pin;
}
 
 
还可以:
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_4)));
 
还有其他的方法没想到,希望大家一起分享!
 
好了,今天简单将STM32 GPIO的端口介绍整理了下 ,大部分是网上网友们分享的资料,我只是简单集中了一下.希望大家学习和工作中遇到的以及总结的资料一起分享!
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sunrier/archive/2011/03/12/6243511.aspx
回复

使用道具 举报

8

主题

80

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-4-8 20:08:27 | 显示全部楼层

回复:STM32 GPIO 入门学习

楼主真用心,真详细,顶~
回复 支持 反对

使用道具 举报

0

主题

14

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-4-8 21:20:55 | 显示全部楼层

RE:STM32 GPIO 入门学习

楼主真用心,真详细,顶~
回复 支持 反对

使用道具 举报

0

主题

2

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-5-26 15:36:41 | 显示全部楼层

RE:STM32 GPIO 入门学习

这个必须顶,很有帮助!
回复 支持 反对

使用道具 举报

3

主题

0

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-7-19 16:56:59 | 显示全部楼层

回复:STM32 GPIO 入门学习

feichanghao  谢谢楼主
回复 支持 反对

使用道具 举报

1

主题

10

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-9-22 11:00:32 | 显示全部楼层

回复:STM32 GPIO 入门学习

谢谢楼主...刚开始学STM32,遇到不少问题
回复 支持 反对

使用道具 举报

0

主题

15

回帖

0

蝴蝶豆

新手上路

最后登录
1970-1-1
发表于 2011-10-15 12:37:47 | 显示全部楼层

回复:STM32 GPIO 入门学习

......
回复 支持 反对

使用道具 举报

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版