实验一 STC8H8K64U数据类型定义与引用

📋 实验一 STC8H8K64U数据类型定义与引用

一、实验目的

  1. 掌握在STC8H8K64U单片机C语言程序中定义和初始化基本数据类型(字符型、整型、浮点型)的方法。
  2. 掌握一维数组的定义、初始化及元素的引用方法。
  3. 掌握结构体类型的定义、结构体变量的初始化及成员引用方法。
  4. 熟悉在无串口输出条件下,通过仿真或内存观察验证数据操作的正确性。

二、实验设备与软件环境

1、硬件:STC8H8K64U单片机开发板(含USB下载电路)、USB数据线。

2、软件:

  • Keil C51(或Keil MDK,需支持STC8H系列)集成开发环境。
  • STC-ISP下载软件(用于程序烧录)。

三、实验原理

3.1 C语言基本数据类型

  1. 字符型(char):占用1字节,用于存储ASCII字符或小整数。
  2. 整型(int):STC8H8K64U中默认16位,范围-32768~32767。
  3. 浮点型(float):占用4字节,符合IEEE-754标准,用于带小数点的数值。

3.2 数组

相同类型元素的集合,通过下标索引访问。例如 int scores[5] 定义5个整型元素的数组。

3.3 结构体

将不同类型的数据组合为一个整体。例如本实验中的 Student 结构体包含姓名(字符数组)、年龄(整型)、成绩(浮点型)。

3.4 变量的引用

引用即使用变量名访问其存储的值,可通过赋值、运算、函数参数等方式实现。

四、实验内容

分析并运行提供的参考程序,该程序演示了以下操作:

  1. 字符型变量:定义 grade 并初始化为 'A',随后重新赋值为 'B'
  2. 整型变量:定义 countresult,计算 count + 5 并存入 result
  3. 浮点型变量:定义 piarea,计算半径为2.0的圆面积。
  4. 数组:定义 scores[5] 并初始化五个成绩,修改第三个元素,然后循环累加求和。
  5. 结构体:
    • 定义 Student 结构体类型。
    • 定义结构体变量 stu1 并在定义时初始化。
    • 定义结构体变量 stu2,通过逐成员赋值方式初始化。
    • 计算两名学生的平均成绩。

五、实验步骤

5.1 创建工程并编写代码

  1. 打开Keil软件,新建工程,选择单片机型号STC8H8K64U(若列表中无,可先选择任一8051型号,后期通过STC-ISP添加头文件)。
  2. 新建源文件 main.c,将提供的实验代码完整输入。
  3. 工程配置:生成HEX文件(Output → Create HEX File)。

5.2 编译与语法检查

点击编译(Build),确保无错误、无警告。若提示 stc8h.h 找不到,请从STC官方下载并复制到Keil安装目录的 C51/INC 文件夹下,或使用 #include <reg51.h> 并手动补充必要定义(建议直接使用官方头文件)。

5.3 仿真调试(观察变量值)

由于程序无串口输出,推荐采用仿真方式观察各变量的内存值:

  1. 进入Keil调试模式(Debug → Start/Stop Debug Session)。
  2. 在main函数入口处设置断点(双击代码行左侧灰色区域)。
  3. 单步执行(F11),依次观察变量窗口(Watch Window)中以下变量的变化:
    gradecountresultpiareascores[0..4]sumstu1.agestu1.scorestu2.nameavgScore 等。
  4. 验证每个变量是否按预期被正确初始化或修改。

5.4 硬件下载与运行(可选)

  1. 使用STC-ISP软件,选择单片机型号STC8H8K64U,打开生成的HEX文件。
  2. 开发板上电,通过USB或串口线连接,点击“下载/编程”。
  3. 下载成功后程序自动运行。虽然无输出外设,但可通过观察开发板现象(如自行添加LED闪烁代码)或内存中变量的最终状态来确认程序运行正常。

5.5 修改与扩展练习

  1. 修改 scores 数组的初始值,并重新计算和。
  2. 添加一个 Student 类型数组 class[3],并为其三个元素赋值,计算全班平均分。
  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.0farea = pi * 4.0f 相比,哪种更精确?为什么?

答:两种写法在数学上等价,但由于浮点数乘法遵循结合律和舍入规则,连续两次乘法可能引入稍多的舍入误差。实际测试中两者可能只有最低有效位差异,通常 pi * 4.0f 会更精确一点点,因为只进行一次乘法。

4. 如果不使用 volatile 关键字,在Keil默认优化级别下,dummy 的计算可能被优化掉,请验证并解释原因。

答:因为 dummy 赋值后从未被其他代码使用,编译器判定其无副作用,可能会优化掉整条计算,导致仿真时看不到所有相关变量的变化。volatile 强制编译器每次必须真实执行该操作。

八、实验报告要求

  1. 简述实验目的及实验原理。
  2. 粘贴完整的实验代码,并逐段注释说明每种数据类型的定义、初始化和引用过程。
  3. 记录仿真调试中观察到的各变量值(可截图或列表),与预期结果对比。
  4. 回答“思考题”中的任意两个问题。
  5. 总结实验中遇到的问题及解决方法,写出心得体会。

注意:本实验不强制要求串口输出,所有验证均可通过软件仿真完成。若需硬件直观显示,可在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 闪烁),但题目无要求 */
    }
}
💡 提示:代码中结构体姓名赋值部分仅作为实验教学演示,实际涉及中文字符存储时需要正确处理编码(如GB2312或UTF-8)。实验重点关注数据类型定义、初始化和引用的语法,仿真时请留意 volatile 的作用,并善用 Watch Window 观察变量。

本站所有文章、数据、图片来源于网络,仅供学习使用,如有侵权,联系删除!