久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3793|回復: 7
打印 上一主題 下一主題
收起左側

51單片機PWM輸出,定時器定時不準問題?

[復制鏈接]
跳轉到指定樓層
樓主
3黑幣
  我編寫了一個PWM輸出的函數,根據傳進來的參數不同來選擇使用定時器0或者定時器1,對P1口的某一個引腳輸出PWM。并且可以根據入口參數實現不同的占空比。設計的PWM波周期為10ms,定時器每100us中斷一次(TH0=0xff;TL0=0x9c;) 每個周期包含100個中斷。但用Keil的調試工具邏輯分析儀進行測試時發現,實測PWM波周期為80ms。即使考慮了中斷調用和其他語句的執行所耗費的時間也不應該差這么多倍吧?是不是程序有問題?麻煩各位大佬幫忙看看程序吧。工程由pwm.h,pwm.c和main.c組成。main.c中程序為
#include "reg52.h"
#include "pwm.h"
void main()
{
pwm(P1_0,30,Timer0);
}

pwm.h和pwm.c


最佳答案

查看完整內容

不存在定時器不準,而是使用不當。 #include sbit PWM=P1^0; unsigned char i; unsigned char j=50;//0~100%占空比 void InitTimer0(void)//100us { TMOD = 0x02;//自動重裝 TH0 = 0x9C; TL0 = 0x9C; EA = 1; ET0 = 1; TR0 = 1; } void main(void) { InitTimer0(); while(1); } void Timer0Interrupt() interrupt 1 { if(i
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

來自 2#
ID:694871 發表于 2020-5-17 12:44 | 只看該作者
pwm.h文件
#ifndef __PWM__
#define __PWM__

#define Timer0 0x8A  //Timer 0的低字節
#define Timer1 0x8B  //Timer 1的低字節

#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

//對PWM函數參數判斷
#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;   //用于中斷計數,控制占空比
//輸出周期為10ms,占空比可調的PWM波
//@param Pin:指定輸出PWM波的引腳,支持P1口的8個引腳,格式:P1_X
//@param: Duty_cycle:指定占空比,應為從1-99的整數
//@param: Timer:指定使用Timer0或Timer1進行定時
//@retval None
void pwm(u8 Pin,u8 Duty_cycle,u8 Timer)
{
        //該函數開啟相應的定時計數器,完成相關初始化工作,最后由中斷服務函數完成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)
        {
                //完成定時器的初始化
                TH0=0xff;
                TL0=0x9c;   //設置初值為65436,每100us產生一次中斷
                //啟動Timer0及相應中斷
                IE|=0x82;   //允許Timer0中斷
                TMOD|=0x01;
                TCON|=0x10;  //開啟Timer0
        }
        else
        {
                //完成定時器的初始化
                TH1=0xff;
                TL1=0x9c;   //設置初值為65436,每100us產生一次中斷
                //啟動Timer1及相應中斷
                IE|=0x88;   //允許Timer1中斷
                TMOD|=0x10;
                TCON|=0x40;  //開啟Timer1
        }
        g_Voltage=1;
        P1|=Pin;//將相應IO口設為高電平
        g_Count=Duty_cycle;
}

void timer0() interrupt 1
{
                TH0=0xff;
                TL0=0x9c;   //重新賦計數初值
                g_Count--;
                if(!g_Count)//計數器計數至0說明電平需要發生翻轉
                {
                        if(g_Voltage)//原來為高電平,翻轉為低電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=0;
                                g_Count=100-g_Duty_cycle;
                        }
                        else//原來為低電平,再次翻轉為高電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
void timer1() interrupt 3
{
                TH1=0xff;
                TL1=0x9c;   //重新賦計數初值
                g_Count--;
                if(!g_Count)//計數器計數至0說明電平需要發生翻轉
                {
                        if(g_Voltage)//原來為高電平,翻轉為低電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=0;
                                g_Count=99-g_Duty_cycle;
                        }
                        else//原來為低電平,再次翻轉為高電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
回復

使用道具 舉報

板凳
ID:213173 發表于 2020-5-17 08:01 | 只看該作者
不存在定時器不準,而是使用不當。
#include <reg51.h>
sbit PWM=P1^0;
unsigned char i;
unsigned char j=50;//0~100%占空比

void InitTimer0(void)//100us
{
    TMOD = 0x02;//自動重裝
    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;
}
回復

使用道具 舉報

地板
ID:342911 發表于 2020-5-17 09:36 | 只看該作者
似乎文件沒上傳上來?
回復

使用道具 舉報

5#
ID:694871 發表于 2020-5-17 12:29 | 只看該作者
pwm.h的代碼如下:
#ifndef __PWM__
#define __PWM__

#define Timer0 0x8A  //Timer 0的低字節
#define Timer1 0x8B  //Timer 1的低字節

#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

//對PWM函數參數判斷
#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;   //用于中斷計數,控制占空比
//輸出周期為10ms,占空比可調的PWM波
//@param Pin:指定輸出PWM波的引腳,支持P1口的8個引腳,格式:P1_X
//@param: Duty_cycle:指定占空比,應為從1-99的整數
//@param: Timer:指定使用Timer0或Timer1進行定時
//@retval None
void pwm(u8 Pin,u8 Duty_cycle,u8 Timer)
{
        //該函數開啟相應的定時計數器,完成相關初始化工作,最后由中斷服務函數完成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)
        {
                //完成定時器的初始化
                TH0=0xff;
                TL0=0x9c;   //設置初值為65436,每100us產生一次中斷
                //啟動Timer0及相應中斷
                IE|=0x82;   //允許Timer0中斷
                TMOD|=0x01;
                TCON|=0x10;  //開啟Timer0
        }
        else
        {
                //完成定時器的初始化
                TH1=0xff;
                TL1=0x9c;   //設置初值為65436,每100us產生一次中斷
                //啟動Timer1及相應中斷
                IE|=0x88;   //允許Timer1中斷
                TMOD|=0x10;
                TCON|=0x40;  //開啟Timer1
        }
        g_Voltage=1;
        P1|=Pin;//將相應IO口設為高電平
        g_Count=Duty_cycle;
}

void timer0() interrupt 1
{
                TH0=0xff;
                TL0=0x9c;   //重新賦計數初值
                g_Count--;
                if(!g_Count)//計數器計數至0說明電平需要發生翻轉
                {
                        if(g_Voltage)//原來為高電平,翻轉為低電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=0;
                                g_Count=100-g_Duty_cycle;
                        }
                        else//原來為低電平,再次翻轉為高電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
void timer1() interrupt 3
{
                TH1=0xff;
                TL1=0x9c;   //重新賦計數初值
                g_Count--;
                if(!g_Count)//計數器計數至0說明電平需要發生翻轉
                {
                        if(g_Voltage)//原來為高電平,翻轉為低電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=0;
                                g_Count=99-g_Duty_cycle;
                        }
                        else//原來為低電平,再次翻轉為高電平
                        {
                                P1^=g_Pin;                                //相應Pin翻轉電平
                                g_Voltage=1;
                                g_Count=g_Duty_cycle;
                        }
                }
}
回復

使用道具 舉報

6#
ID:482935 發表于 2020-5-18 02:54 來自觸屏版 | 只看該作者
星水天河 發表于 2020-5-17 17:12
對你說的沒有錯。你說100次中斷造成80us的誤差。但是現在問題是我設計的10ms為一個周期,實際仿真測出80m ...

沒看出來。。你這個用了兩個定時器生成1路pwm波,可能是定時器0會打斷定時器1吧(中斷優先級,我記得默認T1不能打斷T0),生成中斷嵌套。 其實用一個定時器就可以生成1路pwm波了。
你這個開頭.h寫的像stm32風格,我看懂了造了個入口檢驗。中斷里沒看懂,有點復雜了感覺(耗時長),周期那里為什么要100-duty不太理解。你看看我寫的那個吧,一個定時器就夠了,誤差也還行。
回復

使用道具 舉報

7#
ID:694871 發表于 2020-5-18 08:52 | 只看該作者
感謝大家的幫助!問題已經解決。問題出在中斷服務函數。當原來為低電平,要翻轉為高電平時,應該用P1&=(~g_Pin)而不是P1^=g_Pin; 感謝上面網友給出的代碼,我對現有的函數作了一些優化。能滿足預期要求
回復

使用道具 舉報

8#
ID:426861 發表于 2020-5-18 09:23 | 只看該作者
現在增強型51一般都有硬件PWM輸出
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日韩一区二区三区在线观看视频 | 91久久久久久 | 在线成人精品视频 | 亚洲视频 欧美视频 | 久久久久久免费观看 | 日日干夜夜操天天操 | 色天堂影院 | japan21xxxxhd美女 日本欧美国产在线 | 亚洲精品一区二区在线观看 | 日韩视频中文字幕 | 国产精品九九 | www.日韩| 亚洲精彩视频 | 亚洲欧美一区二区三区在线 | 欧美日韩久久精品 | 成人av资源在线 | 国产中文区二幕区2012 | 久久久国产一区二区三区 | 国产一区二区影院 | 午夜影院在线观看 | 在线观看一区 | 日韩精品中文字幕一区二区三区 | 免费一级黄色 | 国产精品综合 | 免费三级黄 | 国产精品一区二区三区在线播放 | 中文字幕av网 | 91视频亚洲 | 国产香蕉视频 | 欧美日一区二区 | 天天干精品 | av在线播放一区二区 | 伊人一区 | 欧美视频一区二区三区 | 九九热免费在线观看 | 欧美舔穴| 黄色av网站在线观看 | 黄网站在线播放 | 天天艹| 99久久日韩精品免费热麻豆美女 | 中文字幕在线播放不卡 |