单片机主程序
- 格式:doc
- 大小:91.00 KB
- 文档页数:12
单片机上机实验报告【实验一】端口实验,掌握通过端口编程实现数据输出和输入的方法,并观察结果。
实验内容: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; 人眼可分辨。
单片机最小系统单片机最小系统是指以单片机为核心,配以必要的外围电路,实现一定功能的电路系统。
它通常包含单片机、电源、时钟电路、复位电路和程序存储器等部分。
下面将详细介绍单片机最小系统的构成和特点。
单片机:单片机是整个系统的核心,它负责数据处理和控制信号输出。
常用的单片机型号有AT89CPIC16F877A等。
电源:为单片机提供电能,一般采用直流电源,如5V、3V等。
时钟电路:为单片机提供时钟信号,常用的时钟芯片有0592MHz和4MHz等。
复位电路:当单片机出现程序跑飞或异常情况时,可以通过复位电路使单片机重新启动。
常用的复位芯片有MAX811等。
程序存储器:用于存储单片机程序,常用的存储器有EPROM、EEPROM 和Flash等。
结构简单:单片机最小系统以单片机为核心,配以外围电路,结构简单,易于实现。
功能灵活:通过编程,单片机可以实现各种不同的功能,如数据采集、控制输出、通信等。
可靠性高:由于单片机最小系统结构简单,所以其可靠性较高,适用于各种工业控制和智能家居等领域。
成本低廉:单片机最小系统的硬件成本较低,适用于各种低成本应用场景。
单片机最小系统是一种简单、灵活、可靠且低成本的电路系统,广泛应用于各种嵌入式系统开发中。
随着物联网、智能家居等领域的快速发展,单片机最小系统的应用前景也将更加广阔。
在嵌入式系统和智能硬件领域,单片机最小系统作为一种基本的控制器单元,具有广泛的应用价值。
本文将介绍单片机最小系统的设计与应用,包括系统设计、系统应用和系统优化等方面的内容。
单片机最小系统通常由微处理器(MCU)、电源电路、时钟电路和复位电路等组成。
在设计单片机最小系统时,需要根据具体的应用需求选择合适的微处理器,并搭建相应的电源电路、时钟电路和复位电路。
单片机最小系统的架构设计应考虑应用需求和系统可靠性。
一般而言,系统架构应包括以下几个部分:(1)微处理器:作为系统的核心,微处理器负责数据计算、处理和传输等任务。
单片机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语言编写单片机的开关程序,我们可以实现对开关状态的监测和控制。
单片机基础操作流程
单片机是一种集成电路,可以完成各种控制任务。
在进行单片
机的基础操作之前,我们需要准备好一些工具和材料,比如单片机
开发板、USB数据线、编程软件等。
首先,我们需要连接单片机开发板和电脑,使用USB数据线将
它们连接起来。
然后,打开编程软件,比如Keil或者Arduino IDE,开始进行编程。
在编程之前,我们需要了解单片机的引脚功能和寄存器的作用。
单片机的引脚可以用来输入输出信号,连接外部设备,比如LED灯、按钮等。
寄存器则用来存储数据和控制单片机的各种功能。
接下来,我们可以开始编写程序了。
首先,我们需要定义引脚
的功能,比如将某个引脚设置为输出模式,控制LED灯的亮灭。
然后,我们可以编写控制逻辑,比如通过按下按钮来控制LED灯的开关。
编写好程序后,我们需要将程序下载到单片机中。
这个过程称
为烧录。
在Keil中,我们可以通过点击“Build”按钮来生成hex文件,然后通过烧录器将hex文件下载到单片机中。
在Arduino IDE 中,我们可以直接点击“Upload”按钮将程序下载到单片机中。
下载完成后,我们可以开始测试程序了。
通过按下按钮或者输
入信号,我们可以看到LED灯的亮灭情况,验证程序的正确性。
除了控制LED灯,单片机还可以实现更多功能,比如控制电机、读取传感器数据等。
通过不断学习和实践,我们可以掌握更多单片
机的基础操作流程,为以后的项目开发打下坚实的基础。
新型的按键扫描程序不过我在网上游逛了很久,也看过不少源程序了,没有发现这种按键处理办法的踪迹,所以,我将他共享出来,和广大同僚们共勉。
我非常坚信这种按键处理办法的便捷和高效,你可以移植到任何一种嵌入式处理器上面,因为C语言强大的可移植性。
同时,这里面用到了一些分层的思想,在单片机当中也是相当有用的,也是本文的另外一个重点。
对于老鸟,我建议直接看那两个表达式,然后自己想想就会懂的了,也不需要听我后面的自吹自擂了,我可没有班门弄斧的意思,hoho~~但是对于新手,我建议将全文看完。
因为这是实际项目中总结出来的经验,学校里面学不到的东西。
以下假设你懂C语言,因为纯粹的C语言描述,所以和处理器平台无关,你可以在MCS-51,AVR,PIC,甚至是ARM平台上面测试这个程序性能。
当然,我自己也是在多个项目用过,效果非常好的。
好了,工程人员的习惯,废话就应该少说,开始吧。
以下我以AVR的MEGA8作为平台讲解,没有其它原因,因为我手头上只有AVR的板子而已没有51的。
用51也可以,只是芯片初始化部分不同,还有寄存器名字不同而已。
核心算法:unsigned char Trg;unsigned char Cont;void KeyRead( void ){unsigned char ReadData = PINB^0xff; // 1Trg = ReadData & (ReadData ^ Cont); // 2Cont = ReadData; // 3}完了。
有没有一种不可思议的感觉?当然,没有想懂之前会那样,想懂之后就会惊叹于这算法的精妙!!下面是程序解释:Trg(triger)代表的是触发,Cont(continue)代表的是连续按下。
1:读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来。
2:算法1,用来计算触发变量的。
一个位与操作,一个异或操作,我想学过C 语言都应该懂吧?Trg为全局变量,其它程序可以直接引用。
单片机操作流程
第一步:点击PROJECT中的NEW PROJECT然后命名(要知道路径) ,保存,选择相对应的芯片型号,确定。
第二步:点击FILE,选NEW,输入程序,保存,需要知道路径名及其后缀。
第三步:在界面左侧窗口中的source group 1上点击右键,add file to group,找到刚保存的源文件,add,close 第四步:界面左侧窗口中的target 1上点击右键,options for target"target 1”第五步:在出现的界面中选择上方的output在“create hex file”前打对勾,确定。
第六步:在界面左侧窗口中的target 1上点击右键built target如提示信息中没有警告及错误即可。
第七步:关闭KEIL窗口,打开编程窗口(必须通讯正常) ,选择正确的芯片型号,点击擦除,然后点击加载,找到刚刚KEIL中编译生成的HEX文件,确定,编程即可。
(其间把芯片正确放入编程器的座上。
)。
一、程序的预处理和外部变量、函数定义#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];}}}}。