实验一 STC8H8K64U数据类型定义与引用
📋 实验一 STC8H8K64U数据类型定义与引用
一、实验目的
- 掌握在STC8H8K64U单片机C语言程序中定义和初始化基本数据类型(字符型、整型、浮点型)的方法。
- 掌握一维数组的定义、初始化及元素的引用方法。
- 掌握结构体类型的定义、结构体变量的初始化及成员引用方法。
- 熟悉在无串口输出条件下,通过仿真或内存观察验证数据操作的正确性。
二、实验设备与软件环境
1、硬件:STC8H8K64U单片机开发板(含USB下载电路)、USB数据线。
2、软件:
- Keil C51(或Keil MDK,需支持STC8H系列)集成开发环境。
- STC-ISP下载软件(用于程序烧录)。
三、实验原理
3.1 C语言基本数据类型
- 字符型(char):占用1字节,用于存储ASCII字符或小整数。
- 整型(int):STC8H8K64U中默认16位,范围-32768~32767。
- 浮点型(float):占用4字节,符合IEEE-754标准,用于带小数点的数值。
3.2 数组
相同类型元素的集合,通过下标索引访问。例如 int scores[5] 定义5个整型元素的数组。
3.3 结构体
将不同类型的数据组合为一个整体。例如本实验中的 Student 结构体包含姓名(字符数组)、年龄(整型)、成绩(浮点型)。
3.4 变量的引用
引用即使用变量名访问其存储的值,可通过赋值、运算、函数参数等方式实现。
四、实验内容
分析并运行提供的参考程序,该程序演示了以下操作:
- 字符型变量:定义
grade并初始化为'A',随后重新赋值为'B'。 - 整型变量:定义
count和result,计算count + 5并存入result。 - 浮点型变量:定义
pi和area,计算半径为2.0的圆面积。 - 数组:定义
scores[5]并初始化五个成绩,修改第三个元素,然后循环累加求和。 - 结构体:
• 定义Student结构体类型。
• 定义结构体变量stu1并在定义时初始化。
• 定义结构体变量stu2,通过逐成员赋值方式初始化。
• 计算两名学生的平均成绩。
五、实验步骤
5.1 创建工程并编写代码
- 打开Keil软件,新建工程,选择单片机型号STC8H8K64U(若列表中无,可先选择任一8051型号,后期通过STC-ISP添加头文件)。
- 新建源文件
main.c,将提供的实验代码完整输入。 - 工程配置:生成HEX文件(Output → Create HEX File)。
5.2 编译与语法检查
点击编译(Build),确保无错误、无警告。若提示 stc8h.h 找不到,请从STC官方下载并复制到Keil安装目录的 C51/INC 文件夹下,或使用 #include <reg51.h> 并手动补充必要定义(建议直接使用官方头文件)。
5.3 仿真调试(观察变量值)
由于程序无串口输出,推荐采用仿真方式观察各变量的内存值:
- 进入Keil调试模式(Debug → Start/Stop Debug Session)。
- 在main函数入口处设置断点(双击代码行左侧灰色区域)。
- 单步执行(F11),依次观察变量窗口(Watch Window)中以下变量的变化:
grade、count、result、pi、area、scores[0..4]、sum、stu1.age、stu1.score、stu2.name、avgScore等。 - 验证每个变量是否按预期被正确初始化或修改。
5.4 硬件下载与运行(可选)
- 使用STC-ISP软件,选择单片机型号STC8H8K64U,打开生成的HEX文件。
- 开发板上电,通过USB或串口线连接,点击“下载/编程”。
- 下载成功后程序自动运行。虽然无输出外设,但可通过观察开发板现象(如自行添加LED闪烁代码)或内存中变量的最终状态来确认程序运行正常。
5.5 修改与扩展练习
- 修改
scores数组的初始值,并重新计算和。 - 添加一个
Student类型数组class[3],并为其三个元素赋值,计算全班平均分。 - 尝试使用
double类型(STC8H支持但较慢)定义变量,观察编译后的代码大小差异。
六、实验结果与分析
6.1 预期结果(仿真观察值)
| 变量名 | 初始值 | 操作后值 |
|---|---|---|
| grade | 'A' | 'B' (ASCII 66) |
| result | (未初始化) | 15 |
| area | (未初始化) | 12.56636 (约4π) |
| scores[0..4] | 85, 92, 78, 90, 88 | 85, 92, 82, 90, 88 |
| sum | 0 | 85+92+82+90+88 = 437 |
| stu1.name | "张三" (GB2312编码) | 不变 |
| stu1.age | 20 | 不变 |
| stu1.score | 89.5 | 不变 |
| stu2.name | 未初始化 | "李四" |
| stu2.age | 未初始化 | 22 |
| stu2.score | 未初始化 | 94.0 |
| avgScore | 未初始化 | (89.5+94.0)/2 = 91.75 |
6.2 分析
- 程序通过赋值、算术运算、数组下标访问、结构体成员操作等多种方式展示了数据类型的“引用”过程。
- 字符型变量可直接用单引号字符赋值,也可视为小整数参与算术运算(最后
dummy计算时隐式类型转换)。 - 结构体成员可通过点运算符(
.)引用,字符数组成员需要逐个字符赋值并手动添加结束符'\0'。 - 使用
volatile修饰dummy变量,防止Keil优化导致所有变量被清除。
七、思考题
1. 如果将 char grade = 'A' 改为 unsigned char grade = 'A',对后续运算结果有何影响?
答:在仅存储ASCII字符时('A' = 65),两者没有区别。但如果参与算术运算(如 dummy 计算),signed char 的范围是 -128~127,而 unsigned char 是 0~255,当字符最高位被置1时会影响符号扩展,但本实验中只是 'A'/'B',无实质影响。
2. 为什么 stu2.name 必须手动添加 '\0' 而 stu1.name 初始化时不需要?
答:因为 stu1 在定义时用字符串常量初始化,编译器会自动在末尾补 '\0';而 stu2.name 是通过逐个字符赋值的方式,必须手动添加结束符才能确保作为字符串正确处理。
3. 本程序中 area = pi * 2.0f * 2.0f 与 area = pi * 4.0f 相比,哪种更精确?为什么?
答:两种写法在数学上等价,但由于浮点数乘法遵循结合律和舍入规则,连续两次乘法可能引入稍多的舍入误差。实际测试中两者可能只有最低有效位差异,通常 pi * 4.0f 会更精确一点点,因为只进行一次乘法。
4. 如果不使用 volatile 关键字,在Keil默认优化级别下,dummy 的计算可能被优化掉,请验证并解释原因。
答:因为 dummy 赋值后从未被其他代码使用,编译器判定其无副作用,可能会优化掉整条计算,导致仿真时看不到所有相关变量的变化。volatile 强制编译器每次必须真实执行该操作。
八、实验报告要求
- 简述实验目的及实验原理。
- 粘贴完整的实验代码,并逐段注释说明每种数据类型的定义、初始化和引用过程。
- 记录仿真调试中观察到的各变量值(可截图或列表),与预期结果对比。
- 回答“思考题”中的任意两个问题。
- 总结实验中遇到的问题及解决方法,写出心得体会。
注意:本实验不强制要求串口输出,所有验证均可通过软件仿真完成。若需硬件直观显示,可在while(1)循环中添加LED闪烁或数码管显示代码,但需保证不影响原数据类型实验的核心逻辑。
📎 附件:实验代码
#include <stc8h.h>
/* 结构体定义:包含字符数组(姓名)、整型(年龄)、浮点型(成绩) */
typedef struct {
char name[20]; /* 字符型数组,存储姓名 */
int age; /* 整型,年龄 */
float score; /* 浮点型,成绩 */
} Student ;
void main(void)
{
/* ========== 所有变量声明必须放在函数开头(C89 规范) ========== */
/* 字符型 */
char grade;
/* 整型 */
int count;
int result;
int i; /* 循环变量(C89 不允许在 for 内声明) */
int scores[5]={1,2,3,4,5};
int sum;
/* 浮点型 */
float pi;
float area;
/* 结构体 */
Student stu1={"xiaowang",10,10};
Student stu2;
float avgScore;
/* 防止编译优化的临时变量 */
volatile unsigned char dummy;
/* ========== 以下是可执行语句 ========== */
/* 1. 字符型变量初始化与引用 */
grade = 'A'; /* 初始化 */
grade = 'B'; /* 重新赋值(引用) */
/* 2. 整型变量初始化与引用 */
count = 10; /* 初始化 */
result = count + 5; /* 引用 count 和常量 5,运算后赋值给 result */
/* 3. 浮点型变量初始化与引用 */
pi = 3.14159f; /* 初始化 */
area = pi * 2.0f * 2.0f; /* 引用 pi 进行运算 */
/* 4. 数组初始化与引用 */
scores[0] = 85;
scores[1] = 92;
scores[2] = 78;
scores[3] = 90;
scores[4] = 88; /* 逐个元素赋值(与 int scores[5] = {85,92,78,90,88}; 效果相同) */
scores[2] = 82; /* 修改第 3 个元素(引用) */
sum = 0;
for (i = 0; i < 5; i++) {
sum += scores[i]; /* 引用数组元素求和 */
}
/* 5. 结构体初始化与引用 */
/* stu1 初始化 */
stu1.name[0] = '老'; // 实际代码中这里应为正确的中文字符处理,实验参考代码如此
stu1.name[1] = '张';
stu1.age = 20;
stu1.score = 89.5f;
/* stu2 初始化 */
stu2.name[0] = '老';
stu2.name[1] = '张'; /* 实验代码中原始写法,实际工程需注意编码 */
/* 引用结构体成员进行计算 */
avgScore = (stu1.score + stu2.score) / 2.0f;
/* 简单运算,防止变量被优化(实际工程中可放入 while(1) 内) */
dummy = (unsigned char)(grade + result + (int)area + sum + (int)avgScore);
/* 主循环空转,演示完成 */
while (1) {
/* 可在此添加其他功能(如 LED 闪烁),但题目无要求 */
}
}
volatile 的作用,并善用 Watch Window 观察变量。
本站所有文章、数据、图片来源于网络,仅供学习使用,如有侵权,联系删除!