手把手教你写单片机的结构体

article/2025/10/15 4:41:51

手把手教你写单片机的结构体

摘要:听说还有好多学单片机的小伙伴不会用结构体?指针和结构体是学单片机必须要掌握的,如果你C语言掌握的不牢,单片机根本学不到精髓,只能完成一些低级的项目。看得懂结构体并且能够灵活运用结构体才能说你入门了单片机。本篇将以最通俗的方式结合STM32单片来讲讲结构体的运用。解决你学完C语言、考过了计算机二级还是看不懂单片机结构体的苦恼。宝藏文章,记得点赞转发收藏图片。

大家知道指针和结构体是单片机的难点,所以就去学习C语言,找视频看书…

在这里插入图片描述

这里面每一个视频的播放量都非常高。对于单纯的学习C语言,这里讲的很清楚。看完你不禁在下面评论一句:哇!讲的真的太清楚了吧!但是等你真正的学单片机的时候,你会发现我不是学过C语言吗?计算机二级我也过了啊!怎么这个指针和结构体都不懂啊?难道我学了一个假的C语言?

其实这不是你的错,也不是单片机的错,而是在C语言和单片机之间需要一个过渡!这个需要过渡的点在很多单片机视频教程中并没有去讲解。因为教育机构默认你是知道的,所以在讲流水灯时他们并不会讲解GPIO初始化这个结构体,因为默认你是知道如何操作的。

在这里插入图片描述

申明一个GPIO_InitTypeDef的结构体,然后在LED_Init(void)函数中定义一个GPIO_InitStructure的变量GPIO_InitStructure,那么这个变量就可以设置这个GPIO_InitTypeDef的结构体中的成员。这里先做了解,请接着往下看。

1 为什么需要结构体

这里先不说什么是结构体,说说为什么需要结构体?只有知道为什么需要,才能按照你的需要去学习,这样效率才会高。你才知道在什么情况下我们需要写一个结构体,怎么样去用结构体。

这里我们以一个智能家居的项目为例。

先来看一个实际的问题

话说有一个项目上有4个传感器:光照传感器、烟雾传感器、酒精传感器、湿度传感器。然后这四个各个传感器还有设置报警的阈值范围。

一般都是这样写

#include "sys.h"
#include "delay.h"
#include "usart.h"/*记录传感器的数值*/
float temperature; //温度
char  humidity;  //湿度
char  alcohol;  //酒精浓度
int   illumination; //光照强度/*记录传感器高低阈值*/
float temperature_threshold[2];
float humidity_threshold[2];
float alcohol_threshold[2];
float illumination_threshold[2];int main(void)
{ uart_init(115200);//串口初始化delay_init();while(1){ } 
}

在这里插入图片描述

当然你做一个项目肯定还定义了很多其他的变量,还需要记录其它变量

在这里插入图片描述

然后过了几天又增加了个一氧化碳传感器

在这里插入图片描述

然后过了几天,每个传感器还需要加个是否正常工作的标志位

在这里插入图片描述

因为项目的需要,然后又增加了4个相同的传感器:温湿度、光照强度、烟雾浓度、酒精浓度。

在这里插入图片描述

然后又增加了4个相同的传感器:温湿度、光照强度、烟雾浓度、酒精浓度。

截图截不开了…

在这里插入图片描述

满屏的变量…

满屏的变量…

满屏的变量…

在项目刚开始做的时候如果不能未雨绸缪,接着干下去整个程序代码别说维护了,就是接着写都让人头疼!

满屏的变量…

满屏的变量…

2 结构体闪亮登场

然后搞C语言那帮家伙就造了个功能struct

1、结构体就是可以把变量包含到里面的东西

struct就代表要定义一个结构体,sensors是这个结构体的名字, 然后是一个大括号 { }

大括号里面就随意定义变量啦~

在这里插入图片描述

怎么使用里面的变量呢?

注意结构体是一个数据类型就像是int和char一样的这种类型

既然是一种数据类型, 那么就可以用这个数据类型定义变量

定义一个该结构体的变量

在这里插入图片描述

为啥要那样子定义啊?

答:你去问造C语言的那帮家伙去!问问他们为啥要设计成这样子!

然后操作结构体变量里面的成员变量。当我们定义好结构体变量后,在初始化变量里面的成员变量时就会自动出现结构体里面的成员变量,如果这个代码是你一个一个敲出来的话,你就会感叹结构体在单片机中是那么的奇妙!

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

有人会问为啥是结构体变量中间加个点?

答:你去问造C语言的那帮家伙去!问问他们为啥要设计成这样子。

2、其实定义结构体变量可以下面这样子

在这里插入图片描述

也可以定义多个

在这里插入图片描述

在这里插入图片描述

发现了没,每个结构体变量都是单独拥有结构体里面的全部成员变量。

就像是最开始说的,如果再增加一套传感器:温湿度、光照强度、烟雾浓度、酒精浓度。

使用结构体的话只需要再定义一个结构体变量即可。

但是很多时候我们在单片机中见到的结构体并不是上面那样定义的,而是在前面加了一个typedef 关键字。

这样的例子在库函数的头文件中我们经常会看到如下结构体

在这里插入图片描述

3 typedef关键字

先看一下百度百科对typedef的定义

在这里插入图片描述

总结一句就是:typedef可以把一个数据类型取一个别的名字

typedef {数据类型} {别的名字}

#include "sys.h"
#include "delay.h"
#include "usart.h"typedef int zhjiguoxin;//zhjiguoxin就是intzhjiguoxin value = 0;int main(void)
{ uart_init(115200);//串口初始化delay_init(); printf("value=%d\r\n",value);while(1){ } 
}

在这里插入图片描述

在这里插入图片描述

虽然typedef可以给变量取别名,但是没有谁会像上面那样取名字,我这里只是举一个例子。

4 结构体的精髓

注意下:

1、下面的代表了这个结构体数据类型

在这里插入图片描述

2、给这个数据类型起一个别名

注意是三部分, typedef {数据类型} {别的名字}。所以sensor就代表了这个结构体了。

建议初学者把下面这张图保存到你的电脑,这样你就永远也不会忘记typedef在结构体中的用法了,也能很快的记住结构体这个东东。

在这里插入图片描述

3、以后定义结构体变量的时候就不需要像最开始那样struct sensors sen;这样的定义结构体变量了,只需要sensor sen;即可。

在这里插入图片描述

4、结构体名字可以省略

注意结构体定义可以不写结构体名,对C语言来说,那个sensors不叫结构体名,而是叫标签(tag)。C语言结构体名是struct关键字 + tag。所以为了简便我们看到的单片机中的结构体都是写成如下的形式。

在这里插入图片描述

5 结构体的变量可以放任何变量

1、结构体变量可以放任何变量(int型指针)

#include "sys.h"
#include "delay.h"
#include "usart.h"
typedef struct 
{float temperature; //温度char  humidity;    //湿度char  alcohol;    //酒精浓度int   illumination;//光照强度char  CO;  //一氧化碳浓度int   *p;  //int型的指针变量
} sensor;
sensor sen;
int value =0;
int main(void)
{uart_init(115200);//串口初始化delay_init(); sen.p=&value;//把value的地址赋值 //打印p代表的地址里面的值(其实就是打印value的值)printf("value=%d\r\n",*(sen.p)); while(1){ } 
}

既然是指针变量,所以给指针变量赋值时当然是赋值的是一个地址。

在这里插入图片描述
在这里插入图片描述

2、结构体变量可以放任何变量(函数指针)

#include "sys.h"
#include "delay.h"
#include "usart.h"
typedef struct 
{float temperature; //温度char  humidity;    //湿度char  alcohol;    //酒精浓度int   illumination;//光照强度char  CO;  //一氧化碳浓度int   *p;  //int型的指针变量void (*fun)();
} sensor;
sensor sen;
void function()
{printf("zhiguoxin\r\n");
}
int value =0;
int main(void)
{ uart_init(115200);//串口初始化delay_init(); sen.fun=function; sen.fun(); while(1){ } 
}

既然是函数指针变量,所以给函数指针变量赋值时当然是赋值的也是地址,并且还要是一个函数的地址,而一个函数的函数名就是该函数的地址。所以才会有下面的把函数function();的地址function赋值给函数指针fun。这样大家是不是很清楚了。如果不清楚建议看个3遍以上!

在这里插入图片描述

在这里插入图片描述

3、结构体变量可以放任何变量(结构体变量)

这就是结构体嵌套,在一个结构体内包含了另一个结构体作为其成员。当出现结构体嵌套时,必须以级联方式访问结构体成员,即通过成员选择运算符逐级找到最底层的成员时再引用。

#include "sys.h"
#include "delay.h"
#include "usart.h"typedef struct 
{int i;
}zhiguoxin;typedef struct 
{float temperature; //温度char  humidity;    //湿度char  alcohol;    //酒精浓度int   illumination;//光照强度char  CO;  //一氧化碳浓度int   *p;  //int型的指针变量void (*fun)(); zhiguoxin guougo; 
}sensor;sensor sen;int main(void)
{ uart_init(115200);//串口初始化delay_init();sen.guougo.i=100;printf("i=%d\r\n",sen.guougo.i);while(1){ } 
}

在这里插入图片描述

在这里插入图片描述

4、结构体变量可以放任何变量(结构体指针)

结构体是一个数据类型。数据类型当然也可以定义对应的指针变量啦。

就像是int 类型可以定义 int *p; 一样

在这里插入图片描述

所以当大家如果发现你的代码中结构体是通过—>访问的话,那么这个结构体变量一定是指针类型的变量。同理如果代码中结构体是通过.访问的话,那么这个结构体变量就不是指针变量,而是一般的变量。


在这里插入图片描述

总结:到这里结构体在单片机中的应用你已经掌握的差不多了,大家可能感觉本期讲的内容太简单了,不过只有你把这个简单的基础性知识打牢,你就会进步的更快。否则你总感觉你的代码差点意思。

参考原文:《手把手教你写单片机的结构体》


http://chatgpt.dhexx.cn/article/ekVlIJLb.shtml

相关文章

STM32基于Flash对结构体读写暨再认识结构体内存分配

目录 前言 认识结构体内存分布 模拟结构体搬运 实现FLASH的结构体读写 前言 记录本篇主要是记录我进行stm32学习中利用stm32的flash(闪存)读写结构体的总结。 认识结构体内存分布 结构体,主要要来存放我们的自定义类型的数据,结…

单片机的结构体

手把手教你写单片机的结构体 FROM8号线攻城狮 公众号 电子信息工程硕士在读,分享单片机、嵌入式linux、物联网等知识,致力于打造最硬核的嵌入式技术公众号。 半碗鸡汤,半碗杂粮。 摘要:听说还有好多学单片机的小伙伴不会用结构…

windows下mysql初始密码设置

转载自:http://blog.csdn.net/ofreelander/article/details/50802780 1.my-default.ini 改名my.ini 在解压的目录下面复制my-default.ini一份改名字为 my.ini。 2.打开 Windows 环境变量设置, 新建变量名 MYSQL_HOME , 变量值为 MySQL 安装目录路径, 在 环境变量 …

MYSQL修改初始化密码的方法

解决方法之一: “ ALTER USER rootlocalhost identified by 123456 ; ” 最近安装了mysql,在使用“ set password for rootlocalhostpassword(123456);”时会遇到 “ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that…

Centos下安装mysql查看初始密码并修改密码

题记:当我们在centos成功安装了mysql后,需要查看初始密码,大概率也需要自己修改密码。 一,查看mysql历时密码 cat var/log/mysqld.log二,进入到mysql mysql -u root -p按回车,然后再password:输入刚才所…

MySQL设置初始密码—注意版本mysql-8.0.30

MySQL设置初始密码—注意版本mysql-8.0.30 第一步:使用管理员模式下的命令行,进入mysql的所在文件下的bin目录; 第二步:输入命令mysql -u root -p; 第三步:这里第一次不用输入密码; 第四步: ALTER USER rootlocalhost…

安装mysql的初始密码在哪里

mysql初始密码是多少 介绍怎么找到mysql安装的root的初始密码 mysql初始密码是多少 介绍怎么找到mysql安装的root的初始密码 怎么给mysql设置用户名和密码 登录数据库 “命令提示字符”窗口录入, 录入cd C:\mysql\bin 并按下回车键,将目录切换为 cd C:\m…

关于MySQL初始化密码忘记的问题

本文章可以解决MySQL密码忘记的问题!!! 1、到mysql安装的bin目录下运行PowerShell 2、在命令行输入 mysql -u root -p 登录 mysql,可以随意输入一个密码,返回”ERROR 1045 (28000): Access denied for user rootlocal…

mysql安装,以及初始化密码

1.首先下载 mysql安装包, 我这里下载的mysql 5.7(免安装版) https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.24-winx64.zip 然后解压到你自己的目录中,我这里为 D 盘下: 此处,下下来的压缩包里面, data 目…

mysql初始没有密码怎么设置

由于本人是win7的忠实用户,最近被win10所吸引索性换了系统,还是改不了恋旧的习惯。所以用的mysql还是5.6。进入正题 在装完mysql并且配置完环境变量之后发现密码为空 1.首先进入到你安装的目录下,这里我的是E盘 2.之后输入mysql -u root -p …

1、数据库-MySql

什么是数据库 数据库(DataBase,简称DB) 概念:长期存放在计算机内,有组织,可共享的大量数据的集合,是一个数据"仓库" 作用:保存,并能安全管理数据(如:增删改查等),减少冗余… 数据…

C++中字符串大小写字母转换

最近在学习 STL,string 也是 STL 中的一种容器,遇到一个字符串中字母大小写转换的例子,这里就顺便总结一下在C中常用的字符串大小写转换方法,有需要的可以参考。代码如下: 1、char[]类型,调用库函数 // …

大小写字母转换(java大小写字母转换)

苹果4SQQ密码大小写字母怎么转换不?苹果4SQQ密码大小写字母 每次要输密码,当时在电脑上设置的密码,可以改变大小写,但是到了手机上,我不知道怎么换大小写,那位朋友告诉下 苹果手机输入法怎么改字母的大小写 (很高兴为您解答,有帮助请给好评,谢谢! ) 大小写转换-键盘…

英文字母大小写转换

从键盘输入一个大写英文字母,将其转换味小写字母后,再显示到屏幕上(显示字符后要输出一个换行) 输入格式要求:提示信息:"Press a key and then press Enter:" 程序运行实例如下: P…

Java 字符串中的大小写字母转换

Java 实现字符串中字母大小写转换函数 实现思路:将字符串中的每个字符取出,判断该字符是不是大写字母,如果是的话则该字符32(ASCII码)并进行强制转换,转换为char,然后在通过字符串的合并操作进…

大写字母转换成小写字母

大写字母转换成小写字母 大写字母转换成小写字母1.示例:2. 解题思路3. 代码展示及分析3.1 ASCII码操作字符串转换大小写3.2 位运算 4. 运行结果 大写字母转换成小写字母 题目: 实现函数 ToLowerCase(),该函数接收一个字符串参数 str&#xf…

C++ | 大小写字母转换

1.题目描述 实现字母的大小写转换。多组输入输出。 输入描述: 多组输入&#xff0c;每一行输入大写字母。 输出描述: 针对每组输入输出对应的小写字母。 答案如下&#xff1a; #include<iostream> using namespace std;int main(){ //----------------------------…

Java-大小写字母转换

题目&#xff1a;输入一段字符&#xff0c;包含大写字母或者小写字母&#xff0c;输出对应的大写或者小写转换&#xff0c;数字不管 代码实现&#xff1a; import java.util.Scanner;public class ZimuChange {public static void main(String[] args) {System.out.println(&qu…

线程中CreateEvent、SetEvent、WaitForSingleObject的用法

原文地址&#xff1a;https://www.cnblogs.com/MrYuan/p/5238749.html 首先介绍CreateEvent是创建windows事件的意思&#xff0c;作用主要用在判断线程退出&#xff0c;线程锁定方面. CreateEvent 函功能描述&#xff1a;创建或打开一个命名的或无名的事件对象. EVENT有两种…

CreateEvent SetEvent WaitForSingleObjec

在自动重置事件对象中&#xff0c;当WaitSingleObject/WaitForMultipleObjects接收到SetEvent发送过来的信号后则返回WAIT_OBJECT_0&#xff0c;此时操作系统&#xff08;待定&#xff09;自动重置等待的事件对象&#xff08;即自动将其设置为无信号状态。无论何时通过SetEvent…