嵌入式C语言-P13
本笔记是学习 B站 嵌入式C语言高级课程过程中产生的疑问和回答汇总,有比较基础的知识也有嵌入式硬件结合的知识

1. 地址相差4个字节?
这些地址之间相差4个字节(即0x4)是一个非常普遍且重要的硬件设计特征。这并非偶然,而是由两个关键因素共同决定的:
-
地址总线按字节编址
-
寄存器宽度为32位(4字节)
详细解释:
1.1. 地址总线按字节编址
现代处理器的内存地址空间通常是以字节为最小单位进行编址的。这意味着:
-
地址
0xE270_0000指向第1个字节 -
地址
0xE270_0001指向第2个字节 -
地址
0xE270_0002指向第3个字节 -
地址
0xE270_0003指向第4个字节
1.2. 寄存器宽度为32位(4字节)
从图片中Reset Value(复位值)一列可以看到,这些寄存器的默认值如 0x00008021,这是一个32位的数值(8个十六进制数)。因此,每个看门狗定时器寄存器都需要占用 4个字节 的地址空间。
1.3. 结论:地址计算
将以上两点结合起来,原因就非常清晰了:
-
WTCON 是第一个寄存器,从基地址
0xE270_0000开始,占用了0x0000到0x0003这4个字节。 -
下一个寄存器 WTDAT 必须紧挨着它存放,所以从下一个可用的字节地址开始,也就是
0xE270_0000 + 4 = 0xE270_0004。 -
同理,WTCNT 的地址就是
0xE270_0004 + 4 = 0xE270_0008。 -
以此类推。
可以这样形象地理解:每个寄存器都是一个“房间”,这个“房间”的大小是4个“格子”(字节)。系统给每个“房间”分配门牌号(地址)时,用的是第一个“格子”的编号。那么下一个“房间”的门牌号,自然要往后数4个格子。
| 寄存器 | 地址(起始字节) | 占用的地址范围 |
| :— | :--------------- | :----------------------- |
| WTCON | 0xE270_0000| 0xE270_0000- ...0003|
| WTDAT | 0xE270_0004| 0xE270_0004- ...0007|
| WTCNT | 0xE270_0008| 0xE270_0008- ...000B|
| WTCLRINT | 0xE270_000C| 0xE270_000C- ...000F|
这种设计保证了每个寄存器都在其自然边界上对齐(32位数据在地址能被4整除的地方对齐),CPU访问对齐的内存时速度最快、效率最高,这是硬件设计的最佳实践。
2. 结构体定义
2.1. 什么是结构体?
你可以把它想象成一个“自定义的包裹”或“超级变量”。
-
普通变量:只能存储一个单一类型的数据,比如一个
int变量存整数,一个char变量存字符。 -
结构体变量:可以将多个不同类型的数据打包在一起,形成一个逻辑上的整体。这个“包裹”里的每一个数据称为结构的成员。
2.2. 为什么需要结构体?
在没有结构体之前,如果想描述一个学生(包含学号、姓名、成绩),您可能需要声明三个独立的变量:
int id;
char name[20];
float score;
这三个变量在语法上是完全独立的,管理起来很麻烦,尤其是当有多个学生时。
使用结构体,就可以创建一个名为 Student的新数据类型,把这三个信息捆绑在一起:
struct Student {
int id;
char name[20];
float score;
};
这样,每个 Student类型的变量就自然包含了这三项信息,逻辑清晰,易于管理。
2.3. 两个关键步骤
使用结构体通常分为两步:
2.3.1. 第一步:定义结构体类型(蓝图)
struct myabc {
unsigned int a;
unsigned int b;
unsigned int c;
unsigned int d;
};
-
作用:创建一种新的数据类型,而不是创建一个变量。
-
详解:
-
struct是C语言的关键字,告诉编译器“我要开始定义一个结构体了”。 -
myabc是这个新类型的名字,它被称为“结构标签”。它和int,float一样,现在是一种有效的类型名。 -
大括号
{}内是它的成员列表。这里定义了四个成员,都是unsigned int类型。 -
最后的分号
;至关重要,它标志着这个类型定义语句的结束。忘记这个分号是初学者常见的错误。
-
-
重要提示:这一步不会分配任何内存。它只是告诉编译器:“嗨,以后如果你看到
struct myabc,就知道它里面包着四个无符号整数,名字分别叫a, b, c, d。” 这就像绘制了一张建筑的蓝图,定义了房子的结构,但蓝图本身并不等于一栋真实的房子。
2.3.2. 第二步:声明结构体变量(根据蓝图盖房子)
struct myabc mybuf;
-
作用:使用已定义的结构体类型来创建具体的变量。
-
详解:
-
struct myabc指明了这个变量的类型。就像我们用int来声明一个整型变量一样,这里我们用自己定义的struct myabc来声明变量。 -
mybuf是您为这个结构体变量起的名字。
-
-
重要提示:到这一步,编译器才会为
mybuf分配实际的内存空间。这块内存的大小至少足以存放四个unsigned int(具体大小可能因内存对齐而略有增加)。-
现在,
mybuf就是一个实实在在的“包裹”了,你可以在程序中使用它。 -
你可以创建多个该类型的变量,例如
struct myabc yourbuf, hisbuf;,每个变量都有自己的独立内存空间。
-
2.4. 如何访问和使用结构体变量?
创建了结构体变量后,我们需要访问其内部的成员。这时需要使用成员访问运算符 .。
// 给 mybuf 的成员赋值
mybuf.a = 10;
mybuf.b = 20;
mybuf.c = 30;
mybuf.d = 40;
// 从 mybuf 的成员中读取值
int sum = mybuf.a + mybuf.b; // sum 的值将是 30
// 打印成员的值
printf("The value of a is: %u\n", mybuf.a);
2.5. 总结与类比
| 步骤 | 代码示例 | 类比 | 作用 | 是否分配内存 |
|---|---|---|---|---|
| 1. 定义类型 | struct MyStruct { int x; char c; }; |
绘制蓝图 | 创建一种名为 MyStruct的新复合数据类型 |
否 |
| 2. 声明变量 | struct MyStruct variable1; |
根据蓝图盖房子 | 创建一个实际可用的变量,类型为 MyStruct |
是 |
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)