亲宝软件园·资讯

展开

c语言结构体单片机 一文读懂c语言结构体在单片机中的应用

weixin_45806329 人气:0
想了解一文读懂c语言结构体在单片机中的应用的相关内容吗,weixin_45806329在本文为您仔细讲解c语言结构体单片机的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:c语言结构体单片机,c语言结构体,下面大家一起来学习吧。

Struck

看到单片机中有很多struck 的应用,但是呢我当初学C语言的时候又没有很认真的去学习,今天复习下,写一篇小小的交流,希望能够给大家带来帮助。

1.struck的定义

/***********方式一**********/
struct Book
	{
		char title[128];
		char aurhor[40];
		float price;
		unsigned int date;
		char pubilsher[40];	
	};
/*定义了Book这个模板*/
struct Book book1,book2,book3;//使用struct Book这个模板建立了一个book1变量

/***********方式二**********/
struct Book
	{
		char title[128];
		char aurhor[40];
		float price;
		unsigned int date;
		char pubilsher[40];	
	}book1,book2,book3;
//和方式1的结果相同

2.struck调用

scanf(“%s”,book.title)//使用的.(点)运算符,表示book变量里的title属性
scanf(“%s”,&book.price)//数组不需要加取地址符,整型需要

3.struck的初始化

/********方式一*******/
struct Book book1
	{
		“小甲鱼带你学习带你飞”,
		“小甲鱼”,
		48.8,
		2017111111,
		“清华大学出版社”,
	};
/********方法二*******/
struct Book book1{.price=48.8	};//可以以这种方式定义多种数值

4.struck在单片机中的应用

好的,进入正题。复习了struck结构体的基本用法。也就是大家在课堂上学习的知识之后。我们在单片机的学习以及编译过程中是如何使用的呢。

void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;

    __HAL_RCC_GPIOB_CLK_ENABLE();           	//开启GPIOB时钟
	__HAL_RCC_GPIOE_CLK_ENABLE();           	//开启GPIOE时钟
	
    GPIO_Initure.Pin=GPIO_PIN_5; 				//PB5
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);

	GPIO_Initure.Pin=GPIO_PIN_5; 				//PE5
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);
	
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);	//PB5置1,默认初始化后灯灭
    HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);	//PE5置1,默认初始化后灯灭
}

这是一段led灯的初始化代码

(进入方式如下图,选中LED_Init,右键,Go to Defintion of xxxxxx)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mtUqVX8i-1622116136280)(Struck%20224c53c2d9e240c2af26d85e538af920/Untitled.png)]

我们来逐行分析这些代码

void LED_Init(void)
//空函数空返回值,定义了一个函数,函数的名字是LED_Init,空形参,空返回值
/***c语言函数部分**/

第一行很简单没什么问题,下一行GPIO_InitTypeDef GPIO_Initure;遇到问题了。看不懂

首先打开百度翻译翻译下这句话

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KVa8PrbF-1622116136282)(Struck%20224c53c2d9e240c2af26d85e538af920/Untitled%201.png)]

大概就是GPIO初始化的意思。我们再次右键看下,第一个可能是个函数,将后面的这部分定义了。

typedef struct
{
  uint32_t Pin;       /*!< Specifies the GPIO pins to be configured.
                           This parameter can be any value of @ref GPIO_pins_define */

  uint32_t Mode;      /*!< Specifies the operating mode for the selected pins.
                           This parameter can be a value of @ref GPIO_mode_define */

  uint32_t Pull;      /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
                           This parameter can be a value of @ref GPIO_pull_define */

  uint32_t Speed;     /*!< Specifies the speed for the selected pins.
                           This parameter can be a value of @ref GPIO_speed_define */
} GPIO_InitTypeDef;

还是和刚刚一样右键然后Go to Defintion of xxxxxx。我们来到了这里,但是全是英文。所以又要借助我们的老朋友了,百度翻译。

/************翻译之后的**************/
typedef struct
{
  uint32_t Pin;       /*指定要配置的GPIO引脚,此参数可以是@ref GPIO_pins_define中的值*/

  uint32_t Mode;      /*指定所选管脚的工作模式。此参数可以是@ref GPIO\u mode\u define的值*/

  uint32_t Pull;      /*指定选定接点的上拉或下拉激活。此参数可以是@ref GPIO\u pull\u define的值*/

  uint32_t Speed;     /*指定选定接点的速度。此参数可以是@ref GPIO\u speed\u define的值*/
} GPIO_InitTypeDef;

我们可以看到这里的用法与我们c语言中的struck有些类似,但是又有些许的不同。结果是一样的。

现说结论,他这里建立了一个 GPIO_InitTypeDef的模板。与下列的代码相似。或者说是结果相同

struct  GPIO_InitTypeDef
	{
		uint32_t Pin;    //uint32_t是定义了一个32位的变量,右键go to也能找到对应的位置
		uint32_t Mode;
		uint32_t Pull;
	  uint32_t Speed;
	};

/******************************/
/*******go to之后得到的内容*****/
//typedef unsigned          char uint8_t;           -->将unsigned char改名为uint8_t
//typedef unsigned short     int uint16_t;         -->将unsigned short int改名为uint16_t
//typedef unsigned           int uint32_t;          -->将unsigned int改名为uint16_t
//typedef unsigned       __INT64 uint64_t;          -->将unsigned __INT64改名为uint64_t
/***进行变化之后更方便我们使用时候选取适合字节数的变量名来定义****/

但是他这里用了一个typedef,相当于把这部分重命名了方便了我们以后的使用。对比下

/******使用纯粹的C语言编程*******/
struct  GPIO_InitTypeDef
	{
		uint32_t Pin;
		uint32_t Mode;
		uint32_t Pull;
	  uint32_t Speed;
	}GPIO_Initure;

//或者如下
struct  GPIO_InitTypeDef
	{
		uint32_t Pin;
		uint32_t Mode;
		uint32_t Pull;
	  uint32_t Speed;
	};
struct GPIO_InitTypeDef GPIO_Initure;
/********使用改进后的代码进行编程******/

typedef struct
{
  uint32_t Pin;       /*指定要配置的GPIO引脚,此参数可以是@ref GPIO_pins_define中的值*/
  uint32_t Mode;      /*指定所选管脚的工作模式。此参数可以是@ref GPIO\u mode\u define的值*/
  uint32_t Pull;      /*指定选定引脚的上拉或下拉激活。此参数可以是@ref GPIO\u pull\u define的值*/
  uint32_t Speed;     /*指定选定引脚的速度。此参数可以是@ref GPIO\u speed\u define的值*/
} GPIO_InitTypeDef;
//这段代码放在底层文件中,官方配置的。我们直接调用即可。

 GPIO_InitTypeDef GPIO_Initure;//我们自己书写的函数时使用的
//总的来说是提高了代码的可移植性以及可读性。

总的来说就是定义了一个结构体,方式与我们正常的C语言编程不同而已。结果是一样的。我们继续往下看

void LED_Init(void)
/***c语言函数部分**/
//空函数空返回值,定义了一个函数,函数的名字是LED_Init,空形参,空返回值

{
    GPIO_InitTypeDef GPIO_Initure;

//定义了一个名字为GPIO_Initure的结构体,里面有pin(引脚),mode(工作方式),pull(输出方式)
//speed(输出速度)几个属性的一个结构体

    __HAL_RCC_GPIOB_CLK_ENABLE();           	//开启GPIOB时钟
		__HAL_RCC_GPIOE_CLK_ENABLE();           	//开启GPIOE时钟
	//两个函数,功能如注释所示

    GPIO_Initure.Pin=GPIO_PIN_5; 				//PB5
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速
//使用struck的初始化方式对struck结构体进行了初始化
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
//这里又出现了一个新的函数HAL_GPIO_Init,我们继续go to去看下

	GPIO_Initure.Pin=GPIO_PIN_5; 				//PE5
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);
	
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);	//PB5置1,默认初始化后灯灭
    HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);	//PE5置1,默认初始化后灯灭
}

HAL_GPIO_Init的go to结果(快速翻过即可)

void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
  uint32_t position = 0x00u;
  uint32_t ioposition;
  uint32_t iocurrent;
  uint32_t temp;
  uint32_t config = 0x00u;
  __IO uint32_t *configregister; /* Store the address of CRL or CRH register based on pin number */
  uint32_t registeroffset;       /* offset used during computation of CNF and MODE bits placement inside CRL or CRH register */

  /* Check the parameters */
  assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
  assert_param(IS_GPIO_MODE(GPIO_Init->Mode));

  /* Configure the port pins */
  while (((GPIO_Init->Pin) >> position) != 0x00u)
  {
    /* Get the IO position */
    ioposition = (0x01uL << position);

    /* Get the current IO position */
    iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;

    if (iocurrent == ioposition)
    {
      /* Check the Alternate function parameters */
      assert_param(IS_GPIO_AF_INSTANCE(GPIOx));

      /* Based on the required mode, filling config variable with MODEy[1:0] and CNFy[3:2] corresponding bits */
      switch (GPIO_Init->Mode)
      {
        /* If we are configuring the pin in OUTPUT push-pull mode */
        case GPIO_MODE_OUTPUT_PP:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_PP;
          break;

        /* If we are configuring the pin in OUTPUT open-drain mode */
        case GPIO_MODE_OUTPUT_OD:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_OD;
          break;

        /* If we are configuring the pin in ALTERNATE FUNCTION push-pull mode */
        case GPIO_MODE_AF_PP:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_PP;
          break;

        /* If we are configuring the pin in ALTERNATE FUNCTION open-drain mode */
        case GPIO_MODE_AF_OD:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_OD;
          break;

        /* If we are configuring the pin in INPUT (also applicable to EVENT and IT mode) */
        case GPIO_MODE_INPUT:
        case GPIO_MODE_IT_RISING:
        case GPIO_MODE_IT_FALLING:
        case GPIO_MODE_IT_RISING_FALLING:
        case GPIO_MODE_EVT_RISING:
        case GPIO_MODE_EVT_FALLING:
        case GPIO_MODE_EVT_RISING_FALLING:
          /* Check the GPIO pull parameter */
          assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
          if (GPIO_Init->Pull == GPIO_NOPULL)
          {
            config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_FLOATING;
          }
          else if (GPIO_Init->Pull == GPIO_PULLUP)
          {
            config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;

            /* Set the corresponding ODR bit */
            GPIOx->BSRR = ioposition;
          }
          else /* GPIO_PULLDOWN */
          {
            config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;

            /* Reset the corresponding ODR bit */
            GPIOx->BRR = ioposition;
          }
          break;

        /* If we are configuring the pin in INPUT analog mode */
        case GPIO_MODE_ANALOG:
          config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_ANALOG;
          break;

        /* Parameters are checked with assert_param */
        default:
          break;
      }

      /* Check if the current bit belongs to first half or last half of the pin count number
       in order to address CRH or CRL register*/
      configregister = (iocurrent < GPIO_PIN_8) ? &GPIOx->CRL     : &GPIOx->CRH;
      registeroffset = (iocurrent < GPIO_PIN_8) ? (position << 2u) : ((position - 8u) << 2u);

      /* Apply the new configuration of the pin to the register */
      MODIFY_REG((*configregister), ((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << registeroffset), (config << registeroffset));

      /*--------------------- EXTI Mode Configuration ------------------------*/
      /* Configure the External Interrupt or event for the current IO */
      if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
      {
        /* Enable AFIO Clock */
        __HAL_RCC_AFIO_CLK_ENABLE();
        temp = AFIO->EXTICR[position >> 2u];
        CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));
        SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));
        AFIO->EXTICR[position >> 2u] = temp;

        /* Configure the interrupt mask */
        if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
        {
          SET_BIT(EXTI->IMR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->IMR, iocurrent);
        }

        /* Configure the event mask */
        if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
        {
          SET_BIT(EXTI->EMR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->EMR, iocurrent);
        }

        /* Enable or disable the rising trigger */
        if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
        {
          SET_BIT(EXTI->RTSR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->RTSR, iocurrent);
        }

        /* Enable or disable the falling trigger */
        if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
        {
          SET_BIT(EXTI->FTSR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->FTSR, iocurrent);
        }
      }
    }

	position++;
  }
}

……………………………………

??????????

什么玩意……………………

好吧,抱歉拉下了一行

/**
  * @brief  Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
  * @param  GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
  * @param  GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains
  *         the configuration information for the specified GPIO peripheral.
  * @retval None
  */

很显然我们进入的是官方的配置文件了,也就是官方的库。所谓的标准库以及hal库是不同的。当然我们也可以自己写库(这就是学习51单片机的同学最应该掌握的部分以及学习的部分)。但是对于学习32的同学来说我们只需要去看懂相应的函数用法即可。也就是说我们上面的长串代码不需要读懂,只需要看懂这段代码前面的官方注释即可。也提醒我们同学,在自己写库以及写代码的时候一定要加上注释加上简介,方便后续的使用。

/**
  *@简介   根据GPIO_Init中指定的参数初始化GPIOx外围设备。
	*@参数   GPIOx:其中x可以是(A~G,取决于使用的设备)来选择GPIO外围设备
	*@参数   GPIO_Init:指向包含指定GPIO外围设备的配置信息的GPIO_InitTypeDef结构的指针。
	*@返回值 无
  */

void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
大致意思就是将我们定义的那个结构体放到GPIO_x中去
  HAL_GPIO_Init(GPIOB,&GPIO_Initure);
//所以这行代码是说,将我们定义的结构体放到GPIOB中得到的结果就是 
//		GPIOB_pin_5的配置如下
//    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出
//    GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉
//    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速

这段分析之后我们再回到源代码中

void LED_Init(void)
/***c语言函数部分**/
//空函数空返回值,定义了一个函数,函数的名字是LED_Init,空形参,空返回值

{
    GPIO_InitTypeDef GPIO_Initure;

//定义了一个名字为GPIO_Initure的结构体,里面有pin(引脚),mode(工作方式),pull(输出方式)
//speed(输出速度)几个属性的一个结构体

    __HAL_RCC_GPIOB_CLK_ENABLE();           	//开启GPIOB时钟
		__HAL_RCC_GPIOE_CLK_ENABLE();           	//开启GPIOE时钟
	//两个函数,功能如注释所示

    GPIO_Initure.Pin=GPIO_PIN_5; 				//PB5
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速
//使用struck的初始化方式对struck结构体进行了初始化
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
//		GPIOB_pin_5的配置如下
//    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出
//    GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉
//    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速

	GPIO_Initure.Pin=GPIO_PIN_5; 				//PE5
//这里应该对代码没有改变,应该只是为了加个注释
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);
//		GPIOE_pin_5的配置如下
//    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出
//    GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉
//    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速
	
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);	//PB5置1,默认初始化后灯灭
    HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);	//PE5置1,默认初始化后灯灭
}
//The end

5.总结

我们可以看到,单片机的编程依旧是以C语言为基础的。同时今天讲解的这个struck结构体的方式不仅教授了大家struck在单片机中的应用。也教会了大家一些在keil中的常用检索方式,以及如何应对keil中的未知代码以及函数。当然还有一个最重要的最重要的!!找一个好的翻译软件。

加载全部内容

相关教程
猜你喜欢
用户评论