一文讀懂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)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,參考自己的吧]

我們來逐行分析這些代碼

void LED_Init(void)
//空函數空返回值,定義瞭一個函數,函數的名字是LED_Init,空形參,空返回值
/***c語言函數部分**/

第一行很簡單沒什麼問題,下一行GPIO_InitTypeDef GPIO_Initure;遇到問題瞭。看不懂

首先打開百度翻譯翻譯下這句話

外鏈圖片轉存失敗,先不給大傢展示圖片。

大概就是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中的未知代碼以及函數。當然還有一個最重要的最重要的!!找一個好的翻譯軟件。

以上就是c語言結構體在單片機中的應用的詳細內容,更多關於c語言結構體單片機的資料請關註WalkonNet其它相關文章!

推薦閱讀: