c语言结构体单片机 一文读懂c语言结构体在单片机中的应用
weixin_45806329 人气:0Struck
看到单片机中有很多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中的未知代码以及函数。当然还有一个最重要的最重要的!!找一个好的翻译软件。
加载全部内容