stm32入门——跑马灯(基于stm32f103zet6)

2019-10-21来源: eefocus关键字:stm32  跑马灯  stm32f103zet6

最近开始学stm32,着实感觉到了stm32和51之间的区别,但也有联系,总我感觉32与51之间最大的区别就是在使用某个外设之前,要对该外设进行时钟的使能(以达到降低功耗的目的),和相关配置。


刚学完跑马灯,下面对跑马灯用到的对IO口的配置相关知识分别对应官方库函数和寄存器进行总结。


如有错误或不足,请在下方留言。


文章内容基于正点原子战舰。


IO口的状态

       IO口有八大模式:─  输入浮空(  GPIO_Mode_IN_FLOATING = 0x04,)

                         ─  输入上拉(  GPIO_Mode_IPU = 0x48,)

                         ─  输入下拉(  GPIO_Mode_IPD = 0x28,)

                         ─  模拟输入(GPIO_Mode_AIN = 0x0,)

                         ─  开漏输出(  GPIO_Mode_Out_OD = 0x14,)

                         ─  推挽式输出(  GPIO_Mode_Out_PP = 0x10,)

                         ─  推挽式复用功能(GPIO_Mode_AF_PP = 0x18)

                         ─  开漏复用功能(  GPIO_Mode_AF_OD = 0x1C,) 


      IO口有三种速   -2MHZ( GPIO_Speed_2MHz=1,)


                       -10MHz( GPIO_Speed_10MHz = 1,)


                       -50MHz(  GPIO_Speed_50MHz=3,)   //当看到这些配置相应的值是否会感到疑惑呢,稍后讲解。 


跑马灯的原理图

显然led的硬件连接很简单分别连接了IO口PE5和PB5,另一端串联一个电阻共同接地。


实验的代码分析

我们知道任何外设的驱动都要使能相应的时钟,首先看stm32系统的时钟框图

经查阅资料可知,GPIO的时钟在APB2的外设时钟使能寄存器上,相关函数的定义在stm32f10x_rcc.h中 void   RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)其源代码为:


void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)

{

  /* Check the parameters */ //检查值的有效性

  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));

  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)

  {

    RCC->APB2ENR |= RCC_APB2Periph; //配置APB2ENBR寄存器

  }

  else

  {

    RCC->APB2ENR &= ~RCC_APB2Periph; //配置APB2ENR寄存器

  }

}

 

//与该函数相关的一些宏定义  检查RCC_APB2Periph参数的有效性

 

#define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)

#define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)

#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)

#define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)

#define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)

#define RCC_APB2Periph_GPIOE             ((uint32_t)0x00000040)

#define RCC_APB2Periph_GPIOF             ((uint32_t)0x00000080)

#define RCC_APB2Periph_GPIOG             ((uint32_t)0x00000100)

#define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)

#define RCC_APB2Periph_ADC2              ((uint32_t)0x00000400)

#define RCC_APB2Periph_TIM1              ((uint32_t)0x00000800)

#define RCC_APB2Periph_SPI1              ((uint32_t)0x00001000)

#define RCC_APB2Periph_TIM8              ((uint32_t)0x00002000)

#define RCC_APB2Periph_USART1            ((uint32_t)0x00004000)

#define RCC_APB2Periph_ADC3              ((uint32_t)0x00008000)

#define RCC_APB2Periph_TIM15             ((uint32_t)0x00010000)

#define RCC_APB2Periph_TIM16             ((uint32_t)0x00020000)

#define RCC_APB2Periph_TIM17             ((uint32_t)0x00040000)

#define RCC_APB2Periph_TIM9              ((uint32_t)0x00080000)

#define RCC_APB2Periph_TIM10             ((uint32_t)0x00100000)

#define RCC_APB2Periph_TIM11             ((uint32_t)0x00200000)

 

#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xFFC00002) == 0x00) && ((PERIPH) != 0x00))

  

//与该函数相关的枚举变量定义  检查NewState参数的有效性

 

typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;

#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))

  我们来看这个使能GPIO时钟函数的源代码,函数没有返回值,接受两个参数 unint32_t(unsigned int)类型的RCC_APB2Periph和FunctionalState(枚举变量)类型的NewState 。


  函数首先检查传入值的有效性,我们可以看到和RCC_APB2Periph相关的宏定义中,规定了相关参数的取值范围,相关的值实际上是APB2  外设时钟使能寄存器(RCC_APB2ENR)相关位的配置,在这里我们也可以看出库函数实际上就是操作寄存器,对操作寄存器进行了一系列的封装。我们这里从硬件来看需要启动GPIOB和GPIOE的时钟使能,则RCC_APB2Periph分别为RCC_APB2Periph_GPIOB,RCC_APB2Periph_GPIOE。再看参数NewState  有相关定义可知{DISABLE = 0, ENABLE = !DISABLE}则当NewState为ENABLE时,开启使能,GPIO相关使能完毕。(实际上库函数就是对寄存器RCC_APB2ENR的相关操作,理解该函数便可写出相关的寄存器版本)


与51单片机不同的是每次使用IO口还要对IO口进行初始化,配置IO的模式(MODE),速度(SPEED)及针脚(PIN),


GPIO初始化函数   void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct),其源代码:


/**

  * @brief  Initializes the GPIOx peripheral according to the specified

  *         parameters in the GPIO_InitStruct.

          //  根据指定初始化GPIOx外设GPIO_InitStruct中的参数。

  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.

                 //    其中x可以是(A..G)来选择GPIO外设

  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that

  *         contains the configuration information for the specified GPIO peripheral.

           // GPIO_InitStruct:指向GPIO_InitTypeDef结构的指针包含指定GPIO外设的配置信息。

  * @retval None

  */

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)//GPIO初始化函数

{

  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;

  uint32_t tmpreg = 0x00, pinmask = 0x00; 

    //设置相关变量 currentmode存储CRL CRH配置信息 tmpreg 存储当前及最终CRL CRH配置信息

  /* Check the parameters */

  assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); //检查GPIO的有效性

  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode)); //检查GPIO_Mode的有效性

  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  //检查GPIO_Pin的有效性

  

/*---------------------------- GPIO Mode Configuration GPIO模式配置 -----------------------*/

  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F); 

    //取GPIO_Mode中的低四位,这里的做法和GPIO_Mode的值有关,可自行参考结构体中的值进验证

  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)

    //该判断的意思是如果模式GPIO_Mode的第五位不是零就执行该语句,由结构体中的模式的值可得如果    

    //第五位为1,则该模式为输出模式

  { 

    /* Check the parameters *///检查速度的GPIO_Speed的有效性

    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));

    /* Output mode */

    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;

    //如果为输出模式则用模式GPIO_Mode的低四位|GPIO_Speed,便可得到输出模式寄存器中相关配置的 

    //值,可自行验证

  }

/*---------------------------- GPIO CRL Configuration GPIO CRL配置------------------------*/

  /* Configure the eight low port pins */ //设置低八位 CRL寄存器

  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)

        //由GPIO_Pin的范围可知,该语句的意思是判断0-7脚是否有定义

  {

    tmpreg = GPIOx->CRL;  //获取当前CRL配置

    for (pinpos = 0x00; pinpos < 0x08; pinpos++)  //循环检查引脚 ,判断引脚位置

    {

      pos = ((uint32_t)0x01) << pinpos;  //循环一次pos便左移一次

/* Get the port pins

[1] [2] [3]
关键字:stm32  跑马灯  stm32f103zet6 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic477805.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:32位嵌入式系统的字节对齐
下一篇:STM32流水灯的几种实现方法

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm32 看门狗 BKP(HAL库)
(一)概述stm32有两个看门狗:硬件看门狗(LSI 40KHz,时间精度不高)和窗口看门狗(APB1)。(二)硬件看门狗实现代码IWDG_HandleTypeDef hiwdg; // 硬件看门狗初始化static void MX_IWDG_Init(IWDG_HandleTypeDef *pHiwdg){    pHiwdg->Instance = IWDG;    pHiwdg->Init.Prescaler = IWDG_PRESCALER_4;    pHiwdg->Init.Reload = 0xFFF; // Tout
发表于 2019-11-16
STM32 HAL库学习系列第11篇---定时器TIM---看门狗基本配置及使用
基本配置使用cube配置溢出时间记住准时喂狗独立看门狗: /* IWDG 1s 超时溢出 */  MX_IWDG_Init(IWDG_PRESCALER_64,625);  /* 启动独立看门狗 */  HAL_IWDG_Start(&hiwdg);   LED1_ON;   /* while部分是我们在项目中具体需要写的代码,这部分的程序可以用独立看门狗来监控   * 如果我们知道这部           分代码的执行时间,比如是50ms,那么我们可以设置独立看门狗的 &nb
发表于 2019-11-16
STM32-自学笔记(18.独立看门狗,使用到的库函数)
为16IWDG_Prescaler_256设置IWDG预分频值为256IWDG_Prescaler_32设置IWDG预分频值为32例子:IWDG_SetPrescaler(IWDG_Prescaler_8);                //设置IWDG预分频值为82.IWDG_SetReload函数原型:void IWDG_SetReload(u16 Reload)功能:设置IWDG重装载值参数:Reload:IWDG的重装载值。取值范围0~0x0FFF例子:IWDG_SetReload(0xFFF);       
发表于 2019-11-16
HAL库 STM32CubeMX教程五----看门狗(独立看门狗,窗口看门狗)
的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环;或者因为用户配置代码出现BUG,导致芯片无法正常工作,出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 简单说:看门狗的本质就是定时计数器,计数器使能之后一直在累加 而喂狗就是重新写入计数器的值,时计数器重新累加,如果在一定时间内没有接收到喂狗信号(表示MCU已经挂了),便实现处理器的自动复位重启(发送复位信号)STM32的内置看门狗STM32内置两个看门狗,提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗、窗口看门狗)可以用来检测和解决由软件错误
发表于 2019-11-16
HAL库 STM32CubeMX教程五----看门狗(独立看门狗,窗口看门狗)
怎样用STM32CAN总线接口发送和接收数据
,禁止高7位都为隐性,即不能:ID=1111111XXXX。RTR,远程请求位。0,数据帧;1, 远程帧;SRR,替代远程请求位。设置为1(隐性电平);IDE,标识符选择位。0,标准标识符;1,扩展标识符;r0,r1:保留位。必须以显现电平发送,但是接收可以是隐性电平。DLC:数据长度码。0~8,表示发送/接收的数据长度(字节)。IDE,标识符选择位。0,标准标识符;1,扩展标识符;位时序分解为了实现位同步,CAN协议把每一个数据位的时序分解成SS段、PTS段、PBS1段、PBS2段,这四段的长度加起来即为一个CAN数据位的长度。分解后最小的时间单位是Tq,而一个完整的位由8~25个Tq组成。STM32中的CAN接口STM32的芯片
发表于 2019-11-16
怎样用STM32CAN总线接口发送和接收数据
stm8s_iwdg(独立看门狗)
; IWDG_Prescaler_16  = (uint8_t)0x02, /*!< Used to set prescaler register to 16 */  IWDG_Prescaler_32  = (uint8_t)0x03, /*!< Used to set prescaler register to 32 */  IWDG_Prescaler_64  = (uint8_t)0x04, /*!< Used to set prescaler register to 64 */  IWDG_Prescaler_128 = (uint8_t
发表于 2019-11-16
小广播
何立民专栏 单片机及嵌入式宝典

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

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