完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
前日看到一篇很好的代码。有好代码就要拿出来与坛友分享嘛
![]() 程序可以利用51单片机输出频率和占空比可调的PWM波程序。作者写的很详细,程序写的很漂亮!!!但我还是有地方不明白 ![]() 现在咱们大家来探讨探讨吧!!! 我有三个问题,恳求网友不吝赐教。 1. 频率计算函数,当频率变化,计算出定时器0初值; 2. 脉宽计算函数,脉宽变化时,计算出定时器1初值; 3. 关定时器1,一定要这一步,因为定时器1的定时短于定时器0; //------------------------------------------------------------------------------------ //程序功能简介:本程序产生15HZ~~~50KHZ的方波,并且实现频率和脉宽的独立调制,即可 //在改变频率的同时不改变脉宽,再改变脉宽的同时不改变频率;同时设置 //两个调节步长------在KEY键按下时,粗调,没有按下时,细调; //程序思路: 本程序用到两个定时器------定时器0和定时器1,其中定时器0工作在定时方式下, //决定方波的频率;定时器1,同样工作在定时方式下,用于设定脉宽; //------------------------------------------------------------------------------------ #include #include #define uchar unsigned char #define uint unsigned int #define ALL 65536 //定时器工作方式1时,最大基数长度 65536; #define F_osc 12000000 //晶振频率12M; ***it KEY_F_UP=P0^2; //频率上调按钮; ***it KEY_F_DOWN=P0^3; //频率下调按钮; ***it KEY_W_UP=P0^4; //脉宽上调按钮; ***it KEY_W_DOWN=P0^5; //脉宽下调按钮; ***it KEY=P0^6; //粗细调节按钮-----按下为粗调,否则为细调; ***it OUTPUT=P1^0; //波形输出; uchar tiMER0_H,TIMER0_L,TIMER1_H,TIMER1_L; //定时器0和定时器1的初值设置; uchar PERCENT=50; //初始占空比; uchar FLAG_F=0,FLAG_W=0; //频率调节标志和脉宽调制标志; uint FREQ=50000; //初始频率; float temp; //临时全局变量,用于数据传递; void delay(uchar t); //延时函数,用于按键去抖; void init(); //初始化函数,用于定时器的初始化; void calculate_F(); //频率计算函数,当频率变化,计算出定时器0初值; void calculate_W(); //脉宽计算函数,脉宽变化时,计算出定时器1初值; void key_scan(); //按键扫描函数; void timer0(); //定时器0中断函数; void timer1(); //定时器1中断函数; void delay(uchar t) { uchar i,j; while(t--) //每个脉冲为1us { for(i=0;i<100;i++) for(j=0;j<100;j++); } } void calculate_F() { temp = ALL - F_osc/12.0/FREQ; TIMER0_H = (uint)temp/256; TIMER0_L = (uint)temp%256; } void calculate_W() { float TEMP; TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0; TIMER1_H = (uint)TEMP/256; TIMER1_L = (uint)TEMP%256; } void key_scan() { delay(4); if(!KEY_F_UP) //频率上调键按下; { FLAG_F=1; //置标志位; if(!KEY) FREQ+=10; else FREQ++; if(FREQ>50000) FREQ=1; } else if(!KEY_F_DOWN) //频率下调键按下; { FLAG_F=1; //置标志位; if(!KEY) FREQ-=10; else FREQ--; if(FREQ<1) FREQ=50000; } else if(!KEY_W_UP) //脉宽上调键按下; { FLAG_W=1; //置标志位; if(!KEY) PERCENT+=5; else PERCENT++; if(PERCENT>49) PERCENT=1; } else if(!KEY_W_DOWN) //脉宽下调键按下; { FLAG_W=1; //置标志位; if(!KEY) PERCENT-=5; else PERCENT--; if(PERCENT<1) PERCENT=49; } else ; } void timer0() interrupt 1 //决定频率 { TH0=TIMER0_H; TL0=TIMER0_L; TR1=1; //开定时器1; OUTPUT=1; } void timer1() interrupt 3 //决定脉宽 { TH1=TIMER1_H; TL1=TIMER1_L; TR1=0; //关定时器1,一定要这一步,因为定时器1的定时短于定时器0; OUTPUT=0; } void init() { TMOD=0x11; //定时器0和定时器1都工作在方式1,16位计数器; calculate_F(); //初始为1KHZ,占空比为50%; calculate_W(); TH0=TIMER0_H; TL0=TIMER0_L; TH1=TIMER1_H; TL1=TIMER1_L; ET0=1; ET1=1; EA=1; TR0=1; TR1=1; } main() { init(); while(1) { key_scan(); if(FLAG_F) //改变频率时要注意要进行脉宽的重新设置; { calculate_F(); calculate_W(); FLAG_F=0; } if(FLAG_W) // 脉宽改变,频率不改变; { calculate_W(); FLAG_W=0; } } } |
|
相关推荐
13个回答
|
|
|
本帖最后由 傻大个牌纯碱 于 2016-11-2 22:23 编辑
偶然间看到这段代码,我解释下面这段代码:======================================================== void calculate_F() { temp = ALL - F_osc/12.0/FREQ; // 理解这段程序的关键点,在于理解时钟周期和机器周期; // 从程序上看,这个单片机的时钟周期(即外部晶振周期)是1/(12 MHz)=1/F_osc ,而机器周期是12个时钟周期,即12/F_osc。 // 所以,如果要得到频率=FREQ的方波,必须赋予计数器一个初始值temp,然后计数器进行自加(ALL-temp)次,就有如下等式: // (ALL-temp)*(12/F_osc)=1/FREQ,做等式变换,把temp做变量就可以得到: // temp = ALL - F_osc/12.0/FREQ TIMER0_H = (uint)temp/256; TIMER0_L = (uint)temp%256; } void calculate_W() { float TEMP; TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0; // 如果你理解了上面那段,这段我相信你也理解了; TIMER1_H = (uint)TEMP/256; TIMER1_L = (uint)TEMP%256; } ===================================================================== 不谢!
最佳答案
评分 |
|
|
|
|
|
有具体的资料和线路吗 求分享一下
|
|
|
|
|
|
这就是存粹的用51单片机产生PWM波代码,我觉得代码很经典,就分享出来与大家一起讨论了。 朋友我遇到了一些问题,请您赐教
|
|
|
|
|
|
我对单片不了解 这个正好我最近要用到 希望楼主能够将全套资料分享一下 谢谢 |
|
|
|
|
|
有什么问题啊?你理解的已经很清楚了啊
|
|
|
|
|
|
这条代码(红字)不太明白,请您赐教! //关定时器1,一定要这一步,因为定时器1的定时短于定时器0; |
|
|
|
|
傻大个牌纯碱 发表于 2016-11-2 22:21 上面的推导看懂了,下面的推导还真没想明白,是利用占空比的定义进行推导的吗?指示指示,学习一下,谢谢 TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0; |
|
|
|
|
|
使用stm32系列的单片机做起来就简单多了
|
|
|
|
|
傻大个牌纯碱 发表于 2016-11-2 22:21 不明白这条代码意思,请您赐教! //关定时器1,一定要这一步,因为定时器1的定时短于定时器0; |
|
|
|
|
张全武5 发表于 2016-11-3 18:04 //不明白有两个原因 1. 没理解晶振频率与机器周期的关系 2. 没理解占空比(高电平占整个周期的时间)计算方法 void calculate_F() { temp = ALL - F_osc/12.0/FREQ; // 理解这段程序的关键点,在于理解时钟周期和机器周期; // 从程序上看,这个单片机的时钟周期(即外部晶振周期)是1/(12 MHz)=1/F_osc ,而机器周期是12个时钟周期,即12/F_osc。 // 所以,如果要得到频率=FREQ的方波,必须赋予计数器一个初始值temp,然后计数器进行自加(ALL-temp)次,就有如下等式: // (ALL-temp)*(12/F_osc)=1/FREQ,做等式变换,把temp做变量就可以得到: // temp = ALL - F_osc/12.0/FREQ TIMER0_H = (uint)temp/256; TIMER0_L = (uint)temp%256; } void calculate_W() { float TEMP; TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0; //计算占空比就是计算一个周期中的高电平时间(占空比*周期)(PERCENT/100)1/FREQ // 这个单片机的时钟周期(即外部晶振周期)是1/(12 MHz)=1/F_osc ,而机器周期是12个时钟 周期,即12/F_osc。 // 所以,如果要得到频率=FREQ,占空比为PERCENT/100方波,必须赋予计数器一个初始值TEMP,然后计数器进行自加(ALL-TEMP)次,就有如下等式: // (ALL-TEMP)*(12/F_osc)=(PERCENT/100)1/FREQ,做等式变换(把temp带入替换)可得 //TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0;(完全可以不用temp替换,以上等式即可) TIMER1_H = (uint)TEMP/256; TIMER1_L = (uint)TEMP%256; } |
|
|
|
|
|
clever Boy or Girl!
|
|
|
|
|
|
在这借鉴 一些经验
|
|
|
|
|
|
硬件开销有点大,不过单个定时器做的话做很难做到50k
|
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
265 浏览 0 评论
【原创】【RA4M2-SENSOR开发板评测】低功耗+USB综合测试
789 浏览 0 评论
1306 浏览 2 评论
787 浏览 0 评论
【RA4M2-SENSOR开发板评测】Analogue+Timers综合测试
1587 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
16900 浏览 31 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-2 01:12 , Processed in 1.007902 second(s), Total 103, Slave 81 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
3521