单片机减法错误_单片机减法运算 - CSDN
  • 一个负数,在单片机中,是没有负数的概念的,如果减得-60的话,如果是16位单片机, 实际上-60是被表示为FFC4,实际上是65476,那样的话,实际上就和我们原来的意思相反, 而应该用?:运算符判断一下,如果不够减,...
      下面的式子中,如果SecondCnt<LastSecondCnt,那么它们减的差值将会是
    一个负数,在单片机中,是没有负数的概念的,如果减得-60的话,如果是16位单片机,
    实际上-60是被表示为FFC4,实际上是65476,那样的话,实际上就和我们原来的意思相反,

    而应该用?:运算符判断一下,如果不够减,取0;

      应该改为if((cnt++ >= 5)||((SecondCnt>=LastSecondCnt?SecondCnt-LastSecondCnt:0+cnt)>6))



                if((cnt++ >= 5)||((SecondCnt-LastSecondCnt+cnt)>6))
                {
                    RebootCar();
                }
    展开全文
  • 最近有位师弟找到我,希望我能帮他指导一下,利用AT89C52单片机设计一个最小系统,其中包括矩阵键盘、数码管显示、中断、2位数加减法、定时计数与暂停等功能。我也粗略的设计了一个,在此分享出来,希望能对初学者...

      中南民族大学,电子信息工程学院,开设了一门课程,叫《嵌入式电路设计》,由舒老师带头,旨在引导低年级的学生入门嵌入式,其内容比较多,包括模电、数电、C语言、单片机、EDA技术等。最近有位师弟找到我,希望我能帮他指导一下,利用AT89C52单片机设计一个最小系统,其中包括矩阵键盘、数码管显示、中断、2位数加减法、定时计数与暂停等功能。我也粗略的设计了一个,在此分享出来,希望能对初学者有所帮助,使更多的人加入到嵌入式的行业来。

      开发工具:keil

      仿真工具:proteus

    电路图

    代码如下:

    头文件:inc_all.h

     1 #ifndef INC_ALL_H_
     2 #define INC_ALL_H_
     3 
     4 volatile unsigned char keyValue;
     5 volatile unsigned char sign;
     6 volatile long int opr1;
     7 volatile long int opr2;
     8 volatile long int SysValue=0;
     9 volatile int keyCounter;
    10 volatile int cnt50ms=0;
    11 volatile bit StartFlag;
    12 
    13 void Init_Timer0();
    14 void Init_Timer1();
    15 void delayms(int t);
    16 unsigned char KeyScan(void);
    17 void showNumber(long int num);
    18 void keyAnalyzing(unsigned char keyval);
    19 
    20 #endif

    源文件如下:main.c

      1 #include <reg52.h>
      2 #include "inc_all.h"
      3 //=======================================================
      4 //  数码管显示译码,共阴极
      5 //  0,1,2,3,4,5,6,7,8,9,灭,‘E’,'-'
      6 //=======================================================
      7 unsigned char code table[]={0x3F,0x06,0x5b,0x4F,0x66,
      8                             0x6d,0x7d,0x07,0x7F,0x6F,
      9                             0x00/* trun off */,
     10                             0x79/* Error */,
     11                             0x40/* - */};
     12 //========================================================
     13 //  定时器0初始化函数,定时50毫秒
     14 //  用键盘上的“START”键启动计数
     15 //  用键盘上的“SUS”键暂停计数
     16 //========================================================
     17 void Init_Timer0()      
     18 {
     19     TMOD |= 0x01;
     20     TH0  = 0x3C;
     21     TL0  = 0xB0;
     22     TR0  = 0;
     23     ET0  = 1;
     24 }
     25 //=========================================================
     26 //  定时器1初始化函数
     27 //  定时23毫秒,用于显示
     28 //  初始化后计时启动
     29 //=========================================================
     30 void Init_Timer1()     
     31 {
     32     TMOD |= 0x10;
     33     TH1  = 0xA6;
     34     TL1  = 0x28;
     35     TR1  = 1;
     36     ET1  = 1;
     37 }
     38 //=========================================================
     39 //  延时函数
     40 //=========================================================
     41 void delayms(int t)
     42 {
     43     int i,j;
     44     for(i=t;i>0;i--)
     45         for(j=25;j>0;j--)
     46             ;
     47 }
     48 //=========================================================
     49 //  四位数码管显示函数
     50 //  能自动灭零,自动识别正负号
     51 //  数值超出显示范围时显示错误"E---"
     52 //========================================================= 
     53 void showNumber(long int num)
     54 {
     55     unsigned char q,s,b,g;
     56     if(num>=0)
     57     {
     58         q = num/1000;
     59         b = num/100%10;
     60         s = num/10%10;
     61         g = num%10;
     62         if(num<10)
     63         {
     64             q = 10;
     65             b = 10;
     66             s = 10;
     67         }
     68         else if(num<100)
     69         {
     70             q = 10;
     71             b = 10;
     72         }
     73         else if(num<1000)
     74             q = 10;
     75         else if(num>9999)
     76         {
     77             q = 11;     //show error
     78             b = 12;
     79             s = 12;
     80             g = 12;
     81         }
     82     }
     83     else
     84     {
     85         if(num>-1000)
     86         {
     87             q = 12;
     88             b = (0-num)/100;
     89             s = (0-num)/10%10;
     90             g = (0-num)%10;
     91         }
     92         else
     93         {
     94             q = 11;     //show error
     95             b = 12;
     96             s = 12;
     97             g = 12;
     98         }
     99     }
    100     P0 = 0x00;
    101     P0 = table[q];
    102     P2 = 0xFE;
    103     delayms(10);
    104     P0 = 0x00;
    105     P0 = table[b];
    106     P2 = 0xFD;
    107     delayms(10);
    108     P0 = 0x00;
    109     P0 = table[s];
    110     P2 = 0xFB;
    111     delayms(10);
    112     P0 = 0x00;
    113     P0 = table[g];
    114     P2 = 0xF7;
    115     delayms(10);       
    116 }
    117 //=========================================================
    118 //  键盘扫描函数
    119 //  返回按键情况,扫描结果
    120 //=========================================================      
    121 unsigned char KeyScan(void)
    122 {
    123     unsigned char temp=0xF0;
    124     P1 = temp;
    125     temp = P1;
    126     if(temp!=0xF0)
    127     {
    128         delayms(5);     //去抖动
    129         temp = P1;
    130         if(temp!=0xF0)
    131         {
    132             int t=0x01,i;
    133             for(i=0;i<4;i++)
    134             {
    135                 P1 = ~(t<<i);
    136                 temp = P1;
    137                 switch(temp)                //按行扫描
    138                 {
    139                     case 0xee:  return '1';
    140                     case 0xde:  return '2';
    141                     case 0xbe:  return '3';
    142                     case 0x7e:  return '+'; //加号
    143 
    144                     case 0xed:  return '4';
    145                     case 0xdd:  return '5';
    146                     case 0xbd:  return '6';
    147                     case 0x7d:  return '-'; //减号
    148 
    149                     case 0xeb:  return '7';
    150                     case 0xdb:  return '8';
    151                     case 0xbb:  return '9';
    152                     case 0x7b:  return 'r'; //复位
    153 
    154                     case 0xe7:  return '0';
    155                     case 0xd7:  return 's'; //启动
    156                     case 0xb7:  return 't'; //暂停
    157                     case 0x77:  return '='; //等于
    158                     default:    ;
    159                 }
    160             }
    161         }
    162     }
    163     return '0';
    164 }
    165 //=========================================================
    166 //  键盘解析函数
    167 //  对扫描得到的键值进行解析
    168 //=========================================================
    169 void keyAnalyzing(unsigned char keyval)
    170 {
    171     if(keyval>='0' && keyval<='9')
    172     {
    173         switch(keyCounter)
    174         {
    175             case 0: SysValue = (int)keyval-0x30; 
    176                     keyCounter++;     
    177                     break;
    178             case 1: ;
    179             case 2: ;
    180             case 3: SysValue =SysValue*10+(int)keyval-0x30;
    181                     keyCounter++;
    182                     break;
    183             case 4: SysValue =SysValue*10+(int)keyval-0x30; 
    184                     keyCounter=0; 
    185                     break;
    186         }
    187     }
    188     else
    189     {
    190         switch(keyval)
    191         {
    192             case '+':   sign = '+';                        
    193                         opr1 = SysValue;
    194                         SysValue = 0;
    195                         keyCounter = 0;                        
    196                         break;
    197             case '-':   opr1 = SysValue;
    198                         SysValue = 0;
    199                         keyCounter = 0;
    200                         sign = '-'; 
    201                         break;
    202             case 's':   sign = 's';  
    203                         TR0 = 1;     //启动计数
    204                         StartFlag = 1;
    205                         break;
    206             case 't':   sign = 't'; 
    207                         if(StartFlag) 
    208                             TR0 ^= 1;//暂停/启动计数
    209                         break;
    210             case 'r':   sign = 'r';  
    211                         opr1 = 0;
    212                         opr2 = 0;
    213                         SysValue = 0;
    214                         keyCounter = 0;
    215                         TR0 = 0;    //停止计数器
    216                         StartFlag = 0;
    217                         break;
    218             case '=':   opr2 = SysValue;
    219                         if(sign=='+')
    220                             SysValue = opr1+opr2;
    221                         else if(sign=='-')
    222                             SysValue = opr1 - opr2;
    223                         opr1 = 0;
    224                         opr2 = 0;
    225                         keyCounter = 0;
    226                         sign = '='; 
    227                         break;
    228         }
    229     }
    230 }
    231 //=========================================================
    232 //  主函数main
    233 //  全局采用中断方式,有利于降低功耗
    234 //=========================================================
    235 void main()
    236 {
    237     EX0 = 1;        //允许外部0中断
    238     IT0 = 1;        //外部0中断方式为 “下降沿”
    239     Init_Timer0();  /*初始化定时器0,在键盘上点击“START”后
    240                     开始计数,定时时间为1秒*/
    241     Init_Timer1();  /*初始化定时器1,用于定时显示,定时时间
    242                     为23毫秒,即每隔23毫秒调用一次显示函数*/
    243     EA  = 1;        //总中断开
    244     P1 = 0xF0;      //初始键盘接口     
    245     while(1) ; 
    246 }
    247 //=========================================================
    248 //  按键中断服务函数,采用外部中断0
    249 //  按键中断,在中断里面检测按键并解析按键
    250 //=========================================================
    251 void key_isr(void) interrupt 0
    252 {
    253     EA = 0;
    254     keyValue = KeyScan();
    255     keyAnalyzing(keyValue);
    256     P1 = 0xF0;
    257     EA = 1;
    258 }
    259 //=========================================================
    260 //  定时器0中断服务函数
    261 //  用于,定时1秒计数,计数到8888后返回重新新计数
    262 //=========================================================
    263 void timer0_isr(void) interrupt 1
    264 {
    265     TR0  = 0;
    266     TH0  = 0x3C;
    267     TL0  = 0xB0;
    268     TR0  = 1;   
    269     cnt50ms++;          
    270     if(cnt50ms==19)     //计数20次  20*50 = 1000毫秒,即1秒
    271     {
    272         cnt50ms = 0;
    273         SysValue=(SysValue>8887)?0:SysValue+1;
    274     }
    275 }
    276 //=========================================================
    277 //  定时器1中断服务函数
    278 //  方式1,定时时间为23毫秒
    279 //  用于数码管显示
    280 //=========================================================
    281 void timer1_isr(void) interrupt 3
    282 {
    283     TR1  = 0;
    284     TH1  = 0xA6;
    285     TL1  = 0x28;
    286     showNumber(SysValue);
    287     TR1  = 1;   
    288 }

     

    转载于:https://www.cnblogs.com/phelonYang/archive/2012/12/18/2823550.html

    展开全文
  • 困惑求解答,为了减法运算,机器中都用补码表示数了,那为什么还用减法的指令。 如此题:SUB AL,BL.AL=80H,BL=80H。在机器中是怎么算的?直接减还是再变成补码然后算加法。 溢出标志和进位标志是什么?
  • 单片机原理及应用》复习提纲 单片机应用系统的典型结构图   单片机应用系统核心硬件技术包括: 1.时序 2.中断 3.地址译码   单片机应用系统核心软件技术包括: 1.寻址...
    《单片机原理及应用》复习提纲

    单片机应用系统的典型结构图

     

    单片机应用系统核心硬件技术包括:

    1.时序

    2.中断

    3.地址译码

     

    单片机应用系统核心软件技术包括:

    1.寻址方式、指令系统

    2.典型程序结构

    3.中断程序设计


    《单片机原理及应用》复习提纲

    (2015年)

    一.概述

    掌握:1.单片机的基本概念、特点、单片机与通用微机的主要区别、应用领域

    总线的概念,微型计算机的基本工作过程

    (1)基本概念:

       单片机是将CPU、存储器、I/O接口电路等微型机的主要部件集成在一块芯片上的计算机,简称单片机(Microcontroller)。

    (2)特点:

             可靠性高;使用方便、灵活,便于用户开发;易于面向工业控制;易于构成嵌入式系统。

    (3)单片机与通用微机的主要区别

             单片机是专门为控制和智能仪器设计的一种集成度很高的微型计算机。

    (4)应用领域

             <1>单片机在智能仪表和测量仪器中的应用

             <2>单片机在机电/光机电一体化产品中的应用

             <3>单片机在计算机网络及通信产品中的应用

             <4>单片机在消费类电子产品中的应用

    (5)总线的概念

             用来传送信息的一组导线,为CPU和其它部件之间提供数据、地址和控制信息的传输通道

             地址总线:用于传送地址信息。

             数据总线:用于传送数据信息。

             控制总线:用于传送控制信息。

    (6)微型计算机的基本工作过程

      <1>在进入运行前,要将事先编好的程序装入存储器中。

       <2>读取指令:在CPU的控制下,由内部程序计数器(PC)形成指令存储地址,并从该地址中读取指令后送到指令寄存器(IR)中保存

       <3>执行指令:在CPU的控制下,由指令译码器(ID)对指令译码,产生各种定时和控制信号,并执行该指令所规定的操作。

     

    2.定点小数的表示方法

            小数点通常有两种表示方法:定点表示法和浮点表示法。

            在定点表示法中,小数点的位置是固定不变的,它是事先约  
    定好的,不必用符号表示。通常,将小数点固定在数值部分的最高位之前或最低值之后, 前者将数表示为纯小数,后者将数表示为纯整数

     

    3.BCD码的两种存储格式(压缩和非压缩形式)

            1)压缩BCD码用4位二进制数表示1位十进制数,一个字节表示2位十进制数。

          例如10010111B表示十进制数97。

            2)非压缩BCD码用8位二进制数表示1位十进制数,高4位总是0000。

        例如,00001001B表示十进制数9。 

     

    4.ASCII的作用和特点:

            0-9的ASCII:30H-39H

            A,B,C,D,E,F的ASCII:41H-46H

     

      5.二进制、十进制、十六进制之间的转换方法(熟练掌握整数的转换方法)

      6.负数的3种表示方法:原码、反码和补码

      7.补码和真值的计算方法(熟练掌握,整数)

      8.单字节HEXàBCD; 单字节BCDàHEX的转换方法HEXàASCII; ASCII àHEX的转换方法

     

    二.内部结构(以AT89C51、AT89C52为背景机型)

    引脚部分:

    理解ALE,/PESN,/EA,/WR,/RD 的作用

    1.ALE:地址锁存使能输出(Address Latch Enable),下跳沿时锁存

    2./PESN:程序存储器读选通信号(Progrom Store Enable),访问代码空间

    3.外部ROM访问允许

     EA=0:访问片外程序存储器

     EA=1:访问片内程序存储器,

            当PC值大于0FFFH后,转向访问片外程序存储器。

    4./WR:访问数据空间,写外部数据存储器控制信号

    5./RD:访问数据空间,读外部数据存储器控制信号

    CPU部分:

    了解CPU的基本组成部件

    运算器(ALU,A,B, PSW(CY,AC,OV,P))

    ALU:算术逻辑部件

         组成:加法器和其他电路

         主要功能:算术运算和逻辑运算

    A:累加器,存放操作数或中间运算结果的寄存器

    B:寄存器,一般用于乘、除法指令

    PSW:程序状态字寄存器

     CY(PSW.7)——进位标志:

    在进行加或减运算时,如果操作结果最高位有进位或借位时,CY由硬件置“1”,否则清“0”。

      AC(PSW.6)——半进位标志:

    在进行加或减运算时,如果操作结果的低半字节向高半字节产生进位或借位时,将由硬件置“1”,否则清“0”。

      OV(PSW.2) ——溢出标志:

    在有符号数加减运算中,若有异常结果,OV硬件置1,否则硬件清0。

      P(PSW.0) ——奇偶标志位

    该位始终跟踪累加器A中含“1”个数的奇偶性。

    如果A中有奇数个“1”,则P置“1”,否则置“0”。满足偶校验原则。

     

    控制器 (IR,ID,PC,SP,DPTR)

    IR:中断允许控制寄存器

    ID:中断优先级控制寄存器

    PC:程序计数器(Program Counter)

    SP:堆栈指针(Stack Pointer)

    DPTR:数据指针寄存器(Data Pointer)

     

         理解PC,SP,DPTR,PSW的作用,以及PSW中各位的含义和使用方法

     

    时序部分:

    了解时钟周期、状态周期、机器周期和指令周期之间的关系

      1个机器周期

     =6个状态周期(时钟周期)

     =12个振荡周期

     =完成一个基本指令所需时间

      指令周期:完成一个指令所需时间

     

    重点掌握机器周期的计算方法

      12*晶振周期

     

    时钟电路硬件连线

     

    时钟部分:

    了解给单片机提供时钟的必要性;掌握提供时钟的基本方法

     

    复位部分:

    了解给单片机复位的必要性,掌握复位的基本方法和电路(上电复位、按键复位)

    1.复位条件:RST引脚端出现持续时间不短于 2个机器周期的高电平。

    2.

    上电复位                       按键复位                     复合复位

     

    掌握和理解单片机复位后的初始状态。

    SP=07H

    P1~P3=0FFH

    IP=XXX00000B

    IE=0XX00000B

    PCON=0XX00000B

    SBUF(串行口数据缓冲寄存器)=XXH

    其他=00H

     

     

    复位电路硬件连线

           

    片内RAM部分和SFR区:

    了解片内128Byte(256Byte)RAM的分区情况和使用特点

    1.分区情况

    (1) 低128字节的区域

          ①工作寄存器区(00H~1FH)

         ②可位寻址区(20H~2FH)

          ③用户RAM区(30H~7FH)

    (2)高128字节区域

              SFR区:承担着51单片机片上资源的管理工作

    2.使用特点

         ①区和③区只能按字节进行数据存取操作,②区则可按字节和位两种方式存取操作。

         每个存储单元都有一个字节地址,但只有其中21个单元可以使用,并有相应寄存器名称。


    掌握4组寄存器的选择方法和0组寄存器所对应的地址范围

      当前工作寄存器组取决于PSW的设置

    CPU复位后RS1和 RS0默认值为0,即默认第0组为当前工作寄存器组。

    (RS1,RS0)=(0,0):寄存器0组

    (RS1,RS0)=(0,1):寄存器1组

    (RS1,RS0)=(1,0):寄存器2组

    (RS1,RS0)=(1,1):寄存器3组

     

    了解可位寻址区的分布区域:

    20H-2FH,部分SFR

     

    堆栈部分:

    掌握堆栈的基本的概念、作用和数据存储方法

      1.概念:MCS-51单片机的堆栈,是在片内RAM中开辟的一个专用区,用来暂时存放数据或存放返回地址,并按照“后进先出”(LIFO)的原则进行操作。

      2.作用:进栈时,SP首先自动加1,将数据压入SP所指示的地址单元中;

             出栈时,将SP所指示的地址单元中的数据弹出,然后SP自动减1

      3.数据存储方法:先进后出

                     指定内部数据存储器地址07H~7FH中的一部分连续存储区作为堆栈。

     

    片上IO口部分:

    了解P0-P3口的功能和使用特点P1:通用输入输出口

    P0:通用输入输出口

            地址总线低8位输出口,

            数据总线口

     

    P2:通用输入输出口

            地址总线高8位输出口

     

    P3:通用输入输出口

     

            /RD、/WR:外部数据存储器读写控制

            /INT0、/INT1:外部中断信号输入引脚

           T0、T1:计数信号输入引脚

           RXD、TXD:串行通信口接收、发送引脚

     

     

     

     

    三总线实现方法

    P2P0合起来构成16位地址总线(P2高8位,P0低8位

    P0口为数据总线(P0口分时实现数据和地址的传输,一般通过373锁存器来实现)

    P3口一部分及几个特殊控制引脚构成不完整的控制总线

     

    重点理解准双向口的概念,准双向口使用注意事项,读预备操作的意义

    1.概念:P1、2、3有固定的内部上拉电阻,所以有时称它们为准双向口;只有高低电平状态,没有高阻状态

    2.注意事项:P1、P2、P3口无需外接上拉电阻(已有内部上拉电阻);做输入用的时候要有向锁存器写1的这个预备操作

    3.预备操作意义:输入时,为正确读出P1.n引脚电平,需设法在读引脚前先使场效应管截止,即向锁存器写一

    读锁存器、读引脚、“读-修改-写”指令

          

    1.读锁存器:ANL P1,A

    2.读引脚:MOV P1,#0FFH

             MOV A,P1

    3.读改写:

           

           


    三.指令系统

    寻址方式部分:理解7种寻址方式、特点及适用范围

    寻址方式:寻找操作数地址或指令地址的方式。

       寻址方式类型: 

       1.立即寻址

         特点:操作数可以从指令中直接取得,速度快。

         用途:用于对寄存器或存储单元进行初始赋值。

       2.直接寻址

         特点:在指令中直接给出操作数的字节地址或位地址。

         适用范围:只能在下述三种地址空间内寻址。

                   (1)特殊功能寄存器(SFR);

                   (2)内部数据存储器RAM的低128个字节;

                   (3)位地址空间。

       3.寄存器寻址

         特点:指令短,速度快

         适用范围:

             (1)工作寄存器区中的R0-R7 

             (2)A(累加器)、B(仅限于乘除法指令)、DPTR、C(布尔处理器)

       4.寄存器间接寻址

         特点:指令简洁,便于对连续存放的数据进行处理

         适用范围(特定寄存器):

                 R0,R1:用于访问片上RAM空间

                 DPTR:用于访问外部数据空间

                 SP:用于访问堆栈空间 

       5.变址寻址

         特点:操作数的有效地址为基址寄存器与变址寄存器内容之和;基址寄存器:PC(或DPTR),变址寄存器:A 

         适用范围:用于查表指令,读取存放于程序空间中的常数表,如函数表,字模表等。

       6.相对寻址

         适用范围:用于确定下一条执行指令的入口地址 ,在指令中给出程序跳转的偏移量rel,用于转移指令中。

       7.位寻址

         特点:直接操作单元中的某一个位,方便了程序设计,提高了程序的可读性。

         适用范围:

             (1)片内RAM区支持位寻址方式的单元,即20H-2FH。

             (2)SFR中支持位寻址方式的寄存器。

     

    指令部分:

    1. 理解全部指令的功能,正确掌握其使用方法P46~P62

        掌握MOV、MOVC、MOVX指令的使用特点

        掌握ADD,AADC,SUBB,DA,INC,DEC指令的特点

    掌握PUSH、POP、LCALL、ACALL、RET、RETI指令

    掌握控制转移类指令的应用:DJNZ,CJNE;JC/JNC; JB/JNB/JBC

           掌握逻辑操作类指令的应用:CPL,ANL,ORL,XRL,RR/RRC, RL/RLC

    2.掌握估算指令长度的方法

          指令长度估算方法:

             指令基本长度为1 字节;

             逢立即数(8bits)长度加1;

             逢立即数(16bits)长度加2;

             逢直接寻址方式,指令长度加1。

     

    3. 掌握相对转移指令中偏移量的计算方法

     

     

    四.汇编语言程序设计

    掌握基本伪指令的使用:ORG、END、EQU、DATA、DB、DW、BIT

    掌握基本程序结构的设计方法

    1. 分支程序:二分支、三分支

              散转程序(重点掌握转移指令表方式)

    2. 循环程序 :循环变量、循环条件

    3. 子程序:掌握基本调用方法和参数传递方法

    入口参数、出口参数传递方法:

    1). 利用A

    2). 利用寄存器,或存储单元

    3). 利用堆栈

    4. 查表程序:掌握表格的定义方法和两种查表方法

    两种查表方法:

    MOVC  A,  @A + DPTR ;对应于DPTR 查表方式

    MOVC  A,  @A + PC    ;对应于PC 查表方式

     

    掌握以下应用程序的设计方法:

    运算程序:加法(含多字节十六进制数、BCD码数)

    减法(含多字节十六进制数、BCD码数)

    针对数据块的操作:

    清零、初始化、移动(复制)、求和、求最大值、求最小值、找寻特殊字符

    延时程序的设计和分析

    码制转换:HEX与ASCII之间的转化,单字节HEX与BCD码之间的转化

     

    五.中断系统

    了解:

    微机与外设之间的数据传送方式,各种传送方式的特点

    与中断相关的SFR和中断标志

    CPU对外部中断信号的基本要求

    掌握重要概念:

    中断、 中断申请、中断优先、中断响应、中断服务和中断返回

    中断源,中断申请方式(电平、边沿)

    中断响应:

    响应时间(一般3-8机器周期,或更长)

    响应中断的条件(基本条件和阻止CPU立即响应中断的3种情况)

    中断屏蔽和中断优先

    中断服务:

    重要的中断入口矢量地址:0003H/0013H,000BH/001BH,0023H                      

    现场保护

    重点掌握:外部中断0/1的应用和中断服务程序的设计

     

     

    六.定时/计数器

    了解:

    定时/计数信号的来源及对计数信号的要求

          中断源:发出中断请求的设备和电路

          中断信号形式:电平信号或边沿信号

     

    重要的SFR、其作用和相关标志位的作用(TMOD,TCON,TH0,TL0, TH1,TL1)

    定时器或计数器初值:TH0.TL0;TH1,TL1

    T2定时计数器的特点和使用方法

    T2(仅52系列有)

    它的特点是具有可编程性,即计数位数、启动方式、计数信号来源均可以通过程序进行控制。

    可编程性体现在3个方面:

         位数、启动方式、定时/计数方式

     

     

    重点掌握

    方式1,2的使用方法(包括定时和计数)

    1.计数信号源要求高电平或低电平的持续时间不能短于一个机器周期

      定时方式:对机器周期计数,

                        计数信号频率=fOSC/12

      计数方式:对外部脉冲信号计数 ,

                        来源于引脚T0(P3.4)、T1(P3.5)

                        信号频率不可高于 fOSC/24。

    2.(1)软件启动方式(内部控制):

         GATE=0时, TRx=1 启动定时或计数

     (2)门控方式(外部触发):

         GATE=1时,TRx=1且 /INTx引脚(P3.3 或 P3.5)为高电平,才能启动定时或计数

     

    TMOD的设置和初值的计算方法

    1.(1)定时方式: 

         方式1(16bits):(65536-X)×cycle=定时时间

         方式2(8bits):  (256-X)×cycle=定时时间

         其中,cycle指代机器周期(μs)

      (2)计数方式:

         方式1(16bits):65536-X=计数值

         方式2(8bits):  256-X=计数值

    2.TMOD=00H:2^13-N=32TH0+TL0

      TMOD=01H:2^16-N=256TH1+TL1

     

    不同占空比的脉冲波形产生方法(包括查询方式和中断方式的程序设计)

     

    理解:门控启动控制方法和脉冲宽度测量的基本原理和编程实现。

     

    七.存储器和并口的扩展

    掌握:

    半导体存储器的分类、各类存储器的特点

    存储器分类

      1.存储器的类型

        (1)按工作时与CPU联系密切程度分类

           主存和辅存,或者称作内存和外存.主存直接和CPU交换信息,容量小,速度快。辅存则存放暂时不执行的程序和数据,只在需要时与主存进行批量数据交换,通常容量大,但存取速度慢;

        (2)按存储元件材料分类

           半导体存储器、磁存储器及光存储器;

        (3)按存储器读写工作方式分类

           只读存储器(ROM)

           随机存储器(RAM)

           可现场改写的非易失性存储器(NVM)

     

    三总线的构成方法

    1.P2P0合起来构成16位地址总线(P2高8位,P0低8位

     P0口为数据总线(P0口分时实现数据和地址的传输,一般通过373锁存器来实现)

     P3口一部分及几个特殊控制引脚构成不完整的控制总线

    2.地址总线(Adress Bus, AB)

      A0-A15

     数据总线(Data Bus, DB)

      D0-D7

     控制总线(Control Bus,CB)

      /PSEN       访问代码空间

      /WR, /RD   访问数据空间和IO空间

     

    并行IO口的总线扩展方法(利用TTL器件的扩展方法)

     

    掌握:

    2764、6264,62256的基本接口方法

    书P167

     

    线选法、译码法(利用简单逻辑电路译码或译码器译码)硬件实现

    1.线选法:直接利用单根地址线作为片选信号

          

        2.译码法:多根地址线经过译码器、简单逻辑电路、可编程逻辑阵列处理后产生片选信号

    地址译码法又有部分译码和全译码两种方式

        

     

    存储器扩展的硬件连线(三总线信号连接)

     

     

    存储空间的分配、存储芯片地址范围的计算

     

    理解:

    2764, 6264, 373,273,244,245,138,139芯片的读写信号及控制信号

     

     

    访问片外程序和数据存储器的读写时序

     

    八.键盘和显示器

    了解:

       按键的基本输入过程,按键响应程序的基本功能

       1.响应程序

       独立式按键:

       矩阵式键盘:

      

       2.基本功能

           (1)按键检测:如何识别有键按下;

           (2)去抖动:识别被按键与释放键时必须避开抖动状态,只有处在稳定接通或断开状态时,才能保证识别正确无误;

          (3)键码产生:为了从键的行列坐标编码得到反映键功能的键码,一般在程序存储器中建立了一个键盘编码表,通过查表获得键码。

           (4)防串键:防串键是为了解决多个键同时按下或者前一键没有释放而又有新键按下时产生的问题;

      

       消除按键抖动的必要性和方法

    1.必要性:

       监测有无键按下

       保证可靠性:采取软件消抖

       不管按键过程持续多长时间,仅执行一次按键功能程序。

       输出确定的键号(键值)

    2.方法:

           (1)程序扫描方式:当CPU空闲时,扫描键盘,判断有无键按下。

           (2)定时扫描方式:利用CPU的定时器,每隔一定时间扫描一次键盘。

           (3)中断方式:有键按下时产生中断,由中断服务程序来处理。

     

    LED的基本结构,主要电参数的含义和限流电阻的计算方法

    1.基本结构:

          常用的LED显示器为8段(或7段,8段比7段多了一个小数点“dp”段)。有共阳极和共阴极两种。

    2.主要电参数含义:

          VF:正向压降 

          IF:正向工作电流

    3.限流电阻计算方法:

         

     

    静态LED显示和动态LED显示的基本特点

    1.静态LED显示:

         持续驱动LED显示器的共公端。在显示器工作过程中,系统为每个显示器的公共端都一个有效电平。

         软件编程简单,但占用I/O口线多,功耗大。

    2.动态LED显示:

      单片机定时扫描显示器,采用分时驱动的方法,轮流控制各个显示器的COM端,使各个显示管轮流点亮。该驱动方式利用了人的视觉暂留现象。

      动态扫描驱动方式中,显示管分时工作,每次只有一个LED管显示。

      在轮流点亮扫描过程中,每位显示管的点亮时间是极为短暂的(约1ms)。

      硬件连线少,功耗低;

       软件复杂,需要不停地扫描。

       显示亮度既与导通电流有关,也与点亮时间和间隔有关。

     

    掌握:

    独立式按键和行列式键盘的硬件接口方法

    &独立式按键的应用程序设计方法

     

    行列式键盘扫描和键值读取的基本原理和方法

    程序扫描法原理:

    ①行线(P1.0 — P1.3)同时输出低电平,

      读列线(P1.4 — P1.7)的状态,若全为1, 则无键按下;

      若不全为1, 则有键按下。

    ②在有键按下的情况下,进一步判断是哪个键按下。

      使P1.0 —P1.3依次输出低电平, 读出P1.4 — P1.7的状态。

     

    静态LED显示器的接口和程序设计方法  

     

     

     

    软件代码实现:

    MOV  P1, #0C0H 送字模

    MOV  P2, #0F9H

     

     

     

     

     

     

     

    动态LED显示器的接口方法和软件设计方法

     

    九.A/D和D/A接口

    了解:

    A/D和D/A器件的主要技术指标和选取原则

    A/D器件:

    1.转换精度:

         (1)分辨率:能区分输入电压的最小值=满量程/2^n

         (2)转换误差:实际输出数字量与理论输出数字量的差别,常用最低有效位的倍数表示,如相对误差≦±LSB/2

    2.转换时间:从转换信号到来开始,从输出端得到稳定的数字信号进过时间

    D/A器件:

    1.分辨率:最小非零输出电压/最大输出电压

    2.建立时间:当输入数据从零变化到满量程时,输出模拟信号达到满量程刻度值(或指定与满量程相对误差)所需要时间

    3.转换精度:最大静态转换误差

    4.线性度(非线性误差):理想输入或输出特性偏差/满刻度输出(FSR:full scale range)*100%

    5.温度系数:满量程刻度输出时,温度每升高1ºC,输出变化/满量程*100%

    6.电源抑制比:满量程电压变化/电压变化*100%

    7.输入形式:二进制码/BCD码/特殊形式码;并行输入/串行输入

    8.输出形式:电流输出/电压输出;单路输出/多路输出

    选取原则:

    精度、速度、

    输入/输出方式、

    成本、

    环境参数、

    资源情况(资料、购买的便利性)

     

    采样频率选取原则

    实际情况:

    :采样频率,输入信号vi最高频率分量频率

     

    不同种类A/D器件的主要特点(逐次比较型,双积分型、并行)

    逐次比较型:位数越少,时钟频率越高,转换所需时间越短;转换速度快,精度高

    双积分型:模拟输入电压在固定时间内向电容充电(正向积分),固定积分时间对应于n个时钟脉冲充电的速率与输入电压成正比。当固定时间一到,控制逻辑将模拟开关切换到标准电压端,由于标准电压与输入电压极性相反,电容器开始放电(反向积分),放电期间计数器计数脉冲多少反映了放电时间的长短,从而决定了模拟输入电压的大小;强抗工频能力

    并行比较型:用电阻链将参考电压分压;不用附加采样保持电路,转换速度最快,随分辨率提高,元件数目几何级数增加

     

    掌握:

    ADC0809和DAC0832与51单片机的基本硬件接口连线方法

    ADC0809:

     

    ADC的端口地址是 0XXXXXXXXXXXXXXB也就是7FFFH了

    DAC0832

    单缓冲:

    双缓冲:

     

    理解:

    ADC0809的工作时序,以及启动控制和数据传送方法

    工作时序 

    启动控制

    数据传送方法:无条件数据传送,查询方式,中断方式

     

    掌握:端口地址的概念和端口地址分配(计算)方法

     

    掌握:

    ADC0809基本应用程序设计方法(延时法,查询法,中断法)

    延时法:

    查询法:

    MAIN: MOV   R1,#30H      ;置数据区首址,采样数据缓冲区的首地址

            MOV   DPTR,#0FEF8H   ;指向IN0,利用P2.0=0 选通AD ,                                         ;采用锁存地址总线的方式选择通道0。

            MOV   R7,#08H      ;置通道数

    LOOP:MOVX  @DPTR, A   ;启动A/D转换

             MOV   R6, #05H      ;软件延时,延时时间不短于10us

    DALY:   NOP         

             DJNZ  R6,  DALY 

    WAIT:JB   P3.2,  WAIT      ;查询是否转换结束                                        ;ADC0809 的 EOC经反相器后与P3.2相连

           MOVX  A,  @DPTR     ;读取转换结果

           MOV   @R1,       ;存取数据

            INC   DPTR             ;指向下一个通道

             INC   R1         ;指向下一个单元

            DJNZ  R7, LOOP      ;巡回检测8个通道

             RET

    中断法:

     主程序:

                   ORG    0000H  

                   LJMP   MAIN  

                   ORG   0013H                    ; INT1中断入口地址

                    LJMP   INT1    

                   ORG   0030H  

    MAIM:      MOV  R0,#60H      ;置数据存储区首址

                    MOV   R2,#08H      ;置八路数据采集初值

                   SETB   IT1      ;设置边延触发中断

                    SETB   EA

                 SETB  EX1      ;开放外部中断1

                    MOV   DPTR,#7FF8H   ;指向0809通道0,使用P2.7选通AD

    RD:        MOVX  @DPTR,A   ;启动A/D转换

    HE:            MOV   A,R2      ;八路巡回检测数送A

                   JNZ   HE      ;等待中断,八路未完继续

                  SJMP $         ;!!!

    INT1:        ……    ; 保护现场

     

                  MOVX  A,@DPTR   ;读取A/D转换结果

                   MOV  @R0,A       ;向指定单元存数

                   INC   DPTR      ;输入通道数加1

                   INC   R0      ;存储单元地址加1

                   MOVX   @DPTR, A   ;启动新通道A/D转换

                   DEC   R2      ;待检通道数减1

                  

                 ……     恢复现场

     

                 RETI         ;中断返回

     

    ADC0809多通道巡回采集软件设计方法

           ORG 0000H

           LJMP MAIN

           ORG 0003H

           LJMP INT0

           ORG 0000H

    MAIN:  MOV SP,#40H

           SETB ET0

           SETB IT0

           SETB EA

           MOV R7,#8

           MOV R6,#50

           MOV R0,#20H

           MOV DPTR,#7FF8H

    STOP:  SJMP $

    INT0:  MOVX A,@DPTR

           MOV @R0,A

           INC DPTR

           INC R0

           DJNZ R7,STOP

           MOV R7,#8

           DJNZ R6,STOP

           ACALL DELAY

           RETI

           END

     

    利用DAC0832产生单极性波形的程序设计方法

    1.单极性三角波发生器

                ORG   2000H

    START:     MOV   DPTR,#07FFFH

             MOV   A,#00H

    UP:         MOVX   @DPTR,A      ;三角波上升边

             INC    A

             JNZ    UP

    DOWN:       DEC    A      ;A=0时再减1又为FFH

             MOVX   @DPTR,A

             JNZ    DOWN         ;三角波下降边

             SJMP   UP

    2.单极性锯齿波发生器

    DACS:  MOV       DPTR,#7FFFH;0832 I/O地址

           MOV       A,#00H   ;开始输出0V

    DACL:  MOVX   @DPTR,A   ;D/A转换

           INC       A      ;升压

           ACALL   DELAY      ;延时100ms/256:决定锯齿波的周期

           AJMP       DACL      ;连续输出

    DELAY:…         ;延时子程序

     

    十.串行通讯

    了解:

    MSC-51单片机串行接口工作模式的特点和应用场合

    1.基本特征

      (1)一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)与外设进行全双工的串行异步通信。P3.0是串行数据接收端RXD,P3.1是串行数据发送端TXD。

      (2)4种工作方式

      (3)2个控制寄存器,用来设置工作方式、发送接收状态、特征位、波特率等。

      (4)一个数据寄存器SBUF作为接收发送的数据缓冲,两个数据缓冲器(SBUF)在物理上相互独立,在逻辑上却占用同一字节地址99H

      (5)应用特点

        两个中断标志,RI用于接收,TI用于发送。

        发送/接收前都必须对RI/TI清零,

        一帧数据发送/接收后,RI/TI自动置1,如要再发送/接收,必须用软件清零。

        方式0和1:数据发送/接收完成后,置位RI/TI,请求中断。

        方式2和3:数据接收完成后,视SM2和RB8的状态确定RI和是否请求中断。

     

    RS-232C标准的基本内容和特点

    1.RS232C是美国电子工业协会1962年公布,1969年修订的通用标准串行接口标准。

    2.信号线

      25芯,22根信号线,常用9根线。

      最简方式3根线

               RXD:数据接收线

               TXD:数据发送线

               GND:地线

      例如PC机上的串口COM1、COM2

    3.电平制

      采用负逻辑,对应电平如下:

      1 :-3V ~ -15V

      +3V ~ +15V

     

    SPI,I2C总线的特点和总线构成。

    SPI:Serial  peripheral  interface,由Motorola公司提出。

              波特率可达到 50Mbps。

         三线制 ,全双工,同步串行总线,速度比I2C总线快。

              三线指:SCK:时钟线

                 MOSI (master  output  slave  input): 从设备接收线

                 MISO (master  input  slave  output): 从设备发送线

    I2C:Inter-Integrated Circuit,由Philips公司,80年代提出的同步串行总线。

             波特率: 0 - 400kbps。

             双线制,半双工。

             双线指:时钟线SCL和数据线SDA

     

     

    掌握:  

    串行通讯的基本特点,帧格式、波特率的概念及其计算方法(要求熟练)

    1.基本特点:(帧格式)

    异步串行通信的特点:数据的传送以“Frame”为一个基本单位;

                                             数据的传送可以是不连续的。

    同步通信时A、B双方使用同一时钟信号驱动。

    异步通信时A、B双方使用各自的时钟信号驱动,但时钟信号的频率相同。

    2.波特率

         单位:bps(bit per second)

         定义:每秒钟传送的二进制位数。在计算机系统中也称为波特率。

         数据位宽Td= 1 / Baudrate

     

    两种校验方法(奇偶校验、校验和检验)的基本原理

    1.奇偶校验法:

      比对收、发双方的校验位是否一致。

      有奇校验和偶校验两种。

      校验过程是针对单个字节的。

      只能检查部分错误,当一个字节中同时有偶数个bit出错时,无效。

      当发送数据量较大时,发送的校验信息量也会较大。

    2.校验和方法:

      比对收、发双方的checkSUM是否相同。

      校验是针对一个数据块的。(特列情况是一个字节)

      可以发现一个字节中多个bit同时出错的问题。

      校验信息量小,通常采取1或2个字节就可。   

     

    双机通讯的硬件连线方法(单片机-单片机,单片机-PC机)

     

    数据收发程序编程(查询方式)

    预用51单片机的UART传送数据,要求采用偶校验方法,波特率为9600bps,试选择UART的工作方式,并写出初始化代码。(fosc=6MHz)

     

    多机通信的基本思想

    系统中主机、从机均采用9位UART模式,利用TB8区分地址帧和数据帧

    地址帧:TB8 = 1,

    数据帧:TB8 = 0,

    利用特性:SM2 = 1时, 接收方的UART要求 RB8 = 1 ,

              才能激活RI,才能触发串口中断。

    主机首先发“地址帧”,即地址码,也是要呼叫的从机ID号,

       此时置 TB8 = 1 。

    全体从机都会接收地址帧,并与自己的地址号(ID)比较,

       若主机呼叫自己便回应,

       并置SM2 = 0(切换到双机通信模式),准备接收数据。

    主机若收到从机回应,便开始发送数据,此时置 TB8 = 0 ,连续发送数据,

       直到数据发送完毕。

     主从机一次通信结束后,主从机重置自己的 SM2 = 1。

       主机可以再次呼叫其它从机,并开始新的数据传送过程。

     

    十一.C8051F310单片机的重要新特性及其在实验3、4、5中的应用

    参见C8051F310新特性讲解.pdf

    1)理解Init_Device()配置函数的构成和作用。

    2) 端口的使用方法

    3)定时器的使用方法

    4)WDT的作用和正确使用

    展开全文
  • 延时与中断出错,是单片机新手在单片机开发应用过程中,经常会遇到的问题,本文汇总整理了包含了MCS-51系列单片机、MSP430单片机、C51单片机、8051F的单片机、avr单片机、STC89C52、PIC单片机…..在内的各种单片机...
    延时与中断出错,是单片机新手在单片机开发应用过程中,经常会遇到的问题,本文汇总整理了包含了MCS-51系列单片机、MSP430单片机、C51单片机、8051F的单片机、avr单片机、STC89C52、PIC单片机…..在内的各种单片机常见的延时与中断问题及解决方法,希望对单片机新手们,有所帮助!

    一、单片机延时问题20问

    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那么大的差距,是你的软件的原因。
    不信你实际编写一个秒钟,利用原理计算编写一个烧进单片机和利用软件测试的秒程序烧进单片机,你会发现原理计算的程序是正确的



    4 、51单片机c语言 _nop_()是一个空指令?短时间延时的?空几个机器周期?
    答:这个_nop_()等效与汇编里面的,NOP指令,也就是空一个机器周期,如果是传统51单片机的话,等于空12个时钟周期【即一个机器周期】

    5、51单片机 延时500ms 用机器周期叠加怎么算?
    答:DELAY:
    MOV R7,#4
    D2:MOV R6,#250
    D1:MOV R5,#250
    DJNZ R5,$
    DJNZ R6,D1
    DJNZ R7,D2
    RET
    假设晶振为12MHz
    刚延时时间为:
    250*250*4*2=500MS

    6、51单片机C语言程序中延时函数delay的原理是什么?
    现在找到两个函数
    第一:
    void delay(void)
    { unsigned int i,j;
    for(i=0;i<500;i++)
    { for(j=0;j<121;j++)
    {;}
    }
    }

    第二:
    void delay(unsigned int k)
    { unsigned int i,j;
    for(i=0;i<k;i++)
    { for(j=0;j<121;j++)
    {;}
    }
    }
    现有几个疑问:
    (1):延时函数的原理?
    (2):两个for循环的作用?
    (3):i、j的取值有什么规律和依据?是不是和单片机接的晶振频率有关?所能延时的最小单位时间是怎么计算的?
    延时时间怎么计算啊!假如用的是AT89C51RC+11.0592M的晶振呢?
    答:
    1:原理:仅仅执行一些,没有实质性影响的所谓“无意义指令”,比如做比大小啊,做某个int的自加运算啊之类的
    2:两重for的作用:简单的说,就像高中数学中的“乘法原理”一样,这样可以很轻易的迅速增加上述“无意义指令”的数目
    3:关于取值大小:这个如果是在C下变成,这个值不仅仅与晶振、单片机本身运算速度有关,而且还与C的编译器有关,所以说,这个值虽说是可以精确计算的,但大多数情况下,程序员用的都是“经验值”——当然,如果用汇编编程,情况就不一样了,因为每一条指令所使用的机器周期是一定的,你当然可以根据所有指令使用的总时间,精确的算出具体延时的总时间

    综合你的的问题,我给你一点建议,就是刚学单片机的时候,还是一定要老老实实的从汇编编程学起——这样,在你以后接触到C之后,你才能明白,这中间实际上经历了一个什么样的过程,只有这样你才能真正理解单片机。当然,等最终你完全拿下一种单片机之后,尽量使用C编程,无疑是历史所肯定的。

    7、51单片机,晶振为6M,求一个10ms的延时程序
    答:延时有很多种方法,有一种是让单片机去做无聊的循环,还有一种是用定时器。
    第一种的算法是:
    晶振的周期T1=1/f; 这里f=6MHz 所以T1=1/6 us;(微秒)
    单片机花12个T1去执行一个指令,
    所以一个机器周期等于12个晶振周期,
    T2=12*T1=2us
    10ms=1000 0us
    所以你要得到10ms的延时就要想办法让机器去做5000条“无聊的指令”
    所以
    DEL: MOV R5,#05H
    F1: MOV R6,#05H
    F2: MOV R7,#32H
    F3: DJNZ R7,F3
    DJNZ R6,F2
    DJNZ R5,F1
    RET
    这种方法是用于对时间要求不高的地方,我说的是其思想,程序中可能有错的地方
    用定时器的方法我不太会就不误人了 (补充一下就是这个是用汇编写的,你在主程序中用ACALL DEL调用就延时了。


    8、今天我用单片机做“眨眼的LED”实验时,程序运行,每次只令灯亮或灭都没问题,但是一开延时不能出现期盼的灯亮灯灭的现象,这是怎么回事?
    实验的硬件条件是:STC89C52,编译环境:keil 3。

    下面是我写的程序,请教高手!!!


    #include <reg51.h> // 文件包含处理
    #define uchar unsigned char //宏定义,方便以后程序的书写
    #define uint unsigned int
    sbit P1_0 = P1 ^ 0; //位变量定义
    void Delay(uint t)
    {
    uchar i;
    while(--t)
    {
    for(i = 0; i < 125; i++) //延时1MS,在这里我们用的晶振是是12M,根据机器周期的计算,我们
    {;} //可算得本次循环延时约1MS
    }
    }
    void main(void)
    {
    while(1)
    {
    P1_0 = 0; //点亮LED灯
    Delay(1000); //应单片执行程序的时间很快,所以必须延时,要不看不到实验现象
    P1_0 = 1; //熄灭LED灯
    }

    补充提问:我是让P1.0先低然后延时之后再高,即灯先亮再灭,然后开始循环的

    答:应该这样写
    while(1)
    {
    P1_0 = 0; //点亮LED灯
    Delay(1000); //应单片执行程序的时间很快,所以必须延时,要不看不到实验现象
    P1_0 = 1; //熄灭LED灯
    Delay(1000);
    补充问题回复:问题恰恰就错在这了,循环完一遍之后灯由灭到亮根本没有时间延时,即第一次循环中灯还没来的机灭呢,就进入到第二轮循环中的亮了,所以原因就在这,这错误太低级了,以后引以为鉴吧

    9、单片机延时函数的问题
    void delay(uchar i)
    {
    uchar j;
    while(i--)
    {
    for(j=125;j>0;j--)
    ;
    }
    }
    这个函数中的i,j的大小有**吗?

    答:这个函数中j的大小和你定义的数据类型有关,因为你定义的为无符号字符型,为单字节数据,所以最大为255。.
    如果你需要增大,可以改变j的数据类型定义,如unsigned int (2字节)可以到65535;无符号长整形unsigned long(4字节) 可以到4294967295。 而上面所所256是-1,而你定义的是无符号字符型。

    10、请教一个AVR单片机延时的问题
    外部晶振用的是8MHz,延时1微秒的程序如下:
    void delay_us(unsigned int delay_counter)//延时1us
    {
    do
    {
    delay_counter--;
    }
    while(delay_counter>1);
    }
    请问,为什么能延时1微秒啊?

    答:8MHZ表示单片机的运行周期为1/8us,也就是0.125us执行一步
    你使用的是软件延时
    那么包括程序的提取,执行等都要花费时间
    比如,你提取这个函数可能花去一步,那现在就使用了0.125us啦
    接着你执行这个函数,在单片机内部,运算是通过寄存器的移来移去实现的
    这都需要时间,可能你看到的就一句counter--这个指令,可能会花费好几个时钟周期来实现
    举个例子:
    c=a+b,只有一句,但实际上花费的时间并不短
    mov a,#data1;//数据data1放入a寄存器
    mov b,#data2;//数据data2放入b寄存器
    add a,b;//寄存器a的值与b相加,结果放入a
    mov c,a;//将a的值放入c
    这样才是单片机内部真正执行的指令,这需要花费至少4个时钟周期,而不是1个
    至于晶体管级的我就不解释了,你得好好学习汇编才能理解单片机的运作。

    至于这个函数为什么能延时1ms,这个是靠经验来判断的,最直接的方法就是用示波器看,以上均为推论。



    11、PIC单片机的延时问题 晶振4Mhz:
    void delay()
    {
    unsigned int d=1000;
    while(--d){;}
    }
    此函数在4M晶体下产生10003us的延时,也就是10MS。
    问题:我刚算了一下他应该执行了999条指令,1条单周期的指令也才1US,那就是999us,为什么会有10ms的延时?
    1:for(x=100;--x;){;} : 2: for(x=0;x<100;x++){;} 2句话相同
    第一句:X的值范围是不是 1~99?为什么?
    第二句:X的范围是不是0~99?为什么?这么算的。我知道符号在前在后的区别。2句话应该是不一样的才对啊!
    答:
    问题1:“我刚算了一下他应该执行了999条指令”因为你算错了。延时时间是由产生的汇编代码所决定的,C语言语句只是个假象,千万不要以为C语言一行就是一条指令!此处由于涉及到双字节减法,因此会有额外的判断,编译结果每次循环耗费几十个周期毫不奇怪。

    问题2:前一句x从100开始递减,递减至1时退出循环。后一句x从0开始递增,递增到100时退出循环。所谓“2句话”相同仅仅是指这两个循环体的循环次数相同。实际上两个循环的执行过程是完全不同的,所消耗时间也有可能不同。

    12、stc单片机的延时问题 ,STC10F08XE单片机,晶振22.1184M
    void delay(unsigned long uldata)
    {
    unsigned int j = 0;
    unsigned int g = 0;
    for (j=0;j<5;j++)
    {
    for (g=0;g<uldata;g++)
    {
    _nop_();
    _nop_();
    _nop_();
    }
    }
    }
    当uldata=1时延时多少秒?
    请给出具体算法…………
    答:用keil转换成汇编语句,然后对照指令表计算就行了

    13、我想用单片机连接不断地向电脑发数,如下:
    while (1)
    {
    send_char('9');
    delay(n);
    }
    如每发送一个数,应延时多少微妙好呢?即一般最短能延时多少微米呢?如延时太长的话,那发送很多数据不就用很长时间吗?

    答:不做太多的串口处理分析,只顺着你的问题和你的方法说说:
    先考虑下串口的速率 假设9600,那么发送一个字符要多久?
    (9600bit/S) / 10bit(一个字符1+8+1) = 960字符/秒 约 1ms/byte
    也就是说你如果在1ms内发送超过一个字符就没意义了,硬件速度达不到。
    while(1)
    {
    send_char('9');
    delay(n);
    }
    这个循环是执行周期也就十几微秒+delay()的延迟,所以任何小于1040微秒的延迟对串口硬件来说没意义,上一个还没处理完,下一个就来了根本执行不了嘛。
    如果你send_char()里面有while(!TI);TI = 0;这样的语句或有串口中断TI的处理的话,那么实际上你的delay()已经在发送函数里了,while(!TI);这部就是延迟等待吗?那根本不需要主函数去延迟了,直接发就行了。

    14、一个单片机延时子程序的问题,在延时子程序那里,一直搞不明白,给r7和r6赋予0,然后下面的djnz r7,delayloop不就一直循环了,那还怎么接下去的程序?

    org 0000h
    ljmp start
    org 0030h
    start: mov a,#0feh
    mov r5,#8
    output: mov p1,a
    rl a
    call delay
    djnz r5,output
    ljmp start
    delay: mov r6,#0
    mov r7,#0
    delayloop:djnz r7,delayloop
    djnz r6,delayloop
    ret
    end

    答: 你的延时程序不是因为值为0,而是跳转位置不对,改为如下:
    delay: mov r6,#0
    delayloop:mov r7,#0
    :djnz r7,$
    djnz r6,delayloop
    ret
    R7,R6初值为0,但是当DJNZ执行时,这条指令是先减1再判断,所以0-1=255,判断的话也不为0,仍然循环256次。

    0-1=255的解释:
    0000 0000
    - 0000 0001
    -------------------------
    1111


    15、我想提两个单片机延时与按键的问题
    1:如果一个程序中延时和按键,如果延时子程序比较长(假如2秒),怎样确保按键能够得到及时响应(假如PC正在执行延时子程序,正在这时候有按键输入,不是响应不了)——,,,前提是不能用定时器定时扫描,和中断来做,因为定时器和中断我另有其他用途
    2:单片机没有串口。怎样才能使得他与24C02进行通信(24C02是具有2K内存的EEPROM)
    答:
    首先明确一点你说单片机没有串口,应该是指没有I2C口吧。
    1 在延时程序里面加入按键的检测
    2 用IO口模拟I2C时序读写

    16、51单片机延时小程序,求高手解释什么意思?
    delay200ms:
    mov r2,#82
    l0:mov r1,#116
    l1:mov r0,#9
    djnz r0,$
    djnz r1,l1
    djnz r2,l0
    ret
    答:以下是每条指令的时间,T为一个机器周期
    delay200ms:
    mov r2,#82;1T
    l0:mov r1,#116;1T
    l1:mov r0,#9;1T
    djnz r0,$;2T
    djnz r1,l1;2T
    djnz r2,l0;2T
    ret;2T
    以上共三层循环,忽略部分指令,最简单算法是:
    2*9*116*82=171216
    不忽略指令是:
    1+(1+(1+2*9+2)*116+2)*82+2=200001
    因此延时时间大约为200ms


    17、于51单片机延迟时间的问题
    uchar i;i--;
    uint i;i--;
    这两条语句在12M晶振下运行时间分别是多少??
    答:一个时钟周期,2us,共4us

    18、周期为6MHZ的单片机延时10秒的子程序的怎么编?
    答:/********************************************************************
    * 名称 : Delay()
    * 功能 : 延时,延时时间为 10ms * del。这是通过软件延时,有一定误差。
    * 输入 : del
    * 输出 : 无
    ***********************************************************************/
    void Delay(uint del)
    {
    uint i,j;
    for(i=0; i<del; i++)
    for(j=0; j<1827; j++) //这个是通过软件仿真得出的数
    ;
    }
    这个是晶振为12mhz的单片机延时10ms的程序,你只要在这个基础上减小一倍就行了,当然至于具体值还是要调试下的。


    19、片机的有些程序需要调用延时程序,如何能合理的安排循环次数以及空操作的个数?
    答:用汇编的话就根据你的当前晶振频率去推算你的指令周期,然后结合你需要延迟的时间,编写延迟程序,用C的话还是要看最后生成的汇编码是什么样的了。最简单的方法就是写好程序以后再编译器里软仿真看时间。赞同2| 评论(1)

    20、单片机延时程序问题
    延时程序 void delay(uint dt)
    {
    uchar bt;
    for(;dt;dt--);
    for(bt=0;bt<255;bt++);
    }
    编译时有警告C:\DOCUMENTS AND SETTINGS\ADMINISTRATOR\桌面\字 310 点阵LED显示.C(46): warning C235: parameter 1: different types
    为什么?求大侠指点
    答:某个函数传参类型与声明类型不符。
    另外你这个for(;dt;dt--);没有起到外层循环的作用……


    二、单片机中断问题30例

    1、单片机外中断INT0为下降沿触发,当中断被触发后cpu执行中断程序,若本次中断的程序还未执行完INT0又来了一个相同的下降沿中断信号怎么办?cpu会怎么处理?若是定时器中断呢?串口中断呢?求解释
    答:再来一个INT0信号不会执行。相同的优先级不会打断正在执行的中断。
    一. 如果是高优先级的中断来了,会打断低优先级的正在执行的中断而执行高优先级的中断。
    51单片机的默认(此时的IP寄存器不做设置)中断优先级为:
    外部中断0 > 定时/计数器0 > 外部中断1 > 定时/计数器1 > 串行中断;
    当同时有几种中断到达时,高优先级中断会先得到服务。
    例如:当计数器0中断和外部中断1(优先级 计数器0中断>外部中断1)同时到达时,会进入计时器0的中断服务函数;但是在外部中断1的中断服务函数正在服务的情况下,这时候任何中断都是打断不了它的,包括逻辑优先级比它高的外部中断0计数器0中断。
    51单片机的中断优先级控制寄存器IP可以把默认的中断优先级设置为高或低级,
    例如默认是外部中断0 > 定时/计数器0 > 外部中断1 > 定时/计数器1 > 串行中断;
    现在设为定时1 和串行中断为高优先级 其它为低 ,那么中断0执行时会被定时器1 或串行中断打断,如果设定的两个高优先级定时/计数器1 和串行中断同时响应,会再自然排队,先执行定时1中断再执行串行中断。

    2、单片机中断问题,中断3为什么不执行,整个程序有什么不对的地方呢?
    #include <reg52.h>
    #define uint unsigned int
    #define uchar unsigned char
    sbit p1_0=P1^0;
    sbit p1_1=P1^1;
    sbit p1_2=P1^2;
    sbit p1_3=P1^3;
    sbit p1_4=P1^4;
    sbit p1_5=P1^5;

    uchar PWM_T1 = 0;
    uchar PWM_T2 = 0;
    uint i,m;
    void delay(uint z)
    {
    for(i=z;i>0;i--)
    for(m=0;m<110;m++);
    }
    void PWM_value_left(int pwm_set)
    {
    PWM_T1=pwm_set;
    }
    void PWM_value_right(int pwm_set)
    {
    PWM_T2=pwm_set;
    }
    void main(void)
    {
    bit flag = 1;
    uint n;
    TMOD=0x22;
    TH0=241;
    TH1=241;
    TL0=241;
    TL1=241;
    TR0=1;
    TR1=1;
    ET0=1;
    ET1=1;
    EA=1;
    P1=0xf0;
    delay(20);
    PWM_value_left(7);
    PWM_value_right(10);
    delay(100);
    PWM_value_left(8);
    PWM_value_right(9);
    delay(100);
    PWM_value_left(9);
    PWM_value_right(8);
    delay(100);
    PWM_value_left(10);
    PWM_value_right(7);
    }
    timer0() interrupt 1 using 2
    {
    static uint t ;
    t++;
    if(t==10)
    {
    t=0;
    p1_0=1;
    p1_1=0;
    }
    if(PWM_T1==t)
    P1=P1&0xfc;
    }
    timer1() interrupt 3
    {
    static uint t1 ;
    t1++;
    if(t1==10)
    {
    t1=0;
    p1_2=1;
    p1_3=0;
    }
    if(PWM_T2==t1)
    P1=P1&0xf3;
    }

    答:没有主循环,
    没有等到中断3
    程序运行一次就跑飞了!!!

    void main(void)
    {
    //...你的程序
    //在这里加 死循环,等待中断
    while(1)
    {
    ;
    }
    }
    而且,中断响应函数里必须要清中断标志位(你的没有)!

    3、各位大侠帮我看一下我写的51单片机C程序中断有没有问题,执行中断后不能继续执行主程序,注:P3.2口一直接
    注:P3.2口一直接地,程序如下:
    #include <reg52.h>
    sbit dula=P2^6;
    sbit wela=P2^7;
    sbit d0=P1^0;
    sbit d1=P1^1;
    sbit d2=P1^2;
    sbit d3=P1^3;
    sbit d4=P1^4;
    sbit d5=P1^5;
    sbit d6=P1^6;
    sbit d7=P1^7;
    #define uchar unsigned char
    #define uint unsigned int
    uchar num;
    uchar code table[]={
    0x3f,0x06,0x5b,0x4f,
    0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,
    0x39,0x5e,0x79,0x71};
    void delay(uint z);
    void main()
    {
    EA=1;
    EX0=1;
    IT0=0;
    wela=1;
    P0=0xc0;
    wela=0;
    while(1)
    {

    for(num=0;num<16;num++)
    {
    dula=1;
    P0=table[num];
    dula=0;
    delay(1000);
    }
    }
    }
    void delay(uint z)
    {
    uint a,b;
    for(a=z;a>0;a--)
    for(b=110;b>0;b--);
    }
    void exter0() interrupt 0
    {
    uint c;
    for(c=0;c<25000;c++);
    d0=0;
    for(c=0;c<25000;c++);
    d0=1;
    for(c=0;c<25000;c++);
    d1=0;
    for(c=0;c<25000;c++);
    d1=1;
    for(c=0;c<25000;c++);
    d2=0;
    for(c=0;c<25000;c++);
    d2=1;
    for(c=0;c<25000;c++);
    d3=0;
    for(c=0;c<25000;c++);
    d3=1;
    for(c=0;c<25000;c++);
    d4=0;
    for(c=0;c<25000;c++);
    d4=1;
    for(c=0;c<25000;c++);
    d5=0;
    for(c=0;c<25000;c++);
    d5=1;
    for(c=0;c<25000;c++);
    d6=0;
    for(c=0;c<25000;c++);
    d6=1;
    for(c=0;c<25000;c++);
    d7=0;
    for(c=0;c<25000;c++);
    d7=1;

    }
    答:
    IT0=0;//低电平触发,只要单片机监测到是低电平,就触发中断
    你P3.2一直接地,一直是低电平,那中断就不断的执行,当然回不到主程序中了。
    改成IT0=1;//下降沿触发,单片机监测到高电平到电平跳变,就触发中断
    就算P3.2一直接地,也只触发一次,中断执行完了,就回到主程序中了。

    4、我的单片机这个程序为什么不能完全执行整个程序谁能告诉我!就是没法执行3次亮暗的!
    2010-10-20 21:40 提问者:3865203bin3 | 悬赏分:10
    ORG 0000H
    AG:MOV A,#11111110B
    AG1:RL A
    MOV P0,A
    ACALL DELAY
    DJNZ R0,AG1
    ACALL DELAY
    MOV A,#11111111B
    MOV P1,A
    ACALL DELAY
    MOV P0,#00000000B
    ACALL DELAY
    MOV P0,#11111111B
    ACALL DELAY
    MOV P0,#00000000B
    ACALL DELAY
    MOV P0,#11111111B
    ACALL DELAY
    SJMP AG
    DELAY:MOV R3,#10
    D3:MOV R2,#200
    D1:MOV R1,#250
    D2JNZ R1,D2
    DJNZ R2,D1
    DJNZ R3,D3
    RET
    END

    我是想执行完流水灯亮.就然后执行全亮全暗3次 !可是就是不会跳到全亮全暗3次~~

    答:
    R0没有赋初值!另外建议不要使用前2B个地址,因为51中断矢量就在这个空间里。建议从0030H开始。以下程序在keil4中仿真成功。
    ORG 0000H
    AJMP AG
    ORG 0030H
    AG:MOV A,#11111110B
    MOV R0,#8
    AG1:RL A
    MOV P0,A
    ACALL DELAY
    DJNZ R0,AG1
    ACALL DELAY
    MOV A,#11111111B
    MOV P1,A
    ACALL DELAY
    MOV P0,#00000000B
    ACALL DELAY
    MOV P0,#11111111B
    ACALL DELAY
    MOV P0,#00000000B
    ACALL DELAY
    MOV P0,#11111111B
    ACALL DELAY
    SJMP AG
    DELAY:MOV R3,#10
    D3:MOV R2,#200
    D1:MOV R1,#250
    D2JNZ R1,D2
    DJNZ R2,D1
    DJNZ R3,D3
    RET
    END

    5、STC89C52通过两个外部中断P3.2和P3.3,来控制P1.0和P1.1的数码管亮和灭,一定keil C
    说明:通过外部中断0【P3.2】,P1.0的数码管亮,中断结束后,数码管灭;再由外部中断1【P3.3】,P1.1的数码管亮,次中断结束后,数码管灭;简言之就是一个中断只控制一个数码管,中断之间在功能上没有必然的联系,编程环境keil C51。P1.0和P1.1口上接的都是普通LED小灯,数码管=LED小灯。

    以下是我编的程序,就是一个中断控制一个数码管,但是当有两个中断时,我就抓瞎了
    #include <reg52.h>
    sbit D1=P1^0;
    void main()
    {
    D1=1;
    EA=1;
    EX0=1;
    }
    void exter() interrupt 0
    {
    D1=0;
    }
    求高手帮我改改程序,改成两个中断的那种,功能要求都写在上面了~【希望能有程序注释】3Q,我会去keil里面模拟的~~o()^))o

    答:
    /*模块低电平有效、外部中断0、1为低电平出发*/
    #include "reg52.h"
    void delay( char i)
    {
    unsigned char t;
    while(i--)
    {
    for(t=0;t<108;t++);
    }
    }
    void INT0_ROUTING() interrupt 0//外部中断0子程序
    {
    P0=0xfe;//LED0点亮
    while((P3|0xfb)==0xff);//等待外部中断0口(P3^2松开)
    delay(10);//延时去抖动
    P0=0xff;//LED0熄灭
    }
    void INT0_ROUTING() interrupt 2
    {
    P0=0xfd;//LED1点亮
    while((P3|0xf7)==0xff);//等待外部中断1口(P3^3松开)
    delay(10);//延时去抖动
    P0=0xff;//LED1熄灭
    }

    void main()
    {
    EA=1;//中断总开关
    EX0=1;//外部中断0开
    EX1=1;//外部中断1开
    /*默认低电平触发*/
    while(1);//死循环 防止跑飞
    }


    6、单片机中断问题,下面这段程序不知道为什么只进一次中断,就没有反应了呢?

    #include<reg51.h> // 包含51单片机寄存器定义的头文件
    #define uint unsigned int
    sbit key1=P1^4;
    sbit key2=P1^5;

    void delay1ms(uint i)
    {
    uchar j;
    while(i--)
    {
    for(j=0;j<125;j++) //1ms基准延时程序
    {
    ;
    }
    }
    }
    void init()
    {
    EA=1; //开总中断
    ES=1; //开串口中断
    TMOD= 0x21; //定时器1定时方式2,定时器1工作于8位自动重载模式, 用于产生波特率
    SCON = 0x50; // 设定串行口工作方式1 允许接收
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    TH1= 0xfd; //11.0592M 波特率9600
    TL1= 0xfd;
    PCON =0x00; // 波特率不倍增
    TR1= 1; //启动定时器T1
    TR0=1; //启动定时器T0
    ET0=1; //打开T0中断
    }
    void key()
    {
    if(key2==0)
    P0=0x3f;
    delay1ms(5000);
    P0=0xf3;
    }
    void mainxh()
    {
    while(1)
    {
    key();
    P0=0x32;
    }
    }
    void keybreak()
    {
    P0=0xf1;
    delay1ms(5000);
    P0=0x1f;
    mainxh();
    }
    void main(void)
    {
    init();
    mainxh();
    }
    void Time0(void) interrupt 1
    {
    TH0=(65536-50000)/256; //定时器T0的高8位重新赋初值
    TL0=(65536-50000)%256; //定时器T0的高8位重新赋初值
    if(key1==0)
    keybreak();
    }

    这个程序上电后P0口显示0x32;按下key2显示0x3f;key1用于中断,每20ms检测是否有按下key1键,有的话,P0口显示0xf1。

    答 :
    ORG 0000H AJMP MAIN ORG 0001H LJMP INT_0 ORG 30H MAIN:MOV SP,#8FH MOV P0,#0FFH MOV P3,#0FFH SETB IT0 SETB EA SETB EX0 LJMP START START: MOV A,#10000000B LOOP: MOV P0,A RLC A LCALL DELAY LCALL DELAY LJMP LOOP LJMP START;
    这句是多余的 根本不会执行 INT_0: PUSH ACC ;
    由于p中1断中1A被设为10所以5中7断返回后对A移位没有意义,o A一e直为10 ,并不d是只能中断一1次 .
    还有,不清楚key1是什么中断,貌似是键盘扫描吧,
    while(1)
    {
    key();
    P0=0x32;
    }
    都进入死循环了,所以跳不出来,就一次中断了。

    7、新手学习avr单片机ATmage 128 遇到问题,中断程序被忽略问题,找不到原因。
    avr studio 4 软件仿真时,编译通过了,单在编译信息栏却看到中断程序被忽略。在软件仿真时也发现中断程序没有执行。不知道问题出在哪里,我用的是avr studio 4 ATmage 128 单片机.

    程序如下

    #include <avr/io.h>
    #include <avr/interrupt.h>
    void main() //用的是TC0 溢出中断,来控制八位LED 一秒闪烁
    {
    PORTE = 0xFF; //LED 关 端口高电平位关
    DDRE = 0xFF;
    MCUCR |=(1<<TOIE0); //打开定时器中断使能
    sei(); //开启全局中断
    TIMSK|=(1<<TOIE2); //定时器中断使能
    TCNT0 =155; //定时器赋初值
    TCCR0 |= (1 << CS01); //8分频
    while (1);

    }

    volatile unsigned int j =0;
    #pragma interrupt_handler timer0_ovf_isr:17
    void timer0_ovf_isr(void)
    {
    TCNT0 = 156; //设初值
    j++;
    if(j <= 5000) //中断5000次后 执行LED 电平翻转
    PORTE ^= 0xFF; //LED 电平翻转

    }


    ../lesson2.c:18: warning: ignoring #pragma interrupt_handler timer0_ovf_isr

    上面是写的程序。还有编译信息栏里的话。

    答:
    不是,你那句#pragma interrupt_handler timer0_ovf_isr:17是ICCAVR编译软件中写中断的方式,而看你的头文件#include <avr/io.h>和#include <avr/interrupt.h>应该是用avr studio装GCCavr编译软件的写法,你加上把中断成
    SIGNAL(SIG_OVERFLOW0)
    {
    TCNT0 = 156; //设初值
    j++;
    if(j <= 5000) //中断5000次后 执行LED 电平翻转
    PORTE ^= 0xFF; //LED 电平翻转

    }
    看看,记住,这是GCCAVR 编译软件的写法

    8\新学的C51单片机,编了个电平触发式中断程序,不知道为什么和跳变沿的一样了,诸位帮忙看看.
    #include<reg52.h>
    #define uchar unsigned char
    #define uint unsigned int
    sbit d1=P1^0;
    sbit dula=P2^6;
    sbit wela=P2^7;
    void delay(uint z);
    uchar code table[]={
    0x3f,0x06,0x5b,0x4f,
    0x66,0x6d,0x7d,0x07,
    0x7f,0x6f,0x77,0x7c,
    0x39,0x5e,0x79,0x71};
    void main()
    {
    EA=1;
    EX0=1;
    IT0=0;
    while(1)
    { d1=1;
    dula=1;
    P0=table[1];
    dula=0;
    P0=0xff;
    wela=1;
    P0=0xfe;
    wela=0;
    delay(500);

    dula=1;
    P0=table[2];
    dula=0;
    P0=0xff;
    wela=1;
    P0=0xfd;
    wela=0;
    delay(500);

    dula=1;
    P0=table[3];
    dula=0;
    P0=0xff;
    wela=1;
    P0=0xfb;
    wela=0;
    delay(500);

    dula=1;
    P0=table[4];
    dula=0;
    P0=0xff;
    wela=1;
    P0=0xf7;
    wela=0;
    delay(500);

    dula=1;
    P0=table[5];
    dula=0;
    P0=0xff;
    wela=1;
    P0=0xef;
    wela=0;
    delay(500);

    dula=1;
    P0=table[6];
    dula=0;
    P0=0xff;
    wela=1;
    P0=0xdf;
    wela=0;
    delay(500);


    }
    }
    void delay(uint z)
    {
    uint x,y;
    for(x=100;x>0;x--)
    for(y=z;y>0;y--);
    }
    void enter() interrupt 0
    {
    d1=0;
    }

    答: 你这个程序中设置IT0=0,说明是低电平触发,所以只要P3^2口一直是低电平那么主程序停止,所以发光二极管点亮,如果P3^2口变为高电平,主程序继续,发光二极管熄灭。另一种情况是当IT0=1的时候是负跳变触发,就是当P3^2口检测到一个又高电平到低电平的跳变后,触发中断,在中断函数中点亮灯,立即出中断,执行到d1=1时熄灯。看到的现象就是灯闪一下,直到又检测到一个负跳变,灯又闪一下。两种触发方式的现象是不一样的,如果你硬件没问题的话。你可以把中断函数写成d1=!d1试试。

    9、在C51单片机中,中断服务程序怎么撤销中断引脚上的低电平?
    我用的是,第一个单片机输出低电平到第二个单片机的P3^2,第二个单片机是电平触发方式中断
    低电平触发方式:要求低电平保持到CPU实际响应为止,为了避勉CPU再次响应中断,在中断服务程序中应该撤除中断引脚上的低电平。请问,怎么撤销?在中断服务程序中怎么写? 直接写P3^2=1;行吗?
    答:
    第一个单片机的程序,是谁来编写? 如果也是楼主,那就好办了。
    第二个单片机完成了中断的功能,在退出之前,可以向第一个单片机回送一个脉冲;
    第一个单片机收到这个脉冲,就应该撤消送到第二个单片机的中断申请信号。
    ----
    另外,如果能算出来完成中断的时间,第一个单片机送来的申请信号,就不要超过这个时间,应该及时、自动的撤消申请信号。
    第一个单片机送来的申请信号,也不可过短,应该能让对方检测到。

    10、程序如下,我想要得到的效果是1秒左边的电动机转动,同时黄灯亮,1秒右边转动,蓝灯亮,以此循环下去,但是这个程序用上去后,左边转》右边转》左边转》之后就一直是左边了,不切换了,谁能帮我解决下问题,感激不尽!!
    #include <reg52.h>
    sbit m=P2^0;
    sbit b=P2^6;
    sbit y=P2^7;
    unsigned char count;
    void main()
    {
    TMOD=0x01;
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    TR0=1;
    ET0=1;
    EA=1;
    count=0;
    m=!0;
    b=!1;
    y=!0;
    while(1)
    {
    if(TF0==1)
    {
    count++;
    if(count==20)
    {
    m=0;
    b=1;
    y=0;
    }
    if(count==40)
    {
    m=!0;
    b=!1;
    y=!0;
    }
    TF0=0;
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    }
    }
    }


    答案
    #include <reg52.h>
    sbit m=P2^0;
    sbit b=P2^6;
    sbit y=P2^7;
    unsigned char count;
    void main()
    {
    TMOD=0x01;
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    TR0=1;
    count=0;
    m=!0;
    b=!1;
    y=!0;
    while(1) {
    if(TF0==1) {
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    TF0=0;
    count++;
    if(count==20) {
    m=0; b=1; y=0;
    }
    if(count==40) {
    count=0; //加上这句.
    m=!0; b=!1; y=!0;
    }
    }
    }
    }!
    用T0定时50ms,溢出20次,溢出40次,分别代表了具体的时间。 溢出40次之后,应该从头开始统计溢出次数,所以,此处应该有count=0;。 楼主原来的程序,缺少count=0;,那么它就会继续增加,直到65536,才自动回到0。 这样,时间,就难以控制了。


    11、求助关于51单片机外部中断的问题,小弟最近在学单片机,刚做了一个键盘扫描程序。发现如果外部中断为电平触发,程序能正常运行。但如果改为边沿触发,在将键值送给显示重开中断指令为EX0=1后,中断竟然还会被触发一次,这之后,再按键就不能触发中断了。如果将中断程序中关中断语句去掉,按键能被扫描,但引起中断的次数不好说了。请大侠们看看哪出问题了。谢谢

    uchar keynum,//定义全局变量按键时的键值
    dpnum,//显示值
    time1,//延时计数值
    topen,//延时计数控制
    keyin;//外部中断0向主程序传递有中断标识,有键按下
    keydeal;//按键程序调用标志

    uchar keytable[4][4]={7,8,9,'/',4,5,6,'*',1,2,3,'-','c',0,'=','+'};//按实际键盘编值
    uchar keyboard();//键盘扫描程序,负责键值扫描,判断键释放由主函数完成
    void display(uchar,uchar);// 显示子程序,
    sbit keysign=P3^2;//P3.2为中断0入口,此定义用于程序判断是否真有键按下及键是否释放
    void main()
    {uchar keybiao,keybiao1;//有键按下标志,键放开标志
    IE=0x89;//开总中断,外部中断0,定时器中断1
    IT0=1;//中断触发方式
    PT1=1;//中断优先级
    TMOD=0x90;//定时器1工作方式1
    TH1=(65536-5000)/256;//定时器初值高8位(定时5ms)
    TL1=(65536-5000)%256;
    TR1=1;//开始计时
    P2=0xf0;//给键盘列高电平,行低电平
    keydeal=0x00;//让键处理初值为0,既未处理
    while(1)
    {if(keyin==1) //可能有键按下
    {
    if(time1>=2)//已延时10ms;计数2次,
    {if(keysign==0&&keydeal==0)
    {keynum=keyboard();
    keybiao=1;
    keydeal=1;
    topen=0;//关延时计数
    }//判断是否真有键按下,调用键盘扫描程序
    else if(keybiao==0&&time1>=2&&keybiao1==0)
    {EX0=1;
    keyin=0;
    topen=0;
    }//如果没键按下,重开外部中断0,中断标志清0
    }
    if(keybiao==1&&keysign!=0)
    {keybiao=0;
    time1=0;
    keybiao1=1;//为防止前一次time1的影响而设的标志
    topen=1;
    }

    if(keybiao1==1&&time1>=2)
    {keybiao1=0;
    topen=0;
    EX0=1;
    keyin=0;//重开外部中断0,中断标志清0
    keydeal=0;//重开键未处理,让程序可调用处理程序
    dpnum=keynum;//将键值传给显示
    }
    }
    }
    }
    void display(uchar x,uchar i)//中断控制显示,显示一直持续到下次中断到

    uchar keyboard()
    {uchar con1,con2,i,j;
    con1=P2|0x0f;//只保留P2口高四位,便于switch
    switch(con1)//通过cp可得到列为0的位
    {case 0x7f:j=3;break;//j为列值
    case 0xbf:j=2;break;
    case 0xdf:j=1;break;
    case 0xef:j=0;break;
    }
    for(i=0;i<=3;i++)
    {P2=_crol_(0xfe,i);//依次给行赋0
    con2=P2|0x0f;// 只保留P2口高四位,便于比较
    if(con2!=0xff) break;
    }
    P2=0xf0;//给键盘列高电平,行低电平
    return(keytable[i][j]);

    }

    void T1_time()interrupt 3
    {TH1=(65536-5000)/256;//定时器初值高8位(定时5ms)
    TL1=(65536-5000)%256;
    time1++;
    if(topen!=1) time1=0;//如果延时标志不为1,不开始计时
    display(dpnum,5);
    }
    void int0()interrupt 0
    {EX0=1;
    keyin=1;//向主程序传递键按下
    topen=1;//10ms延时计数开始
    }
    由于字数有限,有部分程序给删了,显示等部分程序应该没问题,我在其它地方能正常运行。

    答:
    不需要每次在进入中断程序后开一次中断;EX0=1可以去掉。
    实际上,外部中断工作在边沿触发方式的时候,第一次电平跳变触发后进入中断程序,然后硬件自动清除IE0中断标志位。但是在执行中断程序的过程中,如果中断引脚再次检测到电平跳变(负到高),那么IE0会被再次置1 。如果在退出中断程序之前没及时清0,那么就会再次引发一次中断。
    而按键的过程,不包括按下和松开时的电平抖动,至少会产生两次电平跳转。
    因此,只需在你中断程序里适当加一点延迟,再将EX=1, 改成IE0=0 。

    12、我用的单片机是8051F的单片机,在程序中我用了两个中断。一个是定时计数器2产生的中断100MS一次的数据采集。另一个是向上位机发送采集来的数据,使用的串口来实现的,用的单片机的UART来实现。也是一个中断。这两个中断在一起工作时需要注意些什么?我的中断程序出了一些问题。
    (就是默认情况下,UART的中断级别更高,但是有的时候UART的中断不能及时响应,这是为甚?)
    答:
    之前和你做的一样就两个中断 UART0加一个定时器 我用的是C8051F040
    你向上位机发送数据使用UART0时 要确认定时器工作完毕
    T2定时中断后 你加一个完成标志如T2FLAG
    if(T2FLAG==1) 将采集的数据放入 UART0的SBUF0 是UART0工作
    你100ms的中断时间 C8051这么快速的单片机怎么都该发送完成了吧。

    13、MSP430单片机中断嵌套,如何跳出中断?
    当进行A中断时,来了一个B中断,我想让B中断程序执行完后不继续
    执行A中断而跳出整个中断,去执行主程序,请问这个怎么设置呢?
    答:
    中断的时候会把SR状态跟中断下来要执行语句的地址放进堆栈中,实现处理完中断以后cpu要执行的语句,注意是地址先进,SR后进,出栈时SR先出,地址后出,当然了在中断里面可以嵌套中断的,对可屏蔽中断来说,主要是CPU响应中断以后,GIE会自动复位,所以不能对可屏蔽中断进行嵌套,如果在中断中要嵌套可屏蔽中断的话可以开GIE,但要注意的是如果此时正在响应的中断标志还是置位的情况下会反复进入此中断,就像死循环一样,这时会引起堆栈的溢出,而在响应可屏蔽中断时,不可屏蔽中断不受此影响,因为他不受GIE的影响,只受自己单独的使能位影响。在堆栈中的操作原理类似。

    14、MSP430单片机有几个需要软件清除的中断标志?如何清除?
    (1)清除各个端口的外中断用:PxIFG,相应的位置0即可;
    (2)清除Timer中断用:TAIFG,TBIFG,相应的位置0即可;
    答:
    MSP430的16个外中断比如软件清除Flag,在进入外中断后,首先要做的就是把相应的PxIFG清0;
    而定时器Timer中断是自动清除Flag;
    还有在中断嵌套的时候会用到,在进入中断后,MCU会自动把全局中断位GIE清零,这样在进入本中断后就不会再相应其他中断,若要进行中断嵌套,必须在进入中断后把GIE再置1.

    15、MCS-51系列单片机的有几个中断源?各中断标志是如何产生的?如何清除各中断标志?
    答:
    标准51有5个中断向量(不算复位),分别是外部中断0,定时器0,外部中断1,定时器1,串行口;总共有6个中断标志,串行口的发送和接受共享一个中断向量。
    各个终端标志产生情况如下:
    外部中断可以设置边沿触发或者电平触发,边沿触发进入中断程序后硬件自动清中断标志,电平触发需要软件清标志位;
    定时器T0,T1计数溢出产生中断,进入中断程序硬件自动清标志位;
    串行口发送完成或者接收到数据就触发中断,由于是两个中断标志共享一个中断向量,所以需要在中断程序里由软件判断是发送中断还是接受中断,并且只能由软件清标志位;

    以上是标准51的中断系统,52由于多了一个T2定时器(T2定时器跟T0,T1功能相差很大,T2要强大很多),因此多了一个中断向量2个中断标志(溢出中断和T2外部中断),T2中断标志必须由软件清除标志位
    中断使能位于IE寄存器
    各中断标志位于相应的模块控制寄存器里面
    模块 位地位 位名称 说明
    T1 TCON.7 TF1 T1溢出标志
    T0 TCON.5 TF0 T0溢出标志
    T2 T2CON.7 TF2 T2溢出中断标志
    T2CON.6 EXF2 T2外部中断标志
    外部中断1 TCON.3 IE1 外部中断1标志
    外部中断0 TCON.1 IE0 外部中断0标志
    串行口 SCON.1 TI 发送中断标志
    SCON.0 RI 接受中断标志

    16、MCS51单片机的汇编语言的中断服务程序最多有几个?
    答:一般而言有5个对:2个外中断 ,2个定时器中断, 1个串口中断。
    但是单片机的中断服务资源是根据硬件的结构设计,会有不同的数量和类型的中断服务,,,因此中断并不是对语言来讲的,而是对于硬件资源来讲的。比如52有6个中断。
    基于语言编译器来讲,我就举例个人感觉最好的开发51大系列的开发环境Keil,其编译器最多支持32个中断服务,,,,因此中断对编译来说,是一个“模拟”的概念。


    17、单片机中断改变频率,为什么几个输出频率无法改变? 程序如下?
    #include<reg51.h>
    #define uchar unsigned char
    #define uint unsigned int
    uchar T,t1;
    unsigned char data table[5] = {486,236,151,111,86} ;
    sbit CLK=P2^3 ;
    sbit EN=P2^0 ;
    void init();
    void main()
    {
    init();
    }
    void init()
    {
    EN=1;
    T=0;
    TMOD=0x01;
    EA=1;
    TR0=1;
    ET0=1;
    t1=table[T];
    TH0=(65536-t1)/256;
    TL0=(65536-t1)%256;
    }
    void timer0() interrupt 1
    {
    TMOD=0x01;
    EA=1;
    TR0=1;
    ET0=1;
    t1=table[T];
    TH0=(65536-t1)/256;
    TL0=(65536-t1)%256;
    CLK=~CLK;
    }
    答:
    T你只付了0值,怎么会变化频率呢?你在主函数里加个T的赋值语句就行了,例如:while(T){T--;delay1s();}

    18、单片机中断程序的书写步骤?
    答:
    标准形式:
    void 函数名(void)interrupt n using m
    {函数体语句}
    n ----中断编号
    m-----要使用工作寄存器组号

    19、我想知道单片机的蜂鸣器音乐程序中断是如何响应的?从main主程序中如何到中断程序?具体步骤是啥?谢谢!
    #include <reg52.h>
    sbit speaker = P1^5;
    unsigned char timer0h, timer0l, time;
    //--------------------------------------
    //单片机晶振采用11.0592MHz
    // 频率-半周期数据表 高八位 本软件共保存了四个八度的28个频率数据
    code unsigned char FREQH[] = {
    0xF2, 0xF3, 0xF5, 0xF5, 0xF6, 0xF7, 0xF8, //低音1234567
    0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC,//1,2,3,4,5,6,7,i
    0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, //高音 234567
    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF}; //超高音 1234567
    // 频率-半周期数据表 低八位
    code unsigned char FREQL[] = {
    0x42, 0xC1, 0x17, 0xB6, 0xD0, 0xD1, 0xB6, //低音1234567
    0x21, 0xE1, 0x8C, 0xD8, 0x68, 0xE9, 0x5B, 0x8F, //1,2,3,4,5,6,7,i
    0xEE, 0x44, 0x6B, 0xB4, 0xF4, 0x2D, //高音 234567
    0x47, 0x77, 0xA2, 0xB6, 0xDA, 0xFA, 0x16}; //超高音 1234567
    //--------------------------------------
    //世上只有妈妈好数据表 要想演奏不同的乐曲, 只需要修改这个数据表
    code unsigned char sszymmh[] = {5,1,1,5,1,1,6,1,2,5,1,2,1,2,2,7,1,4,5,1,1,5,1,1,6,1,2,5,1,2,2,2,2,1,2,4,
    5,1,1,5,1,1,5,2,2,3,2,2,1,2,2,7,1,2
    };
    //--------------------------------------
    void t0int() interrupt 1 //T0中断程序,控制发音的音调
    {
    TR0 = 0; //先关闭T0
    speaker = !speaker; //输出方波, 发音
    TH0 = timer0h; //下次的中断时间, 这个时间, 控制音调高低
    TL0 = timer0l;
    TR0 = 1; //启动T0
    }
    //--------------------------------------
    void delay(unsigned char t) //延时程序,控制发音的时间长度
    {
    unsigned char t1;
    unsigned long t2;
    for(t1 = 0; t1 < t; t1++) //双重循环, 共延时t个半拍
    for(t2 = 0; t2 < 8000; t2++); //延时期间, 可进入T0中断去发音
    TR0 = 0; //关闭T0, 停止发音
    }
    //--------------------------------------
    void song() //演奏一个音符
    {
    TH0 = timer0h; //控制音调
    TL0 = timer0l;
    TR0 = 1; //启动T0, 由T0输出方波去发音
    delay(time); //控制时间长度
    }
    //--------------------------------------
    void main(void)
    {
    unsigned char k, i;
    TMOD = 1; //置T0定时工作方式1
    ET0 = 1; //开T0中断 IE=0x82;
    EA = 1; //开CPU中断
    while(1) {
    i = 0;
    time = 1;
    while(time) {
    k = sszymmh[i] + 7 * sszymmh[i + 1] - 1;
    //第i个是音符, 第i+1个是第几个八度
    timer0h = FREQH[k]; //从数据表中读出频率数值
    timer0l = FREQL[k]; //实际上, 是定时的时间长度
    time = ssz
    ymmh[i + 2]; //读出时间长度数值
    i += 3;
    song(); //发出一个音符
    }
    }
    }
    答:
    你看main()函数就行了,首先进行k、i的定义,然后是定义中断的类型(程序中用的是定时器中断),这个定时器有点特殊,它的作用是定义频率的,频率间隔小则声调高,反之声调低。这个频率就是时间的倒数呗,所以TH的值越大,声调越高;TL的值越小,声调越低。接着往下走,while(1) 就是等待中断的意思,这个程序中的定时器中断没有设置初值,所以中断几乎没有等待,时时触发(要是有等待时间,音乐不就连不上了么)。综上:这个定时器中断完成两个任务:1、使单片机时时触发(等待时间几乎为0);2、控制了音符的演奏频率。
    再往下 while(time) 的循环就是为演奏的音符赋值的操作了。

    20、单片机中断该什么时候进如?
    答:
    中断看是外部中断、定时器还是串行口中断了。
    如果是外部中断,就是p3.2、p3.3检测到这两个口电平变化时(假设这两个口接上按键,那么当按键按下时表明产生中断),然后跳到中断程序执行。
    如果是定时器中断的话,有个中断标志位TFx(x表示0或者1),比如说你设置一个1S的定时器程序,你以50ms为基准,20次产生1s的时间,然后当50ms一过,标志位就产生变化,进入定时器中断程序执行!
    串行口中断也是一样有一个标志位,接受或者发送数据满了以后,标志位就发生变化,然后进入中断执行!


    21、PIC单片机AD中断什么时候开启,对AD中断应该怎样理解。
    答:
    AD模数转换,是把模拟电压数值采样进来,然后转换成数字信号。这一采样和转换是需要时间的。并不是一开AD就能读到数字信号数据。
    一般来说其时间都只有几微秒到几百微秒(根据设置不同而定)。如果单片机没有其他工作的时候,可以用循环等待的方式等AD转换结束(转换结束后DONE位会被置位)。但如果你的单片机还有其他工作,那就没必要在等待它上面花费时间。可以开AD操作后,继续执行其他程序。而转换结束后,AD中断可以暂时断开现有炒作,而把AD数据读进来。这就是AD中断的作用。

    22\51单片机的五个中断分别在什么时候(什么情况)执行里面的程序!
    答:
    外部中断0 :P3.2口有低电平(IT0=0)/ 下降沿(IT0=1)。
    外部中断1 :P3.3口有低电平(IT1=0)/ 下降沿(IT1=1)。
    定时器0中断:当定时器0计数到FFFF溢出时
    定时器1中断:当定时器1计数到FFFF溢出时
    串口中断:串口接收到一帧。或发送完一帧数据都会产生中断。
    你网上找一下TCON和SCON。什么条件让中断标志位的值改变。 那么就会进入中断服务程序去。

    23、51单片机,如果中断函数比较长,执行到一半又触发了这个中断,程序会停止从头执行,还是执行结束后响应中
    答:
    51单片机中,中断分高低两个优先级,高优先级的中断能打断低优先级的中断。
    但同级中断是不能打断同级中断的!无论该中断函数有多长,在执行到一半这个中断又发生了,还是要等到该中断函数执行完毕,并再执行了一条主程序指令后才会再次进入该中断。
    不过,若楼主恰好在这个低优先级中断服务程序中修改了该中断为高优先级,那么如果该中断函数比较长,执行到一半又触发了这个中断,则该中断函数就会被重新从头开始执行(中断嵌套)。这是因为除串口中断以外的其他中断,在 CPU 响应该中断,程序转入该中断函数前就已经将该中断的中断标志清零了。
    另外,51的串口中断比较特别,因为需要软件清除串口中断标志,所以只要在未清串口中断标志前,是不会发生上述这样的中断嵌套的。

    24、求51单片机程序,两个计数器,主要是中断函数的函数名以及初始化设置
    答:
    void into_into() interrupt 1 定时器0中断入口函数
    {
    。。。。中断服务程序。。。。
    TH0=0;//
    TL0=0;// 重新给T0赐值
    }
    void into_into() interrupt 3 定时器1中断入口函数
    {
    。。。。中断服务程序。。。。
    TH1=0;//
    TL1=0;// 重新给T1赐值
    }
    void to_to()
    {
    TMOD=0x11; //顶时器T0和T1工作方式1
    TH0=0;//
    TL0=0;// T0赐初值
    TH1=0;//
    TL1=0// T1赐初值
    TR0=1;// 开始记数
    ET0=1;// 允许T0中断
    TR1=1;// 开始记数
    ET1=1;// 允许T1中断
    EA=1; // 打开总中断
    }
    void main()
    {
    INIT_T0(); //定时器中断初始化
    while(1)
    {
    ...........
    }

    25、请教一个单片机中断的问题:比如来了一个脉冲,开始中断,但中断里的程序执行到一半时,又来了一个脉冲,请问这时中断里的程序是从头开始呢还是继续呢?
    我的意思是程序就一个中断A,来了一个脉冲,A执行,A执行到一半时,又来了一个脉冲,通知A执行。这时A是从头执行还是先不理会呢?
    答:
    需要具体情况具体分析,因为不同的单片机在中断机制上有细微的差别,需要查他的资料。
    一般来说,一个中断源请求中断,对CPU来说,是一次性的做了一个“中断挂号”。假如当时因条件不满足(例如CPU正在“关中断”,即没有打开“中断允许”),而没有响应中断,则挂号信息还在,这样,将来一旦打开了中断允许,仍然会响应,只是晚了一点而已。
    而中断响应以后,必须有办法把这个“中断挂号”消除掉。有的CPU的功能是:只要响应了这个中断,挂号就自动消除了。也有的CPU不能自动清除挂号,必须在中断服务程序中编入“清除中断挂号”的操作,否则,一旦打开了中断允许,它又会重复发生中断。

    现在的大多数单片机里,中断控制器和CPU是在同一个芯片中,它可以做到自动消除中断挂号。而过去许多种CPU,所配用的中断控制器是另外一个芯片,自然就无法自动消除了。

    也有的CPU中有另外一种“不挂号”的中断请求。它必须由外界(发出中断请求的那个设备)来保持一直不停申请,等到响应中断的时候,再设法(例如,在中断服务程序中发出一个输出信号)通知那个设备撤销申请。

    大多数的CPU中,一旦响应中断进入了服务程序,就把“中断允许”关掉了。故此时如果又有下一个中断请求来了,不能立即响应,只能挂一个号,等以后“开中断”时才能再响应。如果程序员希望能够“嵌套中断”(即在一次中断服务程序的执行中途又进入了另一个中断服务程序),就需要在服务程序内编入“开中断”的操作。

    “嵌套中断”原则上允许“自己嵌套自己”,也就是说,一次中断服务程序的执行中途又被打断并进入了和自己一样的中断服务程序,并从头到尾执行一遍,结束后返回到先前打断的那一点,并继续执行后半截服务程序。这种情况会产生什么效果,是需要程序员自己考虑的。

    也有的CPU具有“优先次序”机制,可以在某一级的中断服务程序里禁止优先级不比自己高的其他中断来打断自己。同时,也提供给程序员有“放弃优先权”以及“修改优先级”的灵活性。
    而被优先机制暂时“屏蔽”的那些较低优先级的中断申请,同样挂号仍在,以后高优先级的中断结束以后,还能响应。

    不过需要注意,大多数的CPU中,“中断挂号”是只能挂一个的。也就是说,在前一次的中断申请所挂的号还没有被清除以前,又来了下一个中断申请,那么,第二个挂号是挂不上的。

    不过某些处理器中,中断挂号可能分成几个层次:CPU里面是一层,外围针对各个具体的设备,还有另外一级“预备挂号”,那就比较复杂了。

    另外多说几句:上面已经说,程序员可以自己决定你的中断服务程序允许还是不允许“嵌套”。

    如果不允许,您可以采用关中断的办法,或者利用优先机制,来屏蔽同一中断源的第二个中断请求。
    这样,第二个中断就不会被响应。但它仍可以挂上一个号(只要它发生在上一个中断挂号已经被清除掉以后的时间)。然后,中断服务程序结束时,一般都会开中断并释放优先级屏蔽。然后,第二个中断请求就会被响应,于是再一次执行中断服务程序。

    如果允许“嵌套”,那就会如我上面所说:
    一次中断服务程序的执行中途又被打断并进入了和自己一样的中断服务程序,并从头到尾执行一遍,结束后返回到先前打断的那一点,并继续执行后半截服务程序。


    26、我用51单片机定时/计数器1计数为什么不计数?想让它记数产生中断让蜂鸣器响。
    sbit fengming=P1^6;
    void main()
    {
    TMOD=0x50;
    EA=1;
    ET1=1;
    TH1=0xff;//来一次中断记一次数
    TL1=0xff;
    TR1=1;
    }
    void time1(void) interrupt 3
    {
    fengming=0;
    }

    答:
    不知道是你在网页上打错了,还是怎么回事。
    void time1(void) interrupt 3-------》void timer1(void) interrupt 3

    主程序最后,要加个死循环:while(1){};

    还有,你在这用了方式1,这个方式在你进中断后,TH1和TL1会变成0000H。你不对他重新赋值,你要等FFFFH次计数,才会进中断。


    27\MCS-51 单片机定时器/计数器1的中断入口地址是: 一共有四个A. 0003H B. 000BH C. 0013H D. 001BH,到底是是哪一个?
    \答:答案是D.1BH
    因为:
    外中断0——03h
    定时器0——0bh
    外中断1——13h
    定时器1——1bh
    串口———23h
    请背熟

    28、我看很多程序都是主程序进入while(1),就死在while(1)里了,然后等待外中断。那么现在的问题是我想让它进入外中断完事后,跳过while(1),执行下边的程序,该怎么办?
    while里边用break吗?不知道好使不好使,还有标志位我看是硬件自动清零,查询标志应该不能用吧,那该怎么办呢?
    答:
    结束while(1)语句最好的方法就是使用break来跳出死循环,关键就是选择合适的flag(标志位),如果说中断标志位是硬件自动清零的话,那么楼主不妨在中断服务子程序中自己加入一个标志位:如果用汇编语言的话,PSW中的F0位就可以很好的使用;如果用C的话,就可以随便定义一个位变量,如bit a=0;。也就是说,楼主需要在程序中定义一个位变量a,在中断服务子程序中将a置1,退出中断后查询a是否为1,例如:if(a) {a=0;break;}这样就跳出了while语句了。
    比方说,如果楼主想写一个等待按键按下中断的程序,就可以用while(!a);而不用while(1)语句了。

    29、我用外部中断1,中断一次显示下一个数,数码管显示没问题。但是我用P3-3口用导线连接,接触一次地线,松开一次,这时候数码管显示会乱跳,有时候加两次数,有时候加好多次数,反正就是不稳定。假如p3-3口通过按键接地的话,按一次按键一般情况会加一次数,但有时候也是不稳定,可能中断好几次。
    程序如下:
    #include<reg52.h>
    #define uint unsigned int
    #define uchar unsigned char
    uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
    uchar times;
    uchar i=0;
    void delay(uint z)
    {
    uint x,y;
    for(x=z;x>0;x--)
    for(y=112;y>0;y--);
    }

    void main()
    {

    EA=1;
    EX1=1;
    IT1=1;
    while(1)
    {
    P1=table[i];
    P2=0x00;
    }
    }


    void into() interrupt 2
    { delay(1000);
    i++;
    if(i==10) i=1;

    }

    答:
    是抖动的问题。
    应该采取消抖措施,硬件、软件方法皆可。
    ----
    楼主在中断函数中,延时,时间看来很是不短!
    但是延时后,并没有检测按键是否还在按下,这就不能算是软件消抖。

    30、 (1) 为什么单片机有两个外部中断0允许位?有什么作用?
    (2)在51内核单片机中,当允许响应外部中断0的中断请求时,其特殊功能寄存器ie中的位必须为1 es exo ea et0?

    答:
    (1)两个中断是因为一般的单片机有两个中断源,可以实现两级中断嵌套,在实现复杂功能上两级中断嵌套很有用。

    (2)
    EA--总中断允许位,必须为1
    ES--串行中断允许位,不必开,为0
    EX0--外部中断0允许位,应为1
    ET0--定时计数溢出中断允许位,不必开,为0

    展开全文
  • 前言 这篇文章用来记录呼吸灯实验的设计思路并进行经验的归纳总结 源代码 main.h文件 #ifndef __main_h #define __main_h #define P_led1 P2_0 #define P_led2 P2_1 ...#define F_led2...
  • 51单片机开发系列一 51单片机开发环境搭建以及入门汇编代码 象棋小子 1048272975 1. 51单片机概述 51单片机是对所有兼容Intel 8031指令系统的单片机的统称。目前教科书基本都是以早期的MCS-51为原型,讲解微机...
  • 文章目录前言一、加法指令 ADDADD A, XXX二、带进位加法指令 ADDCADDC A, XXX三、带借位减法指令 SUBBSUBB A, XXX四、乘除法指令MUL ABDIV AB五、十进制调整指令DA A六、加一减一指令INC XXXDEC XXX 前言 1.算术...
  • MCS-51是指由美国INTEL公司生产的一系列单片机的总称,这一系列单片MCS-51是指由美国INTEL公司生产的一系列单片机的总称,这一系列单片机包括了好些品种,如8031,8051,8751,8032,8052,8752等,其中8051是最早最...
  • 单片机基础-第一个单片机系统 简单的单片机系统 构成单片机系统——单片机+外围器件 如果把单片机和外围器件组合起来,实现一定的功能,那我们就称单片机和外围器件组成了单片机系统。 如何控制一个发光...
  • 最大能计算7位数*7位数的值,可以计算负数,小数点结果保留有三位,在每次按下计算符号后,接着只能按下数字,再按下符号键无效,也就是每次计算只能按一个计算符号,如输入错误需按N清零键,或者复位单片机。...
  • 1. 51单片机概述51单片机是对所有兼容Intel 8031指令系统的单片机的统称。目前教科书基本都是以早期的MCS-51为原型,讲解微机的原理及其接口技术的。早期的51单片机功能都较弱,需扩展rom,ram等才能组成一个较复杂...
  • 今天一个QQ群里有人扔出一段代码: #include float sum_elem(float a[],unsigned length){ int i; float result = 0; for(i=0;i;i++){ //printf("test\n"); result+=a[i]; } return result;...}
  • 单片机延时问题20问

    2019-03-22 16:19:26
    简介:延时与中断出错,是单片机新手在单片机开发应用过程中,经常会遇到的问题,本文汇总整理了包含了MCS-51系列单片机、MSP430单片机、C51单片机、8051F的单片机、avr单片机、STC89C52、PIC单片机…..在内的各种...
  • 51单片机汇编

    2013-07-18 16:32:29
    一个单片机所需执行指令的集合即为单片机的指令系统。单片机使用的机器语言、汇编语言及高级语言,但不管使用是何种语言,最终还是要“翻译”成为机器码,单片机才能执行之。现在有很多半导体厂商都推出了自己的...
  • 理解单片机系统 一、理解CPU的三种工作模式 从80386开始,CPU有三种工作方式:实模式(real-mode)、保护模式(protected-mode)和虚拟8086模式。只有在刚刚启动的时候是实模式,等到操作系统运行起来以后就切换到...
  • 单片机汇编指令集

    2010-02-23 14:16:00
    一个单片机所需执行指令的集合即为单片机的指令系统。单片机使用的机器语言、汇编语言及高级语言,但不管使用是何种语言,最终还是要“翻译”成为机器码, 单片机才能执行之。现在有很多半导体厂商都推出了自己的...
  • 单片机面试

    2017-06-23 00:57:29
    答:MCS51单片机有5个中断源,2个中断优先级,中断优先级由特殊功能寄存器IP控制,在出现同级中断申请时,CPU按如下顺序响应各个中断源的请求:INT0、T0、INT1、T1、串口,各个中断源的入口地址分别
  • 1:单片机简叙  什么是单片机 一台能够工作的计算机要有这样几个部份构成:CPU(进行运算、控制)、RAM(数据存储)、ROM(程序存储)、输入/输出设备(例如:串行口、并行输出口等)。在个人计算机上这些部份被...
1 2 3 4 5 ... 20
收藏数 469
精华内容 187
关键字:

单片机减法错误