单片机主程序
单片机-第五章 单片机中断系统

(1)CPU正在执行一个同级或高优先级的中断服务程序; (2)正在执行的指令尚未执行完; (3)正在执行中断返回指令RETI或者对寄存器IE、IP进 行读/写的指令。 CPU在执行完上述指令之后,要再执行一条指令,才 能响应中断请求。
二、中断响应过程 从中断请求发生直到被响应,准备去执行中断服务程 序,此过程即中断响应过程。中断响应过程一般包括如下几 个阶段: 1、中断采样并置位 中断采样过程:CPU在每个机器周期S5P2期间顺序对 中断源采样、置中断标志。 2、查询标志 在中断采样后的下一个周期的S6按优先级顺序查 询中断标志。
第5章 MCS-51单片机中断系统
5.1.1中断的概念
单片机系统中,CPU和外部设备之间不断进行信息的传 输。通常CPU和外设之间的信息传送方式有以下几种: 程序控制方式 中断方式 直接存储器存取(DMA)方式
1、 程序控制方式 可以分为以下两种方式。 (1)无条件传送方式 外设始终处于就绪状态,CPU不必查询外设的状 态,直接进行信息传输,称为无条件传送方式。 此种信息传送方式只适用于简单的外设。如开 关和数码段显示器等。
三、中断响应的时间
一般来说,中断的响应时间最短为3个机器周期,最长 为8个机器周期。 一般中断请求标志位查询占1个机器周期。而机器周期 又恰好是指令的最后一个机器周期。执行此指令后,CPU 将响应中断,产生硬件长调用指令。 长调用LCALL指令需要2个机器周期。这样,中断响应 时间为3个机器周期。
是不可寻址的
在同级的几个中断源中同时发生请求时, 内部对同级的各中断源的优先级别有一个规 定的查询顺序: 自然优先级
外部中断请求 INT0 最高 定时/计数器 T0 外部中断请求 INT1 定时/计数器 T1 串行口 UART 最低 定时/计数器 T2
单片机程序流程图及源代码

单片机上机实验报告【实验一】端口实验,掌握通过端口编程实现数据输出和输入的方法,并观察结果。
实验内容:1)输出实验:假定4个端口全部连接发光二极管,编程实现所有发光二极管同时亮,延迟一定时间(自定)后,又同时灭,如此循环。
2)输入:从P0口输入某个数据到累加器A,打开观察窗口观察数据是否进入累加器A。
实现方式:通过peripherals实现端口数据观察实验。
程序流程图:将P0到P3端口先赋值为0,调用延迟后,再赋1,然后循环执行。
源代码:ORG 0000H ;程序入口地址LJMP MAIN ;跳转到主程序ORG 0300H ;主程序地址MAIN:MOV P0,#00H;MOV P1 ,#00H;MOV P2 ,#00H;MOV P3 ,#00H ;P0~P3均赋值为0ACALL DEL;调用延迟MOV P0 ,#0FFH;MOV P1 ,#0FFH;MOV P2 ,#0FFH;MOV P3 ,#0FFH;P0~P3均设为1MOV A,P0;将P0口值赋给累加器ACALL DEL;AJMP MAIN;跳转到主程序入口ORG 0200H;延迟程序入口地址DEL:MOV R5,#04H;寄存器实现延迟,F3:MOV R6,#0FFH;若主频为12MHZ则F2:MOV R7,#0FFH;延时为256*256*4F1:DJNZ R7,F1;0.26S,人眼可分辨DJNZ R6,F2;DJNZ R5,F3;RET;从延迟程序返回END;结束3.假设P0口外接一个数码管(共阴),如图,请在数码管上轮流显示数字0~9(采用软件延时)。
程序流程图:将数码管的真值编码0~9依次赋给P0并调用延迟,然后循环运行程序即可。
源代码:ORG 0000H; 程序入口SJMP MAIN; 跳转到主程序ORG 0300H; 主程序入口地址MAIN:MOV P0,#0FCH; 将数码管0的编码赋给P0口ACALL DELAY; 调用延迟,使数码管亮0持续0.33SMOV P0,#60H; show 1ACALL DELAY;MOV P0,#0DAH; show 2ACALL DELAY;MOV P0,#0F2H; show 3ACALL DELAY;MOV P0,#66H; show 4ACALL DELAY;MOV P0,#0B6H; show 5ACALL DELAY;MOVP0,#0BEH; show 6ACALL DELAY;MOV P0,#0E0H; show 7ACALL DELAY;MOV P0,#0FEH; show 8ACALL DELAY;MOV P0,#0F6H; show 9ACALL DELAY;AJMP LOOP; 跳转到主程序入口ORG 0200H; 延迟程序入口DEL:MOV R5,#05H; 采用软件延迟,若主频为12MHz,则DEL1:MOV R6,#0FFH; 定时时间为256*256*5*1uS=0.33S,DEL2:MOV R7,#0FFH; 人眼可分辨。
单片机C语言的程序设计

单片机(Microcontrollers)诞生于 1971 年,经历了 SCM、MCU、SoC 三大阶段,早期的 SCM 单片机都是 8 位或 4 位的。其中最成功的是 INTEL 的 8051,此后在 8051 上发展出了 MCS51 系列 MCU 系统。基于这一系统的单片机系统直到现在还在广泛使用。随着工业控制领域要求的提高,开始出现了 16 位单片机,但因为性价比不理想并未得到很广泛的应用。90 年代后随着消费电子产品大发展,单片机技术得到了巨大提高。随着 INTEL i960 系列特别是后 来的 ARM 系列的广泛应用,32 位单片机迅速取代 16 位单片机的高端地位,并且进入主流市场。而传统的 8 位单片机的性能也得到了飞速提高,处理能力比 起 80 年代提高了数百倍。高端的 32 位 Soc 单片机主频已经超过 300MHz,性能直追 90 年代中期的专用处理器,而普通的型号出厂价格跌落至 1 美元,最高 端的型号也只有 10 美元。当代单片机系统已经不再只在裸机环境下开发和使用,大量专用的嵌入式操作系统被广泛应用在全系列的单片机上。而在作为掌上 电脑和手机核心处理的高端单片机甚至可以直接使用专用的 Windows 和 Linux 操作系统。
03 8 只 LED 左右来回点亮
/*
名称:8 只 LED 左右来回点亮 说明:程序利用循环移位函数_crol_和_cror_形成来回滚动的效果
*/ #include<reg51.h> #include<intrins.h> #define uchar unsigned char #define uint unsigned int //延时 void DelayMS(uint x)
01
闪烁的 LED
/*
单片机基本结构及常用程序运行构架

switch(State) { case 1:分支程序1;
break;
case2:分支程序2;
break;
…… default:break;
}
二、程序的基本结构
2.3循环结构
在应用程序中,有时需要多次反复执行相同的操作, 只是操作的操作数(数据)不同,这是就可以采用循环 程序结构。循环程序可以显著缩短程序,减少程序所 占存储空间(ROM),使程序结构大大优化。
二、程序的基本结构
2.2 分支结构
分支结构根据分支数出口的多寡分 为单分支结构和多分支结构。
单支程序结构如右图:
EX:
if(Key==1) goto @F; //跳到下一 处@@处
$ LED Toggle; .delay 1000000; @@: NOP;
开始 程序段1
条件
Y
N
程序段A
程序段B
二、程序的基本结构
单片机程序基本构架及实 现
Kerwin 2019.11.20
目录
• 一、总述 • 二、程序的基本结构
• 2.1 顺序结构 • 2.2 分支结构 • 2.3 循环结构
• 三、单片机程序执行构架
• 3.1 简单顺序执行法 • 3.2 时间片轮询法 • 3.3 操作系统(略)
一、总述
单片机程序普遍采用结构化程序设计方法,任何复 杂的程序都是由
顺序结构 ……
程序段A
程序段B
……
二、程序的基本结构
2.2分支结构 顺序结构只解决一些简单的运算、
逻辑处理等。实际控制MCU往往 要求CPU能根据给定的条件进行 判断,再选择不同的处理路径, 从而表现出某种智能。 这时候就要求改变程序的执行顺 序,即程序的流向有两个或两个 以上,这种程序结构称为分支程 序结构。分支程序结构的特点是 程序根据不同条件,进行判断和 跳转。如右图
单片机最小系统

单片机最小系统单片机最小系统是指以单片机为核心,配以必要的外围电路,实现一定功能的电路系统。
它通常包含单片机、电源、时钟电路、复位电路和程序存储器等部分。
下面将详细介绍单片机最小系统的构成和特点。
单片机:单片机是整个系统的核心,它负责数据处理和控制信号输出。
常用的单片机型号有AT89CPIC16F877A等。
电源:为单片机提供电能,一般采用直流电源,如5V、3V等。
时钟电路:为单片机提供时钟信号,常用的时钟芯片有0592MHz和4MHz等。
复位电路:当单片机出现程序跑飞或异常情况时,可以通过复位电路使单片机重新启动。
常用的复位芯片有MAX811等。
程序存储器:用于存储单片机程序,常用的存储器有EPROM、EEPROM 和Flash等。
结构简单:单片机最小系统以单片机为核心,配以外围电路,结构简单,易于实现。
功能灵活:通过编程,单片机可以实现各种不同的功能,如数据采集、控制输出、通信等。
可靠性高:由于单片机最小系统结构简单,所以其可靠性较高,适用于各种工业控制和智能家居等领域。
成本低廉:单片机最小系统的硬件成本较低,适用于各种低成本应用场景。
单片机最小系统是一种简单、灵活、可靠且低成本的电路系统,广泛应用于各种嵌入式系统开发中。
随着物联网、智能家居等领域的快速发展,单片机最小系统的应用前景也将更加广阔。
在嵌入式系统和智能硬件领域,单片机最小系统作为一种基本的控制器单元,具有广泛的应用价值。
本文将介绍单片机最小系统的设计与应用,包括系统设计、系统应用和系统优化等方面的内容。
单片机最小系统通常由微处理器(MCU)、电源电路、时钟电路和复位电路等组成。
在设计单片机最小系统时,需要根据具体的应用需求选择合适的微处理器,并搭建相应的电源电路、时钟电路和复位电路。
单片机最小系统的架构设计应考虑应用需求和系统可靠性。
一般而言,系统架构应包括以下几个部分:(1)微处理器:作为系统的核心,微处理器负责数据计算、处理和传输等任务。
单片机c语言开关程序

单片机c语言开关程序单片机是一种集成电路,它具有微处理器、存储器和输入输出端口等功能。
在单片机中,C语言是一种常用的编程语言,可以用来开发各种程序。
本文将详细介绍如何使用C语言编写一个简单的开关程序。
开关是我们日常生活中常见的一种电子元件,它可以控制电路的通断。
在单片机中,我们可以通过编写程序来控制开关的状态。
下面是一个使用C语言编写的开关程序示例:```c#include <reg52.h> // 包含单片机的头文件sbit LED = P1^0; // 将P1.0引脚定义为LED输出口sbit SW = P3^2; // 将P3.2引脚定义为开关输入口void main(){LED = 0; // 初始状态下关闭LEDwhile(1){if(SW == 0) // 当开关按下时{LED = 1; // 打开LED}else{LED = 0; // 关闭LED}}}```上述程序使用了51单片机的C语言编程,通过将P1.0引脚定义为LED输出口,P3.2引脚定义为开关输入口,实现了一个简单的开关控制LED的功能。
在主函数中,我们首先将LED置为0,即关闭LED。
然后通过一个无限循环,不断检测开关的状态。
当开关按下时,开关引脚的电平为低电平(0),此时将LED置为1,即打开LED;当开关松开时,开关引脚的电平为高电平(1),此时将LED置为0,即关闭LED。
通过这段简单的代码,我们可以实现一个基本的开关控制LED的功能。
当按下开关时,LED会亮起;当松开开关时,LED会熄灭。
这个程序可以很好地理解开关的工作原理和单片机的输入输出控制。
当然,这只是一个简单的示例程序,实际应用中可能会更加复杂。
在实际开发中,我们可以根据需要添加更多的功能,如控制多个LED灯、设置开关的触发条件等。
通过不断学习和实践,我们可以掌握更多关于单片机C语言开发的技巧和知识,实现更多有趣和实用的功能。
通过C语言编写单片机的开关程序,我们可以实现对开关状态的监测和控制。
精品课件-单片机原理及应用系统设计-第4章

;
PUSH
DPL
;
保护现场, 将主程序中
; DPTR的低八位放入堆
MOV
DPTR, #TABLE
; 在子程
第四章 单片机程序设计语言
恢复现场,
MOVC A, @A+DPTR
POP
DPL
将主程序中DPTR
; ;
;的低八位从堆栈中弹出
POP 场, 将主程序中DPTR
DPH
; 恢复现
;的高八位从堆栈中弹出
图 4-8 循环程序的典型形式
第四章 单片机程序设计语言
【例 4-4】 冒泡程序。假设有N个数, 它们依次存放 于LIST地址开始的存储区域中, 将N个数比较大小后, 使它 们按照由小到大的顺序排列,
编写该程序的方法: 依次将相邻两个单元的内容作比较, 即第一个数和第二个数比较,第二个数和第三个数比 较, ……, 如果符合从小到大的顺序则不改变它们在内存 中的位置,否则交换它们之间的位置。如此反复比较, 直到 数列排序完成为止。
LJMP MAIN
;
MAIN: MOV A, X
XRL A, Y
; (X)与(Y)进行异或操作
JB ACC.7, NEXT1
; 累加器A的第7位
为1, 两个数
;符号不同, 转移到
第四章 单片机程序设计语言
MOV
CJNE
转移到NEQUAL
CLR
P1.0置0
S
MOV DXCE1COUNTER, #00H
; 将DXCE1COUNTER赋值为0
而如下的注释则给出了额外有用的信息:
JNZ PC Comm_Err
;
第四章 单片机程序设计语言
(2) 注释应与其描述的代码相近, 对单条语句的注释应 放在其上方或右方相邻位置, 不可放在下面, 如放于上方
单片机基础操作流程

单片机基础操作流程
单片机是一种集成电路,可以完成各种控制任务。
在进行单片
机的基础操作之前,我们需要准备好一些工具和材料,比如单片机
开发板、USB数据线、编程软件等。
首先,我们需要连接单片机开发板和电脑,使用USB数据线将
它们连接起来。
然后,打开编程软件,比如Keil或者Arduino IDE,开始进行编程。
在编程之前,我们需要了解单片机的引脚功能和寄存器的作用。
单片机的引脚可以用来输入输出信号,连接外部设备,比如LED灯、按钮等。
寄存器则用来存储数据和控制单片机的各种功能。
接下来,我们可以开始编写程序了。
首先,我们需要定义引脚
的功能,比如将某个引脚设置为输出模式,控制LED灯的亮灭。
然后,我们可以编写控制逻辑,比如通过按下按钮来控制LED灯的开关。
编写好程序后,我们需要将程序下载到单片机中。
这个过程称
为烧录。
在Keil中,我们可以通过点击“Build”按钮来生成hex文件,然后通过烧录器将hex文件下载到单片机中。
在Arduino IDE 中,我们可以直接点击“Upload”按钮将程序下载到单片机中。
下载完成后,我们可以开始测试程序了。
通过按下按钮或者输
入信号,我们可以看到LED灯的亮灭情况,验证程序的正确性。
除了控制LED灯,单片机还可以实现更多功能,比如控制电机、读取传感器数据等。
通过不断学习和实践,我们可以掌握更多单片
机的基础操作流程,为以后的项目开发打下坚实的基础。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、程序的预处理和外部变量、函数定义#include “at89x52.h”#include<math.h>#include<absacc.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned int#define nop _nop_() /*定义空操作指令*/#define maxvolt 300#define minvolt 5#define minfre 0#define maxfre 4000#define UM 300#define IM 2#define fc 12000#define KP 0.2#define KI 25#define KD 0#define COM8155 XBYTE[0x7FF8]#define PA XBYTE[0x7FF9]#define PB XBYTE[0x7FFA]#define R0 XBYTE[0Xdf00]#define R1 XBYTE[0Xdf01]#define R2 XBYTE[0Xdf02]#define R3 XBYTE[0Xdf03]#define R4 XBYTE[0Xdf04]#define R5 XBYTE[0Xdf05]#define R14 XBYTE[0Xdf0E]#define R15 XBYTE[0Xdf0F]sbit SCL=P3^4; /*24C01 SCL接脚=89C52 T0 P3.4*/sbit SDA=P3^5; /*24C01 SDA接脚=89C52 T1 P3.5*/sbit RST=P1^0;bit FLAG0=0,wuxiao=0,CHF=0,CHA=0,exit;/*设定位标号FLAG0=1键盘扫描回应*/Char ptr=0,ptr1=0; /*PTR键盘扫描指标,ptr1显示器扫描指标*/Char a1=0,b1=100; /*宣告变数a1为TIMER0的中断次数,ptr为TIMER1扫描数码管指标*/char ini[6]={0x40,0x5A,0x2c,0x02,0x00,0x00};//放置初始化数据char con[6]={0xcd,0xcc,0x06,0x80,0x80,0x80};//放置控制数据static const char tab[16]={0x01,0x02,0x03,0x0c, /*键盘码00,01,02,03,*/0x04,0x05,0x06,0x0d, /*键盘码04,05,06,07,*/0x07,0x08,0x09,0x0e, /*键盘码08,09,0a,0b,*/0x0a,0x00,0x0b,0x0f}; /*键盘码0c,0d,0e,0f*/static const char duanxuan[17]={0x3F,0x06,0x5b,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};char lia=0,lu=0,dot,weishu=0;char dispel[8]; //显示值存放阵列char bufdata[9];char bufuart[6]; //串口接收值存放列阵float vdataset=220;float vdata[3]={220,220,220};void delay (uint value) //延时子程序{while(value!=0)value--;//10US延时}void tserial(void); //串口serial发送子程序void rserial(void); //串口serial接收子程序void chvolt(void); //改变输出电压幅值子程序void chfre(void); //改变输出电压频率子程序void xch(void); //宣告按键存放/显示器阵列disple[]右键滚入子程序二、主程序清单main() /*主程序*/{ char I;TMOD=0X21; /*TIMER0工作在方式MODE1,16位定时器*//*TIMER1工作在MODE2,自动重新装载模式*//*方式寄存器TMOD *//*|定时器1 |定时器1 |*//*|GATE|C/T|M1|M0|GATE|C/T|M1|M0|*//*|||*/ TH0=(65536-3000)/256; /*设定每隔3000us中断扫描一次数码管*/TL0=(65536-3000)%256;TR0=1; /*启动TEMER0*/TH1=(65536-9200)/256; /*设TIMER1计数值*/TL1=(65536-9200)%256;TR1=1; //启动TEMER1//显示初始化disple[7]=0x73; //最左的显示器显示P,表示处于停止态for(i=2;i<=6;i++)disple[i]=0x00; //第3-7位显示器灭disple[1]=0x3e;//初态第二位显示器显示U,表示电压disple[0]=0x06;//初态第一位显示器显示1,表示第一相P2_0=1;P1=0XF0; //P1低4位为全0,高4位写入1COM8155=3; /*8155初始化,设定PA、PB工作在基本输出方式*/RST=0;//进行4828初始化;R0=imi[0];R1=imi[1];R2=imi[2];R3=imi[3];R4=imi[4];R5=imi[5];R14=0; //R0-R5装入初始化寄存器//向8248写控制数据R0=con[0];R1=con[1];R2=con[2];R3=con[3];R4=con[4];R5=con[5];R15=0; //RO-R5装入控制寄存器IP=0x0b; /*中断优先级寄存器IP *//*|︱|PT2|PS|PT1|PX1|PT0|PX0|*/IE=0X9f; /*︱7 6 5 4︱3 2 1 0︱*//*|EA||ET2|ES|ET1|EX1|ET0|EX0|*/While(1); //等中断}三、故障中断处理程序Void service_int0() interrupt 0 using 0 /*外部中断0,为故障中断*/ { int i;RST=0;for(i=0;i<=7;i++)disple[i]=0x31; //显示故障信息}四、键盘中断处理程序Void external_int1()interrupt2 using 2//键盘中断,进行按键命令处理{char a1=0xf7,i,m,xiantai; /*a1=0XF7行扫描初值,I行*/bit flag1=0;IE&=OXFB;Delay(1000); //延时10msFLAG0=0; /*设按键回应旗号为0,键盘扫描计数指标为0*/ptr=0;if(P3_2==0) /*按键仍闭合则进行键处理*/{For(i=0;i<4;i++) /*键盘4个扫描列*/{P1=a1; /*行扫描输出,读入P1存入M,以便侦测列与侦测按键是否按下*/m=P1;switch(m&0xf0) /*取P1的高4位元。
侦测那一列被按*/{case 0x70:ptr=i*4; /*第一列被按否?是则扫描指标=列X4*/FLAG0=1; /*是则设FLAG0=1表有按键输入*/break; /*跳出此循环*/case 0xb0:ptr=i*4+1; /*第二列被按否?是则扫描指标=列X4+1*/FLAG0=1; /*是则设FLAG0=1表有按键输入*/break; /*跳出此循环*/case 0xd0:ptr=i*4+2; /*第三列被按否?是则扫描指标=列X4+2*/FLAG0=1; /*是则设FLAG0=1表有按键输入*/break; /*跳出此循环*/case 0xe0:ptr=i*4+3; /*第四列被按否?是则扫描指标=列X4+3*/FLAG0=1; /*是则设FLAG0=1表有按键输入*/Default: break; /*跳出此循环*/}if(FLAG0==1)break; /*不为1,则扫描行右移,扫描下一行*/a1=a1>>1|0x80; /*高位补1*/}if(FLAG0==0)return;switch(tab[ptr])/*是键盘扫描计数器指标至TAB[]取到的键盘码*/ {case 0x0a: /*是否是第一次按“START”,是则启动SA4828的SPWM输出,最左的显示器显示D,表示SA4828在运行*/if(flag1==0){RST=1;flag1=1;dispel[7]=duanxuan[0x0D];}break; /*跳出此循环*/case 0x0b: /*是否按“STOP”是则停止SA4828的SPWM输出*/RST=0;flag1=0;dispel[7]=0x73;//最左的显示器显示P,表示处于停止态break; /*跳出此循环*/case 0x0e: /*是否按“调压”,是则进行相应处理*/if(CHF==0) /*调压与调频互锁,当调频时,按调压键无效*/{If(CHA==0){ CHA=1;for(i=2;i<=6;i++)dispel[i]=0x00;/*进入调压状态2位-6位显示器起初为全灭*/xiantai=disple[7];disple[1]=0x3e;dispel[0]=0x00;}else{ if(weishu!=0)chvolt();//进行改变电压控制数据的处理;If(wuxiao==1){for(i=2;i<=6;i++)dispel[i]=0;//调用显示“00000”for(i=0;i<10;i++)delay(10000);/*延时1秒*/while(m==p1);delay(1000);}weishu=0;dot=0;disple[7]=xiantai;if(lia==0)disple[1]=0x3e;else disple[1]=duanxuan[0x0A];disple[0]=duanxuan[lu+1];CHA=0;If(wuxiao==1){wuxiao=0;return;}}}Break; /*跳出此循环*/case 0x0f: /*是否按“调频”,是则进行相应处理*/if(CHA==0) /*调压与调频互锁,当调压时,按调频键无效*/ { if(CHF==0){CHF=1;for(i=2;i<=6;i++)disple[i]=0x00;/*进入调频状态2位-6位显示器起初为全灭*/xiantai=disple[7];disple[7]=duanxuan[0x0A];disple[1]=duanxuan[0x0F];disple[0]=0x00;}else{if(weishu!=0)chfre(); //进行改变频率控制数据的处理;if(wuxiao==1){for(i=2;i<=6;i++)disple[i]=0;//调用显示“00000”;for(i=0;i<10;i++)delay(10000);/*延时1秒*/while(m==P1);delay(1000);}weishu=0;dot=0;disple[7]=xiantai;if(lia==0)disple[1]=0x3e;else disple[1]=duanxuan[0x0A];disple[0]=duanxuan[lu+1];CHF=0;If(wuxiao==1){wuxiao=0;return;}}}break; /*跳出此循环*/case 0x0c: /*是否按“显示切换及·键”,是则进行相应处理*/if(CHA==1||CHF==1)/*当进入数字输入处理时,该键为·键,进行处理*/{ if(dot==0)dot=1;}else //为显示切换键{lia++;if(lia>1)lia=0;if(lia==0)disple[1]=0x3e;else disple[1]=duanxuan[0x0A];}break; /*跳出此循环*/case 0x0d: /*是否按“三相切换及退出键”,是则进行相应处理*/ if(CHA==1‖CHF==1)//当进入数字输入处理时,该键为退出键{exit=1;for(i=2;i<=6;i++)disple[i]=0;disple[7]=xiantai;if(lia==0)disple[1]=0x3e;else disple[1]=duanxuan[0x0A];disple[0]=duanxuan[lu+1];while(m==P1);delay(1000); //按钮抗机械反弹跳delay(10000); //延时100ms显示if(CHA==1){CHA=0;}if(CHF==1){CHF=0;}exit=0;return;}else //为三相切换键{lu++;if(lu>3)lu=0;disple[0]=duanxuan[lu+1];}break; //跳出此循环default: //以上均不是则为数字键,当进入调压、调频/调速状态才有效 if(CHA==1‖CHF==1)xch(); //数字键输入处理break; //跳出此循环}while(m==P1); //等键释放delay(1000); //按钮抗机械反弹跳P1=0Xf0; //回复P1低4位为全0,高4位写入1 }}五、数字显示向左移动子程序Void xch(void) /*数字显示向左移动子程序*/{ char c;if(dot!=2)if(weishu<5){ weishu ++;for(c=6;c>3;c--)disple[c]=disple[c-1]; /*将显示器disple[]移位交换,disple[3]->disple[4]->disple[5]…*/ }disple[2]=duanxuan[tab[ptr]]; /*新的按键值存入disple[2]*/if(dot==1)dot=2;} /*返回主程序*/六、改变输出电压幅值子程序Void chvolt(void){ char I,j,VA,APE;int k;vdataset=0;for(i=0;i<weishu;i++){ k=1;for(j=1;j<=I;j++)k*=10;vdataset+=disple[i+2]*k;}if(dot==2)vdataset+=disple[2]/10; /*当有输入小数点且小数点后有输入数字,则加上只有一位的小数部分*/ if(vdataset<=maxvolt&&vdataset>minvolt)//进行输入电压数据是否有效判别{for(i=0;i<=2;i++)vdata[i]=vdataset;APE=vdataset/maxvolt;VA=APE*255+0.5; //进行向SA4828写调压数据;con[3]=VA;R3=con[3]; //只改变输出电压幅值,其他寄存器不用变;R4=con[3];R5=con[3];R15=0;}else wuxiao=1;}七、改变输出电压频率子程序Void chfre(void){ char i,j,fdatain=0,m,k;Uint npfs;float fdata=0,fr;for(i=0;i<weishu;i++){ k=1;for(j=1;j<=i;j++)k*=10;fdatain+=disple[i+2]*k;}if(dot==2)fdata=fdatain+disple[2]/10;/*当有输入小数点且小数点后有输入数字,则加上只有一位的小数部分*/ if(fdata<=maxfre&&fdata>=minfre)//进行输入频率数据是否有效判别{if(fdata<=50)fr=62.5;if(fdata<=100)fr=125;else if(fdata<=1000)fr=1000;else if(fdata<=4000)fr=4000;i=fr*384/fc;j=0;k=1;for(m=0;m<=6;m++){ if(i==k)j=1;if(j==1)break;k=k<<1;}if(j==0){wuxiao=1;return;}//重写初始化数据for(j=1;j<=5;j++)m=m<<1;ini[0]&=0x0f;ini[0]︱=m;RST=0;R0=ini[0];R1=ini[1];R2=ini[2];R3=ini[3];R4=ini[4];R5=ini[5];R14=0;//重写控制数据npfs=fdata*65536/fr;con[0]=npfs%256;con[1]=npfs/256;R0=con[0];R1=con[1];R2=con[2];R3=con[3];R4=con[4];R5=con[5];R15=0;RST=1;}else wuxiao=1;}八、数码管扫描定时中断程序Void service_timer0() interrupt 1 using 1{ static char ch=0X01;TH0=(65536-3000)/256; /*每隔3000US扫描一次*/TL0=(65536-3000)%256;//写8155PA、PB口PA=ch;PB=disple[ptrl];if(CHA==1‖CHF==1){if(wuxiao==0&&exit==0){ if(dot==1){if(ptr1==2)PB︱=0x01;}else if(dot==2){if(ptr1==3)PB︱=0x01;}}}else{if(lia==0){if(ptr1==3)PB︱=0x01;} //显示电压数据的小数点else if(ptr1==4)PB︱=0x01; //显示电流数据的小数点}ch=ch<<1;if(ch==0)ch=1;ptr1++;if(ptr1>7)ptr1=0;}九、定时采集、计算、控制中断程序清单#define address 0Xbff8Char b2=5;Float vcdata[3][3],verror[3][3],vadjust[3];Void service_timer1() interrupt 3 using 3/*TIMER1 中断程序-50ms计时器,进行定时数据采集、计算、控制及显示*/ {int dispdataint;char i,j,k,n,t,wei=0;float APE,dispdata,xiaodata;char VA;TH1=(65536-9200)/256; /*重设TIMER1计数值*/TL1=(65536-9200)%256;b2--; /*中断次数减1*/if(b2==0) /*中断次数完成否,是则表50ms到了*/{b2=5; /*重设中断次数*/for(i=0,k=0;i<=1;i++) //i=0,测量电压;i=1,测量电流for(j=0;j<=2;j++)//j表示测量那一路,是0路、1路还是2路{vcdata[i][j]=0;for(n=1;n<=3;n++)//对一个量进行连续三次采样,取平均值,起滤波作用{XBYTE[address+k]=k;delay(10);while(P3_4==0);vcdata[i][j]+=XBYTE[0Xbfff];k++;}if(i==0) vcdata[i][j]=vcdata[i][j]*UM/(255*3);else vcdata[i][j]=vcdata[i][j]*IM/(255*3);if(i==0)//电压须计算偏移量、调整量,然后向SA4828写控制数据{verror[j][0]=verror[j][1];verror[j][1]=verror[j][2];verror[j][2]=vcdata[i][j]-vdataset;vadjust[j]=KP*(verror[j][2]-verror[j][1]+KI*0.05*verror[j][2]/KP+KD*(verror[j][2]-2*verror[j][1]+verror[j][0])/(KP*0.05));vdata[j]=vdata[j]+vadjust[j];//进行向SA4828写调压数据APE=vdata[j]/maxvolt;if(APE>1)APE=1;VA=APE*255+0.5;if(j==0)R3=VA; //只改变输出电压幅值,其它寄存器不用变; else if(j==1)R4=VA;else R5=VA;R15=0;}}/*当满足条件时,将要显示的电量写入显示缓冲区*/dispdata=vcdata[lia][lu];dispdataint=(int)dispdata;if(CHA==0&&CHF==0){if(lia==0)/*为显示电压数据*/{j=dispdataint/1000;if(j!=0){disple[6]=duanxuan[j];wei=4;}else disple[6]=0;dispdataint=dispdatint-j*1000;}K=dispdataint/100;if(wei==0){if(k!=0){disple[5+lia]=duanxuan[k];wei=3;}else disple[5+lia]=0;}Else disple[5+lia]=duanxuan[k];dispdataint=dispdatain-k*100;n=dispdataint/10;if(wei==0){if(n!=0){disple[4+lia]=duanxuan[n];wei=2;}else disple[4+lia]=0;}else disple[4+lia]=duanxuan[n];dispdataint=dispdataint-n*10;t=dispdataint;disple[3+lia]=duanxuan[t];if(t!=0)wei=1;xiaodata=dispdata-(int)dispdata;dispdataint=(int)(xiaodata*10);disple[2+lia]=duanxuan[dispdataint];if(lia==1){dispdataint=(int)(xiaodata*100-dispdataint*10);disple[2]=duanxuan[dispdataint];}}}}。