zoukankan      html  css  js  c++  java
  • 51单片机产生1Hz-5kHz可调占空比方波

    学校的课程设计,总结一下。

    注意

    1.高低电平的改变不适合在主函数的while循环中,因为要有数码管动态显示的延时和其它逻辑处理,时间太长会不能及时改变高低电平值。

    2.中断的执行时间一定是不能超过定时时间的,不然就会中断没处理完又来了下一个中断,造成频率出错。

    3.假设100us中断一次,中断程序执行时间40us,则当前中断执行完毕距下一个中断到来还有70us,这剩下的时间就执行主函数的while循环了,因此设计中断时要给主函数留时间。

    4.假设原来的延时函数设置延时1ms,而现在延时函数要被100us中断一次,每次中断执行40us,则延时时间变成了 1*(1+40/100)=1.4ms,另外除了延时函数其他语句也会被中断,因此定时时间越短,也就是说中断的越频繁,则越要将原来延时变短,不然会造成数码管闪烁、按键要长按等等。

    一种方法是在中断中轮流将高低电平持续时间的定时值赋给定时器,这种方法在频率高时误差很大,经测试发现是重装计数值使频率不准。

    因此后来采用固定定时为50us的定时器方式2(自动重装方式),每进中断将计数值加一,然后和设定的值比较来输出高低电平,这种方式的5k频率很准,只要保证中断程序执行时间不要超过50us即可。

    对于11.0592M晶振,中断程序中C语言写上不到10行就超过20us了,所以我设置为50us定时中断,如这样设置的话再另每次中断中将引脚状态取反,可以得到最高10k的方波。而如果是产生5k的方波,则可以设置25、50、75的占空比。如25%占空比,就是50us高电平,150us低电平。

    如果定时时间设置的更小,而中断程序里只有一句将引脚取反的命令,50k的方波就是极限了。

      1 #include <reg52.h>
      2 
      3 typedef unsigned char uint8;
      4 
      5 sbit wave=P1^2;    //波形输出
      6 sbit du=P1^0;    //段选锁存器
      7 sbit we=P1^1;    //位选锁存器
      8 
      9 #define FNUM 5    //频率数目
     10 #define DNUM 3    //占空比数目
     11 
     12 //共阴段码表
     13 uint8 code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
     14 
     15 unsigned dnum,fnum;
     16 unsigned count;
     17 
     18 uint8 key_scan(void);
     19 void display(uint8 num[]);
     20 void delayms(unsigned ms);
     21 
     22 void main(void)
     23 {
     24     uint8 fsel=4,dsel=2;    //默认选择
     25     unsigned long freq[FNUM]={1,10,100,1000,5000};    //频率
     26     uint8 duty[DNUM]={25,50,75};    //占空比
     27     uint8 num[4]={0};
     28 
     29 
     30     TMOD=0x02;    //方式2
     31     TH0=TL0=256-46;    //50us    
     32     count=0;
     33     fnum=1000000/50/freq[fsel-1];
     34     dnum=1000000/50/freq[fsel-1]*duty[dsel-1]/100;
     35 
     36     EA=1;
     37     ET0=1;
     38     TR0=1;
     39 
     40     while(1)
     41     {
     42         switch(key_scan())
     43         {    //分别是频率减、加,占空比减、加,确定键
     44             case 0:
     45                 if(fsel--==1)
     46                     fsel=FNUM;
     47             break;
     48             case 1:
     49                 if(fsel++==FNUM)
     50                     fsel=1;                
     51             break;
     52             case 2:
     53                 if(dsel--==1)
     54                     dsel=DNUM;        
     55             break;
     56             case 3:
     57                 if(dsel++==DNUM)
     58                     dsel=1;
     59             break;
     60             case 7:
     61             TR0=0;
     62             count=0;
     63             fnum=1000000/50/freq[fsel-1];
     64             dnum=1000000/50/freq[fsel-1]*duty[dsel-1]/100;
     65             TR0=1;
     66             
     67             break;
     68             default:    //无键按下
     69             break;
     70         }
     71         
     72         //数码管显示选择的频率、占空比
     73         num[1]=fsel;    
     74         num[0]=dsel;
     75         display(num);
     76     }
     77 }
     78 
     79 
     80 //翻转法扫描矩阵键盘,返回按键值
     81 uint8 key_scan(void)
     82 {
     83     uint8 key,i,ret=0xff;    //无键按下返回0xff
     84     P2=0xf0;
     85     
     86     if(P2!=0xf0)
     87     {
     88         delayms(10);
     89         if(P2!=0xf0)
     90         {
     91             key=P2;
     92             P2=0x0f;
     93             key|=P2;
     94             while(P2!=0x0f)
     95                 ;
     96             for(i=0;(key>>i)&0x01;i++)
     97                 ;
     98             ret=3-i;
     99             for(i=4;(key>>i)&0x01;i++)
    100                 ;
    101             ret+=(7-i)*4;
    102         }
    103     }
    104     return ret;
    105 }
    106 
    107 //数码管动态显示
    108 void display(uint8 num[])
    109 {
    110     uint8 i;
    111     for(i=0;i<4;i++)
    112     {
    113         P0=0xff;    //消影
    114         we=1;
    115         we=0;
    116     
    117         P0=table[num[i]];
    118         du=1;
    119         du=0;
    120         P0=~(1<<i);
    121         we=1;
    122         we=0;
    123         delayms(1);        
    124     }
    125 }
    126 
    127 void timer0(void) interrupt 1
    128 {
    129     count++;
    130 
    131     if(count==fnum)//频率计数值
    132     {
    133         count=0;
    134         wave=1;
    135     }
    136     else if(count==dnum)//占空比计数值
    137         wave=0;
    138 
    139 }
    140 
    141 void delayms(unsigned ms)
    142 {
    143     uint8 i=11;    //将延时调小
    144     while(ms--)
    145         while(i--)
    146         ;
    147 }
    pwm

    参考

    http://bbs.21ic.com/forum.php?mod=redirect&goto=findpost&ptid=393340&pid=2552279&fromuid=1189318

  • 相关阅读:
    【年度回顾】2020,云开发的20个重大更新
    SQL 排序检索数据
    【JVM进阶之路】三:探究虚拟机对象
    【JVM进阶之路】二:Java内存区域
    【JVM进阶之路】一:Java虚拟机概览
    这些不可不知的JVM知识,我都用思维导图整理好了
    计算机网络的七层结构、五层结构和四层结构
    synchronized详解
    Linux内核中I2C总线及设备长啥样?
    C语言中这些预定义宏的不可不会
  • 原文地址:https://www.cnblogs.com/zackcoder/p/3838477.html
Copyright © 2011-2022 走看看