历史上的今天
返回首页

历史上的今天

今天是:2025年03月29日(星期六)

2019年03月29日 | STM32学习笔记2——GPIO点灯

2019-03-29 来源:eefocus

学会了建立建立工程,接下来一定是迫不及待的想用自己的开发板大显身手了吧。别急,慢慢来。在C语言学习时,你最先编译的一定是那条永恒经典的代码,对,就是Hello World——简单、明了,而且能直观的看见现象。在STM32上也有一个简单、明了,而且能直观的看见现象的程序——点灯。这就是我们现在的hello world,让我们从他开始学习吧!!!


学习

点灯我们要用到的就是控制我们需要的I/O口,所以,让我们先来看一下STM32F的GPIO端口。在STM32F0系列微控制器的每个GPIO端口有:两个32位配置寄存器(GPIOx_OTYPER和GPIOx_MODER)、两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR)、一个32位置位/复位寄存器(GPIOx_BSRR)、一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。根据数据手册中列出的每个I/O口的特定硬件特性,GPIO的端口的每个位可以软件分别配置成:输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、推挽复用和开漏复用功能等多种模式。具体见表 


这里写图片描述
这里写图片描述


每个I/O口可以自由编程,然而I/O口的寄存器必须按32位字节进行访问。GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器的读/写的独立访问; 


由此,我们可以编程对寄存器进行操作,使I/O口产生方波对灯进行亮灭控制。但首先我们要找到开发板上的LED在哪个I/O口上:找到开发板的原理图你会发现 


这里写图片描述


LED接在PA5端口,高电平点亮。(由于板子不一样,大家自行寻找自己的LED挂在哪个口上,是在找不到,可外接) 

下面就开始对我们的开发板进行点灯的编程了


按照昨天的工程建立一个工程,Lib组里继续添加gpio.c和rcc.c。

来到main.c下进行程序的编写。

程序

1.包含头文件


#include"stm32f0xx.h"


2.延时函数


void Delay(volatile unsigned int ncount)

{

    while(ncount--);

}


3.定义GPIO初始化结构体


GPIO_InitTypeDef        GPIO_InitStructure;


4.进入主函数


int main(void)

{

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //enable the clock

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_P;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  GPIO_Init(GPIOA, &GPIO_InitStructure);


  while (1)

  {

     GPIO_SetBits(GPIOA,GPIO_Pin_5);

     Delay(0xfffff);

     GPIO_ResetBits(GPIOA,GPIO_Pin_5);

     Delay(0xfffff);

  }

}


接下来把程序按照昨天写的下到开发板上,看到LED灯开始闪烁,好了。一切都完工了没?早着呢,这才开始,下面我们开始分析为什么这么写。知其然,还要知其所以然。


分析

延时函数没问题(但还要注意volatile的应用,在KEIL中无所谓,但如果你使用GCC进行编程,没有volatile的地方就会被优化掉,从而使延时函数无意义)

那么接下来的GPIO_InitTypeDef GPIO_InitStructure;是什么意思呢?

在GPIO.h中还有如下代码


typedef struct

{

  uint32_t GPIO_Pin;              /*!< Specifies the GPIO pins to be configured.

                                       This parameter can be any value of @ref GPIO_pins_define */


  GPIOMode_TypeDef GPIO_Mode;     /*!< Specifies the operating mode for the selected pins.

                                       This parameter can be a value of @ref GPIOMode_TypeDef   */


  GPIOSpeed_TypeDef GPIO_Speed;   /*!< Specifies the speed for the selected pins.

                                       This parameter can be a value of @ref GPIOSpeed_TypeDef  */


  GPIOOType_TypeDef GPIO_OType;   /*!< Specifies the operating output type for the selected pins.

                                       This parameter can be a value of @ref GPIOOType_TypeDef  */


  GPIOPuPd_TypeDef GPIO_PuPd;     /*!< Specifies the operating Pull-up/Pull down for the selected pins.

                                       This parameter can be a value of @ref GPIOPuPd_TypeDef   */

}GPIO_InitTypeDef;


两段代码合起来就是我们要找的了,先定义GPIO_InitTypeDef,然后根据这个结构定义了GPIO_InitStructure,这个结构体在后面的GPIO的设置中会用到。


主函数中的第一句RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);又是什么呢?我不是配置GPIO么,这是什么东西? 

在STM32中,上电后默认所有的时钟都是关的,需要手动打开,所以这一部是先进行时钟打开,在M0内核中控制GPIOPA的时钟在AHB上 

这里写图片描述

所以要打开PA5上的时钟,必须对AHB使能,在函数中

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)

{

  /* Check the parameters */

  assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph));

  assert_param(IS_FUNCTIONAL_STATE(NewState));


  if (NewState != DISABLE)

  {

    RCC->AHBENR |= RCC_AHBPeriph;

  }

  else

  {

    RCC->AHBENR &= ~RCC_AHBPeriph;

  }

}


变量uint32_t RCC_AHBPeriph在库中有如下定义#define RCC_AHBPeriph_GPIOA RCC_AHBENR_GPIOAEN #define RCC_AHBENR_GPIOAEN ((uint32_t)0x00020000)将0x00020000与寄存器按位或后进行赋值正好对应GPIOA进行使能。


GPIO设置 

先对结构体内的变量赋值,设置PA5口,设置端口为输出、推挽输出(模电的知识,我也是一知半解),设置输出速度为50MHz. 

然后进入让LED亮灭的程序,对GPIO_SetBits(GPIOA,GPIO_Pin_5);我们看他的原函数:

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;

}


他传递了两个参数:*GPIOx,GPIO_Pin。在stm32f0xx.h中有


typedef struct

{

  __IO uint32_t MODER;        

  __IO uint16_t OTYPER;       

  uint16_t RESERVED0;       

  __IO uint32_t OSPEEDR;     

  __IO uint32_t PUPDR;       

  __IO uint16_t IDR;         

  uint16_t RESERVED1;      

  __IO uint16_t ODR;          

  uint16_t RESERVED2;         

  __IO uint32_t BSRR;        

  __IO uint32_t LCKR;         

  __IO uint32_t AFR[2];       

  __IO uint16_t BRR;         

  uint16_t RESERVED3;       

}GPIO_TypeDef;


对__IO的定义volatile,大家可以去看这篇文章这里写链接内容谢谢作者。通过这个结构体大家也该明白为什么能对BSRR寄存器进行操作了吧。在BSRR寄存器 


这里写图片描述

#define GPIO_Pin_5                 ((uint16_t)0x0020) 


所以该函数就是对第五位ODR置位。之后延时,GPIO_ResetBits(GPIOA,GPIO_Pin_5);和上面的差不多,就不一一讲了。 

至此点灯程序就差不多了,做出来不一定能写出来,写的过程是一个升华提升的过程,能扎实自己的能力,再把自己的想一想,把以前认为理所当然的过一遍,能收获很多。。。 

PS:库里的*.c文件添加后,如编译时提示找不到头文件,要去stm32f0xx_cof.h中使能相应的.h 文件(就是把前面的注释去掉)。

推荐阅读

史海拾趣

GSME Electronics公司的发展小趣事

随着生产设备的引进和技术团队的壮大,GSME Electronics开始专注于半导体器件的研发与生产。公司产品线逐渐丰富,涵盖了片式各种系列表面贴装的小信号三极管、中功率驱动三极管、肖特基、开关二极管及小功率可控硅等多种半导体分立器件。这些产品广泛应用于移动通信、计算机、消费类电子信息产品、家用电器、工业自动化控制设备等领域,满足了市场的多样化需求,推动了公司业务的快速增长。

承兴(CX)公司的发展小趣事

2017年,承兴公司做出了一个大胆的决定——收购由“漫威之父”斯坦·李创立的POW!娱乐公司。这一收购不仅使承兴在泛娱乐产业获得了重要的IP资源,也为其未来的发展注入了新的动力。承兴开始将电子技术与泛娱乐产业相结合,推出了一系列具有创新性和竞争力的产品。

BUSSMANN公司的发展小趣事

随着汽车工业的快速发展,对熔断器的需求也急剧增加。Bussmann五兄弟敏锐地抓住了这一市场机遇,开始专注于汽车熔断器的研发和生产。他们深入研究汽车电路的特点,不断优化熔断器的设计和性能,使其能够更好地适应汽车的工作环境。凭借这一创新,Bussmann的汽车熔断器迅速占领了市场,为公司的发展奠定了坚实的基础。

Daito Communication Apparatus Co Ltd公司的发展小趣事

自1948年成立以来,Daito公司一直致力于电子元器件的研发与生产。在公司的早期阶段,他们意识到保险丝在电子设备中的重要性,并决定投入大量资源进行研发。经过数年的努力,Daito公司成功开发出了高精度报警保险丝,这一创新产品凭借其卓越的性能和可靠性,迅速在市场上获得了认可。

高精度报警保险丝的成功并没有让Daito公司停止创新的步伐。他们不断对保险丝的失效原因与寿命进行预测和分析,通过全面质量管理,使产品质量得到了显著的提高。同时,Daito公司还将各系列保险丝的额定值多层次化,以满足不同客户的需求,扩大了顾客的选择余地。

Custom Components Inc公司的发展小趣事

随着全球环保意识的不断提高,电子行业对绿色环保和可持续发展的要求也日益严格。CCI积极响应这一趋势,将绿色环保理念融入公司的战略规划和日常运营中。

公司不仅采用了环保材料和绿色生产工艺来降低产品对环境的影响,还通过优化生产流程和资源利用等方式降低能耗和排放。此外,CCI还积极参与行业环保组织和公益活动,推动整个行业向更加绿色、环保的方向发展。

Electrocube Inc公司的发展小趣事

在稳固国内市场的同时,Electrocube Inc公司积极开拓国际市场。公司参加了多个国际电子展会,与全球知名电子企业建立了广泛的合作关系。通过不断的市场拓展,Electrocube Inc公司的产品已经远销欧美、亚洲等多个国家和地区,实现了跨越式的发展。

问答坊 | AI 解惑

基于SPMC75系列单片机的高性能三相变频电源方案

1 引言   变频电源是一种电源变换设备,因具有输出波形纯正、输出电压稳定、输出频率和输出电压可调等优点。其良好的性能,在传感、仪器仪表、工业控制等领域有广泛应用。本文主要介绍利用SPMC75F2413A和IPM(PS21865A)实现高性能三相变频电源的 ...…

查看全部问答>

电子信息工程的大学四年之感悟

本帖最后由 paulhyde 于 2014-9-15 09:13 编辑 题记: 我平时懒于BBS的灌水,属于潜水一族,也看到很多人在毕业之际写一些心得 体会之类,我本不想写这些东东,自我感觉有点哗众取宠,但终究是写下了。文中 所述,仁者见仁,智者见智,同意或 ...…

查看全部问答>

XL2000步进电机完整版C程序(带正反转与加减速)

#include        //51芯片管脚定义头文件 #include          //内部包含延时函数 _nop_(); #define uchar unsigned char #define uint  unsigned int uchar code FFW[8]={0xf1,0x ...…

查看全部问答>

请问大家谁了解H3C?

大家好 我刚收到H3C的 低端以太网交换机产品管理部 的 offer 本人刚刚毕业 请问有了解这个公司的吗? 该部门怎么样?谢谢 …

查看全部问答>

WINCE 下怎么显示鼠标图标?

今天看到G3上可以设置轨迹球和鼠标的切换,用户可以选择鼠标箭头操作,想问下这是怎么实现的?…

查看全部问答>

问一个显示模块的问题

你好,一家公司出了道面试题,用的是三星的128S64AA1显示模块, 要求把输出给这模块的中文显示信号转化成英文显示信号。 我不太了解,比如这模块的中文字库是怎么调用的, 谁了解这方面的内容吗,能谈下吗,有这方面的资料吗…

查看全部问答>

用vmware、windbg调试驱动

在google上搜了下,有好多文章教怎样用vmware和windbg调试驱动,于是就按他们说的做,但windbg和vmware连接上了,然后我按windbg上break后,vmware就死了,着是什么原因?…

查看全部问答>

花了一万元的PCB高级讲座课件(高频电路布线技巧)

这是射频与数模混合类PCB设计教程课件,希望对做高频电路的人们有所帮助 里面主要包括: 射频PCB布局与数模混合类PCB布局      无线终端PCB常用HDI工艺介绍􀂾 信号完整性(SI)的基础概念􀂾 射频PCB与数模 ...…

查看全部问答>

STM32F101C6的ADC有没内部参考电源?

                                 还是直接用的就是电源?…

查看全部问答>

无法对其进行硬件仿真!

芯片为TMS320VC5509A,只是用MCBSP扩展了一个外部FLASH,但与仿真器接通的时候CCS每次试图连接都出现错误,提醒CPU初始化失败,通过检查发现JTAG口线路连接没有问题,电源电压正常,内核电压正常,复位脚正常,晶振有起振(不过连接的12M晶振但频率 ...…

查看全部问答>