单片机实验2【完整】代码
单片机接口技术及实验(附原理图及源程序)

位,再循环回第一位。
(2)当开关K0接高电平时,四位动态显示“HELP”
二、实验原理图
三、实验流程图
四、实验程序
org 0000h
ljmp main
org 0100h
main:
mov p2,#0ffh
setb p1.0
mov dptr,#tab
LJMPPASS
L2: MOV A,#0C0H
LJMPPASS
L3: MOV A,#0AAH
LJMPPASS
L4: MOV A,#0E0H
LJMPPASS
PASS: RETI
END
实验三七段LED数码管控制实验
一、实验功能
1.实验采用4位一体的数码管,用P1口通过驱动芯片控制段码输出信号线,P0口
通过驱动芯片控制位选线:
JB 50H,S1
JNB 50H,S2
STEP1:JB 51H,LOOP1
JNB 51H,LOOP2
S1: LCALL DELAY1
LJMP STEP1
S2: LCALL DELAY2
LJMP STEP1
DELAY1: MOV R7,#100
D1: MOV R6,#100
D2: MOV R5,#10
2.
一、实验功能
实现一个4位秒表:
(1)用开关K0模拟秒表的启动、停止、清零功能,按一次启动计时,按一次停
止,再按一次清零,在三个状态中循环。
(2)最低位按1/10秒计数,依次计数单位为1/10秒,1秒,1分
(3)要求K0使用外部中断,优先级高于T0的优先级
二、实验原理图
单片机程序流程图及源代码

单片机上机实验报告【实验一】端口实验,掌握通过端口编程实现数据输出和输入的方法,并观察结果。
实验内容: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; 人眼可分辨。
单片机个实验代码详细

(1).初始化:启动AT89S51单片机进入ISP下载状态,若启动成功,则状态显示区就会显示如图3.2所示的文字。否则,不成功会有“初始化失败”的字样提示。
图3.2
(2).特征字:点击一下检测器件,会读出单片机的芯片的特征字,对于AT89S51单片机的特征字为:1E5106。
进入Keil C51后,屏幕如下图所示。几秒钟后出现编辑界
启动Keil C51时的屏幕
进入Keil C51后的编辑界面
简单程序的调试
学习程序设计语言、学习某种程序软件,最好的方法是直接操作实践。下面通过简单的编程、调试,引导大家学习Keil C51软件的基本使用方法和基本的调试技巧。
1)建立一个新工程
6)回到编辑界面后,单击“Target 1”前面的“+”号,然后在“Source Group1”上单击右键,弹出如下菜单
然后单击“Add File to Group ‘Source Group 1’”屏幕如下图所示
选中Test.c,然后单击“Add ”屏幕好下图所示 注意到“Source Group1”文件夹中多了一个子项“Text1.c”了吗?子项的多少与所增加的源程序的多少相同
单片机原理课程实验
实验一LED显示器指示
实验二软件延时及灯光控制实验
实验三多级外部中断实验
实验四脉冲频率的测量实验
实验五串行口扩展实验
实验六串行EEPROM的读出和写入实验
实验七8位A/D、D/A转换器的应用实验
实验八串行A/D、D/A的应用实验
实验九直流继电器的驱动及控制实验
实验十数据采集的软件抗干扰实验
(15)EEPROM
EEPROM(AT24C16),用来保存数据信息,接口序号为:串行数据线:SDA;时钟线:SCL;写保护线:WP。
单片机实验程序new

第一个实验:闪烁灯$regfile = "m16def.dat" '定义单片机型号$crystal = 8000000 '定义时钟频率8Mhz Config Portc.0 = OutputConfig Portc.1 = OutputDoPortc = 1 'portc=(01)2C0亮,C1不亮Wait 1 '延时1秒Portc = 2 'portc=(10)2C0不亮,C1亮Wait 1 '延时1秒Loop '循环End第二个实验:LED管跑马灯实验$regfile = "m16def.dat" '定义单片机型号$crystal = 8000000 '定义时钟频率8MhzConfig Portc = Output '定义端口portc为输出端口Dim I As Byte '定义计数变量IPortc = 1 ' 0000 0001 PC口最低位置高电平Wait 1DoFor I = 1 To 7Rotate Portc , Left ‘ PC口所有位循环左移一位Wait 1NextFor I = 1 To 7Rotate Portc , Right ‘ PC口所有位循环右移一位Wait 1NextLoopEnd第三个实验:6个数码管扫描实验$regfile = "m16def.dat" '明确工作芯片型号$crystal = 2000000 '定义时钟频率2Mhz Config Porta = Output 'PA口为数码管选通口Config Portc = Output 'PC口为数字显示段码输出口Dim A As Byte , X As Byte , I As ByteA = 0 : X = 0 : I = 0Dim B0 As Byte , B1 As Byte , B2 As Byte , B3 As Byte , B4 As Byte , B5 As ByteB0 = 0 : B1 = 0 : B2 = 0 : B3 = 0 : B4 = 0 : B5 = 0Dim C(16) As ByteRestore Duanma '让READ指针指向Duanma标号后的第一个数据For I = 1 To 10Read C(i) '让数组C(I)内依次存放共阴数码管的数字显示段码Next IDoX = X + 1B5 = B4 : B4 = B3 : B3 = B2 : B2 = B1 : B1 = B0 : B0 = C(x) '对即将在各位数码管显示的数字的设定,控制显示的数字的左移If X > 9 Then X = 0For I = 1 To 55 '数码管动态扫描的循环控制,循环的次数控制每个数字移动时间约为1秒左右Portc = B0 : Porta = &B01111111 : Waitms 3 '依次控制从右到左的6个数码管的显示,Portc送出显示段码,Porta从右到左依次选通各位数码管Portc = B1 : Porta = &B10111111 : Waitms 3Portc = B2 : Porta = &B11011111 : Waitms 3Portc = B3 : Porta = &B11101111 : Waitms 3Portc = B4 : Porta = &B11110111 : Waitms 3Portc = B5 : Porta = &B11111011 : Waitms 3Next ILoopEndDuanma: '定义数码管段码Data &HED , &H81 , &HF4 , &HB5 , &H99 '数字0,1,2,3,4的段码Data &H3D , &H7D , &H85 , &HFD , &HBD '数字5,6,7,8,9的段码第四个程序:8通道AD转换+LCD显示实验'不连4.2伏时,可以短路一下R13,再次观察Channel 0 的采集值,并调节WE1,观察有没有反应。
北京工商大学单片机课设实验的实验程序

实验二:带电子表的直流电动机控制器班级:姓名:学号:#include <reg51.h>#define LEDLen 6#define PB1 2 // 164 时钟位#define PB0 1 // 164 数据位xdata unsigned char OUTBIT _at_ 0x8002; // 位控制口xdata unsigned char OUTSEG _at_ 0x8004; // 段控制口xdata unsigned char IN _at_ 0x8001; // 键盘读入口#define mode 0x82xdata unsigned char CTL _at_ 0xA003; //8255并行口xdata unsigned char status _at_ 0xA001;xdata unsigned char CS0832 _at_ 0x9000; //数模转换unsigned int count;#define DC_P 1void Delay(unsigned char CNT){unsigned char i;while (CNT-- !=0)for (i=100; i !=0; i--);}code unsigned char KeyTable[] = { // 键码定义0x16, 0x15, 0x14, 0xff,0x13, 0x12, 0x11, 0x10,0x0d, 0x0c, 0x0b, 0x0a,0x0e, 0x03, 0x06, 0x09,0x0f, 0x02, 0x05, 0x08,0x00, 0x01, 0x04, 0x07};unsigned char TestKey(){OUTBIT = 0; // 输出线置为0return (~IN & 0x0f); // 读入键状态(高四位不用) }unsigned char InKey(){unsigned char Pos;unsigned char i;unsigned char k;i = 6;Pos = 0x20; // 找出键所在列do {OUTBIT = ~ Pos;Pos >>= 1;k = ~IN & 0x0f;} while ((--i != 0) && (k == 0)); // 键值= 列x 4 + 行if (k != 0){i *= 4;if (k & 2)i += 1;else if (k & 4)i += 2;else if (k & 8)i += 3;OUTBIT = 0;do Delay(20); while (TestKey()); // 等键释放return(KeyTable[i]); // 取出键码}else return(0xff);}unsigned char LEDBuf[LEDLen]; // 显示缓冲unsigned char shu[11]={0}; // 显示缓冲code unsigned char LEDMAP[] = { // 八段管显示码0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};void DisplayLED(){unsigned char i;unsigned char Pos;unsigned char LED;Pos = 0x20; // 从左边开始显示for (i = 0; i < LEDLen; i++) {OUTBIT = 0; // 关所有八段管LED = LEDBuf[i];OUTSEG = LED;OUTBIT = Pos; // 显示一位八段管Delay(1);Pos >>= 1; // 显示下一位}}#define Tick 10000 // 10000 x 100us = 1s#define T100us (256-50) // 100us时间常数(6M)记忆周期2us,所以2X50=100usunsigned char Hour, Minute, Second;unsigned int C100us; // 100us记数单元void T0Int() interrupt 1{C100us--;if (C100us == 0) {C100us = Tick; // 100us 记数器为0, 重置记数器Second++;if (Second == 60) {Second = 0;Minute++;if (Minute == 60) {Minute = 0;Hour++;if (Hour == 24) Hour = 0;}}}}//电机程序--------------------------------------------------------unsigned int read(){TMOD = 0x12; // 16位计时TR1 = 0;TH1 = 0;TL1 = 0;while(!(status & DC_P)); // 等待低电平完while(status & DC_P); // 等待高电平完TR1 = 1;while(!(status & DC_P)); // 等待低电平完while(status & DC_P); // 等待高电平完TR1 = 0;return (TH1*0x100+TL1);}//电机开关程序unsigned int dianjikai(){CTL = mode;CS0832 = 0xf0; // 产生电压控制电机// Delay(500); // 等待电机运转稳定count = read(); // 读取电压值}unsigned int dianjiting( ){CTL = mode;CS0832 = 128; // 产生电压使电机停止运转//Delay(500); // 等待电机运转稳定//count = read(); // 读取电压值}//主程序-------------------------------------------------------------void main(){ unsigned char i=0;TMOD = 0x02; // 方式2, 定时器TH0 = T100us;TL0 = T100us;IE = 0x82; // EA=1, IT0 = 1 中断允许控制寄存器IE Hour = 0;Minute = 0;Second = 0;C100us = Tick;TR0 = 1; // 启动定时器0CS0832 = 128; // 电机初始化,停止运转while(i<=11){if (TestKey()){shu[i]=InKey();i++;}} //键盘读入数据while (1){ unsigned char a,b,c;LEDBuf[0] = LEDMAP[Hour/10];LEDBuf[1] = LEDMAP[Hour%10] | 0x80;LEDBuf[2] = LEDMAP[Minute/10];LEDBuf[3] = LEDMAP[Minute%10] | 0x80;LEDBuf[4] = LEDMAP[Second/10];LEDBuf[5] = LEDMAP[Second%10];a=((Hour*60)+Minute)*60+Second;//b=((shu[0]*10+shu[1])*60+(shu[2]*10+shu[3]))*60+shu[4]*10+shu[5];//c=((shu[6]*10+shu[7])*60+(shu[8]*10+shu[9]))*60+shu[10]*10+shu[11];b=shu[0]*10+shu[1];c=shu[2]*10+shu[3];// b=shu[4]*10+shu[5];//c=shu[10]*10+shu[11];DisplayLED();if(a>=b&&a<=c){dianjikai();}if(a>c){dianjiting();} //控制电机开与停}}。
单片机试验源程序文件

单片机实验指导书(实验源程序)实验二、三 I/O接口实验1、输出实验例1:ORG 0000HAJMP START ;跳转到初始化程序ORG 0033H;----- 主程序开始 -----START: MOV P1,#0FFH ;是所有LED熄灭ACALL DELAY ;调用延时子程序CLR P1.0 ;P1.0输出低电平,使LED3点亮ACALL DELAY ;调用延时子程序SETB P1.0 ;P1.0输出高电平,使LED3熄灭CLR P1.1 ;P1.1输出低电平,使LED4点亮ACALL DELAY ;调用延时子程序SETB P1.1 ;P1.1输出高电平,使LED4熄灭CLR P1.2 ;P1.2输出低电平,使LED5点亮ACALL DELAY ;调用延时子程序SETB P1.2 ;P1.2输出高电平,使LED5熄灭CLR P1.3 ;P1.3输出低电平,使LED6点亮ACALL DELAY ;调用延时子程序MOV P1, #0F0H ;LED3~LED6全部发光ACALL DELAY ;调用延时子程序AJMP START ;返回到标号START处再循环;----- 延时子程序 -----DELAY: MOV R5,#10LOOP: MOV R6,#200LOOP1: MOV R7,#250LOOP2: DJNZ R7,LOOP2DJNZ R6,LOOP1DJNZ R5,LOOPRET例2:ORG 0000HAJMP START ;跳转到初始化程序ORG 0033H;----- 主程序开始 -----START: MOV P1,#0FFH ;是所有LED熄灭ACALL DELAY ;调用延时子程序MOV ACC,#0FEH ;ACC中先装入LED3亮的数据(二进制的11111110) MOV P1,ACC ;将ACC的数据送P1口ACALL DELAY ;调用延时子程序MOV R0,#03H ;上句送到P1口的数据就点亮了LED1,所以将数据再移动3次就完成一个4位流水过程LOOP3: RL A ;将ACC中的数据左移一位MOV P1,A ;把ACC移动过的数据送p1口显示ACALL DELAY ;调用延时子程序DJNZ R0,LOOP3 ;没有移动够4次继续移动MOV P1, #0F0H ;LED3~LED6全部发光ACALL DELAY ;调用延时子程序AJMP START ;返回到标号START处再循环;----- 延时子程序 -----DELAY: MOV R5,#10LOOP: MOV R6,#200LOOP1: MOV R7,#250LOOP2: DJNZ R7,LOOP2DJNZ R6,LOOP1DJNZ R5,LOOPRET2、输入实验例1:;****************************************************************;* K1控制LED3亮灭交替 *;****************************************************************org 0star: mov p1,#0hmov p3,#0ffhst1: jb p3.2,$jnb p3.2,$cpl p1.0sjmp st1end例2:;****************************************************************************** ;* 按压实验板上的按钮K1,控制P1.0的LED亮灭 * ;* 按压K1,LED点亮,再次按压K1,LED熄灭 * ;* 程序没有进行按键消抖动处理,控制结果会因为按键抖动而出错 * ;* 按压K1十次,大概有3~5次输出会因为按键抖动而发生错误 * ;* 实验时请多按几次,观察一下效果,加深对按键消抖动重要性的认识 * ;******************************************************************************ORG 0000HAJMP START ;跳转到初始化程序ORG 0033HSTART: MOV SP,#60H ;SP初始化MOV P3,#0FFH ;端口初始化MAIN: JB P3.2,MAIN ;检测按键K1有没有按下CPL P1.0 ;执行按键命令,改变P1.0指示灯状态JNB P3.2,$ ;等待按键K1释放AJMP MAIN ;返回重新检测按键END例3:;****************************************************************************** ;* 按压实验板上的按钮K1,控制P1.0的LED亮灭 * ;* 按压K1,LED点亮,再次按压K1,LED熄灭 * ;* 程序进行了按键消抖动处理,不会出现控制结果出错的现象 * ;* 由此可以看出按键软件消抖动的功效 * ;******************************************************************************ORG 0000HAJMP START ;跳转到初始化程序ORG 0033HSTART: MOV SP,#60H ;SP初始化MOV P3,#0FFH ;端口初始化MAIN: JB P3.2,MAIN ;检测按键P3.2有没有按下ACALL YS20ms ;消前沿抖动延时,实现软件去抖动JB P3.2,MAIN ;再次检测按键,如果为高电平,则是抖动CPL P1.0 ;执行按键命令,改变P1.0指示灯状态JNB P3.2,$ ;等待按键释放AJMP MAIN ;返回重新检测按键YS20ms: MOV R7,#40 ;延时20ms子程序YS1: MOV R6,#229DJNZ R6,$DJNZ R7,YS1RET实验四多级外部中断控制实验例程:;************************************************************************ ;* INT0,INT1为边沿触发方式,INT1为高级中断*;* 主程序中8个LED轮流闪烁 * ;* 外中断程序0中,8个指示灯同时闪烁8次*;* 外中断程序1中,左右4个指示灯交替闪烁*;* 因为INT1为高级中断,所以INT1中断可以中断INT0中断程序 * ;* 即当按压K1进入外中断0时,8个LED同时闪烁,此时按压K2可以中断 * ;* TIN0的执行。
单片机原理及应用实验二报告

单片机原理及应用实验二报告实验二:单片机IO口的输入输出实验一、实验目的:1.理解并掌握单片机IO口的输入输出原理;2.掌握基础的输入输出编程技巧;3.熟悉单片机实验的基本流程和实验报告格式。
二、实验器材:1.STM32F103C8T6开发板2.LED灯3.电阻(220Ω)4.面包板、杜邦线等。
三、实验原理:单片机的IO口是实现与外部器件进行通信的重要接口,通过编程,我们可以控制IO口的状态(低电平或高电平)来实现对外部器件的控制或检测。
IO口的输入输出原理主要有两种:1.三态输出方式:通过设置IO口的DDR寄存器来将IO口设置为输出模式(推挽输出),并通过设置IO口的ODR寄存器来控制IO口的输出状态为低电平或高电平;2.上拉输入方式:通过设置IO口的DDR寄存器来将IO口设置为输入模式,同时设置IO口的CR寄存器的PUPD位为上拉使能,通过读取IO口的IDR寄存器可以获取IO口的输入状态。
四、实验步骤:1.连接电路:将STM32F103C8T6开发板的VDD和VSS(即5V和GND)分别连接到面包板的3V3和GND,将LED的阳极(长脚)连接到STM32F103C8T6开发板的PA0引脚,将LED的阴极(短脚)通过一个220Ω的电阻连接到GND。
2. 打开Keil uVision5软件,创建一个新的工程,并选择适合的芯片型号(STM32F103C8T6)。
3.编写代码实现将PA0引脚设置为输出模式,并控制LED的亮灭。
五、实验代码:```c#include "stm32f10x.h"void GPIO_Configuration(void)GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);int main(void)GPIO_Configuration(;while (1)GPIO_SetBits(GPIOA, GPIO_Pin_0); // 点亮LEDGPIO_ResetBits(GPIOA, GPIO_Pin_0); // 关闭LED}```六、实验结果与分析:七、实验心得:本次实验主要学习了单片机IO口的输入输出原理,了解了三态输出方式和上拉输入方式,并通过实际编写代码的方式,在STM32F103C8T6开发板上实现了控制LED的亮灭。
单片机实验二程序

1(3),按K0-K3,D1-D4对应亮(switch)
• #include <reg51.h>//实验内容1,按K0-K3,D1-D4对应亮 (switch) • void main() • { • • P0=0x00; //置p0口全为0 • while(1) • { • P1=0x00;//置 p1口低四位为1 • switch(P1&0x0f) • { • case 0x0e: P0=0x01; • case 0x0d: P0=0x02; • case 0x0b: P0=0x04; • case 0x07: P0=0x08; • default:; • } • } • }
《单片机》实验二程序
1(1),按K0-K3,D1-D4对应亮(if)
• #include <reg52.h>//实验内容1,按K0-K3,D1-D4对应亮 (if) • main() • { • P0=0x00; • while(1) • { • P1=0x0f; • if((P1&0x0f)==0x0e) P0=0x01; • if((P1&0x0f)==0x0d) P0=0x02; • if((P1&0x0f)==0x0b) P0=0x04; • if((P1&0x0f)==0x07) P0=0x08; • } • }
• void delay(unsigned char i) • { • unsigned char j,k; • for(k=0;k<i;k++) • for(j=0;j<255;j++); • }
2(2),实现D1-D8依次循环点亮(while)
• #include <reg51.h>//实验内容2,实现D1-D8依次 循环点亮(while) • void delay(unsigned char i); • void main() • { • unsigned char a,b; • while(1) • { • P0=0x00; • delay(500); • b=0xfe; • a=0; •
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
电子系统综合设计报告学号201009120229姓名李文海年级专业2010级电子信息工程(二)指导教师刘怀强学院理学院走马灯实验论文--《嵌入式系统技术》1、实验目的1、学会DP-51PRO实验仪监控程序下载、动态调试等联机调试功能的使用;2、理解和学会单片机并口的作为通用I/O的使用;3、理解和学会单片机外部中断的使用;4、了解单片机定时器/计数器的应用。
2、实验设备z PC 机、ARM 仿真器、2440 实验箱、串口线。
3、实验内容z熟悉A RM 开发环境的建立。
z使用A RM 汇编和C语言设置G PIO 口的相应寄存器。
z编写跑马灯程序。
5、实验原理走马灯实验是一个硬件实验,因此要求使用DP-51PRO 单片机综合仿真实验仪进行硬件仿真,首先要求先进行软件仿真,排除软件语法错误,保证关键程序段的正确。
然后连接仿真仪,下载监控程序,进行主机与实验箱联机仿真。
为了使单独编译的C语言程序和汇编程序之间能够相互调用,必须为子程序间的调用规定一定的规则。
ATPCS ,即ARM ,Thumb 过程调用标准(ARM/Thumb Procedure Call Standard),是A RM 程序和T humb 程序中子程序调用的基本规则,它规定了一些子程序间调用的基本规则,如子程序调用过程中的寄存器的使用规则,堆栈的使用规则,参数的传递规则等。
下面结合实际介绍几种A TPCS 规则,如果读者想了解更多的规则,可以查看相关的书籍。
1.基本A TPCS基本A TPCS 规定了在子程序调用时的一些基本规则,包括下面3方面的内容:(1)各寄存器的使用规则及其相应的名称。
(2)数据栈的使用规则。
(3)参数传递的规则。
相对于其它类型的A TPCS,满足基本A TPCS 的程序的执行速度更快,所占用的内存更少。
但是它不能提供以下的支持:ARM 程序和T humb 程序相互调用,数据以及代码的位置无关的支持,子程序的可重入性,数据栈检查的支持。
而派生的其他几种特定的ATPCS 就是在基本ATPCS 的基础上再添加其他的规则而形成的。
其目的就是提供上述的功能。
2.寄存器的使用规则寄存器的使用必须满足下面的规则:(1) 子程序间通过寄存器R0~R3 来传递参数。
这时,寄存器R0~R3 可以记作A0~A3。
被调用的子程序在返回前无需恢复寄存器R0~R3 的内容。
(2) 在子程序中,使用寄存器R4~Rll 来保存局部变量。
这时,寄存器R4~R11 可以记作V1~V8。
如果在子程序中使用到了寄存器V1~V8 中的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值;对于子程序中没有用到的寄存器则不必进行这些操作。
在T humb 程序中,通常只能使用寄存器R4~R7 来保存局部变量。
(3) 寄存器R12 用作子程序间s cratch 寄存器,记作I P。
在子程序间的连接代码段中常有这种使用规则。
(4) 寄存器R13 用作数据栈指针,记作S P。
在子程序中寄存器R13 不能用作其他用途。
寄存器S P 在进入子程序时的值和退出子程序时的值必须相等。
(5) 寄存器R14称为连接寄存器,记作LR。
它用于保存子程序的返回地址。
如果在子程序中保存了返回地址,寄存器R14则可以用作其他用途。
(6) 寄存器R15 是程序计数器,记作P C。
它不能用作其他用途。
3.参数传递规则根据参数个数是否固定可以将子程序分为参数个数固定的(nonvariadic)子程序和参数个数可变的(variadic)子程序。
这两种子程序的参数传递规则是不同的。
(1)参数个数可变的子程序参数传递规则对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3 来传递参数;当参数超过4个时,还可以使用数据栈来传递参数。
在参数传递时,将所有参数看作是存放在连续的内存字单元中的字数据。
然后,依次将各字数据传送到寄存器R0、R1、R2、R3 中,如果参数多于4个,将剩余的字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。
按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过数据栈传递,也可能一半通过寄存器传递,另一半通过数据栈传递。
(2)参数个数固定的子程序参数传递规则对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同。
如果系统包含浮点运算的硬件部件,浮点参数将按照下面的规则传递:·各个浮点参数按顺序处理。
·为每个浮点参数分配F P 寄存器。
·分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP 寄存器。
第一个整数参数,通过寄存器R0~R3 来传递。
其他参数通过数据栈传递。
(3)子程序结果返回规则子程序中结果返回的规则如下:·结果为一个32 位的整数时,可以通过寄存器R0 返回。
·结果为一个64 位整数时,可以通过寄存器R0 和R l 返回,依次类推。
·结果为一个浮点数时,可以通过浮点运算部件的寄存器f0、d0 或者s0 来返回。
·结果为复合型的浮点数(如复数)时,可以通过寄存器f0~fN 或者d0~dN 来返回。
·对于位数更多的结果,需要通过内存来传递。
4.C 语言函数和A RM 汇编语言函数间相互调用高级语言函数与汇编语言函数的混合调用也要遵循A TPCS 规则,保证程序调用时参数的正确传递。
在汇编程序中使用EXPORT 伪指令声明本子程序,使其它程序可以调用此子程序,而在C语言程序中使用ex tern 关键字声明外部函数(声明要调用的汇编子程序),即可调用此汇编子程序。
下面给出两个例子来介绍函数相互调用。
6、实验步骤1.编写一段程序,用P1口作为控制端口,使D1区的LED 轮流点亮。
原理图如下图。
图3-1 走马灯实验原理图①仿照实验一的过程,编写程序、汇编、连接、软件仿真,基本达到功能要求。
ORG 0000HLJMP MAINORG 0100HMAIN: MOV A,#0FEH ;准备点亮第一只发光管NEXT: MOV P1,AACALL DELAYRL A ; 准备点亮下一只发光管SJMP NEXT; 延时子程序DELAY: MOV R2,#5DELAY2: MOV R3,#100DELAY3: MOV R4,#100DJNZ R4,$DJNZ R3,DELAY3DJNZ R2,DELAY2RETEND调试成功以后,将程序中的ORG部分的偏移地址再加上8000H,重新编译。
②按照原理图,将A1区P1口的引线分别连接到D1区J52上。
③下载监控程序到实验仪上。
短接A1区的JP15,连接实验仪串口和主机的串口,将MOD-SW1拨到LOAD一边,FLASH-E和SRAM-E断开,运行主机上DPFLASH,下载MON51.HEX到实验仪上。
④在Keil系统上,完成程序的动态调试。
在主菜单DEBUG下的Options for Target ‘Target 1’,点击Debug,选择Use Keil Monitor-51 Driver,并且设置其他参数,将MOD-SW1拨到RUN一边,按复位键,再按DEBUG下的全速运行命令运行监控程序后,就可以进行动态调试了。
观察和记录各个寄存器内容的变化,端口P1的内容变化,以及对应的LED的变化。
全速运行时,观察LED的变化和闪烁速度。
7、实验相关寄存器GPBCON――端口配置寄存器GPBDAT――端口数据寄存器GPBUP――端口上拉电阻使能寄存器8、实验电路图2.编写一段程序,用P1 口作为控制端口,使D1 区的LED 轮流点亮。
用外部中断0控制走马灯的暂停/继续。
(此实验也可脱机运行)ORG 0000HLJMP MAINORG 0003LJMP ZEX0ORG 0100HMAIN: MOV SP,#60HSETB IT0SETB EX0SETB EAMOV A,#0FEH ;准备点亮第一只发光管MOV R5,#00HNEXT: CJNE R5,#00H,NEXT ;00表示继续,FF表示暂停MOV P1,AACALL DELAYRL A ;准备点亮下一只发光管SJMP NEXT; 延时子程序DELAY: MOV R2,#5DELAY2: MOV R3,#100DELAY3: MOV R4,#100DJNZ R4,$DJNZ R3,DELAY3DJNZ R2,DELAY2RET;外部中断0服务子程序ZEX0: PUSH ACCMOV A,R5XRL A,#0FFHMOV R5,APOP ACCRETIEND将A1区P1口的引线分别连接到D1区J52上,将D1区的J53的KEY1连接到A1区的外部中断0上。
◆观察实验结果,解释如何实现走马灯的暂停和继续。
◆比较电平触发和边沿触发时走马灯控制的难易程度。
3.编写一段程序,用P1 口作为控制端口,使D1 区的LED 轮流点亮。
用定时/计数器0控制走马灯的闪烁速度。
(此实验也可脱机运行)ORG 0000HLJMP MAINORG 000BHLJMP ZIT0ORG 0100HMAIN: MOV SP,#60HMOV TMOD,#01HMOV TH0,#3CHMOV TL0,#0B0HMOV R6,#20 /循环次数MOV R7,#0FEH ;准备点亮第一只发光管SETB ET0SETB EASETB TR0SJMP $;定时中断0服务子程序ZIT0: DJNZ R6,ZRET /为零时,跳转!MOV A,R7MOV P1,ARL AMOV R7,AMOV R6,#20 /循环次数ZRET: MOV TH0,#3CHMOV TL0,#0B0HRETIEND◆修改R6=0或1时,观察走马灯的速度快慢。
◆ZRET:处没有重置初值时的走马灯的速度与ZRET处有重置初值时的走马灯的速度的比较。
◆R6=50时,改变T0的初值,设为最大、最小时,比较走马灯的速度。
◆去掉R6的软件辅助延时,是否可以,速度怎样?9、实验记录第一个程序走马灯逐步地闪亮第二个程序当按下D1区k1时, 走马灯暂停, 再按下时就又开始了!第三个程序把 R6值改大了,那间隔时间就增大 ! 走马灯越来越慢!10、实验结果分析程序运行后,LED 灯D3、D4不断闪烁,跑马灯程序运行。
11、实训分析与总结:1、简述LED灯点亮的原理2、观察并描述实验现象,尝试修改参数,使得LED灯变化的更快或者更慢。
3、实验的体会。
实验现象:1号灯亮→ 2号灯亮→ 1、2号灯亮→ 3号灯亮→ 1、2、3号灯亮→ 4号灯亮→ 4个灯全亮→ 4个灯全灭→ 4号灯亮→ 3号灯亮→2号灯亮→ 1号灯亮→ 1、2号灯亮→ 1、2、3号灯亮→ 4个灯全亮→4个灯全灭→ 4号灯亮→ 3、4号灯亮→ 2、3、4号灯亮→ 4个灯全亮→全灭→ 1、2号灯亮→ 1、2、3号灯亮→全亮→全灭。