欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

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

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 4115|回復(fù): 7
收起左側(cè)

51單片機(jī)PWM輸出,定時(shí)器定時(shí)不準(zhǔn)問(wèn)題?

[復(fù)制鏈接]
ID:694871 發(fā)表于 2020-5-17 08:01 | 顯示全部樓層 |閱讀模式
3黑幣
  我編寫(xiě)了一個(gè)PWM輸出的函數(shù),根據(jù)傳進(jìn)來(lái)的參數(shù)不同來(lái)選擇使用定時(shí)器0或者定時(shí)器1,對(duì)P1口的某一個(gè)引腳輸出PWM。并且可以根據(jù)入口參數(shù)實(shí)現(xiàn)不同的占空比。設(shè)計(jì)的PWM波周期為10ms,定時(shí)器每100us中斷一次(TH0=0xff;TL0=0x9c;) 每個(gè)周期包含100個(gè)中斷。但用Keil的調(diào)試工具邏輯分析儀進(jìn)行測(cè)試時(shí)發(fā)現(xiàn),實(shí)測(cè)PWM波周期為80ms。即使考慮了中斷調(diào)用和其他語(yǔ)句的執(zhí)行所耗費(fèi)的時(shí)間也不應(yīng)該差這么多倍吧?是不是程序有問(wèn)題?麻煩各位大佬幫忙看看程序吧。工程由pwm.h,pwm.c和main.c組成。main.c中程序?yàn)?/font>
#include "reg52.h"
#include "pwm.h"
void main()
{
pwm(P1_0,30,Timer0);
}

pwm.h和pwm.c


最佳答案

查看完整內(nèi)容

不存在定時(shí)器不準(zhǔn),而是使用不當(dāng)。 #include sbit PWM=P1^0; unsigned char i; unsigned char j=50;//0~100%占空比 void InitTimer0(void)//100us { TMOD = 0x02;//自動(dòng)重裝 TH0 = 0x9C; TL0 = 0x9C; EA = 1; ET0 = 1; TR0 = 1; } void main(void) { InitTimer0(); while(1); } void Timer0Interrupt() interrupt 1 { if(i
回復(fù)

使用道具 舉報(bào)

ID:694871 發(fā)表于 2020-5-17 12:44 | 顯示全部樓層
pwm.h文件
#ifndef __PWM__
#define __PWM__

#define Timer0 0x8A  //Timer 0的低字節(jié)
#define Timer1 0x8B  //Timer 1的低字節(jié)

#define P1_0 0x01
#define P1_1 0x02
#define P1_2 0x04
#define P1_3 0x08
#define P1_4 0x10
#define P1_5 0x20
#define P1_6 0x40
#define P1_7 0x80

//對(duì)PWM函數(shù)參數(shù)判斷
#define IS_P1(Pin) ( ((Pin)==P1_0)|| \
                                                                                 ((Pin)==P1_1)|| \
                                                                                 ((Pin)==P1_2)|| \
                                                                                 ((Pin)==P1_3)|| \
                                                                                 ((Pin)==P1_4)|| \
                                                                                 ((Pin)==P1_5)|| \
                                                                                 ((Pin)==P1_6)|| \
                                                                                 ((Pin)==P1_7) )
#define IS_Timer(Timer) (  ((Timer)==Timer0)|| \
                                                                                                         ((Timer)==Timer1) )
typedef unsigned char u8;
typedef int u16;

void pwm(u8 Pin,u8 Duty_cycle,u8 Timer);


#endif

pwm.c文件
#include "pwm.h"
#include "reg52.h"

u8 g_Pin;
u8 g_Duty_cycle;
u8 g_Voltage;
u8 g_Count;   //用于中斷計(jì)數(shù),控制占空比
//輸出周期為10ms,占空比可調(diào)的PWM波
//@param Pin:指定輸出PWM波的引腳,支持P1口的8個(gè)引腳,格式:P1_X
//@param: Duty_cycle:指定占空比,應(yīng)為從1-99的整數(shù)
//@param: Timer:指定使用Timer0或Timer1進(jìn)行定時(shí)
//@retval None
void pwm(u8 Pin,u8 Duty_cycle,u8 Timer)
{
        //該函數(shù)開(kāi)啟相應(yīng)的定時(shí)計(jì)數(shù)器,完成相關(guān)初始化工作,最后由中斷服務(wù)函數(shù)完成PWM功能
        if(!IS_P1(Pin))
                return;
        if(!IS_Timer(Timer))
                return;
        if(Duty_cycle>99 || Duty_cycle<1)
                return;
       
        g_Pin=Pin;
        g_Duty_cycle=Duty_cycle;
       
        if(Timer==Timer0)
        {
                //完成定時(shí)器的初始化
                TH0=0xff;
                TL0=0x9c;   //設(shè)置初值為65436,每100us產(chǎn)生一次中斷
                //啟動(dòng)Timer0及相應(yīng)中斷
                IE|=0x82;   //允許Timer0中斷
                TMOD|=0x01;
                TCON|=0x10;  //開(kāi)啟Timer0
        }
        else
        {
                //完成定時(shí)器的初始化
                TH1=0xff;
                TL1=0x9c;   //設(shè)置初值為65436,每100us產(chǎn)生一次中斷
                //啟動(dòng)Timer1及相應(yīng)中斷
                IE|=0x88;   //允許Timer1中斷
                TMOD|=0x10;
                TCON|=0x40;  //開(kāi)啟Timer1
        }
        g_Voltage=1;
        P1|=Pin;//將相應(yīng)IO口設(shè)為高電平
        g_Count=Duty_cycle;
}

void timer0() interrupt 1
{
                TH0=0xff;
                TL0=0x9c;   //重新賦計(jì)數(shù)初值
                g_Count--;
                if(!g_Count)//計(jì)數(shù)器計(jì)數(shù)至0說(shuō)明電平需要發(fā)生翻轉(zhuǎn)
                {
                        if(g_Voltage)//原來(lái)為高電平,翻轉(zhuǎn)為低電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=0;
                                g_Count=100-g_Duty_cycle;
                        }
                        else//原來(lái)為低電平,再次翻轉(zhuǎn)為高電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
void timer1() interrupt 3
{
                TH1=0xff;
                TL1=0x9c;   //重新賦計(jì)數(shù)初值
                g_Count--;
                if(!g_Count)//計(jì)數(shù)器計(jì)數(shù)至0說(shuō)明電平需要發(fā)生翻轉(zhuǎn)
                {
                        if(g_Voltage)//原來(lái)為高電平,翻轉(zhuǎn)為低電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=0;
                                g_Count=99-g_Duty_cycle;
                        }
                        else//原來(lái)為低電平,再次翻轉(zhuǎn)為高電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
回復(fù)

使用道具 舉報(bào)

ID:213173 發(fā)表于 2020-5-17 08:01 | 顯示全部樓層
不存在定時(shí)器不準(zhǔn),而是使用不當(dāng)。
#include <reg51.h>
sbit PWM=P1^0;
unsigned char i;
unsigned char j=50;//0~100%占空比

void InitTimer0(void)//100us
{
    TMOD = 0x02;//自動(dòng)重裝
    TH0 = 0x9C;
    TL0 = 0x9C;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}

void main(void)
{
        InitTimer0();
        while(1);
}

void Timer0Interrupt() interrupt 1
{
        if(i<j)
                PWM=1;
        else PWM=0;
        i++;
        i%=100;
}
回復(fù)

使用道具 舉報(bào)

ID:342911 發(fā)表于 2020-5-17 09:36 | 顯示全部樓層
似乎文件沒(méi)上傳上來(lái)?
回復(fù)

使用道具 舉報(bào)

ID:694871 發(fā)表于 2020-5-17 12:29 | 顯示全部樓層
pwm.h的代碼如下:
#ifndef __PWM__
#define __PWM__

#define Timer0 0x8A  //Timer 0的低字節(jié)
#define Timer1 0x8B  //Timer 1的低字節(jié)

#define P1_0 0x01
#define P1_1 0x02
#define P1_2 0x04
#define P1_3 0x08
#define P1_4 0x10
#define P1_5 0x20
#define P1_6 0x40
#define P1_7 0x80

//對(duì)PWM函數(shù)參數(shù)判斷
#define IS_P1(Pin) ( ((Pin)==P1_0)|| \
                                                                                 ((Pin)==P1_1)|| \
                                                                                 ((Pin)==P1_2)|| \
                                                                                 ((Pin)==P1_3)|| \
                                                                                 ((Pin)==P1_4)|| \
                                                                                 ((Pin)==P1_5)|| \
                                                                                 ((Pin)==P1_6)|| \
                                                                                 ((Pin)==P1_7) )
#define IS_Timer(Timer) (  ((Timer)==Timer0)|| \
                                                                                                         ((Timer)==Timer1) )
typedef unsigned char u8;
typedef int u16;

void pwm(u8 Pin,u8 Duty_cycle,u8 Timer);


#endif

pwm.c的代碼如下:
#include "pwm.h"
#include "reg52.h"

u8 g_Pin;
u8 g_Duty_cycle;
u8 g_Voltage;
u8 g_Count;   //用于中斷計(jì)數(shù),控制占空比
//輸出周期為10ms,占空比可調(diào)的PWM波
//@param Pin:指定輸出PWM波的引腳,支持P1口的8個(gè)引腳,格式:P1_X
//@param: Duty_cycle:指定占空比,應(yīng)為從1-99的整數(shù)
//@param: Timer:指定使用Timer0或Timer1進(jìn)行定時(shí)
//@retval None
void pwm(u8 Pin,u8 Duty_cycle,u8 Timer)
{
        //該函數(shù)開(kāi)啟相應(yīng)的定時(shí)計(jì)數(shù)器,完成相關(guān)初始化工作,最后由中斷服務(wù)函數(shù)完成PWM功能
        if(!IS_P1(Pin))
                return;
        if(!IS_Timer(Timer))
                return;
        if(Duty_cycle>99 || Duty_cycle<1)
                return;
       
        g_Pin=Pin;
        g_Duty_cycle=Duty_cycle;
       
        if(Timer==Timer0)
        {
                //完成定時(shí)器的初始化
                TH0=0xff;
                TL0=0x9c;   //設(shè)置初值為65436,每100us產(chǎn)生一次中斷
                //啟動(dòng)Timer0及相應(yīng)中斷
                IE|=0x82;   //允許Timer0中斷
                TMOD|=0x01;
                TCON|=0x10;  //開(kāi)啟Timer0
        }
        else
        {
                //完成定時(shí)器的初始化
                TH1=0xff;
                TL1=0x9c;   //設(shè)置初值為65436,每100us產(chǎn)生一次中斷
                //啟動(dòng)Timer1及相應(yīng)中斷
                IE|=0x88;   //允許Timer1中斷
                TMOD|=0x10;
                TCON|=0x40;  //開(kāi)啟Timer1
        }
        g_Voltage=1;
        P1|=Pin;//將相應(yīng)IO口設(shè)為高電平
        g_Count=Duty_cycle;
}

void timer0() interrupt 1
{
                TH0=0xff;
                TL0=0x9c;   //重新賦計(jì)數(shù)初值
                g_Count--;
                if(!g_Count)//計(jì)數(shù)器計(jì)數(shù)至0說(shuō)明電平需要發(fā)生翻轉(zhuǎn)
                {
                        if(g_Voltage)//原來(lái)為高電平,翻轉(zhuǎn)為低電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=0;
                                g_Count=100-g_Duty_cycle;
                        }
                        else//原來(lái)為低電平,再次翻轉(zhuǎn)為高電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
void timer1() interrupt 3
{
                TH1=0xff;
                TL1=0x9c;   //重新賦計(jì)數(shù)初值
                g_Count--;
                if(!g_Count)//計(jì)數(shù)器計(jì)數(shù)至0說(shuō)明電平需要發(fā)生翻轉(zhuǎn)
                {
                        if(g_Voltage)//原來(lái)為高電平,翻轉(zhuǎn)為低電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=0;
                                g_Count=99-g_Duty_cycle;
                        }
                        else//原來(lái)為低電平,再次翻轉(zhuǎn)為高電平
                        {
                                P1^=g_Pin;                                //相應(yīng)Pin翻轉(zhuǎn)電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
回復(fù)

使用道具 舉報(bào)

ID:482935 發(fā)表于 2020-5-18 02:54 來(lái)自觸屏版 | 顯示全部樓層
星水天河 發(fā)表于 2020-5-17 17:12
對(duì)你說(shuō)的沒(méi)有錯(cuò)。你說(shuō)100次中斷造成80us的誤差。但是現(xiàn)在問(wèn)題是我設(shè)計(jì)的10ms為一個(gè)周期,實(shí)際仿真測(cè)出80m ...

沒(méi)看出來(lái)。。你這個(gè)用了兩個(gè)定時(shí)器生成1路pwm波,可能是定時(shí)器0會(huì)打斷定時(shí)器1吧(中斷優(yōu)先級(jí),我記得默認(rèn)T1不能打斷T0),生成中斷嵌套。 其實(shí)用一個(gè)定時(shí)器就可以生成1路pwm波了。
你這個(gè)開(kāi)頭.h寫(xiě)的像stm32風(fēng)格,我看懂了造了個(gè)入口檢驗(yàn)。中斷里沒(méi)看懂,有點(diǎn)復(fù)雜了感覺(jué)(耗時(shí)長(zhǎng)),周期那里為什么要100-duty不太理解。你看看我寫(xiě)的那個(gè)吧,一個(gè)定時(shí)器就夠了,誤差也還行。
回復(fù)

使用道具 舉報(bào)

ID:694871 發(fā)表于 2020-5-18 08:52 | 顯示全部樓層
感謝大家的幫助!問(wèn)題已經(jīng)解決。問(wèn)題出在中斷服務(wù)函數(shù)。當(dāng)原來(lái)為低電平,要翻轉(zhuǎn)為高電平時(shí),應(yīng)該用P1&=(~g_Pin)而不是P1^=g_Pin; 感謝上面網(wǎng)友給出的代碼,我對(duì)現(xiàn)有的函數(shù)作了一些優(yōu)化。能滿足預(yù)期要求
回復(fù)

使用道具 舉報(bào)

ID:426861 發(fā)表于 2020-5-18 09:23 | 顯示全部樓層
現(xiàn)在增強(qiáng)型51一般都有硬件PWM輸出
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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