下面是我大一在某某群分享的关于51单片机的内容。

大家晚上好,我分享的内容大体是先介绍中断,各寄存器使用(可能这里有点啰嗦),然后就简单写一下定时器,然后PWM原理,以及它的配置和使用。大概今晚就这样了,如果有什么错的,或有什么疑问,请大家马上提出来,共同进步。

中断:当计算机执行正常程序时,系统中出现某些急需处理的异常情况和特殊请求.

中断的执行:当CPU正在执行某一程序时,若有中断响应,则CPU转而执行中断服务程序,当中断服务程序执行完毕后,CPU自动返回原来的程序继续执行.

中断服务程序的语句写法与函数的写法完全相同,所以,中断服务程序也是函数,只不过在函数头部有不同.

中断函数:

void 函数名()interrupt 中断号 using工作组
{    
   中断服务程序内容
}

一般函数:

返回值类型函数名()
{
    函数执行程序
}

中断服务程序的执行与函数的执行不同:函数的执行在固定位置的,是通过函数的调用来完成的;而中断的执行是不固定位置的,只要有中断响应,在一定条件下都会去响应中断。

52单片机中断是分优先级别的
T2是51特有的,但我不怎么使用。

外部中断(INT0,INT1),定时/记时中断(T0,T1,T2),串口中断(TI/RI)要记一下。

在使用之前,通常要设置中断允许寄存器IE(中断开关)和中断优先寄存器IP(优先级顺序设置),它们都是以0,1高低电平进行控制的。其实在我写的过程中,我基本不会去改变它们优先级,除非是那种要优先级影响到,程序正常运行,或者是造成很大的误差,才会去改变它们优先级顺序;中断允许寄存器IE这个要记一下,就OK了;

EX0(EX1):外部中断允许控制位
EX0=1 外部中断0开关闭合   //开外部0中断
EX0=0 外部中断0开关断开
ET0(ET1):定时中断允许控制位
        ET0=1 定时器中断0开关闭合 //开内部中断0
        ET0=0 定时器中断0开关断开
ES: 串口中断允许控制位     
        ES=1 串口中断开关闭合     //开串口中断
        ES=0 串口中断开关断开
EA:  全局中断总开关(一定要开,赋为1就好的。)

打开了寄存器,下一步是设置工作方式;

定时器/计数器工作方式寄存器TMOD:

TMOD的低半字节(D0,D1,D2,D3)用来控制定时器/计数器0

TMOD的高半字节(D4,D5,D6,D7)用来控制定时器/计数器1

对TMOD中的内容说明:

GATE——门控制。(我现在编写基本将GATE置为0,直接接用TR1和TR0启动定时器T0、T1。)
   GATE=1时,由外部中断引脚INT0、INT1来启动定时器T0、T1。   
      当INT0引脚为高电平时TR0置位,启动定时器T0;   
      当INT1引脚为高电平时TR1置位,启动定时器T1。   
   GATE=0时,仅由TR0,TR1置位分别启动定时器T0、T1
C/T——功能选择位 (我一般用定时功能,如果要计数,用个变量,放在中断里累加)  
       C/T=0时为定时功能
       C/T=1时为计数功能。

M0、M1——方式选择功能 (由于有2位,因此有4种工作方式 )
外部中断:(我没怎么用过)(INT0,INT1)

IE0(IE1):外部中断请求标志位

         (原理)  当INT0(INT1)引脚出现有效的请求信号,此位由单片机自动置1,
          cpu开始响应,处理终端,而当入中断程序后由单片机自动置0.

         //外部中断,即外部中断相应的引脚接入低电平或下降沿信号时,中断开始响应。

IT0(IT1):外部中断触发方式控制位(一般不用)

         IT0(IT1)=1:脉冲触发方式,下降沿有效。

         IT0(IT1)=0:电平触发方式,低电平有效。

内部中断:

    TF0(TF1):内部定时器/计数器溢出中断标志位

             (原理)  当定时器、计数器计数溢出的时候,此位由单片机自动置1,
              cup开始响应,处理中断,而当进入中断程序后由单片机自动置0.

              //内部中断实际上就是利用内部的计数器,只不过提供计数的脉冲来自单片机自身。

内部中断,我经常使用的,将GATE置为0,直接接用TR0和TR1启动定时器T0、T1。

    TRO(TR1):定时器/计数器启动位                    //启动定时器

    TRO(TR1)=1; 启动定时器/计数器0

    TR0(TR1)=0; 关闭定时器/计数器0

其实定时器中断时间是就将一个容器填满的<时间>,因为是16位定时器,TH0表示的是高八位,TL0表示的是低八位,如何算出比较精确的时间,这就不细讲了,

这是52单片机精准延时1ms,最基本的程序,就简写了

【代码实现】

TMOD=0x01;//0000 0001选择16位定时器
TH0=(65535-45872)/256;//高八位重装初值
TL0=(65535-45872)%256;//低八位重装初值
EA=1;//总开关
ET0=1;//开定时器0的中断
TR0=1;//启动定时器0

void T0_time()interrupt 1    //使用T0寄存器 晶振是11.0592MHZ的1ms
{
  TH0=(65535-45872)/256;//重装初值 较精准的1ms的初值
  TL0=(65535-45872)%256;

   自个添加代码片段

}

PWM的基本原理:

  PWM就是脉冲宽度调制,也就是占空比可变的脉冲波形。

占空比:就是输出的PWM中,高电平保持的时间与该PWM的时钟周期的时间之比。

该技术以该结论为理论基础,对半导体开关器件的导通和关断进行控制,使输出端得到一系列幅值相等而宽度不相等的脉冲,用这些脉冲来代替正弦波或其他所需要的波形。按一定的规则对各脉冲的宽度进行调制,既可改变逆变电路输出电压的大小,也可改变输出频率。

我个人对PWM的理解,就是利用用单片机定时器(也可以延时函数进行控制,但是不太精准)控制PWM的高电平的输出时间对时钟周期所占的比值的不同,进而对PWM进行控制。

这是我写的一个PWM,虽然看起来比较繁杂,但所用到的计算公式比较全面,步骤比较清晰。这里我就不展开讲了,计算好多内容的,有兴趣的可以去了解一下。

【代码实现】

void pwm(unsigned intzhankongbi, unsignedintfr)//fr是机器频率,一般是50HZ,zhankongbi是占空比
{
    if (zhankongbi > 100)//这几句是将占空比控制在0-100;
        zhankongbi = 100;

    else if (zhankongbi < 0)
        zhankongbi = 0;

    T0out_h = (65536 - (zhankongbi / 100) * ((11059200 / 12) / fr) + 12) / 256;
    T0out_l = (65536 - (zhankongbi / 100) * ((11059200 / 12) / fr) + 12) % 256;
    T0in_h = (65536 - ((100 - zhankongbi) / 100) * ((11059200 / 12) / fr) + 12) / 256;
    T0in_l = (65536 - ((100 - zhankongbi) / 100) * ((11059200 / 12) / fr) + 12) % 256;//这几句就不展开讲了

    TH0 = T0out_h;//初始化 高八位
    TL0 = T0out_l;//初始化 低八位
    TR0 = 1;//启动T0定时器
    b = 1;//控制开关的变量
}

int main()
{
    TMOD = 0x01;//0000 0001选择16位定时器
    IE = 0X82;//开启IE寄存器中的EA总开关和ET0定时器中断0开关
    TH0 = 0xfe;//高八位装初值 
    TL0 = 0x33;//低八位装初值(初值是经过一系列的计算)
    TR0 = 1;//启动T0定时器
}

void Time_T0()interrupt 1//T0定时器进行一系列高低电平的变换
{
    if (b == 1)
    {
        TH0 = T0in_h;
        TL0 = T0in_l;
        b = 0;
    }
    else
    {
        TH0 = T0out_h;
        TL0 = T0out_l;
        b = 1;
    }
}