实验二 STC8H8K64U程序控制结构与函数综合实验
📋 实验二 STC8H8K64U程序控制结构与函数综合实验
一、实验目的
- 掌握顺序结构程序的设计方法,理解语句按书写顺序执行的特性。
- 掌握选择结构(
if-else、switch-case)的语法格式及应用场景。 - 掌握循环结构(
while、do-while、for)的三种形式及其区别。 - 掌握函数的声明、定义和调用方法,理解模块化编程思想。
- 学会在无串口输出条件下通过软件仿真观察变量变化,验证程序逻辑。
二、实验设备与软件环境
1、硬件:STC8H8K64U单片机开发板(含USB下载电路)、USB数据线。
2、软件:
- Keil C51(支持STC8H系列)集成开发环境。
- STC-ISP下载软件(用于程序烧录)。
三、实验原理
3.1 顺序结构
程序按照代码书写顺序从上到下逐条执行,没有分支和循环。例如赋值、算术运算等语句。
3.2 选择结构
- if-else:根据条件表达式的真假执行不同分支。可嵌套或多分支(else if)。
- switch-case:基于整型表达式的值跳转到对应case执行,常用于多分支等值判断。
3.3 循环结构
- while:先判断条件,条件为真时执行循环体,可能一次都不执行。
- do-while:先执行一次循环体,再判断条件,至少执行一次。
- for:集初始化、条件判断、循环变量更新于一体,适用于已知循环次数的情况。
3.4 函数
- 声明:告诉编译器函数名、返回值类型和参数类型。
- 定义:提供函数的具体实现。
- 调用:通过函数名和实参执行函数体,可获得返回值。
四、实验内容
分析并运行提供的参考程序,该程序演示了以下内容:
- 顺序结构:定义整型变量a、b、c、d,依次进行加法和乘法运算。
- 选择结构:
• 用if-else根据成绩score划分等级level。
• 用switch-case根据option的值给resultSwitch赋值。 - 循环结构:
•while计算1~10的和。
•do-while计算5的阶乘。
•for遍历数组arr并求和。 - 函数:
• 声明并定义加法函数add、偶数判断函数isEven。
• 定义demoFunctionCall函数,内部调用add和isEven。
• 在main中调用上述函数,并使用addResult、evenCheck接收返回值。
五、实验步骤
5.1 创建工程并编写代码
- 打开Keil软件,新建工程,选择单片机型号STC8H8K64U(若无此型号,可先选任意8051,然后通过STC-ISP添加头文件)。
- 新建源文件
main.c,将实验代码完整输入(注意代码中for (int k=0;...若编译器报错,可将int k提前到函数开头定义,如int k;后for(k=0;...)。 - 工程配置:生成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)中以下变量的变化:
顺序结构:a、b、c、d
选择结构:score、level、option、resultSwitch
循环结构:sumWhile、product、sumFor
函数相关:addResult、evenCheck - 验证每个变量是否按预期变化。例如c应为15,d应为30,level应为'B'(ASCII 66),resultSwitch应为20,sumWhile应为55,product应为120,sumFor应为30,addResult应为300,evenCheck应为1。
5.4 硬件下载与运行(可选)
- 使用STC-ISP软件,选择单片机型号STC8H8K64U,打开生成的HEX文件。
- 开发板上电,通过USB或串口线连接,点击“下载/编程”。
- 下载成功后程序自动运行。虽无输出外设,但可通过在while(1)中添加LED闪烁代码(例如
P10=~P10; delay();)来验证程序正常运行。
5.5 修改与扩展练习
- 将
if-else的分数段改为90以上'A',80~89为'B',70~79为'C',60~69为'D',其余为'E',修改代码并仿真验证。 - 将
switch的option值改为3,观察resultSwitch的变化。 - 用
for循环改写while的1~10求和,比较两种写法的异同。 - 编写一个函数
int factorial(int n),计算n的阶乘,并在main中调用它计算6!。
六、实验结果与分析
6.1 预期结果(仿真观察值)
| 变量名 | 初始值 | 操作后值 |
|---|---|---|
| c | 未初始化 | 15 |
| d | 未初始化 | 30 |
| level | 未初始化 | 'B' (ASCII 66) |
| resultSwitch | 0 | 20 |
| sumWhile | 0 | 55 |
| product | 1 | 120 (1×2×3×4×5) |
| sumFor | 0 | 30 (2+4+6+8+10) |
| addResult | 未初始化 | 300 (100+200) |
| evenCheck | 未初始化 | 1 (300是偶数) |
| finalCheck | 0 | 15+30+66+20+55+120+30+300+1 = 637 |
6.2 分析
- 顺序结构:变量c和d严格按书写顺序计算,结果正确。
- 选择结构:score=85满足score>=75,执行level='B';option=2匹配case 2,resultSwitch=20。
- 循环结构:
while循环累加1~10,循环变量i从1递增至11时退出。do-while循环先执行一次product*=j,j从1到5,得到120。for循环用k作为下标遍历数组,累加元素值。
- 函数调用:add(100,200)返回300,isEven(300)返回1;demoFunctionCall内部局部变量dummy不影响外部。
- 防优化:volatile修饰的finalCheck强制编译器保留计算过程,便于仿真观察。
七、思考题
1. do-while循环与while循环的根本区别是什么?本实验中如果将计算阶乘的do-while改为while,需要修改哪些地方?
答:do-while至少执行一次循环体,while可能一次也不执行。改为while时需先初始化 j=1, product=1,然后 while{product*=j; j++;},结果相同。
2. 在switch语句中,如果省略break会发生什么?请结合本实验的option=2举例说明。
答:省略break会发生“穿透”,即执行完匹配的case后继续执行后续case的代码。例如本实验中若case 2后无break,则执行 resultSwitch=20 后再执行 case 3 的 resultSwitch=30,最终结果为30。
3. 函数的声明和定义可以放在调用之后吗?本实验中将add的定义放在main之后,但程序仍能编译,为什么?
答:可以,但必须在调用前进行声明。本实验在文件开头声明了 add,所以定义可以放在main之后。若既无声明也无定义(完全在调用后定义),则编译报错。
4. 为什么要使用volatile关键字修饰finalCheck?如果不使用,在Keil默认优化级别下可能发生什么?
答:volatile告诉编译器该变量可能被外部因素改变(实际此处为防止优化),避免编译器将未被使用的变量或计算删除。无volatile时,由于finalCheck后续未被使用,编译器可能优化掉整个计算过程,导致仿真时看不到正确结果。
八、实验报告要求
- 简述实验目的及实验原理。
- 粘贴完整的实验代码,并在关键行添加注释,说明顺序、选择、循环结构和函数的实现。
- 记录仿真调试中观察到的各变量值(可截图或列表),与预期结果对比。
- 回答“思考题”中的任意两个问题。
- 总结实验中遇到的问题(如语法错误、仿真观察技巧等)及解决方法,写出心得体会。
📎 附件:实验代码
#include <stc8h.h>
// 函数声明
int add(int a, int b);
int isEven(int num);
void demoFunctionCall(void);
// 加法函数
int add(int a, int b) {
return a + b;
}
// 判断偶数函数
int isEven(int num) {
if (num % 2 == 0)
return 1;
else
return 0;
}
// 演示函数调用的函数
void demoFunctionCall(void) {
int x, y, sum, evenFlag;
volatile unsigned char dummy; /* C89 要求所有变量在最前面声明 */
x = 7;
y = 8;
sum = add(x, y);
evenFlag = isEven(sum);
dummy = (unsigned char)(sum + evenFlag);
}
void main(void) {
/* ========== C89 风格:所有变量声明放在函数开头 ========== */
int a, b, c, d;
int score;
char level;
int option, resultSwitch;
int sumWhile, i;
int product, j;
int arr[5];
int sumFor, k;
int addResult, evenCheck;
volatile unsigned long finalCheck;
/* ========== 1. 顺序结构 ========== */
a = 5;
b = 10;
c = a + b;
d = c * 2;
/* ========== 2. 选择结构 ========== */
/* 2.1 if-else */
score = 85;
if (score >= 90) {
level = 'A';
} else if (score >= 75) {
level = 'B';
} else {
level = 'C';
}
/* 2.2 switch */
option = 2;
resultSwitch = 0;
switch (option) {
case 1: resultSwitch = 10; break;
case 2: resultSwitch = 20; break;
case 3: resultSwitch = 30; break;
default: resultSwitch = 0; break;
}
/* ========== 3. 循环结构 ========== */
/* 3.1 while 循环 */
sumWhile = 0;
i = 1;
while (i <= 10) {
sumWhile += i;
i++;
}
/* 3.2 do-while 循环 */
product = 1;
j = 1;
do {
product *= j;
j++;
} while (j <= 5);
/* 3.3 for 循环 */
arr[0] = 2; arr[1] = 4; arr[2] = 6; arr[3] = 8; arr[4] = 10;
sumFor = 0;
for (k = 0; k < 5; k++) {
sumFor += arr[k];
}
/* ========== 4. 函数调用 ========== */
demoFunctionCall();
addResult = add(100, 200);
evenCheck = isEven(addResult);
/* 防止优化,汇总结果 */
finalCheck = c + d + (unsigned int)level + resultSwitch + sumWhile
+ product + sumFor + addResult + evenCheck;
/* 主循环 */
while (1) {
/* 空转 */
}
}
本站所有文章、数据、图片来源于网络,仅供学习使用,如有侵权,联系删除!