矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 7496|回复: 15

献给初学者<4> 软件延时和软件延时法PWM回扫输出

[复制链接]
     
发表于 2014-6-12 12:00:01 | 显示全部楼层 |阅读模式
初学贴<1>:               http://www.crystalradio.cn/thread-552316-1-1.html
初学贴<2>:               http://www.crystalradio.cn/thread-552827-1-1.html
初学贴<2>续:            http://www.crystalradio.cn/thread-553057-1-1.html
初学贴<3>函数的应用  http://www.crystalradio.cn/thread-553662-1-3.html

献给初学者的,仅作学习之用,写不好的请老鸟指出,但别喷,谢谢


献给初学者<4>    软件延时和软件延时法PWM回扫输出


一.目的:1. 通过传递不同形参值,打到修改延时时间的目的
         验证方法:通过观察LED灯的亮灭交替闪烁的时间来确认;
       2. 引申试验,通过设置传递不同形参值,以及输出高低电平的时间比例,达到输出脉冲的脉宽调节(PWM)的目的.
         验证方法:
            A.感性分析:通过观察LED灯的是否逐渐亮起后逐渐熄灭来确认;
            B.定性分析: 用万用表直接测量输出的I/O 电压变化情况,应该看到逐渐变化的(变化速度与程序设置延时量有关)

二.硬件准备
51内核单片机最小系统(AT89S51/S52,  STC89C51/C52/等等)一个,晶振12MHZ ,   LED一只,5V电源,下载线一根.
初学贴5-368.png

三.编译环境

请网上搜索KEIL软件下载后安装 初学贴5-392.png

二三歩不做细致说明了,切入正题.


1. 通过传递不同形参值,打到修改延时时间的目的
         验证方法:通过观察LED灯的亮灭交替闪烁的时间来确认;


在 初学贴<3>函数的应用http://www.crystalradio.cn/thread-553662-1-3.html  
中,我们知道:对于重复性的操作,我们可以把这部分功能独立成“模块”-------即函数的形式,需要用的时候,写上函数名和形参就可以了,函数把我们传递给它的数值(形参)作为输入变量,经过函数内部处理后,将结果返回(即输出)给调用它的语句.

本例中,为了让LED亮灭亮灭,实际上就是当I/O端口对地电压为高时,LED灭,端口对地电压为低时LED亮。


当LED点亮或者熄灭后,只要我们不作其它操作,机器也不断电,那么I/O的状态是有记忆的,继续保持这个状态不变,过一段时间后,如果我们想让LED状态改变,那么重写操作就可以了,这里“过一段时间后”的一段时间,就是我们要说的延时量.

初学贴5-898.png
由图二可知道,如果我们已经有了一个耗时为“t”延时函数,调用它并传参数为1时,CPU执行这个函数需要“t”时间,对于点亮灯的T0时间,它的时间是比较长的,可能大几倍甚至几百上千倍,我们打比方就说100倍吧,只要我们调用时传形参值为100,那么CPU运行耗时不就需要

100个单位的t时间吗?同理,假设灭灯的T1时间,它的时间是比较长的,可能大几倍甚至几百上千倍,我们打比方就说50倍吧,只要我们调用时传形参值为50,那么CPU运行耗时不就需要50个单位的t时间吗?以此类推.....   在这里,我们只需要调节函数形参值即可,不需要延时函数返回

啥结果,以此定义时返回值用空类型:void  自定义一个名为delpy的延时函数,形参变量为x,取值0-255

/* 延时功能函数--由x决定延时长度 */  
void delpy (unsigned char x)   
    {

    unsigned int i;

     while( --x != 0)

     {
for(i = 0; i < 500; i++);          //t时间单位,修改常量20000位置的值,这个t时间单位的长短就不同了
  }     
    }

在主函数main()里,我们尽管传参数就可以了,分别传100和50,LED所在端口电平置0置1即可。完整程序:
#include <AT89X51.H>
#define   LED_A   P1_1

/* 延时功能函数--由x决定延时长度 */  
void delpy (unsigned char x)   
    {

    unsigned int i;

     while( --x != 0)

     {
for(i = 0; i < 800; i++);           //t时间单位

  }     
    }





void main(void)
{
while(1)
     {
     // pwm_output();
          LED_A=0;
          delpy (100); //调用延时函数,并将100传给形参

          LED_A=1;
          delpy (50);
      }
}
   



2. 引申试验,通过设置传递不同形参值,以及输出高低电平的时间比例,达到输出脉冲的脉宽调节(PWM)的目的.
         验证方法:
            A.感性分析:通过观察LED灯的是否逐渐亮起后逐渐熄灭来确认;
            B.定性分析: 用万用表(最好是指针表)直接测量输出的I/O 电压变化情况,应该看到逐渐变化的(变化速度与程序设置延时量有关)

#include <AT89X51.H>
#define   LED_A   P1_1
#define   LED_B   P1_0


//* 延时功能函数--由d决定延时长度 */  
void delpy (unsigned char x)   
    {

    unsigned int i;

     while( --x != 0)

     {
for(i = 0; i < 2; i++);           //t时间单位

  }     
    }
/*****************************************************************************************
功    能:改变端口脉宽
入口参数:无
返 回 值:无
附     注:
周期255个单位,255级的脉宽调节,         脉宽从1/255递增到255/255, 然后逐渐递减到 1/255
改变端口的电压值,0-5V间变化
**************************************************************************************/
void pwm_output(void)
{unsigned char n,t=0;

         for (n=254; n>0; n--) /*脉宽从1/255递增到254/255*/
         {
         LED_A = 0;
                 LED_B = 0;
         t = ~t;     /* t值取反 决定灯灭时的占空比,取反,相当于255-t */
         delpy (t);           //调用延时函数,并将数值传给形参

          LED_A = 1;
                  LED_B = 1;
         t = ~t;       /* a值取反,还原 */
         t++;/*改变占空比"t/255" */
         delpy (t);      
         }

         LED_A = 0;
                 LED_B = 0;;     /* 灯全亮 使灯达到最亮 */
        t= 0x00;

         for (n=254; n>0; n--)/*脉宽从254/255递减到1/255*/
        {        
          LED_A = 1;
                  LED_B = 1;;
          t = ~t;     
          delpy (t);

          LED_A = 0;
                  LED_B = 0;;
         t = ~t;      
         t++;
         delpy (t);

         }

         

        }



void main(void)
{
while(1)
     {
      pwm_output();        //调用脉宽控制输出函数
      }
}
   





评分

1

查看全部评分

     
 楼主| 发表于 2014-6-13 22:07:15 | 显示全部楼层
本帖最后由 yangcheng84 于 2014-6-13 22:41 编辑
疯糖蔚男的天 发表于 2014-6-13 11:16
这个是程序设定了的固定值
我的意思是通过输入设备输入一个数值  来改变占空比  
我打算用单片机按键盘 ...




这个也不是很难,此处如果特地展开说明就会打散本帖的主旨了。


只要写一个按键检测及处理的函数,将处理结果返回给主函数就可以了.  在主函数里调用它即可.


/************************************************************
函数功能:按键检测及处理
入口参数:
出口参数: 脉宽(机多少个时间单位)

**********************************************************/
//#define  K0   P1_2        定义按键挂在P1.2端口
unsigned char key(void)
{
static  unsigned char  t;
if  (0==K0)              //按键有按下?
   {
     delpy(1000);//软件法延时消抖动
          if  (0==K0)     //按键确实按下了吗?
             {
                 t+=5;  //每次按一下,PWM 值+5,相当于增加5/255
              }

   }


}


完整程序如下:

#include <AT89X51.H>
#define   LED_A   P1_1
#define   LED_B   P1_0
#define  K0   P1_2        定义按键挂在P1.2端口


/******************函数声明*****************************/
void delpy (unsigned int x);
unsigned char key(void);





/************************************************************
函数功能:软件延时
入口参数:
出口参数: 脉宽(机多少个时间单位)

**********************************************************/
/* 延时功能函数--由x决定延时长度 */  
void delpy (unsigned int x)   
    {

    unsigned int i;

     while( --x != 0)

     {
for(i = 0; i <2; i++);           //t时间单位

  }     
    }






/************************************************************
函数功能:按键检测及处理
入口参数:
出口参数: 脉宽(多少个时间单位)

**********************************************************/
//#define  K0   P1_2        定义按键挂在P1.2端口
unsigned char key(void)
{
static  unsigned char  t;
if  (0==K0)              //按键有按下?
   {
     delpy(1000);//软件法延时消抖动,参数值根据实际选择,大了消抖好,但按键有些迟钝;反之,灵敏,但可能出现按了一次PWM加了好多,折衷取值即可
          if  (0==K0)     //按键确实按下了吗?
             {
                 t+=5;  //每次按一下,PWM 值+5,相当于增加5/255
              }

   }

return( t);  //返回处理结果给函数外部
}




void main(void)
{
unsigned char  temp;//临时变量

while(1)
     {
           temp=key();//读按键,获得处理值(脉宽)

          LED_A=1;
          LED_B=1;
          delpy (temp); //temp(返回值)传给形参,产生temp个时间单位的高电平

          LED_A=0;
          LED_B=0;
          delpy (255-temp);                //产生255-temp个时间单位的低电平
      }
}

评分

1

查看全部评分

回复 支持 1 反对 0

使用道具 举报

     
 楼主| 发表于 2014-6-12 19:40:01 | 显示全部楼层
附上工程文件

LED.rar

46.09 KB, 下载次数: 321

回复 支持 反对

使用道具 举报

发表于 2014-6-12 22:01:51 | 显示全部楼层
一个占空比由小到大  再由大到小变化的过程
  之前没有理解到“脉宽”这个词的正确意思,还以为脉宽也分正脉宽和负脉宽  糗大了

整个过程中没有理解到t=~t这句话  请楼主解释一下  谢谢
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2014-6-12 23:04:38 | 显示全部楼层
本帖最后由 yangcheng84 于 2014-6-12 23:41 编辑
疯糖蔚男的天 发表于 2014-6-12 22:01
一个占空比由小到大  再由大到小变化的过程
  之前没有理解到“脉宽”这个词的正确意思,还以为脉宽也分正 ...


是这样的,8位变量中,如果t=~t (t的按位取反),其实等价于t=255-t 的,比如t=0000 0001, 则~t=1111 1110  它们之和刚好是255.

这么写其实只是个习惯而已,也可以直白的写成t=255-t嘛,效果是一样的.


占空比定义是:高电平时间 /1个周期    * 100%,当周期设置为255个单位时,如果高电平时间是t,那么当然低电平时间就是  255-t  了
回复 支持 反对

使用道具 举报

发表于 2014-6-12 23:13:38 | 显示全部楼层
yangcheng84 发表于 2014-6-12 23:04
是这样的,8位变量中,如果t=~t (A的按位取反),其实等价于t=255-t 的,比如t=0000 0001, 则~t=1111 ...

嗯嗯  谢谢解答这么详细  我刚刚没弄懂是因为把1111 1111给算错了……这下明白了 十分感谢!
回复 支持 反对

使用道具 举报

发表于 2014-6-13 08:35:05 | 显示全部楼层
朋友你好  讲到PWM波  你这个是自动加减实现的自动回扫  那如果需要定量的给出我们输入的一个值的PWM波  那又该怎样实现呢?谢谢!
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2014-6-13 10:44:35 | 显示全部楼层
本帖最后由 yangcheng84 于 2014-6-13 10:57 编辑
疯糖蔚男的天 发表于 2014-6-13 08:35
朋友你好  讲到PWM波  你这个是自动加减实现的自动回扫  那如果需要定量的给出我们输入的一个值的PWM波  那 ...


第一:固定住周期T,比如为100或者255个单位等等(例题中形参unsigned char x 取值是0-255之间的整数),我们以周期255单位为例。


第二:确定需要的占空比.  比如我们需要1.25V的电压输出,本例中,因为电源是5V,所以脉冲峰值也是5V,  占空比为  1.25/5= 0.25(倍),因此,脉宽应该是:占空比*周期(T)=  0.25*255

=63.75  ,此处只能取整,四舍五入取64;

第三:
        程序流程:    i/o  口置高,延时64个时间单位-------- i/o  口置0,延时(255-64)个时间单位   ;如此反复循环,那么I/O的空载或者轻载的电压就是1.25V了,例如本例中的P1.0(没挂负载,不受LED影响)

这个电压值万用表可以直接量出来.



#include <AT89X51.H>
#define   LED_A   P1_1
#define   LED_B   P1_0
/* 延时功能函数--由x决定延时长度 */  
void delpy (unsigned char x)   
    {

    unsigned int i;

     while( --x != 0)

     {
for(i = 0; i <2; i++);           //t时间单位

  }     
    }





void main(void)
{
while(1)
     {
   
          LED_A=1;
          LED_B=1;
          delpy (64); //调用延时函数,并将64传给形参,产生64个时间单位的高电平

          LED_A=0;
          LED_B=0;
          delpy (255-64);                //产生255-64个时间单位的低电平
      }
}
回复 支持 反对

使用道具 举报

发表于 2014-6-13 11:16:23 | 显示全部楼层
yangcheng84 发表于 2014-6-13 10:44
第一:固定住周期T,比如为100或者255个单位等等(例题中形参unsigned char x 取值是0-255之间的整数) ...

这个是程序设定了的固定值
我的意思是通过输入设备输入一个数值  来改变占空比  
我打算用单片机按键盘输入值输出一个电压值做参考  怎样让delay中的参数变化呢?
回复 支持 反对

使用道具 举报

     
发表于 2014-6-13 13:06:16 | 显示全部楼层
楼主辛苦!本版跨版区违规给你置高亮,加精, 每个帖子给你加50分鼓励,来南宁我请你吃老友粉  可惜我不懂C语言, 一直用汇编,兄弟能否传帮带一下?
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2014-6-13 21:48:59 | 显示全部楼层
无烟男人 发表于 2014-6-13 13:06
楼主辛苦!本版跨版区违规给你置高亮,加精, 每个帖子给你加50分鼓励,来南宁我请你吃老友粉  可惜我不 ...

哇,版主原来是老乡,幸会幸会.  学习交流交朋友完全没问题,你的老友粉留着,我下次见你时就去吃
回复 支持 反对

使用道具 举报

发表于 2014-6-13 22:52:35 | 显示全部楼层
yangcheng84 发表于 2014-6-13 22:07
这个也不是很难,此处如果特地展开说明就会打散本帖的主旨了。

非常感谢!我再慢慢消化一下  大意了解了  但是自己写不出
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2015-9-7 20:29:52 | 显示全部楼层
疯糖蔚男的天 发表于 2014-6-13 22:52
非常感谢!我再慢慢消化一下  大意了解了  但是自己写不出

朋友,单片机有进展了吗?
回复 支持 反对

使用道具 举报

     
发表于 2019-5-16 09:36:53 | 显示全部楼层
很好的教程,谢谢分享。学习了,
回复 支持 反对

使用道具 举报

     
发表于 2019-5-16 10:02:33 | 显示全部楼层
收藏备用,谢谢分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-9-21 09:05

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表