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

注意

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

pwm

参考

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

51单片机产生1Hz-5kHz可调占空比方波的更多相关文章

  1. 51单片机—使用PWM对直流电机调速

    文章目录 - 什么是PWM - PWM是怎么对直流电机进行调速的 - 通过定时器中断实现PWM调速 - 上代码 - 什么是PWM PWM(脉宽调制),是靠改变脉冲宽度来控制输出电压,通过改变周期来控制 ...

  2. 基于51单片机个LCD1602的万年历程序

    小白 第一次跟新博客 基于51单片机和LCD1602的万年历程序 可实现走时和调时功能 有简单的1602菜单制作 欢迎大家交流 LCD1602和51单片机的连接方法 RS = P3^5; //数据/命 ...

  3. 51单片机通过ESP8266模块与手机进行通讯(单片机)

    相关连接和资料下载: 个人博客 资料下载 Step1:配置ESP8266 通过USB转TTL模块把ESP8266模块和电脑连接起来,如图: 把ESP8266模块的VCC,GND,CH_PD,UTXD, ...

  4. Windows 通用应用尝试开发 “51单片机汇编”总结

    一.前言 终于完成windows通用应用“51单片机汇编”,半年前开始玩WindowsPhone开发的第一个真正意义上的App(还很多缺点=_=).开发从1月中旬考完试到今天,期间实习了半个月,玩了几 ...

  5. 51单片机中断interrupt……using……

    51单片机中断细节的一些问题. interrupt0:外部中断0interrupt1:定时器中断0interrupt2:外部中断interrupt3:定时器中断1interrupt4:串口 using ...

  6. Windows 通用应用尝试开发 “51单片机汇编”第二次更新总结

    一.前言 昨天更新了10天前上架到windows8.1平台和windowsphone平台的通用应用“51单片机汇编”,总要是添加了动态磁贴以及ListView的Groupstyle应用.下面主要主要复 ...

  7. [新概念51单片机C语言教程·郭天祥] 1、 基础知识必备

    目录: 单片机的大致介绍         1-1.通俗定义         1-2.51系列产品         1-3.标号意思         1-4.引脚介绍         1-5.用C语言开 ...

  8. [51单片机] HC-SR04超声波测距仪 基础代码

    >_<:超声波测距仪模块: >_<:51单片机,11.0592MHz晶振,将采集数据发送到串口的基础例子: >_<:代码: /******************* ...

  9. cc2530 timer 3 PWM <可调占空比>

    前提: 开始用的是 cc2530 timer 1来做PWM的,已经可调占空比了,但是由于硬件的改动,需要用timer 3 和 timer 4 代替.由于调试过程中出了些小问题,于是自己把这个贴出来.关 ...

随机推荐

  1. centOS tengine 安装后 不能访问的问题

    1 安装方式跟在ubuntu下 安装一样.因为都是用源码 2  但安装好以后发现,局域网电脑访问不了!.原以为是安装错了.又装了一遍,还是不行,最终是iptables 没开放80端口... http: ...

  2. mini2440移植uboot-2008.10 遇到的问题

    1.mkimage的使用(u-boot-2008.10/tools/mkimage) 首先./mkimage 运行或者 将mkimage 拷贝到 /bin 目录下面 法一: #mkimage -n ' ...

  3. 深入了解float

    1.float的历史   初衷是为了图片的文字环绕,将img设置float 2.破坏性与包裹性  a.父元素没有设置高度,内部元素浮动后,服务元素的高度被破坏了,可以将其父元素设置overflow:h ...

  4. web api 跨域请求,ajax跨域调用webapi

    1.跨域问题仅仅发生在Javascript发起AJAX调用,或者Silverlight发起服务调用时,其根本原因是因为浏览器对于这两种请求,所给予的权限是较低的,通常只允许调用本域中的资源,除非目标服 ...

  5. PHP中的预定义超全局数组

    定义 超全局变量,是在全部作用域中始终可用的内置变量. PHP中的许多预定义变量都是"超全局的",这意味着它们在一个脚本的全部作用域中都可用. 在函数或方法中无需执行 global ...

  6. (转载)将DELPHI数据库连接写进INI配置文件中

    将DELPHI数据库连接写进INI配置文件中 procedure TDM.DataModuleCreate(Sender: TObject); var piececonfg:Tinifile; pat ...

  7. 为什么很多语言选择在JVM上实现

    非常经济地实现跨平台.你的语言编译器后端只需要输出 JVM 字节码就可以.跨平台需要极大的工作量,举个例子,只是独立开发生成本地代码,就需要花费大量精力去针对不同平台和处理器进行优化(比如 Firef ...

  8. 版本控制工具git入门

    版本控制工具的历史 不说了,放张图 两者的区别:集中式需要一个中心服务器放置最新的文件,需要联网操作.分布式可以再不联网的情况下操作,前提要拥有版本库 git安装  略 github注册 略 如何在g ...

  9. Error Code: 1064 – You have an error in your SQL syntax解决几个方法

    本文转自 http://www.anyiwa.com/?p=1066 Error Code: 1064 – You have an error in your SQL syntax解决几个方法 十一月 ...

  10. settimeout vs setinternal

    http://blog.sina.com.cn/s/blog_6b1ab3be0100pzmo.html http://www.360doc.com/content/11/0412/17/100779 ...