找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 27709|回復(fù): 14
打印 上一主題 下一主題
收起左側(cè)

基于51單片機(jī)產(chǎn)生占空比和頻率可調(diào)的方波信號(hào)發(fā)生器(附全部代碼)

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
       前段時(shí)間開始接觸到單片機(jī),以為單片機(jī)會(huì)很簡(jiǎn)單,但比我預(yù)想的要復(fù)雜一些,特別是剛開始接觸的時(shí)候,需要下載各種軟件,然后自己慢慢地去熟悉這些軟件的操作。我是從51單片機(jī)開始入手,畢竟51單片機(jī)是最基本的了。正好這學(xué)期學(xué)習(xí)了波形的產(chǎn)生,就做一個(gè)基本的函數(shù)信號(hào)發(fā)生器吧。
       這次實(shí)現(xiàn)的函數(shù)發(fā)生器是基于51單片機(jī)的占空比、頻率可調(diào)的方波發(fā)生器,適用于AT89C51/52、STV89C51/52等,現(xiàn)在把具體過程給大家說說。
       第1步:安裝一個(gè)單片機(jī)仿真圖軟件,推薦使用Protues,這是一款專門用來仿真單片機(jī)的,功能十分強(qiáng)大。我用的是Protues8.6,下載安裝步驟大家就自行查詢了,學(xué)習(xí)起來比較簡(jiǎn)單,半小時(shí)就能掌握了。下面是我的仿真圖形。


       第2步:?jiǎn)纹瑱C(jī)仿真圖形界限完成之后,就是寫程序了,程序?qū)懞弥,需要下載Keil軟件將程序轉(zhuǎn)換為單片機(jī)能識(shí)別的機(jī)器語言,即hex文件,程序可以使是c語言,也可以是匯編語言。在Keil上運(yùn)行程序沒有錯(cuò)誤后就會(huì)自動(dòng)生成hex文件,Keil的使用大家自行查詢。下面那個(gè)“單片機(jī)1111.hex”就是我們寫好的程序轉(zhuǎn)換為hex文件了,其他的是附加產(chǎn)物。


      第3步:回到Protues仿真,雙擊單片機(jī),就會(huì)彈出一個(gè)窗口,在Program File欄加入我們剛才產(chǎn)生的hex文件就可以了,然后點(diǎn)擊運(yùn)行就可以運(yùn)行了。很多人仿真的時(shí)候可能沒有示波器窗口,點(diǎn)擊運(yùn)行后,然后點(diǎn)擊上方“調(diào)試”,再點(diǎn)擊彈出窗口的最后一行,示波器窗口就彈出來了,就可以看到單片機(jī)產(chǎn)生的波形了。

下面是仿真波形圖

(兩張圖的頻率不一樣,即頻率可調(diào))


(這兩張圖的占空比不一樣,即占空比可調(diào))

現(xiàn)在說說具體功能,一共有4個(gè)按鍵,初始頻率為500Hz,第1個(gè)按鍵按下后頻率增加500Hz,第2個(gè)按鍵按下后頻率增加100Hz,當(dāng)頻率增加到最大值1MHz后重新定義為500Hz,即頻率500~1MHz可變;初始占空比為50%,第3個(gè)按鍵按下后占空比增加10%,第4個(gè)按鍵按下后占空比增加1%,當(dāng)占空增加到100%后就定義為0%,即占空比0%~100%可調(diào)。大家還可以稍微修改程序,實(shí)現(xiàn)頻率和占空比在不同范圍內(nèi)可調(diào)。
源代碼:
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
float fosc=12000000;
sbit KEY1=P1^0;
sbit KEY2=P1^1;
sbit KEY3=P1^2;
sbit KEY4=P1^3;
sbit OUTPUT=P2^0;
uchar zkb;
uint freq;
uchar TIMER0_L,TIMER0_H,TIMER1_L,TIMER1_H;
void delay(uchar n)
{
uchar i;
while(n--)
{for(i=255;i>0;i--)
{}
}}
void chushihua(void)
{
P1=0x0f;
freq=500;
zkb=50;
TIMER0_L=0xe0;
TIMER0_H=0xb1;
TIMER1_L=0xf0;
TIMER1_H=0xd8;
TL0=0xe0;
TH0=0xb1;
TL1=0xf0;
TH1=0xd8;
TMOD=0x11;
IT0=1;
EX0=1;
ET0=1;
ET1=1;
EA=1;
TR0=1;
TR1=1;
}
void main(void)
{
chushihua();
while(1)
{ }
}
void Timer0_freq() interrupt 1
{
TR1=1;
TL0=TIMER0_L;
TH0=TIMER0_H;
OUTPUT=1;
}
void Timer1_zkb() interrupt 3
{
TR1=0;
TL1=TIMER1_L;
TH1=TIMER1_H;
OUTPUT=0;
}
void keyscan() interrupt 0 using 1
{
float TF0,TZ1;
EX0=0;
delay(10);
if(P1!=0x0f)
{
if(KEY1==0) freq+=500;
if(KEY2==0) freq+=50;
if(freq>10000) freq=500;
if(KEY3==0) zkb+=10;
if(KEY4==0) zkb++;
if(zkb>100) zkb=1;
TF0=(65536-fosc/(12.0*freq));
TZ1=(65536-(fosc*zkb)/(12.0*100*freq));
TIMER0_H=(uint)TF0/256;
TIMER0_L=(uint)TF0%256;
TIMER1_H=(uint)TZ1/256;
TIMER1_L=(uint)TZ1%256;
}
P1=0x0f;
EX0=1;
TR0=1;
TR1=1;
}

評(píng)分

參與人數(shù) 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏25 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:379386 發(fā)表于 2019-11-19 09:15 | 只看該作者
您好,樓主,在您的keyscan()中定義了TF0,這個(gè)是stc的中斷溢出標(biāo)志位,您的程序跑起來沒有問題么?
回復(fù)

使用道具 舉報(bào)

板凳
ID:420256 發(fā)表于 2019-12-20 20:36 | 只看該作者
為什么我的仿真改不了占空比呢
回復(fù)

使用道具 舉報(bào)

地板
ID:671476 發(fā)表于 2020-1-3 11:20 | 只看該作者
請(qǐng)問一般Proutues要從哪里下載呀?
回復(fù)

使用道具 舉報(bào)

5#
ID:308417 發(fā)表于 2020-1-11 11:39 | 只看該作者
誒可以哦,不錯(cuò)哦,真是個(gè)好思路,可以參考參考
回復(fù)

使用道具 舉報(bào)

6#
ID:587438 發(fā)表于 2020-3-13 18:23 | 只看該作者
RV1是什么呀 在Proteus中怎么找呢
回復(fù)

使用道具 舉報(bào)

7#
ID:587438 發(fā)表于 2020-3-13 18:23 | 只看該作者
RV1是什么東西阿 在Proteus中怎么查找呢
回復(fù)

使用道具 舉報(bào)

8#
ID:587438 發(fā)表于 2020-3-13 18:53 | 只看該作者
RV1是什么東西阿
回復(fù)

使用道具 舉報(bào)

9#
ID:718536 發(fā)表于 2020-4-11 21:33 | 只看該作者
丶1u0 發(fā)表于 2020-3-13 18:23
RV1是什么呀 在Proteus中怎么找呢

看圖RV1應(yīng)該似乎可調(diào)電阻。隨便找個(gè)什么高阻值電阻就可以了。反正是測(cè)試波形用的
回復(fù)

使用道具 舉報(bào)

10#
ID:718536 發(fā)表于 2020-4-11 22:17 | 只看該作者
本帖最后由 suqianfu 于 2020-4-11 22:29 編輯

大佬,我添加了一點(diǎn)注釋,不知道理解得對(duì)不對(duì)
#include<reg51.h>                                                 //調(diào)用頭文件
#define uchar unsigned char                                //
#define uint unsigned int
float fosc=12000000;                                        //聲明單片機(jī)運(yùn)行頻率表12Mhz
sbit KEY1=P1^0;                                                        //聲明按鍵1占用腳
sbit KEY2=P1^1;                                                        //聲明按鍵2占用腳
sbit KEY3=P1^2;                                                        //聲明按鍵3占用腳
sbit KEY4=P1^3;                                                        //聲明按鍵4占用腳
sbit OUTPUT=P2^0;                                                //聲明輸出占用腳
uchar zkb;                                                                //聲明占空比變量
uint freq;                                                                //聲明頻率變量
uchar TIMER0_L,TIMER0_H,TIMER1_L,TIMER1_H;//聲明時(shí)間變量
void delay(uchar n)                                                //延時(shí)函數(shù)
{
uchar i;                                                            //局部整型變量
while(n--)                                                            //循環(huán)(執(zhí)行次數(shù))
{for(i=255;i>0;i--)                                                //賦值I為255,I大于0,I--自減1.直至循環(huán)執(zhí)行次數(shù)清零(無中生友系列)
{}
}}
void chushihua(void)                //名為(初始化)之子函數(shù)
{
P1=0x0f;                                //賦值P1口數(shù)據(jù)
freq=500;                                //賦值頻率=500
zkb=50;                                         //賦值占空比為50%
TIMER0_L=0xe0;                         //定時(shí)變量,定時(shí)器0初始時(shí)間高8位賦值,具體定時(shí)時(shí)間自己查資料
TIMER0_H=0xb1;                        //定時(shí)變量,定時(shí)器0初始時(shí)間低8位賦值,具體定時(shí)時(shí)間自己查資料
TIMER1_L=0xf0;                        //定時(shí)變量,定時(shí)器1初始時(shí)間高8位賦值,具體定時(shí)時(shí)間自己查資料
TIMER1_H=0xd8;                        //定時(shí)變量,定時(shí)器1初始時(shí)間低8位賦值,具體定時(shí)時(shí)間自己查資料
TL0=0xe0;                                //定時(shí)器0初始時(shí)間高8位賦值,具體定時(shí)時(shí)間自己查資料
TH0=0xb1;                                //定時(shí)器0初始時(shí)間低8位賦值,具體定時(shí)時(shí)間自己查資料
TL1=0xf0;                                //定時(shí)器0初始時(shí)間高8位賦值,具體定時(shí)時(shí)間自己查資料
TH1=0xd8;                                //定時(shí)器0初始時(shí)間高8位賦值,具體定時(shí)時(shí)間自己查資料
TMOD=0x11;                                //設(shè)定定時(shí)器工作模式
IT0=1;                                        //設(shè)定外部中斷模式
EX0=1;                                        //啟動(dòng)外部中斷
ET0=1;                                        //啟動(dòng)定時(shí)器0中斷
ET1=1;                                        //啟動(dòng)定時(shí)器1中斷
EA=1;                                        //啟動(dòng)全局中斷使能
TR0=1;                                    //啟動(dòng)定時(shí)器0
TR1=1;                                    //啟動(dòng)定時(shí)器1
}
void main(void)                    //主程序
{
chushihua();                        //調(diào)用初始化子程序
while(1)                                //循環(huán)
{ }
}
void Timer0_freq() interrupt 1        //中斷子程序--頻率
{
TR1=1;                                                    //啟動(dòng)定時(shí)器1
TL0=TIMER0_L;                                        //定時(shí)器0高8位重新賦值定時(shí)函數(shù),具體定時(shí)時(shí)間自己查資料
TH0=TIMER0_H;                                        //定時(shí)器0低8位重新賦值定時(shí)函數(shù),具體定時(shí)時(shí)間自己查資料
OUTPUT=1;                                                //輸出高電平
}
void Timer1_zkb() interrupt 3        //中斷子程序--占空比
{
TR1=0;                                                    //關(guān)閉定時(shí)器1
TL1=TIMER1_L;                                    //定時(shí)器1高8位重新賦值定時(shí)函數(shù),具體定時(shí)時(shí)間自己查資料
TH1=TIMER1_H;                                    //定時(shí)器1低8位重新賦值定時(shí)函數(shù),具體定時(shí)時(shí)間自己查資料
OUTPUT=0;                                                //輸出低電平
}
void keyscan() interrupt 0 using 1        //中斷子程序--按鍵檢測(cè)
{
float TF0,TZ1;                                        //聲明浮點(diǎn)變量....這句話不是看得太懂...理解錯(cuò)了勿怪
EX0=0;                                                    //關(guān)閉外部中斷
delay(10);                                                //延時(shí)10
if(P1!=0x0f)                                    //演示后如果檢測(cè)到P1口不等于0X0F這個(gè)值,判斷按鍵按下
{                                                                                                          
if(KEY1==0) freq+=500;                    //如果是按鍵1按下,則頻率變量增加500
if(KEY2==0) freq+=50;                        //如果是按鍵2按下,則頻率變量增加50
if(freq>10000) freq=500;                //如果頻率變量超過10000,則頻率變量重新置為500
if(KEY3==0) zkb+=10;                        //如果是按鍵3按下,則占空比變量增加10
if(KEY4==0) zkb++;                                //如果是按鍵4按下,則占空比變量增加1
if(zkb>100) zkb=1;                                //如果占空比超過100,則占空比變量重新置為1
TF0=(65536-fosc/(12.0*freq));        //定時(shí)器溢出標(biāo)記TF0賦值為65536減去時(shí)鐘頻率12分頻        ??不是太理解
TZ1=(65536-(fosc*zkb)/(12.0*100*freq));        //TZ1這個(gè)啥玩意?跟上一行大概意思吧
TIMER0_H=(uint)TF0/256;
TIMER0_L=(uint)TF0%256;
TIMER1_H=(uint)TZ1/256;
TIMER1_L=(uint)TZ1%256;
}
P1=0x0f;                                                //重新賦值P1口初始化
EX0=1;                                                    //啟動(dòng)外部中斷
TR0=1;                                                        //重新啟動(dòng)定時(shí)器0TR0
TR1=1;                                                    //重新啟動(dòng)定時(shí)器1TR1
}
回復(fù)

使用道具 舉報(bào)

11#
ID:783282 發(fā)表于 2020-7-6 00:27 | 只看該作者
這個(gè)怎么調(diào)占空比
回復(fù)

使用道具 舉報(bào)

12#
ID:792300 發(fā)表于 2021-1-12 22:03 | 只看該作者
丶1u0 發(fā)表于 2020-3-13 18:23
RV1是什么呀 在Proteus中怎么找呢

RU1是滑動(dòng)變阻器。元件名是:POT-HG
回復(fù)

使用道具 舉報(bào)

13#
ID:253767 發(fā)表于 2021-1-13 07:52 | 只看該作者
zkb=50;
回復(fù)

使用道具 舉報(bào)

14#
ID:945571 發(fā)表于 2021-6-27 16:12 | 只看該作者
您好!有匯編語言的嗎
回復(fù)

使用道具 舉報(bào)

15#
ID:1102160 發(fā)表于 2023-12-2 16:39 | 只看該作者
Lily-lemon 發(fā)表于 2020-1-3 11:20
請(qǐng)問一般Proutues要從哪里下載呀?

在嗶哩嗶哩有一堆的安裝資料以及教程,而且是免費(fèi)的,可以去看看
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表