单片机延时中断小程序
51单片机中断程序大全
//实例 42 :用定时器 T0 查询方式 P2 口 8 位控制 LED 闪烁#include<reg51.h>//包含51单片机寄存器定义的头文件/**************************************************************函数功能:主函数**************************************************************/void main(void){// EA=1;// 开总中断// ET0=1;// 定时器 T0 中断允许TMOD=0x01;// 使用定时器 T0 的模式 1TH0=(65536-46083)/256; // 定时器 T0 的高 8 位赋初值TL0=(65536-46083)%256; // 定时器 T0 的高 8 位赋初值TR0=1;// 启动定时器 T0TF0=0;P2=0xff;while(1)// 无限循环等待查询{while(TF0==0);TF0=0;P2=~P2;TH0=(65536-46083)/256; // 定时器 T0 的高 8 位赋初值TL0=(65536-46083)%256; // 定时器 T0 的高 8 位赋初值}}// 实例43 :用定时器T1查询方式控制单片机发出1KHz音频#include<reg51.h>sbit sound=P3^7;// 将// 包含 51 单片机寄存器定义的头文件sound 位定义为 P3.7 引脚/**************************************************************函数功能:主函数**************************************************************/ void main(void){// EA=1;// 开总中断// ET0=1;// 定时器 T0 中断允许TMOD=0x10;// 使用定时器 T1 的模式 1 TH1=(65536-921)/256; // 定时器 T1 的高 8 位赋初值TL1=(65536-921)%256; // 定时器 T1 的高 8 位赋初值TR1=1;// 启动定时器 T1TF1=0;while(1)// 无限循环等待查询{while(TF1==0);TF1=0;sound=~sound; // 将 P3.7 引脚输出电平取反TH1=(65536-921)/256; // 定时器 T0 的高 8 位赋初值TL1=(65536-921)%256; // 定时器 T0 的高 8 位赋初值}}//实例 44 :将计数器 T0 计数的结果送 P1 口 8 位 LED 显示#include<reg51.h> // 包含 51 单片机寄存器定义的头文件 sbitS=P3^4; // 将 S位定义为 P3.4 引脚/**************************************************************函数功能:主函数**************************************************************/void main(void){// EA=1;// 开总中断// ET0=1;// 定时器 T0 中断允许2TMOD=0x02;// 使用定时器 T0 的模式TH0=256-156; // 定时器 T0 的高 8 位赋初值TL0=256-156; // 定时器 T0 的高 8 位赋初值TR0=1;// 启动定时器 T0while(1)// 无限循环等待查询{while(TF0==0)// 如果未计满就等待{if(S==0)// 按键S 按下接地,电平为0P1=TL0; //计数器 TL0 加 1 后送 P1 口显示}TF0=0; // 计数器溢出后,将TF0清 0}}//实例 45 :用定时器 T0 的中断控制 1 位 LED 闪烁#include<reg51.h> // 包含 51 单片机寄存器定义的头文件sbit D1=P2^0; // 将 D1 位定义为 P2.0 引脚/**************************************************************函数功能:主函数**************************************************************/void main(void){EA=1;// 开总中断ET0=1;// 定时器 T0 中断允许TMOD=0x01;// 使用定时器 T0 的模式 2TH0=(65536-46083)/256; //定时器 T0 的高 8 位赋初值TL0=(65536-46083)%256; //定时器 T0 的高 8 位赋初值TR0=1;// 启动定时器 T0while(1)// 无限循环等待中断;}/**************************************************************函数功能:定时器T0 的中断服务程序**************************************************************/void Time0(void) interrupt 1 using 0 // “interrupt ”声明函数为中断服务函数// 其后的 1 为定时器 T0 的中断编号; 0 表示使用第 0 组工作寄存器{D1=~D1; // 按位取反操作,将P2.0 引脚输出电平取反TH0=(65536-46083)/256; //定时器 T0 的高 8 位重新赋初值TL0=(65536-46083)%256; //定时器 T0 的高 8 位重新赋初值}//实例 46 :用定时器 T0 的中断实现长时间定时#include<reg51.h> //包含51单片机寄存器定义的头文件sbit D1=P2^0; // 将 D1 位定义为 P2.0 引脚unsigned char Countor; //设置全局变量,储存定时器T0 中断次数/**************************************************************函数功能:主函数**************************************************************/void main(void){EA=1;// 开总中断ET0=1;// 定时器 T0 中断允许TMOD=0x01;// 使用定时器 T0 的模式 2 TH0=(65536-46083)/256; //定时器 T0 的高 8 位赋初值TL0=(65536-46083)%256; //定时器 T0 的高 8 位赋初值TR0=1; Countor=0;// 启动定时器 T0// 从 0 开始累计中断次数while(1)// 无限循环等待中断;}/**************************************************************函数功能:定时器T0 的中断服务程序**************************************************************/void Time0(void) interrupt 1 using 0 // “interrupt ”声明函数为中断服务函数// 其后的 1 为定时器 T0 的中断编号; 0 表示使用第 0 组工作寄存器{Countor++; // 中断次数自加 1if(Countor==20)// 若累计满20 次,即计时满1s{D1=~D1; Countor=0;// 按位取反操作,将P2.0 引脚输出电平取反// 将 Countor 清 0,重新从 0 开始计数}TH0=(65536-46083)/256; //定时器 T0 的高 8 位重新赋初值TL0=(65536-46083)%256; //定时器 T0 的高 8 位重新赋初值}//实例 47 :用定时器 T1 中断控制两个 LED 以不同周期闪烁#include<reg51.h> //包含51单片机寄存器定义的头文件sbit D1=P2^0; // 将 D1 位定义为 P2.0 引脚sbit D2=P2^1; // 将 D2 位定义为 P2.1 引脚unsigned char Countor1; //设置全局变量,储存定时器unsigned char Countor2; //设置全局变量,储存定时器T1 中断次数T1 中断次数/**************************************************************函数功能:主函数**************************************************************/ void main(void){EA=1;// 开总中断ET1=1;// 定时器 T1 中断允许TMOD=0x10;// 使用定时器 T1 的模式 1TH1=(65536-46083)/256; //定时器 T1 的高 8 位赋初值TL1=(65536-46083)%256; //定时器 T1 的高 8 位赋初值TR1=1;// 启动定时器 T1Countor1=0;// 从 0 开始累计中断次数Countor2=0;// 从 0 开始累计中断次数while(1)// 无限循环等待中断;}/**************************************************************函数功能:定时器T1 的中断服务程序**************************************************************/void Time1(void) interrupt 3 using 0 // “interrupt ”声明函数为中断服务函数// 其后的 3 为定时器 T1 的中断编号; 0 表示使用第 0 组工作寄存器{Countor1++; //Countor1 自加 1Countor2++; //Countor2 自加 1if(Countor1==2) // 若累计满 2 次,即计时满{100msD1=~D1; Countor1=0;// 按位取反操作,将P2.0引脚输出电平取反// 将 Countor1 清 0,重新从 0 开始计数}if(Countor2==8) // 若累计满 8 次,即计时满 400ms {D2=~D2; Countor2=0;// 按位取反操作,将P2.1引脚输出电平取反// 将 Countor1 清 0,重新从 0 开始计数}TH1=(65536-46083)/256; //定时器 T1 的高 8 位重新赋初值TL1=(65536-46083)%256; //定时器 T1 的高 8 位重新赋初值}//实例 50-1 :输出 50 个矩形脉冲#include<reg51.h> // 包含 51 单片机寄存器定义的头文件sbit u=P1^4;// 将 u 位定义为 P1.4/*************************************************函数功能:延时约30ms (3*100*100=30 000μs =30m*************************************************/void delay30ms(void){unsigned char m,n;for(m=0;m<100;m++)for(n=0;n<100;n++);}/*******************************************函数功能:主函数******************************************/void main(void){unsigned char i;u=1;// 初始化输出高电平for(i=0;i<50;i++) // 输出 50 个矩形脉冲{u=1;delay30ms();u=0;delay30ms();}while(1);// 无限循环,防止程序“跑飞”}//实例 50-2 :计数器 T0 统计外部脉冲数#include<reg51.h> // 包含 51 单片机寄存器定义的头文件/*******************************************函数功能:主函数******************************************/void main(void){TMOD=0x06;// TMOD=0000 0110B,使用计数器 T0 的模式 2EA=1; ET0=0; TR0=1;// 开总中断// 不使用定时器// 启动 T0T0 的中断TH0=0; TL0=0; while(1)// 计数器 T0 高 8 位赋初值// 计数器 T0 低 8 位赋初值// 无限循环,不停地将TL0 计数结果送P1 口P1=TL0; }//实例 51-2 :定时器 T0 的模式 2 测量正脉冲宽度#include<reg51.h> // 包含 51 单片机寄存器定义的头文件sbit ui=P3^2;// 将 ui 位定义为 P3.0( INT0)引脚,表示输入电压/*******************************************函数功能:主函数******************************************/void main(void){TMOD=0x0a;// TMOD=0000 1010B,使用定时器T0 的模式2, GATE置 1EA=1; ET0=0; TR0=1; TH0=0; TL0=0; while(1)// 开总中断// 不使用定时器 T0 的中断// 启动 T0// 计数器 T0 高 8 位赋初值// 计数器 T0 低 8 位赋初值// 无限循环,不停地将TL0 计数结果送P1 口{while(ui==0)//INT0为低电平,T0 不能启动;TL0=0;//INT0 为高电平,启动T0 计时,所以将while(ui==1) // 在 INT0 高电平期间,等待,计时TL0清;P1=TL0;// 将计时结果送P1 口显示}}//实例 53 :用外中断 0 的中断方式进行数据采集#include<reg51.h> sbit S=P3^2;// 包含 51 单片机寄存器定义的头文件// 将 S位定义为 P3.2,/*******************************************函数功能:主函数******************************************/ void main(void){EA=1; // 开放总中断EX0=1; // 允许使用外中断IT0=1;// 选择负跳变来触发外中断P1=0xff;while(1);// 无限循环,防止程序跑飞}/**************************************************************函数功能:外中断T0 的中断服务程序**************************************************************/void int0(void) interrupt 0 using 0 // 外中断 0 的中断编号为 0{P1=~P1; // 每产生一次中断请求,P1 取反一次。
单片机延时500ms程序汇编
单片机延时500ms程序汇编一、概述在单片机编程中,延时操作是非常常见且重要的一部分。
延时可以使程序在执行过程中暂停一段时间,以确保输入输出设备能够正常工作,或者是为了保护其他设备。
本文将介绍如何使用汇编语言编写单片机延时500ms的程序。
二、延时原理在单片机中,延时操作通常通过循环来实现。
每个循环需要一定的时间,通过控制循环次数和循环体内的指令数量,可以实现不同长度的延时。
在汇编语言中,可以使用计数器来控制循环次数,从而实现精确的延时操作。
三、汇编语言编写延时程序接下来,我们将使用汇编语言编写延时500ms的程序。
1. 设置计数器初值在程序的开头我们需要设置计数器的初值,这个初值需要根据单片机的工作频率和所需的延时时间来计算。
假设单片机的工作频率为1MHz,那么在循环500次后,就能够达到500ms的延时。
我们需要将计数器的初值设为500。
2. 循环计数接下来,我们进入一个循环,在循环中进行计数操作。
每次循环结束时,都需要检查计数器的值,当计数器减至0时,表示已经达到了500ms的延时时间,可以退出循环。
3. 优化程序为了提高程序的执行效率,可以对计数器进行优化。
例如可以通过嵌套循环的方式,减少循环的次数,从而提高延时的精度和稳定性。
四、程序示例下面是一个简单的示例程序,演示了如何使用汇编语言编写延时500ms的程序。
```org 0x00mov r2, #500 ; 设置计数器初值为500delay_loop:djnz r2, delay_loop ; 进行计数ret ; 延时结束,退出程序```五、结语通过以上的示例程序,我们可以看到如何使用汇编语言编写单片机延时500ms的程序。
当然,实际的延时程序可能会更加复杂,需要根据具体的单片机型号和工作频率进行调整,但是思路是相似的。
在实际的编程中,需要根据具体的需求和硬件环境来进行调整和优化,以实现更加稳定和精确的延时操作。
希望本文对单片机延时程序的编写有所帮助,也欢迎大家在评论区提出宝贵意见和建议。
单片机延时问题20问
单片机延时问题20问延时与中断出错,是单片机新手在单片机开发应用过程中,经常会遇到的问题,本文汇总整理了包含了MCS-51系列单片机、MSP430单片机、C51单片机、8051F的单片机、avr单片机、STC89C52、PIC单片机…..在内的各种单片机常见的延时与中断问题及解决方法,希望对单片机新手们,有所帮助!1、单片机延时程序的延时时间怎么算的?答:如果用循环语句实现的循环,没法计算,但是可以通过软件仿真看到具体时间,但是一般精精确延时是没法用循环语句实现的。
如果想精确延时,一般需要用到定时器,延时时间与晶振有关系,单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。
第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。
本程序中假设使用频率为12 MHz的晶振。
最长的延时时间可达216=65 536 μs。
若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。
2、求个单片机89S51 12M晶振用定时器延时10分钟,控制1个灯就可以答:可以设50ms中断一次,定时初值,TH0=0x3c、TL0=0xb0。
中断20次为1S,10分钟的话,需中断12000次。
计12000次后,给一IO口一个低电平(如功率不够,可再加扩展),就可控制灯了。
而且还要看你用什么语言计算了,汇编延时准确,知道单片机工作周期和循环次数即可算出,但不具有可移植性,在不同种类单片机中,汇编不通用。
用c的话,由于各种软件执行效率不一样,不会太准,通常用定时器做延时或做一个不准确的延时,延时短的话,在c中使用汇编的nop做延时3、51单片机C语言for循环延时程序时间计算,设晶振12MHz,即一个机器周期是1us。
for(i=0,i<100;i++)for(j=0,j<100;j++)我觉得时间是100*100*1us=10ms,怎么会是100ms答:不可能的,是不是你的编译有错的啊我改的晶振12M,在KEIL 4.0 里面编译的,为你得出的结果最大也就是40ms,这是软件的原因,不可能出现100ms那么大的差距,是你的软件的原因。
单片机汇编延时计算小程序
{
for(x=0;x<256;x++)
{
for(y=0;y<256;y++)
{
periodicity=delay_time/(12.0/f);
delay_period_XY=w*(x*(3+2*y)+3)+3 ;
//精度控制
if((delay_period_XY>periodicity*0.9999)&&(delay_period_XY<periodicity*1.0001))
if((mcu_type==1)&&(delay_time>(12.0/f)*(255*(3+2*255)+3)))
{
printf("您输入的延时长度为%fus,超过了该汇编程序在51单片机下的最大延时长度%fus,将改用三重循环程序来实现该延时。\n",delay_time,(12.0/f)*(255*(3+2*255)+3));
printf("#pragma endasm\n");
if((mcu_type==1)&&(delay_time>(12.0/f)*(255*(255*(3+2*255)+3)+3)))
{
printf("您输入的延时长度为%fus,超过了该汇编程序在51单片机下的最大延时长度%fus,三重循环程序也无法实现。\n",delay_time,(12.0/f)*(255*(3+2*255)+3));
51 单片机 定时器 延时1s函数
51 单片机定时器延时1s函数1.引言1.1 概述本文介绍了51单片机中的定时器功能以及如何通过定时器实现延时1秒的函数。
在单片机应用中,定时器是一种非常重要且常用的功能模块之一。
它能够精确计时,并可用于实现周期性的任务触发、计时、脉冲输出等功能。
本文首先将对51单片机进行简要介绍,包括其基本概念、结构和特点。
随后,重点讲解了定时器的基本原理和功能。
定时器通常由一个计数器和一组控制寄存器组成,通过预设计数器的初值和控制寄存器的配置来实现不同的计时功能。
接着,本文详细介绍了如何通过编程实现一个延时1秒的函数。
延时函数是单片机开发中常用的功能,通过定时器的计时功能可以实现精确的延时控制。
本文将以C语言为例,介绍延时函数的编写步骤和原理,并给出示例代码和详细的说明。
最后,本文对所述内容进行了总结,并展望了定时器在单片机应用中的广泛应用前景。
通过学习定时器的相关知识和掌握延时函数的编写方法,我们可以更好地应用定时器功能,提高单片机应用的效率和精确性。
综上所述,通过本文的学习,读者可全面了解51单片机中定时器的功能和应用,并能够掌握延时函数的编写方法,为单片机应用开发提供一定的参考和指导。
1.2 文章结构本文以51单片机定时器功能为主题,旨在介绍如何使用定时器进行延时操作。
文章分为引言、正文和结论三个主要部分。
在引言部分,首先会对文章的背景进行概述,介绍单片机的基本概念和应用领域。
然后,给出本文的整体结构,并阐述文章的目的和意义。
正文部分将分为两个小节。
在2.1节中,将对单片机进行详细介绍,包括其构造与工作原理。
这部分的内容将帮助读者全面了解单片机的基本知识,为后续的定时器功能介绍打下基础。
2.2节将重点介绍定时器的功能和特点。
这部分将涵盖定时器的基本原理、工作模式以及在实际应用中的使用方法。
同时,还将详细讲解如何使用定时器进行1秒钟的延时操作,包括具体的代码实现和注意事项。
结论部分将对全文进行总结,并强调定时器的重要性和应用前景。
单片机C语言小程序
单片机C语言小程序#include <at89x51.h>#include <absacc.h>#define V AR XBYTE[0x00] /*V AR为外部位址0000*/#define read 0 /*93c46读取的识别码READ=0*/#define write 2 /*93c46写入的识别码WRITE=2*/#define ewen 4 /*93C46写致能的识别码EWEN=4*/#define ewds 6 /*93C46写除能的识别码EWDS=6*/#define cs INT0 /*93C46 CS接脚=8051 RD P3.2*/#define clk INT1 /*93C46 CLK接脚=8051 WR P3.3*/#define di T0 /*93C46 DI接脚=8051 T1 P3.4*/#define d0 T1 /*93C46 DO接脚=8051 T0 P3.5*/#define LOW 0x49 /*存放测试温度的下限值*/#define HIGH 0x51 /*存放测试温度的上限值*/bit FLAG0=0; /*宣告TIMER0响应旗号*///外接工业专用温度传感器时,目前设置测量温度为0-99度:static const char tab[13]={0x3a,0x53,0x6f,0x8a,0xa3, /*0度,10度,20度,30度,40度*/0xB8,0xC8,0xD5,0xDE,0xE5, /*50度,60度,70度,80度,90度*/0xEA,0xEE}; /*100度,110度*///使用板上AD590温度传感器时,目前设置测量温度为0-99度://static const char tab[13]={0x88,0x8d,0x92,0x97,0x9c, /*0度,10度,20度,30度,40度,*/// 0xa1,0xa6,0xab,0xb0,0xb5, /*50度,60度,70度,80度,90度*/// 0xba,0xc0}; /*100度,110度*/char data1[2];char C,S,k=0;char MEP[7]; /*显示器值存放阵列*///MEP[0]=数码管最低位显示值,温度指示小数点后位//MEP[1]=数码管次低位显示值,温度指示个位数//MEP[2]=数码管高位显示值,温度指示十位数//MEP[3]=数码管最低位显示值,功能显示目前定为1,2,3,4,5//MEP[4]=//MEP[5]=暂放置温度显示值,高4位为温度指示十位数值,低4位为温度指示个位数值//MEP[6]=在温度显示与电压调整副程式中,将测量值C暂存MEP[6]中unsigned char combuf[10];unsigned char ADR46,CH,CL,m,C1,C2; /*ADR46,93C46位址,CH高位元组,CL低*/ int sec,sec1;char ptr=0,ptr1=0x10,psr=0; /*ptr显示器值存放阵MEP[]指标,ptr1显示器扫描指标*/ char count=100,sb=0;void delay (unsigned int value) /*延时副程式*/{while (value!=0) value--; /*10us延时*/}void COMP(); /*宣告比较现在温度与设定温度副程式*/void SET();void disp(); /*宣告设定温度副程式*/void to9346(char c); /*宣告TO93C46副程式*/void SDT46(char c); /*宣告串入副程式*/RDT46(); /*宣告串出副程式*/void clear(void); /*宣告清除按键存放/显示器阵列MEP[]副副程式*/void xch(void); /*宣告按键存放/显示器阵列MEP[]右键滚入副程式*/void sjust(void); /*温度显示慢跳调整副程式*/void temper(); /*宣告温度显示与电压调整副程式*/void UP(); /*宣告温度上升键防抖动副程式*/void UPA(); /*宣告温度设置上升副程式*/void DOWN(); /*宣告温度下降键防抖动副程式*/void DOWNA(); /*宣告温度设置下降副程式*/void FONTION(); /*宣告模式键判断模式副程式*/void buf(); /*宣告从93C46取设定值副程式*/void SA VE(); /*宣告设置存储副程式*///********************************************************main() /*主程式*/{TMOD=0x11; /*TIMER0,TIMER1工作在MODE1*/TH0=(65535-50000)/256; /*设定TIMER0初值,50ms*/TL0=(65536-50000)%256;TH1=(65535-4000)/256; /*设定TIMER1初值,4ms*/TL1=(65536-4000)%256;IE=0x8a; /*TIMER0,TIMER1中断致能*/TR1=1; /*启动TIMER1*/P2_7=1; /*测试用,温度下限指示*/P2_6=1; /*测试用,温度在正常上下限间指示*/P2_5=1; /*测试用,温度上限指示*/buf(); /*从93C46取设定值副程式*/while(1) /*无条件循环*/{P3_1=0;MEP[3]=0xff; /*将模式位置零*/V AR=0x00; /*产生写入信号WR=0,令ADC0804开始转换*/while (P2_0==1); /*侦测ADC0804的接脚INTR=0否?是则转换完成*/S=V AR; /*读取ADC0804资料,存入C*/sjust(); /*温度显示慢跳调整副程式*/temper(); /*呼叫温度显示调整副程式*/MEP[5]=(MEP[2] < <4)|MEP[1];if(P2_4==0) SET(); /*如果模式键P2.4按下,则呼叫SET副程式,否则跳过副程式*/if(MEP[5] <combuf[5]) { P2_7=0; /*如果测试温度小于设定温度下限,等式成立时,则将低温指示打开P2_7=0*/P2_6=P2_5=1; /*关闭指示灯*/}if(MEP[5]> combuf[6]) { P2_5=0; /*如果测试温度大于设定温度上限,等式成立时,则将高温指示打开P2_5=0*/P2_7=P2_6=1; /*关闭指示灯*/}if(combuf[5] <MEP[5])if(MEP[5] <combuf[6]) { P2_6=0; /*如果测试温度介于设定温度上下限之间,则将正常指示打开P2_6=0*/ P2_7=P2_5=1;}} /*跳至while(1),无条件循环*/单片机的C语言轻松入门随着单片机开发技术的不断发展,目前已有越来越多的人从普遍使用汇编语言到逐渐使用高级语言开发,其中主要是以C语言为主,市场上几种常见的单片机均有其C语言开发环境.这里以最为流行的80C51单片机为例来学习单片机的C语言编程技术.本书共分六章,每章一个专题,以一些待完成的任务为中心,围绕该任务介绍C语言的一些知识,每一个任务都是可以独立完成的,每完成一个任务,都能掌握一定的知识,等到所有的任务都完成后,即可以完成C语言的入门工作.第1章C语言概述及其开发环境的建立学习一种编程语言,最重要的是建立一个练习环境,边学边练才能学好.Keil软件是目前最流行开发80C51系列单片机的软件,Keil提供了包括C编译器,宏汇编,连接器,库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境( Vision)将这些部份组合在一起.在学会使用汇编语言后,学习C语言编程是一件比较容易的事,我们将通过一系列的实例介绍C语言编程的方法.图1-1所示电路图使用89S52单片机作为主芯片,这种单片机性属于80C51系列,其内部有8K的FLASH ROM,可以反复擦写,并有ISP功能,支持在线下载,非常适于做实验.89S52的P1引脚上接8个发光二极管,P3.2~P3.4引脚上接4个按钮开关,我们的任务是让接在P1引脚上的发光二极管按要求发光.1.1 简单的C程序介绍例1-1: 让接在P1.0引脚上的LED发光./*************************************************平凡单片机工作室Copyright 2003 pingfan's mcustudioAll rights Reserved作者:周坚dddl.c单灯点亮程序*************************************************/图1-1 接有LED的单片机基本电路P1.0EA/VPPVCCXTAL2XTAL1GNDRST+5V+5V+R1E110K10UCY27P27P1KPZ1D8D189×××#include "reg51.h"sbit P1_0=P1^0;void main(){ P1_1=0;}这个程序的作用是让接在P1.0引脚上的LED点亮.下面来分析一下这个C语言程序包含了哪些信息.1)"文件包含"处理.程序的第一行是一个"文件包含"处理.所谓"文件包含"是指一个文件将另外一个文件的内容全部包含进来,所以这里的程序虽然只有4行,但C编译器在处理的时候却要处理几十或几百行.这里程序中包含REG51.h 文件的目的是为了要使用P1这个符号,即通知C编译器,程序中所写的P1是指80C51单片机的P1端口而不是其它变量.这是如何做到的呢打开reg51.h可以看到这样的一些内容:/*-------------------------------------------------------------------------REG51.HHeader file for generic 80C51 and 80C31 microcontroller.Copyright (c) 1988-2001 Keil Elektronik GmbH and Keil Software, Inc.All rights reserved.--------------------------------------------------------------------------*//* BYTE Register */sfr P0 = 0x80;sfr P1 = 0x90;sfr P2 = 0xA0;sfr P3 = 0xB0;sfr PSW = 0xD0;sfr ACC = 0xE0;sfr B = 0xF0;sfr SP = 0x81;sfr DPL = 0x82;sfr DPH = 0x83;sfr PCON = 0x87;sfr TCON = 0x88;sfr TMOD = 0x89; sfr TL0 = 0x8A; sfr TL1 = 0x8B; sfr TH0 = 0x8C; sfr TH1 = 0x8D; sfr IE = 0xA8;sfr IP = 0xB8;sfr SCON = 0x98; sfr SBUF = 0x99; /* BIT Register */ /* PSW */sbit CY = 0xD7; sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0;/* TCON */sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88;/* IE */sbit EA = 0xAF; sbit ES = 0xAC; sbit ET1 = 0xAB; sbit EX1 = 0xAA; sbit ET0 = 0xA9; sbit EX0 = 0xA8; /* IP */sbit PS = 0xBC; sbit PT1 = 0xBB; sbit PX1 = 0xBA; sbit PT0 = 0xB9; sbit PX0 = 0xB8; /* P3 */sbit RD = 0xB7; sbit WR = 0xB6; sbit T1 = 0xB5;sbit T0 = 0xB4;sbit INT1 = 0xB3;sbit INT0 = 0xB2;sbit TXD = 0xB1;sbit RXD = 0xB0;/* SCON */sbit SM0 = 0x9F;sbit SM1 = 0x9E;sbit SM2 = 0x9D;sbit REN = 0x9C;sbit TB8 = 0x9B;sbit RB8 = 0x9A;sbit TI = 0x99;sbit RI = 0x98;熟悉80C51内部结构的读者不难看出,这里都是一些符号的定义,即规定符号名与地址的对应关系.注意其中有sfr P1 = 0x90;这样的一行(上文中用黑体表示),即定义P1与地址0x90对应,P1口的地址就是0x90 (0x90是C语言中十六进制数的写法,相当于汇编语言中写90H).从这里还可以看到一个频繁出现的词:sfrsfr并标准C语言的关键字,而是Keil为能直接访问80C51中的SFR而提供了一个新的关键词,其用法是:sfrt 变量名=地址值.2)符号P1_0来表示P1.0引脚.在C语言里,如果直接写P1.0,C编译器并不能识别,而且P1.0也不是一个合法的C语言变量名,所以得给它另起一个名字,这里起的名为P1_0,可是P1_0是不是就是P1.0 呢你这么认为,C编译器可不这么认为,所以必须给它们建立联系,这里使用了Keil C 的关键字sbit来定义,sbit的用法有三种:第一种方法:sbit 位变量名=地址值第二种方法:sbit 位变量名=SFR名称^变量位地址值第三种方法:sbit 位变量名=SFR地址值^变量位地址值如定义PSW中的OV可以用以下三种方法:sbit OV=0xd2 (1)说明:0xd2是OV的位地址值sbit OV=PSW^2 (2)说明:其中PSW必须先用sfr定义好sbit OV=0xD0^2 (3)说明:0xD0就是PSW的地址值因此这里用sfr P1_0=P1^0;就是定义用符号P1_0来表示P1.0引脚,如果你愿意也可以起P10一类的名字,只要下面程序中也随之更改就行了.3)main称为"主函数".每一个C语言程序有且只有一个主函数,函数后面一定有一对大括号"{}",在大括号里面书写其它程序.从上面的分析我们了解了部分C语言的特性,下面再看一个稍复杂一点的例子.例1-2 让接在P1.0引脚上的LED闪烁发光/*************************************************平凡单片机工作室Copyright 2003 pingfan's mcustudioAll rights Reserved作者:周坚ddss.c单灯闪烁程序*************************************************/#include "reg51.h"#define uchar unsigned char#define uint unsigned intsbit P10=P1^0;/*延时程序由Delay参数确定延迟时间*/void mDelay(unsigned int Delay){ unsigned int i;for(;Delay>0;Delay--){ for(i=0;iNew Project…"菜单,出现对话框,要求给将要建立的工程起一个名字,这里起名为exam2,不需要输入扩展名.点击"保存"按钮,出现第二个对话框,如图1-2所示,这个对话框要求选择目标CPU(即你所用芯片的型号),Keil支持的CPU很多,这里选择Atmel公司的89S52芯片.点击AT M E L前面的"+"号,展开该层,点击其中的89S52, 然后再点击"确定"按钮,回到主窗口,此时,在工程窗口的文件页中,出现了"Target 1",前面有"+"号,点击"+"号展开,可以看到下一层的"Source Group1",这时的工程还是一个空的工程,里面什么文件也没有,需要手动把刚才编写好的源程序加入,点击"Source Group1"使其反白显示,然后,点击鼠标右键,出现一个下拉菜单,如图1-3所示,选中其中的"Add file to Group"Source Group1",出现一个对话框,要求寻找源文件.双击exam2.c文件,将文件加入项目,注意,在文件加入项目后,该对话框并不消失,等待继续加入其它文件,但初学时常会误认为操作没有成功而再次双击同一文件,这时会出现如图1-4所示的对话框,提示你所选文件已在列表中,此时应点击"确定",返回前一对话框,然后点击"Close"即可返回主接口,返回后,点击"Source Group 1"前的加号,exam3.c文件已在其中.双击文件名,即打开该源程序.1.3 工程的详细设置工程建立好以后,还要对工程进行进一步的设置,以满足要求.首先点击左边Project窗口的Target 1,然后使用菜单"Project->Option for target 'target1'"即出现对工程设置的对话框,这个对话框共有8个页面,大部份设置项取默认值就行了. Target页图1-2 选择单片机型号图1-3 加入文件如图1-5所示,Xtal后面的数值是晶振频率值,默认值是所选目标CPU的最高可用频率值,该值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间.正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同,如果没必要了解程序执行的时间,也可以不设.Memory Model用于设置RAM使用情况,有三个选择项:Small: 所有变量都在单片机的内部RAM中;Compact:可以使用一页(256字节)外部扩展RAM;Larget: 可以使用全部外部的扩展RAM.Code Model用于设置ROM空间的使用,同样也有三个选择项:Small:只用低于2K的程序空间;Compact:单个函数的代码量不能超过2K,整个程序可以使用64K程序空间;Larget:可用全部64K空间;这些选择项必须根据所用硬件来决定,由于本例是单片应用,所以均不重新选择,按默认值设置.Operating:选择是否使用操作系统,可以选择Keil提供了两种操作系统:Rtx tiny和Rtx full,也可以不用操作系统(None),这里使用默认项None,即不用操作系统.图1-5 设置目标图1-4 重复加入源程序得到的提示OutPut页如图1-6所示,这里面也有多个选择项,其中Creat Hex file用于生成可执行代码文件,该文件可以用编程器写入单片机芯片,其格式为intelHEX格式,文件的扩展名为.HEX,默认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项.工程设置对话框中的其它各页面与C51编译选项,A51的汇编选项,BL51连接器的连接选项等用法有关,这里均取默认值,不作任何修改.以下仅对一些有关页面中常用的选项作一个简单介绍.Listing页该页用于调整生成的列表文件选项.在汇编或编译完成后将产生(*.lst)的列表文件,在连接完成后也将产生(*.m51)的列表文件,该页用于对列表文件的内容和形式进行细致的调节,其中比较常用的选项是"C Compile Listing"下的"Assamble Code"项,选中该项可以在列表文件中生成C语言源程序所对应的汇编代码,建议会使用汇编语言的C初学者选中该项,在编译完成后多观察相应的List文件,查看C源代码与对应汇编代码,对于提高C语言编程能力大有好处.C51页该页用于对Keil的C51编译器的编译过程进行控制,其中比较常用的是"Code Optimization"组,如图1.7所示,该组中Level是优化等级,C51在对源程序进行编译时,可以对代码多至9级优化,默认使用第8级,一般不必修改,如果在编译中出现一些问题,可以降低优化级别试一试.Emphasis是选择编译优先方式,第一项是代码量优化(最终生成的代码量小);第二项是速度优先(最终生成的代码速度快);第三项是缺省.默认采用速度优先,可根据需要更改.图1-6 设置输出文件Debug页该页用于设置调试器,Keil提供了仿真器和一些硬件调试方法,如果没有相应的硬件调试器,应选择Use Simulator,其余设置一般不必更改,有关该页的详细情况将在程序调试部分再详细介绍.至此,设置完成,下面介绍如何编译,连接程序以获得目标代码,以及如何进行程序的调试工作.1.4 编译,连接下面我们通过一个例子来介绍C程序编译,连接的过程.这个例子使P1口所接LED以流水灯状态显示.将下面的源程序输入,命名为exam3.c,并建立名为exam3的工程文件,将exam3.c文件加入该工程中,设置工程,在Target页将Xtal后的值由24.0改为12.0,以便后面调试时观察延时时间是否正确,本项目中还要用到我们所提供的实验仿真板,为此需在Debug页对Dialog DLL对话框作一个设置,在进行项目设置时点击Debug,打开Debug页,可以看到Dialog DLL对话框后的Parmeter:输入框中已有默认值-pAT52,在其后键入空格后再输入-dledkey,如图1-8所示.例1-3 使P1口所接LED以流水灯状态显示/**************************************************; 平凡单片机工作室; ; Copyright 2003 pingfan's McuStudio; All rights Reserved图1-7C51编译器选项;作者:周坚;lsd.c;流水灯程序**************************************************/#include "reg51.h"#include "intrins.h"#define uchar unsigned char#define uint unsigned int/*延时程序由Delay参数确定延迟时间*/void mDelay(unsigned int Delay){ unsigned int i;for(;Delay>0;Delay--){ for(i=0;iBuild target,对当前工程进行连接,如果当前文件已修改,将先对该文件进行编译,然后再连接以产生目标代码;如果选择Rebuild All target files将会对当前工程中的所有文件重新进行编译然后再连接,确保最终生产的目标代码是最新的,而Translate ….项则仅对当前文件进行编译,不进行连接.以上操作也可以通过工具栏按钮直接进行.图1-9是有关编译,设置的工具栏按钮,从左到右分别是:编译,编译连接,全部重建,停止编译和对工程进行设置.编译过程中的信息将出现在输出窗口中的Build页中,如果源程序中有语法错误,会有错误报告出现,双击该行,可以定位到出错的位置,对源程序修改之后再次编译,最终要得到如图1-10所示的结果,提示获得了名为exam3.hex的文件,该文件即可被编程器读入并写到芯片中,同时还可看到,该程序的代码量(code=63),内部RAM的使用量(data=9),外部RAM的使用量(xdata=0)等一些信息.除此之外,编译,连接还产生了一些其它相关的文件,可被用于Keil的仿真与调试,到了这一步后即进行调试.1.5 程序的调试在对工程成功地进行汇编,连接以后,按Ctrl+F5或者使用菜单Debug->Start/Stop Debug Session即可进入调试状态,Keil内建了一个仿真CPU用来模拟执行程序,该仿真CPU功能强大,可以在没有硬件和仿真机的情况下进行程序的调试.进入调试状态后,Debug菜单项中原来不能用的命令现在已可以使用了,多出一个用于运行和调试的工具条,如图1-11所示,Debug菜单上的大部份命令可以在此找到对应的快捷按钮,从左到右依次是复位,运行,暂停,单步,过程单步,执行完当前子程序,运行到当前行,下一状态,打开跟踪,观察跟踪,反汇编窗口,观察窗口,代码作用范围分析,1#串行窗口,内存窗口,性能分析,工具按钮等命令.点击菜单Peripherals,即会多出一项"键盘LED仿真板(K)",选中该项,即会出现如图1-9 有关编译,连接,项目设置的工具条图1-11 调试工具条图1-10 编译,连接后得到目标代码图1-12所示界面.使用菜单STEP或相应的命令按钮或使用快捷键F11可以单步执行程序,使用菜单STEP OVER或功能键F10可以以过程单步形式执行命令,所谓过程单步,是指把C语言中的一个函数作为一条语句来全速执行.按下F11键,可以看到源程序窗口的左边出现了一个黄色调试箭头,指向源程序的第一行.每按一次F11,即执行该箭头所指程序行,然后箭头指向下一行,当箭头指向"mDelay(1000);"行时,再次按下F11,会发现,箭头指向了延时子程序mDelay的第一行.不断按F11键,即可逐步执行延时子程序.如果mDelay程序有错误,可以通过单步执行来查找错误,但是如果mDelay程序已正确,每次进行程序调试都要反复执行这些程序行,会使得调试效率很低,为此可以在调试时使用F10来替代F11,在main函数中执行到mDelay(1000)时将该行作为一条语句快速执行完毕.Keil软件还提供了一些窗口,用以观察一些系统中重要的寄存器或变量的值,这也是很重要的调试方法.以下通过一个对延时程序的延迟时间的调整来对这些调试方法作一个简单的介绍.这个程序中用到了延时程序mDelay,如果使用汇编语言编程,每段程序的延迟时间可以非常精确地计算出来,而使用C语言编程,就没有办法事先计算了.为此,可以使用观察程序执行时间的方法了来解.进入调试状态后,窗口左侧是寄存器和一些重要的系统变量的窗口,其中有一项是sec,即统计从开始执行到目前为止用去的时间.按F10,以过程单步的形式执行程序,在执行到mDelay(1000)这一行之前停下,查看sec的值(把鼠标停在sec 后的数值上即可看到完整的数值),记下该数值,然后按下F10,执行完mDelay(1000)后再次观察sec值,如图1-13所示,这里前后两次观察到的值分别是:0.00040400和1.01442600, 其差值为1.014022s,如果将该值改为124可获得更接近于1s的数值,而当该值取123时所获得的延时值将小于1s,因此,最佳的取值应该是124.图1-12 51单片机实验仿真板1.6 C语言的一些特点通过上述的几个例子,可以得出一些结论:1,C程序是由函数构成的,一个C源程序至少包括一个函数,一个C源程序有且只有一个名为main()的函数,也可能包含其它函数,因此,函数是C程序的基本单位.主程序通过直接书写语句和调用其它函数来实现有关功能,这些其它函数可以是由C语言本身提供给我们的(如例3中的_crol_(…)函数),这样的函数称之为库函数,也可以是用户自己编写的(如例2,3中用的mDelay(…)函数),这样的函数称之为用户自定义函数.那么库函数和用户自定义函数有什么区别呢简单地说,任何使用Keil C语言的人,都可以直接调用C的库函数而不需要为这个函数写任何代码,只需要包含具有该函数说明的相应的头文件即可;而自定义函数则是完全个性化的,是用户根据自己需要而编写的.Keil C提供了100多个库函数供我们直接使用.2,一个函数由两部份组成:(1)函数的首部,即函数的第一行.包括函数名,函数类型,函数属性,函数参数(形参)名,参数类型.例如:void mDelay (unsigned int DelayTime)一个函数名后面必须跟一对圆括号,即便没有任何参数也是如此.(2)函数体,即函数首部下面的大括号"{}"内的部份.如果一个函数内有多个大括号,则最外层的一对"{}"为函数体的范围.函数体一般包括:声明部份:在这部份中定义所用到的变量,例1.2中unsigned char j.执行部份:由若干个语句组成.在某此情况下也可以没有声明部份,甚至即没有声明部份,也没有执行部份,如:void mDelay(){}这是一个空函数,什么也不干,但它是合法的.在编写程序时,可以利用空函数,比如主程序需要调用一个延时函数,可具体延时多少,怎么个延时法,暂时还不清楚,我们可以主程序的框架结构弄清,先编译通过,把架子搭起来再说,至于里面的细节,可以在以后慢慢地填,这时利用空函数,先写这么一个函数,这样在主程序中就可以调用它了.3,一个C语言程序,总是从main函数开始执行的,而不管物理位置上这个main()放在什么地方.例1.2中就是放在了最后,事实上这往往是最常用的一种方式.图1-13 观察sec确定延时时间4,主程序中的mDelay如果写成mdelay就会编译出错,即C语言区分大小写,这一点往往让初学者非常困惑,尤其是学过一门其它语言的人,有人喜欢,有人不喜欢,但不管怎样,你得遵守这一规定.5,C语言书写的格式自由,可以在一行写多个语句,也可以把一个语句写在多行.没有行号(但可以有标号),书写的缩进没有要求.但是建议读者自己按一定的规范来写,可以给自己带来方便.6,每个语句和资料定义的最后必须有一个分号,分号是C语句的必要组成部份.7,可以用/*…..*/的形式为C程序的任何一部份作注释,在"/*"开始后,一直到"*/"为止的中间的任何内容都被认为是注释,所以在书写特别是修改源程序时特别要注意,有时无意之中删掉一个"*/",结果,从这里开始一直要遇到下一个"*/"中的全部内容都被认为是注释了.原本好好的一个程序,编译已过通过了,稍作修改,一下出现了几十甚至上百个错误,初学C的人往往对此深感头痛,这时就要检查一下,是不是有这样的情况,如果有的话,赶紧把这个"*/"补上.特别地,Keil C也支持C++风格的注释,就是用"//"引导的后面的语句是注释,例:P1_0=!P1_0; //取反P1.0这种风格的注释,只对本行有效,所以不会出现上面的问题,而且书写比较方便,所以在只需要一行注释的时候,我们往往采用这种格式.但要注意,只有Keil C支持这种格式,早期的Franklin C以及PC机上用的TC都不支持这种格式的注释,用上这种注释,编译时通不过,会报告编译错误.第2章分支程序设计第一部分课程学习了如何建立Keil C的编程环境,并了解了一些C语言的基础知识,这一部分将通过一个键控流水灯程序的分析来学习分支程序设计.2.1 程序功能与实现硬件电路描述如下:89S52单片机的P1口接有8个LED,当某一端口输出为"0"时,相应的LED点亮,P3.2,P3.3,P3.4,P3.5分别接有四个按钮K1~K4,按下按钮时,相应引脚被接地.现要求编写可键控的流水灯程序,当K1按下时,开始流动,K2按下时停止流动,全部灯灭,K3使灯由上往下流动,K4使灯由下往上流动.下面首先给出程序,然后再进行分析.例2-1:键控流水灯的程序#include "reg51.h"#include "intrins.h"#define uchar unsigned charvoid mDelay(unsigned int DelayTime){ unsigned int j=0;for(;DelayTime>0;DelayTime--){ for(j=0;j2的结果为真,而3<2的结果为假.C语言一共提供了6种关系运算符:"<"(小于),""(大于),">=(大于等于)","=="(等于)和"!="(不等于).用关系运算符将两个表达式连接起来的式子,称为关系表达式.例:a>b,a+b>b+c,(a=3)>=(b=5)等都是合法的关系表达式.关系表达式的值只有两种可能,即"真"和"假".在C语言中,没有专门的逻辑型变量,如果运算的结果是"真",用数值"1"表示,而运算的结果是"假"则用数值"0"表示.如式子:x1=3>2的结果是x1等于1,原因是3>2的结果是"真",即其结果为1,该结果被"="号赋给了x1,这里须注意,"="不是等于之意(C语言中等于用"=="表示),而是赋值号,即将该号后面的值赋给该号前面的变量,所以最终结果是x1等于1.式子:x2=30;DelayTime--)单片机的C语言轻松入门25{ for(j=0;j<125;j++){;}}}在main函数中用mDelay(1000)的形式调用该函数时,延时时间约为1s.如果将该函数中的unsigned int j改为unsigned char j,其他任何地方都不作更改,重新编译,连接后,可以发现延迟时间变为约0.38s.int和char是C语言中的两种不同的数据类型,可见程序中仅改变数据类型就会得到不同的结果.那么int和char型的数据究竟有什么区别呢3.3.1 整型数据1.整型数据在内存中的存放形式如果定义了一个int型变量i:int i=10; /*定义i为整型变量,并将10赋给该变量*/在Keil C中规定使用二个字节表示int型数据,因此,变量i在内存中的实际占用情况如下:0000,0000,0000,1010也就是整型数据总是用2个字节存放,不足部分用0补齐.事实上,数据是以补码的形式存在的.一个正数的补码和其原码的形式是相同的.如果数值是负的,补码的形式就不一样了.求负数的补码的方法是:将该数的绝对值的二进制形式取反加1.例如,-10,第一步取-10的绝对值10,其二进制编码是1010,由于是整型数占。
51单片机延时函数
51单片机延时函数在嵌入式系统开发中,51单片机因其易于学习和使用、成本低廉等优点被广泛使用。
在51单片机的程序设计中,延时函数是一个常见的需求。
通过延时函数,我们可以控制程序的执行速度,实现定时器功能,或者在需要的时候进行延时操作。
本文将介绍51单片机中常见的延时函数及其实现方法。
一、使用for循环延时这种方法不精确,但是对于要求不高的场合,可以用来估算延时。
cvoid delay(unsigned int time){unsigned int i,j;for(i=0;i<time;i++)for(j=0;j<1275;j++);}这个延时函数的原理是:在第一个for循环中,我们循环了指定的时间次数(time次),然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有很大差异,所以只适用于对延时时间要求不精确的场合。
二、使用while循环延时这种方法比使用for循环延时更精确一些,但是同样因为硬件和编译器的不同,延时时间会有差异。
cvoid delay(unsigned int time){unsigned int i;while(time--)for(i=0;i<1275;i++);}这个延时函数的原理是:我们先进入一个while循环,在这个循环中,我们循环指定的时间次数(time次)。
然后在每一次循环中,我们又循环了1275次。
这样,整个函数的执行时间就是time乘以1275,大致上形成了一个延时效果。
但是需要注意的是,这种方法因为硬件和编译器的不同,延时时间会有差异,所以只适用于对延时时间要求不精确的场合。
三、使用定时器0实现精确延时这种方法需要在单片机中开启定时器0,并设置定时器中断。
在中断服务程序中,我们进行相应的操作来实现精确的延时。
这种方法需要使用到单片机的定时器中断功能,相对复杂一些,但是可以实现精确的延时。
单片机C语言函数中断函数(中断服务程序)
单片机_C语言函数_中断函数(中断服务程序)在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。
中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该知道),我们在这里就不讲了,首先来回忆下中断系统涉及到哪些问题。
(1)中断源:中断请求信号的来源。
(8051有3个内部中断源T0,T1,串行口,2个外部中断源INT0,INT1(这两个低电平有效,上面的那个横杠不知道怎么加上去))(2)中断响应与返回:CPU采集到中断请求信号,怎样转向特定的中断服务子程序,并在执行完之后返回被中断程序继续执行。
期间涉及到CPU响应中断的条件,现场保护,现场恢复。
(3)优先级控制:中断优先级的控制就形成了中断嵌套(8051允许有两级的中断嵌套,优先权顺序为INT0,T0,INT1,T1,串行口),同一个优先级的中断,还存在优先权的高低。
优先级是可以编程的,而优先权是固定的。
80C51的原则是①同优先级,先响应高优先权②低优先级能被高优先级中断③正在进行的中断不能被同一级的中断请求或低优先级的中断请求中断。
80C51的中断系统涉及到的中断控制有中断请求,中断允许,中断优先级控制(1)3个内部中断源T0,T1,串行口,2个外部中断源INT0,INT1(2)中断控制寄存器:定时和外中断控制寄存器TCON(包括T0、T1,INT0、INT1),串行控制寄存器SCON,中断允许寄存器IE,中断优先级寄存器IP具体的是什么,包括哪些标志位,在这里不讲了,所有书上面都会讲。
在这里我们讲下注意的事项(1)CPU响应中断后,TF0(T0中断标志位)和TF1由硬件自动清0。
(2)CPU响应中断后,在边沿触发方式下,IE0(外部中断INT0请求标志位)和IE1由硬件自动清零;在电平触发方式下,不能自动清楚IE0和IE1。
所以在中断返回前必须撤出INT0和INT1引脚的低电平,否则就会出现一次中断被CPU多次响应。
(3)串口中断中,CPU响应中断后,TI(串行口发送中断请求标志位)和RI(接收中断请求标志位)必须由软件清零。
51单片机延时函数
51单片机延时函数
151单片机延时函数
51单片机是一种常用的微控制器,它可以实现一系列功能,如定时器,定时器中断等。
随着科技的发展,许多人需要使用单片机来实现特定功能,而51单片机是最受欢迎的也是最知名的。
本文旨在介绍51单片机延时函数的实现方法。
1.1时钟
任何有效的51单片机使用的延时函数都受时钟的控制。
由于50单片机本身的频率有限,为了让计算机更有效地运行,我们需要精确设置时钟频率。
由于时钟频率的不同,51单片机的延时函数也有所不同。
1.2延时函数的实现
51单片机的延时函数是用来延迟任务的一种方法。
延时函数可以延迟任务的执行,并且可以按照用户设定的起点和终点执行任务。
51单片机使用指令延时来实现延时函数。
指令延时就是指通过控制51单片机内部时钟,来让程序暂停一段指定时间。
这样,我们就可以实现受时钟控制的延时函数。
1.3延时函数的实际应用
51单片机的延时函数可以用来实现许多不同的功能,如断电保护,延时启动,定时控制等。
由于这些函数可以精确控制任务的执
行,可以适应复杂的工作环境。
同时,51单片机还可以实现节能,使系统能够更加稳定可靠。
2结论
51单片机延时函数是51单片机应用中最基础的功能之一。
该函数可以满足不同用户的需求,帮助产品在实际应用中更好地发挥作用,同时还可以实现节能。
51单片机串行口中断服务程序
51单片机串行口中断服务程序//串口中断服务程序,仅需做简单调用即可完成串口输入输出的处理//出入均设有缓冲区,大小可任意设置。
//可供使用的函数名://char getbyte(void);从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。
//getline(char idata *line, unsigned char n); 获取一行数据回车结束,已处理backspce和delete,必须定义最大输入字符数//putinbuf(uchar c);模拟接收到一个数据//putbyte(char c);放入一个字节到发送缓冲区//putbytes(unsigned char *outplace,j);放一串数据到发送缓冲区,自定义长度//putstring(unsigned char code *puts);发送一个字符串到串口//puthex(unsigned char c);发送一个字节的hex码,分成两个字节发。
//putchar(uchar c,uchar j);发送一个字节数据的asc码表达方式,需要定义小数点的位置//putint(uint ui,uchar j);发送一个整型数据的asc码表达方式,需要定义小数点的位置//CR;发送一个回车换行//*************************************************************************#include <w77e58.h> //该头文件包括了51,52,80320的特殊寄存器,用在51,52上也可#define uchar unsignedchar #define uint unsigned int #define OLEN 64/* size of serial transmission buffer */idata unsigned char outbuf[OLEN];/* storage for transmission buffer */unsigned char idata *outlast=outbuf; //最后由中断传输出去的字节位置unsigned char idata *putlast=outbuf;//最后放入发送缓冲区的字节位置#define ILEN 2 /* size of serial receiving buffer */idata unsigned char inbuf[ILEN];unsigned char idata *inlast=inbuf; //最后由中断进入接收缓冲区的字节位置 unsignedchar idata *getlast=inbuf; //最后取走的字节位置 bit outbufsign; //输出缓冲区非空标志有=1 bit inbufsign;//接收缓冲区非空标志有=1bit inbufful;//输入缓冲区满标志满=1#define CR putstring("\r\n") //CR=回车换行//*****************************//放入一个字节到发送缓冲区putbyte(char c) {uchar i,j; ES=0;/*暂停串行中断,以免数据比较时出错? */if (outlast==putlast ){ i=(0-TH1);do{i--;j=36;do {j--;}while(j!=0);}while(i!=0);//延时一个字节发送时间}*putlast=c; //放字节进入缓冲区putlast++; //发送缓冲区指针加一 if(putlast==outbuf+OLEN) putlast=outbuf; //指针到了顶部换到底部if (!outbufsign){outbufsign=1;TI=1;} //缓冲区开始为空置为有,启动发送ES=1; }//****************************** //放一串数据到发送缓冲区putbytes(unsigned char *outplace,unsigned char j){ int i; for(i=0;i<j;i++){putbyte(*outplace);outplace++;}}//******************************//putchar(uchar c,uchar j);发送一个字节数据的asc码表达方式,需要定义小数点的位置putchar(uchar c,uchar j){uchar idata free[4];uchar data i;i=0;free[i++]=(c/100+0x30);if (j==3) free[i++]=‘.‘;free[i++]=(c%100)/10+0x30;if (j==2) free[i++]=‘.‘;if (j==2 && free[i-3]==0x30) free[i-3]=0x20;free[i++]=(c%10)+0x30;if (j==1 && free[i-3]==0x30) free[i-3]=0x20;if (j==1 && free[i-3]==0x20 && free[i-2]==0x30) free[i-2]=0x20;putbytes(free,i);}//******************************//putint(uint ui,uchar j);发送一个整型数据的asc码表达方式,需要定义小数点的位置putint(uint ui,uchar j){uchar idata free[6];uchar data i;//i=0;free[i++]=(ui/10000+0x30);if (j==5) free[i++]=‘.‘;free[i++]=((ui%10000)/1000+0x30);if (j==4) free[i++]=‘.‘;if (j==4 && free[i-3]==0x30) free[i-3]=0x20;free[i++]=((ui%1000)/100+0x30);if (j==3) free[i++]=‘.‘;if (j==3 && free[i-4]==0x30) free[i-4]=0x20;if (j==3 && free[i-4]==0x20 && free[i-3]==0x30) free[i-3]=0x20;free[i++]=((ui%100)/10+0x30);if (j==2) free[i++]=‘.‘;if (j==2 && free[i-5]==0x30) free[i-5]=0x20;if (j==2 && free[i-5]==0x20 && free[i-4]==0x30) free[i-4]=0x20;if (j==2 && free[i-5]==0x20 && free[i-4]==0x20 && free[i-3]==0x30) free[i-3]=0x20;free[i++]=(ui%10+0x30);if (j==1 && free[i-5]==0x30) free[i-5]=0x20;if (j==1 && free[i-5]==0x20 && free[i-4]==0x30) free[i-4]=0x20;if (j==1 && free[i-5]==0x20 && free[i-4]==0x20 && free[i-3]==0x30) free[i-3]=0x20;if (j==1 && free[i-5]==0x20 && free[i-4]==0x20 && free[i-3]==0x20 && free[i-2]==0x30) free[i-2]=0x20; putbytes(free,i);}//***************************************//发送一个字符串到串口putstring(unsigned char *puts){for (;*puts!=0;puts++) //遇到停止符0结束putbyte(*puts);}//*************************************//发送一个字节的hex码,分成两个字节发。
51单片机c语言延时
51单片机c语言延时51单片机(8051微控制器)是一种广泛使用的嵌入式系统芯片,其编程语言包括C语言和汇编语言等。
在C语言中,实现51单片机延时的方法有多种,下面介绍其中一种常用的方法。
首先,我们需要了解51单片机的指令周期和机器周期。
指令周期是指单片机执行一条指令所需的时间,而机器周期是指单片机执行一个操作所需的时间,通常以微秒为单位。
在C语言中,我们可以使用循环结构来实现延时。
#include <reg51.h> // 包含51单片机的寄存器定义void delay(unsigned int time) // 延时函数,参数为需要延时的微秒数{unsigned int i, j;for (i = 0; i < time; i++)for (j = 0; j < 1275; j++); // 1275个机器周期,约等于1ms}void main() // 主函数{while (1) // 无限循环{// 在这里添加需要延时的代码P1 = 0x00; // 例如将P1口清零delay(1000); // 延时1秒P1 = 0xFF; // 将P1口清零delay(1000); // 延时1秒}}在上面的代码中,我们定义了一个名为delay的函数,用于实现延时操作。
该函数接受一个无符号整数参数time,表示需要延时的微秒数。
在函数内部,我们使用两个嵌套的循环来计算延时时间,其中外层循环控制需要延时的次数,内层循环控制每个机器周期的时间(约为1微秒)。
具体来说,内层循环执行了约1275次操作(具体数值取决于编译器和单片机的型号),以实现约1毫秒的延时时间。
需要注意的是,由于单片机的指令周期和机器周期不同,因此我们需要根据具体的单片机型号和编译器进行调整。
在主函数中,我们使用一个无限循环来不断执行需要延时的操作。
例如,我们将P1口的所有引脚清零,然后调用delay函数进行1秒钟的延时,再将P1口清零并再次调用delay函数进行1秒钟的延时。
单片机的延时与中断问题及解决方法
单片机的延时与中断问题及解决方法单片机作为嵌入式系统中非常重要的组成部分,在许多应用中都需要进行延时和中断处理。
延时和中断是单片机中常见的问题,它们直接关系到系统的稳定性和性能。
本文将重点介绍单片机中延时和中断的问题,并提出解决方法。
一、延时问题延时是指在程序执行过程中需要暂停一段时间,以便等待某些条件满足或者执行某些特定的操作。
在单片机中,延时通常需要通过软件实现,也就是在程序中加入延时函数。
常见的延时函数包括循环延时和定时器延时。
1. 循环延时循环延时是指通过循环来实现延时的方式。
具体做法是在程序中使用一个循环来反复执行空操作,从而消耗一定的时间。
下面是一个简单的循环延时函数:```cvoid delay(unsigned int ms){unsigned int i, j;for(i = 0; i < ms; i++)for(j = 0; j < 1000; j++);}```这个函数中,外层循环控制延时的毫秒数,内层循环则是用来消耗时间的。
通过这样的方式可以实现一定量级的延时。
循环延时的精度和稳定性都不够理想,特别是在频繁调用的情况下,容易导致系统性能下降。
2. 定时器延时定时器是单片机中常见的外设之一,它可以生成精确的时间延时。
通过设置定时器的时钟源和计数值,可以实现微秒级甚至更小单位的延时。
在单片机中,通常会使用定时器来实现较为精确的延时操作。
下面是一个使用定时器来实现延时的示例:```cvoid delay_us(unsigned int us){TMOD = 0x01; // 设置定时器为工作方式1TH0 = 0xFF - us / 256; // 设置定时器初值TL0 = 0xFF - us % 256; // 设置定时器初值TR0 = 1; // 启动定时器while(!TF0); // 等待定时器溢出TR0 = 0; // 停止定时器TF0 = 0; // 清除溢出标志}```这段代码中,我们使用定时器0来实现微秒级的延时操作。
单片机中断小程序
#include<reg51.h>#include<intrins.h>typedef unsigned char uc;typedef unsigned int ui;typedef unsigned long ul;void udisplay(uc m,uc n);void delay100us();void delay1ms();void delay100ms();sfr P4 = 0xc0;sfr P4SW = 0xbb;sbit DAT_DIS = P0^4; /* 164 595 公用数据线*/sbit CLK_164 = P0^5; /* 164时钟线*/sbit CLK_595 = P0^6; /* 595时钟线*/sbit RCLK_595 = P0^7; /* 595锁存线*/sbit FMQ = P4^5; /* 蜂鸣器*/uc code displayduan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};/* 0 1 2 3 4 5 6 7 8 9 SP - *///秒分时日月星期年uc code displaywei[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0xff};uc a,b,c,d,e,f,g,h;ul sum;/*************************************************************//* 功能:在某一位数码管上显示某一个数值/* 输入:m,n/*************************************************************/void display(uc m,uc n){uc wei, duan, i;wei = 0x00;for(i=0; i<8; i++){ /* 关显示*/DAT_DIS = (bit)(wei & 0x80);wei <<= 1 ;CLK_595 = 0 ;_nop_();CLK_595 = 1 ;}RCLK_595 = 0;_nop_();RCLK_595 = 1;duan = displayduan[n]; /* 送段码*/for(i=0; i<8; i++){DAT_DIS = (bit)(duan & 0x80);duan <<= 1;CLK_164 = 1;_nop_();CLK_164 = 0;}wei = displaywei[m];for(i=0; i<8; i++){ /* 开显示*/ DAT_DIS = (bit)(wei & 0x80);wei <<= 1 ;CLK_595 = 0 ;_nop_();CLK_595 = 1 ;}RCLK_595 = 0;_nop_();RCLK_595 =1;}void udisplay(uc m,uc n){uc wei, duan, i;duan = displayduan[n]; /* 送段码*/for(i=0; i<8; i++){DAT_DIS = (bit)(duan & 0x80);duan <<= 1;CLK_164 = 1;_nop_();CLK_164 = 0;}wei = displaywei[m];for(i=0; i<8; i++){ /* 开显示*/DAT_DIS = (bit)(wei & 0x80);wei <<= 1 ;CLK_595 = 0 ;_nop_();CLK_595 = 1 ;}RCLK_595 = 0;_nop_();RCLK_595 =1;}void t0(void) interrupt 1 using 0{uc i;TH0=(65536-50000)/256;TL0=(65536-50000)%256;i++;if(i==20){i=0;sum++;{h = sum/10000000;g = sum%10000000/1000000;f = sum%1000000/100000;e = sum%100000/10000;d = sum%10000/1000;c = sum%1000/100;b = sum%100/10;a = sum%10;}}}main(){P4SW=0x70;TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;TR0=1;ET0=1;EA=1;while(1){display(1,b);display(0,a);display(2,c);display(3,d);display(4,e);display(5,f);display(6,g);display(7,h);/* if((c==1)&&(b==0)&&(a==0))FMQ=0;if((c==1)&&(b==0)&&(a==5))FMQ=1;*/}}void delay100us() //@11.0592MHz {uc i, j;_nop_();_nop_();i = 2;j = 15;do{while (--j);} while (--i);}void delay1ms() //@11.0592MHz {uc i, j;_nop_();_nop_();_nop_();i = 11;j = 190;do{while (--j);} while (--i);}void delay100ms() //@11.0592MHz {unsigned char i, j, k;_nop_();_nop_();i = 5;j = 52;k = 195;do{do{while (--k);} while (--j);} while (--i);}。
51单片机延迟函数
51单片机延迟函数51单片机延迟函数是一种非常重要的函数,它可以帮助我们在程序中实现延迟的效果。
在很多应用场景中,我们需要让程序暂停一段时间,比如等待传感器采集数据、等待外设响应等等。
这时候,延迟函数就可以派上用场了。
在51单片机中,延迟函数的实现方式有很多种,比如使用定时器、循环计数等等。
其中,使用循环计数实现延迟函数是最简单、最常用的方法。
具体实现方式如下:```cvoid delay(unsigned int ms){unsigned int i, j;for (i = 0; i < ms; i++){for (j = 0; j < 1141; j++);}}```这个函数的原理很简单,就是通过两个嵌套的循环来实现延迟。
外层循环控制延迟的时间,内层循环则是一个空循环,用来消耗CPU 的时间。
通过调整内层循环的次数,就可以控制延迟的时间。
需要注意的是,这种延迟函数的精度并不高,因为它的延迟时间受到CPU时钟频率的影响。
如果CPU时钟频率发生变化,延迟时间也会发生变化。
因此,在实际应用中,我们需要根据具体的情况来选择合适的延迟函数。
除了使用循环计数实现延迟函数外,还可以使用定时器来实现。
定时器可以精确地控制延迟时间,而且不会受到CPU时钟频率的影响。
但是,定时器的使用比较复杂,需要对定时器的寄存器进行配置,不太适合初学者使用。
51单片机延迟函数是一种非常实用的函数,可以帮助我们在程序中实现延迟的效果。
在实际应用中,我们需要根据具体的情况来选择合适的延迟函数,以达到最佳的延迟效果。
单片机定时器实现1s延迟
单片机定时器实现1s延迟:
在单片机中,使用定时器实现1秒延迟通常需要以下步骤:
1.设置定时器模式:首先,你需要设置单片机的定时器模式。
这通常涉及到选择定时
器的工作方式(例如,模式1、模式2等),并设置适当的预分频值。
预分频值决定了定时器溢出时的时间间隔。
2.计算定时器初值:接下来,你需要计算定时器的初始值。
定时器的初始值是定时器
计数到溢出时所用的时间长度。
要实现1秒延迟,你需要知道单片机的工作频率以及你选择的定时器模式和预分频值。
3.启动定时器:设置好定时器模式和初始值后,你可以启动定时器。
一旦定时器开始
计数,它会不断增加,直到达到设定的初始值。
4.检测定时器溢出:当定时器计数到初始值并溢出时,你可以检测这个事件。
一旦检
测到溢出,你可以执行相应的操作,例如触发一个中断或执行一个函数。
5.重置定时器:在执行完溢出的操作后,你需要重置定时器以开始下一个计时周期。
PIC单片机C语言延时程序和循环子程序
PIC单片机C语言延时程序和循环子程序
PIC单片机C语言延时程序和循环子程序
很多朋友说C 中不能精确控制延时时间,不能象汇编那样直观。
其实不然, 对延时函数深入了解一下就能设计出一个理想的框价出来。
一般的我们都用
for(x=100;--x;){;}此句等同与x=100;while(--x){;};
或for(x=0;x 来写一个延时函数。
在这里要特别注意:X=100,并不表示只运行100 个指令时间就跳出循环。
可以看看编译后的汇编:
x=100;while(--x){;}
汇编后:
movlw 100
bcf 3,5
bcf 3,6
movwf_delay
l2 decfsz _delay
goto l2
return
从代码可以看出总的指令是是303 个,其公式是8+3*(X-1)。
注意其中循环周期是X-1 是99 个。
这里总结的是x 为char 类型的循环体,当x 为int 时候,其中受X 值的影响较大。
建议设计一个char 类型的循环体,然后再用一个循环体来调用它,可以实现精确的长时间的延时。
单片机delay函数用法
单片机delay函数用法1. 引言在单片机编程中,延时函数是一项非常重要的功能。
通过延时函数,我们可以控制程序在执行过程中的时间间隔,以实现各种需要时间控制的功能。
本文将详细介绍单片机中延时函数的用法。
2. 延时函数的原理延时函数的原理是通过软件实现的。
在单片机中,可以使用定时器或循环控制来实现延时功能。
定时器是单片机中的一个硬件模块,通过设置定时器的计数值和时钟源,可以实现精确的定时功能。
而循环控制是通过在程序中加入循环,让程序在指定的时间内空转一段时间,从而实现延时的效果。
3. 延时函数的分类延时函数可以根据其实现的方式进行分类。
常见的延时函数有以下几种:3.1 定时器延时函数定时器延时函数是通过使用定时器模块来实现的。
通过设置定时器的相关参数,可以实现准确的延时功能。
定时器延时函数的优点是精确度高,但需要花费一定的时间和精力来配置定时器。
3.2 循环延时函数循环延时函数是通过在程序中加入循环来实现延时的效果。
循环延时函数的原理是让程序在指定的时间内进行循环,从而实现一段时间的延时。
循环延时函数的优点是简单易实现,但由于程序在延时期间需要不断进行循环,可能会占用较多的处理器资源。
3.3 软件中断延时函数软件中断延时函数是通过使用软件中断的方式实现延时功能。
在延时函数中,可以设置软件中断的定时器,当定时器计数值达到预设值时,触发软件中断,从而实现延时效果。
软件中断延时函数的优点是不需要额外的硬件支持,但在延时期间无法进行其他操作。
4. 常见的延时函数4.1 _delay_ms函数_delay_ms函数是一个常见的延时函数,用于实现以毫秒为单位的延时。
该函数的原型为:void _delay_ms(unsigned int ms);参数ms表示需要延时的毫秒数。
该函数的实现原理是通过循环控制来实现延时的效果。
使用_delay_ms函数时,需要注意以下几点:•延时时间的精确度取决于单片机的主频和循环次数。
keil延时程序讲解
Keil延时程序是指在嵌入式系统中使用Keil编译器编写的用于实现延时功能的代码。
在嵌入式系统中,由于处理器速度较慢,因此需要使用延时程序来实现某些功能,如等待某个事件发生或控制执行时间等。
Keil编译器提供了多种延时函数,其中最常用的是delay_ms()和delay_us()函数。
这两个函数分别用于实现毫秒级和微秒级的延时。
delay_ms(unsigned int ms):该函数用于实现毫秒级延时。
参数ms表示延时的毫秒数。
例如,delay_ms(1000)表示延时1000毫秒,即1秒。
delay_us(unsigned int us):该函数用于实现微秒级延时。
参数us表示延时的微秒数。
例如,delay_us(1000)表示延时1000微秒,即1毫秒。
以下是一个简单的示例,演示如何使用Keil延时程序实现LED闪烁功能:复制代码运行#include <reg52.h> // 包含头文件,定义了51单片机的寄存器#include <intrins.h> // 包含头文件,定义了一些内联函数sbit LED = P1^0; // 定义LED连接的端口void delay_ms(unsigned int ms) {unsigned int i, j;for (i = ms; i > 0; i--)for (j = 114; j > 0; j--);}void delay_us(unsigned int us) {unsigned int i;for (i = us; i > 0; i--);}void main() {while (1) {LED = 0; // LED亮delay_ms(500); // 延时500毫秒LED = 1; // LED灭delay_ms(500); // 延时500毫秒}}在这个示例中,我们首先定义了一个名为LED的变量,用于控制LED的开关。
单片机软件延时原理
单片机软件延时原理单片机软件延时是指通过在单片机程序中使用软件的方法来实现延时功能。
在单片机的开发过程中,我们需要经常使用延时函数来控制程序的执行时间,从而实现各种任务的定时、周期性执行以及时序控制等功能。
单片机软件延时原理主要包括两种实现方式:循环延时和定时器延时。
首先,我们来介绍循环延时的原理。
循环延时是通过在程序中使用循环等待的方式来实现的。
具体来说,我们通过设置一个循环次数或者一个循环计数器,在这个循环中进行空操作,以达到延时的目的。
由于单片机是按照一个指令一个周期的方式执行程序的,所以我们可以通过循环执行一定的指令次数来控制延时的时间。
在使用循环延时的时候,我们需要了解单片机的指令执行时间。
单片机的执行速度与晶振频率有关,通常可以在芯片手册中查找到相关信息。
以AVR单片机为例,其指令执行时间可以通过晶振频率和时钟分频系数来计算。
假设我们的单片机晶振频率为8MHz,时钟分频系数为64,则每个指令的执行时间为64/8000000=8μs。
因此,如果我们想要实现一个10ms的延时,我们可以计算出所需要的循环次数:10ms/8μs=1250。
然后,我们可以用一个循环来进行空操作,执行1250次,从而实现10ms的延时。
除了循环延时,我们还可以使用定时器延时来实现精确的时间控制。
单片机的定时器具有一定的定时精度,我们可以根据需要来选择合适的定时器。
在使用定时器延时的时候,我们首先需要配置定时器的相关寄存器,包括定时器控制寄存器、定时器计数器寄存器和定时器溢出中断等。
然后,我们需要设置定时器的计数初值,使其在溢出之前按照设定的频率进行计数。
当定时器溢出时,会触发相应的中断服务程序,我们可以在中断服务程序中进行相关操作,从而实现延时的功能。
在使用定时器延时的时候,我们需要注意定时器的工作模式和计数初值的设置。
比如,如果我们要实现1ms的延时,我们可以选择一个合适的时钟源和适当的定时器计数初值,从而使得定时器在1ms内溢出一次。