很多朋友正在学习单片机开发技术,但开发中免不了要碰到这样、那样的问题,有些问题可能无碍大局,但有一些问题却直接影响到产品的成本、体积、性能。这里介绍笔者的几个技巧,希望对大家的工作有帮助。
一.C语言中嵌入汇编语言
单片机开发中,通常我们使用C语言编写主程序,这样可以充分借助C语言工具提供的运算库函数及强大的数据处理能力。但C语言的可控性不及汇编语言,在有些对时序要求严格的处理上,我们还需用灵活性更强的汇编语言来编写。这样就产生了C语言和汇编语言混合编程的问题,一般分成三种方式:1.汇编语言调用C语言函数;2. C语言调用汇编语言;3. C语言中嵌入汇编语言。这里我们主要介绍第3种,即C语言中嵌入汇编语言。
下面的一段程序是主程序调用精确的205μS延时子程序并使P1.0交替输出高、低电平的方波。
/*------------程序名test.c------------*/
#include <AT89X51.H>//晶振频率12.000MHz
/****************/
void delay(void)//延时205μS
{
#pragma asm
MOV R0,#100
LOOP:
DJNZ R0,LOOP
#pragma endasm
}
/***************/
void main (void)//主函数,其功能使P1.0交替输出高、低电平的方波
{
while(1)
{P1_0=!P1_0;
delay();}
}
具体实现过程为:
1.先用汇编语言编制一段延时程序,在keil开发环境中编译,然后进行软件仿真,晶振频率的设置应和你的要求相符。仿真时注意观察左边寄存器窗口内的时间显示,调整延时程序的参数可得到我们需要的精确延时。
2.用C51编写主程序及延时子程序的外壳(等待嵌入汇编语言),假定此程序名称为test.c。
3.将第1步所得的汇编延时子程序放入C51编写的延时子程序外壳中。注意在开始及结束时分别加上#pragma asm、#pragma endasm语句,这种方法是通过asm与endasm告诉C51编译器,中间行不用编译为汇编行。
4.按照Keil的使用方法,建立工程文件并添加源程序。
5.点击含有汇编程序的C源程序后再右击,在弹出的下拉菜单中选中Options for File ‘test.c’(图1),这时出现图2所示的界面,勾选Generate Assembler SRC File(生成汇编SRC文件)及Assembler SRC File(封装汇编文件)使其有效。
6. 根据项目的编译模式加载封装库文件,通常在Small模式时为C51S.LIB(该文件在C:\Keil\C51\Lib\C51S.LIB),具体见图3。
7.点击Rebuild target(重建所有目标文件)即可得到编译结果(图4)。
![]()
图1
![]()
图2
![]()
图3
![]()
图4
二.用软件扩展外部中断
大家知道,51单片机的外部中断只有2个,书本上曾介绍了一种扩展外部中断源的方法,但是需增加硬件开销(见图5)。经或非门引入外中断源输入端(/INT0或/INT1),同时又连到某I/0口。这样,每个“源”都可能引起中断,在中断服务程序中通过软件查询便可确定哪一个是正在申请的中断源,其查询的次序则由中断源优先级决定,这就可实现多个外部中断源的扩展。
![]()
图5
这种方法尽管扩展了外部中断源,但也有不尽人意之处,如设计一个具有8个中断源的电路,则需一个8输入端的或非门(或门),显然,对体积与成本都不利。这里介绍笔者设计的扩展外部中断源的方法,由纯软件实现,不添加一个元件(见图6)。
![]()
图6
#include <AT89X51.H>
static unsigned char data m;//m为全局变量
/*-------延时子程序-------*/
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i<k;i++){
for(j=0;j<121;j++)
{;}}
}
/*---外部中断INT0子程序---*/
void init0()interrupt 0
{
delay(10);//延时10mS抗抖动干扰
if(P3_2==0)
{
EX0=0;//关INT0中断
EA=0;//关总中断
P3_2=0;//置P3.2为低电平
P2=0xff;//置P2口为全1
m=P2;//读取P2口状态至m
P2=0x00;//恢复P2口为全0
P3_2=1; //置P3.2为高电平
IT0=1;//置INT0为边沿触发
EX0=1; //开INT0中断
EA=1;} //开总中断
}
/********主程序*********/
void main(void)
{
P2=0x00;// 置P2口为全0
P3_2=1;// 置P3.2为高电平
IT0=1;// 置INT0为边沿触发
EX0=1;// 开INT0中断
EA=1; //开总中断
while(1)//无限循环
{
P0=m;//将全局变量m中的内容输出至P0口
P3_0=!P3_0;//P3.0取反,指示程序状态
delay(500);//延时500mS
}
}
程序解释:无按键按下时,P3.0的发光管闪亮,作程序状态显示。主程序初始化时,置P2口为全0,置P3.2为高电平,同时置INT0为边沿触发,并开放中断。8个按键的任一个按下时都会引起INT0中断,进入中断服务子程序后,首先关闭中断,然后置P3.2为低电平,置P2口为全1,再读取P2口状态至m,通过查询m的状态字即可知道正在申请的中断源。这里我们采用的方法是将m输出至P0口点亮LED作指示。退出中断时,重新开放中断。 |