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

QQ登錄

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

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

PIC單片機(jī)輸出不了占空比50%的方波——幫扶一把學(xué)單片機(jī)的60后

  [復(fù)制鏈接]
ID:27513 發(fā)表于 2021-11-24 11:18 | 顯示全部樓層 |閱讀模式
自我介紹下:60后從業(yè)模電,自封工程師,動(dòng)手能力強(qiáng)。學(xué)單片機(jī)歷程30年,學(xué)級(jí)仍是未入門的學(xué)前班。所以各位看官都是我的老師,各位的每句話都能使我進(jìn)步!期望大家都出一份正能量!廢話不說(shuō)入正題:
PIC12F683單片機(jī),編程平臺(tái)MPLAB IDE -V8.84  編譯器HI-TECH-PICC_9.83
無(wú)單片機(jī)開(kāi)發(fā)板,有RF809H編程器,有GA1202CAL示波器
實(shí)驗(yàn)要求單片機(jī)GP0和GP1輸出20KHz占空比為50%的互補(bǔ)方波

C程序:
#include <pic.h>

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO=0X00;
        }
void timer0_init(void) //定時(shí)器0初始化使用系統(tǒng)默認(rèn)時(shí)鐘4M fosc/4 所以計(jì)數(shù)周期為1us
        {
                T0CS=0;    //timer0工作于定時(shí)器方式
                PSA=1;     //timer0不分頻
                T0IF=0;    //清timer0中斷標(biāo)志
                TMR0=0xE0; /*置初值 20KHz的半個(gè)周期為25us*/
                T0IE=1;    //timer0中斷允許
                GIE=1;     //開(kāi)全局中斷
        }

        void interrupt isr(void)   //中斷子程序
                {
                        TMR0=0xE0; //定時(shí)器0置初值25us
                        T0IF=0;    //清中斷標(biāo)志
                        GP0=~GP0;  //GP0位取反
                        GP1=!GP0;  //使GP1引腳取反GP0
                        /*在這里廢寢忘食3總天,一度引起孫子的奶奶發(fā)飆
                                也沒(méi)有折騰出正確的結(jié)果*/                                 
                }  
void main(void)          //主程序
        {
        
                IO_init();         //引腳初始化函數(shù)
                timer0_init();     //定時(shí)器0初始化函數(shù)
        
                while(1)    //死循環(huán)
                {
               
                        
                }
                        
        }

寫入單片機(jī);手工搭建最小系統(tǒng)上示波器看波形結(jié)果頻率是26.3KHz,GP0引腳正占空比只有12.6%,負(fù)占空比87.3%;GP1引腳正占空比86.3%,負(fù)占空比13.6%幅值5.04V
刪除中斷子程序里的GP1=!GP0語(yǔ)句結(jié)果GP0引腳示波器上只有一條5.17V的直線沒(méi)有波形了,頻率顯示為小于10Hz.
大家說(shuō)怪不怪!本應(yīng)該GP0輸出信號(hào)不受影響的怎么就沒(méi)有了呢????
接下來(lái)就是折騰了反復(fù)換TMR0的初值,最后試到0xE0時(shí)頻率是19.96KHz正占空比9.6%負(fù)占空比是90.4%,也就是說(shuō)正脈沖的寬度是4.8us這個(gè)值基本是恒定的試了下,從10KHz到30KHz這個(gè)值不變.然后大發(fā)現(xiàn)這個(gè)4.8us竟然是執(zhí)行GP1=!GP0 這條語(yǔ)句所耗費(fèi)的時(shí)間,所以上述刪除這條語(yǔ)句示波器上只顯示一直線。


GAS0002副本.jpg
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-24 11:31 | 顯示全部樓層
本帖最后由 xxll 于 2021-11-24 12:03 編輯

現(xiàn)在的問(wèn)題就是怎樣才能使正負(fù)波形占空比為50%  ?

于是我又timer2這個(gè)定時(shí)器來(lái)做程序如下:
#include <pic.h>
#define uchar unsigned char
#define uint  unsigned int
        uchar TA,TB;
void IO_init(void) /*端口初始化*/
        {

                TRISIO=0x00;
               
        }
void timer2_init(void) //fosc/4   8M所以計(jì)數(shù)周期為0.5us
        {
                T2CON=0b00000101;        //timer2控制寄存器設(shè)置        
                PR2=24;        //25us比較數(shù)字
                PEIE=1;        //模塊中斷使能
                TMR2IE=1;                //定時(shí)器2中斷使能
                GIE=1;       //        開(kāi)全局中斷
        }

        void interrupt isr(void)
                {
                        GP1=~GP1;//中斷后設(shè)引腳反相
                        GP0=~GP1;//使GP0與GP1反相                        
                        TMR2IF=0;/*TMR2溢出標(biāo)志清零*/               
                }  
void main(void)
        {
                __CONFIG(FOSC_INTOSCIO&WDTE_OFF);//系統(tǒng)配置,使用內(nèi)置時(shí)鐘,關(guān)看門狗
                OSCCONbits.IRCF0=1;
                OSCCONbits.IRCF1=1;
                OSCCONbits.IRCF2=1;//此3條設(shè)置時(shí)鐘為8M
                IO_init();//端口初始化
                timer2_init();//timer2初始化
                GPIO=0X00;//全部端口設(shè)為0
                while(1)  //死循環(huán)
                {
               
                        
                }
                        
        }
GAS0003副本.jpg
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-11-24 13:42 | 顯示全部樓層
PIC 沒(méi)玩過(guò),本不該發(fā)言,但是看你帖子實(shí)在冷清,深感年紀(jì)大了學(xué)單片機(jī)之不易……,
作為70后,在你身上看到10年后的自己,所以多多少少想幫你頂一把。
雖然PIC沒(méi)有玩過(guò), 有些道理應(yīng)該是互通的所以說(shuō)兩句。

                       GP0=~GP0;  //GP0位取反
                        GP1=!GP0;  //使GP1引腳取反GP0
基于單片機(jī)的工作原理,這里很可能得不到你希望的結(jié)果…… 舉個(gè)簡(jiǎn)單的例子。
GP0 = ~GP0; 這里的等號(hào)左邊 和 等號(hào)右邊,其實(shí)是不同的東西。
等號(hào)的右邊,是當(dāng)前GP0的電平狀態(tài),綜合了外部電平和內(nèi)部設(shè)置之后的最后結(jié)果,然后通過(guò)~取反
等號(hào)左邊,是你給GP0 設(shè)置的新?tīng)顟B(tài)即會(huì)改變GP0的內(nèi)部電平關(guān)系,然后通過(guò)這個(gè)內(nèi)部關(guān)系再去改變端口的外部關(guān)系。
當(dāng)你運(yùn)行完  GP0 = ~GP0   立刻運(yùn)行  GP1=!GP0; 此時(shí)讀取的 GP0, 如上所說(shuō)是結(jié)合內(nèi)部設(shè)置和外部電平綜合后的一個(gè)狀態(tài),而不是你剛剛賦值的結(jié)果,由于各種單片機(jī)不同我不能說(shuō)100%,但是有很大的概率,這個(gè)時(shí)候的GP0,是并沒(méi)有完成  GP0 = ~GP0 這個(gè)操作后更新 的狀態(tài)。 但,也有可能已經(jīng)完成了更新。這個(gè)不好判斷,所以在時(shí)序允許的情況下,一般應(yīng)該這么寫代碼。
                   GP1= GP0;  //使GP1引腳取GP0
                   GP0= !GP0;  //GP0位取反
這樣能保障,兩次讀到的GP0 是相等的。
如果,你一定要先改GP0, 再改GP1 那么也可以用一個(gè)中間變量
                   F0 = GP0;
                   GP0 = !F0;
                   GP1 = F0;
這樣是比較安全的操作。
回復(fù)

使用道具 舉報(bào)

ID:313048 發(fā)表于 2021-11-24 13:55 | 顯示全部樓層
本帖最后由 AUG 于 2021-11-24 14:01 編輯
xxll 發(fā)表于 2021-11-24 11:31
現(xiàn)在的問(wèn)題就是怎樣才能使正負(fù)波形占空比為50%  ?

于是我又timer2這個(gè)定時(shí)器來(lái)做程序如下:

從你這個(gè)圖可以看出,那個(gè)脈沖是你每次進(jìn)去之后GP0=~GP0取反的結(jié)果,后面變低是因?yàn)槟阌諫P1=!GP0,使其變低了.建議如下操作
void main()
{
timer_init();//25us一次中斷   40KHz
GP0 = 1;  //起始值相反
GP1 = 0;
while(1);
}
interrupt timer(void)
{
//重裝計(jì)數(shù)值
//清中斷
GP1=GP0;
GP0=~GP0;
}
回復(fù)

使用道具 舉報(bào)

ID:892596 發(fā)表于 2021-11-24 14:18 | 顯示全部樓層
用過(guò)一個(gè)仿PIC的芯片。
用的T0做的510US定時(shí):
1.jpg
用的T1做的38KHz的方波:
2.jpg
中斷里的IO翻轉(zhuǎn)。
3.jpg
回復(fù)

使用道具 舉報(bào)

ID:892596 發(fā)表于 2021-11-24 14:19 | 顯示全部樓層
不確定寄存器完全一致的,你可以參考一下,看著修改。
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2021-11-24 14:26 | 顯示全部樓層
中斷程序這樣改試一下:
void interrupt isr(void)   //中斷子程序
                {
                        TMR0=0xE0; //定時(shí)器0置初值25us
                        T0IF=0;    //清中斷標(biāo)志
                        GP1=GP0;  //使GP1引腳取反GP0后的GP0   
                        GP0=~GP0;  //GP0位取反                                                
                }
其它參考意見(jiàn):
PIC我用過(guò),個(gè)人感覺(jué)PIC實(shí)在不適合單片機(jī)入門,更多的是工業(yè)產(chǎn)品才用的,很多操作是有嚴(yán)格要求的,比如硬件堆棧,甚至很多學(xué)單片機(jī)的對(duì)堆棧也只是百度大概的看一遍,但真正到PIC硬件堆棧的時(shí)候,問(wèn)題就出來(lái)了
IO的數(shù)據(jù)方向要注意,中斷只有一個(gè)入口.......
數(shù)據(jù)手冊(cè)是肯定要一邊寫代碼一邊看的,但PIC的8位單片機(jī)數(shù)據(jù)手冊(cè)都是匯編的,印象中是沒(méi)有C的,所以,匯編指令最好是也要會(huì)一點(diǎn),不要求能寫程序,至少對(duì)著指令能看明白

回復(fù)

使用道具 舉報(bào)

ID:298123 發(fā)表于 2021-11-24 15:11 | 顯示全部樓層
一般來(lái)說(shuō),端口設(shè)置和讀取的寄存器是分開(kāi)的,設(shè)置后馬上讀取,單片機(jī)速度太快,讀取狀態(tài)值不一定是穩(wěn)定后的值。最好定義個(gè)變量 bit status,   中斷里改變status = !status; 然后賦值給端口寄存器
回復(fù)

使用道具 舉報(bào)

ID:123289 發(fā)表于 2021-11-24 15:12 | 顯示全部樓層
增加一個(gè)中間變T.
每次中斷后:
GP0=T
T=!T
GP1=T
試試看。
回復(fù)

使用道具 舉報(bào)

ID:123289 發(fā)表于 2021-11-24 15:13 | 顯示全部樓層
如果成功,再告訴你原因。不成功就罷了。
回復(fù)

使用道具 舉報(bào)

ID:139866 發(fā)表于 2021-11-24 15:25 | 顯示全部樓層
90后,來(lái)一個(gè)最簡(jiǎn)單的方法,因?yàn)槭种袥](méi)有示波器,只好麻煩樓主驗(yàn)證一下了,如果還是不行就自動(dòng)忽略后面的吧,一般來(lái)說(shuō)對(duì)定時(shí)器要求較高,定時(shí)器中斷里處理的代碼越少越好,能少就盡量少,以下是代碼
  1. #include <pic.h>

  2. char i = 0;

  3. void IO_init(void) /*端口初始化*/
  4. {
  5.         TRISIO=0x00;
  6.         GPIO=0X00;
  7. }
  8. void timer0_init(void) //定時(shí)器0初始化使用系統(tǒng)默認(rèn)時(shí)鐘4M fosc/4 所以計(jì)數(shù)周期為1us
  9. {
  10.         T0CS=0;    //timer0工作于定時(shí)器方式
  11.         PSA=1;     //timer0不分頻
  12.         T0IF=0;    //清timer0中斷標(biāo)志
  13.         TMR0=0x01; /*置初值 20KHz的半個(gè)周期為25us*/
  14.         T0IE=1;    //timer0中斷允許
  15.         GIE=1;     //開(kāi)全局中斷
  16. }

  17. void main()
  18. {
  19.     IO_init();         //引腳初始化函數(shù)
  20.     timer0_init();     //定時(shí)器0初始化函數(shù)
  21.         while()
  22.         {
  23.                 if(i >= 50) {
  24.                         i = 1;
  25.                 }else if(i >= 25) {
  26.                         GP0 = 1;  
  27.                         GP1 = 0;
  28.                 }else if(i >= 0) {
  29.                         GP0 = 0;
  30.                         GP1 = 1;
  31.                 }
  32.         }
  33. }

  34. void interrupt isr(void)   //中斷子程序
  35. {
  36.     TMR0 = 0x01; //定時(shí)器0置初值1us
  37.     T0IF = 0;    //清中斷標(biāo)志                       
  38.         i ++;
  39. }
復(fù)制代碼

回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-24 16:38 | 顯示全部樓層
yzwzfyz 發(fā)表于 2021-11-24 15:12
增加一個(gè)中間變T.
每次中斷后:
GP0=T

首先謝謝你,你這種方法我之前也試過(guò),正脈沖的寬度只增加2.5us
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-24 17:26 | 顯示全部樓層
188610329 發(fā)表于 2021-11-24 13:42
PIC 沒(méi)玩過(guò),本不該發(fā)言,但是看你帖子實(shí)在冷清,深感年紀(jì)大了學(xué)單片機(jī)之不易……,
作為70后,在你身上看 ...

感謝您的參與,你說(shuō)的第一種GP0=~GP0;GP1=!GP0;剛試過(guò)結(jié)果脈寬沒(méi)有改變.這種順序改變?cè)谑静ㄆ魃嫌^看沒(méi)有變化的.當(dāng)然,我知道編程是要講究時(shí)序的,否則實(shí)際應(yīng)用中會(huì)出大問(wèn)題的!至于第二種方法我在早些時(shí)候也試過(guò),中間加一個(gè)變量操作,確實(shí)增加了2.5us寬度.再次謝謝!
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-24 17:53 | 顯示全部樓層
本帖最后由 xxll 于 2021-11-25 07:00 編輯

謝謝各位老師,在這么短的時(shí)間內(nèi)就有許多人參與,出乎我的意料,心情非常激動(dòng)!大家的建議我一定抽時(shí)間一一測(cè)試總結(jié)經(jīng)驗(yàn).再報(bào)告給各位.開(kāi)先也償試出一個(gè)接近答案的程序,但是他不符合中斷的原則.CPU在正程中斷子程序里總總耗費(fèi)25us.現(xiàn)在也把這個(gè)程序給貼出來(lái):
#include <pic.h>
#define uchar unsigned char
#define uint  unsigned int
        uchar TA,TB;
void IO_init(void) /*端口初始化*/
        {

                TRISIO=0x00;
               
        }
void timer2_init(void) //fosc/4   8M所以計(jì)數(shù)周期為0.5us
        {
                T2CON=0b00000101;        //timer2控制寄存器設(shè)置        
                PR2=24;        //25us比較數(shù)字
                PEIE=1;        //中斷使能
                TMR2IE=1;                //中斷使能
                GIE=1;       //        開(kāi)全局中斷
        }
void delay(void)//延時(shí)函數(shù)
{
         uchar i;
         for(i=2 ;i ; i--);                 
}

/*************************************************/
/*中斷子程序正脈寬為24.6us負(fù)脈寬為25.626us,頻率為19.92KHz*/
/*************************************************/
        void interrupt isr(void)
                {
                        GP1=~GP1;//中斷后設(shè)引腳反相
                        delay(); //延時(shí)
                        TA=GP1;//此項(xiàng)也是為延時(shí)2.5us
                        GP0=~TA;//使GP0與GP1反相                        
                        TMR2IF=0;/*TMR2溢出標(biāo)志清零*/               
                }  
void main(void)
        {
                __CONFIG(FOSC_INTOSCIO&WDTE_OFF);//系統(tǒng)配置,使用內(nèi)置時(shí)鐘,關(guān)看門狗
                OSCCONbits.IRCF0=1;
                OSCCONbits.IRCF1=1;
                OSCCONbits.IRCF2=1;//此3條設(shè)置時(shí)鐘為8M
                IO_init();//端口初始化
                timer2_init();//timer2初始化
                GPIO=0X00;//全部端口設(shè)為0
                while(1)  //死循環(huán)
                {
               
                        
                }
                        
        }

GAS0004副本.jpg
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-25 07:25 | 顯示全部樓層
天ノ憶 發(fā)表于 2021-11-24 15:25
90后,來(lái)一個(gè)最簡(jiǎn)單的方法,因?yàn)槭种袥](méi)有示波器,只好麻煩樓主驗(yàn)證一下了,如果還是不行就自動(dòng)忽略后面的吧 ...

你這種思路很好,但是無(wú)法實(shí)現(xiàn)!先不說(shuō)你的初值不對(duì),就中斷定時(shí)1US哪個(gè)單片機(jī)都難實(shí)現(xiàn)。本單片機(jī)時(shí)鐘4M從響應(yīng)中斷開(kāi)始?jí)簵?zhí)行子程序到出棧要9到15us。這還要求子程序特別簡(jiǎn)單高效才可。
回復(fù)

使用道具 舉報(bào)

ID:123289 發(fā)表于 2021-11-25 07:59 | 顯示全部樓層
增加一個(gè)8位的中間 N。初始化時(shí):N=01。 ;目的:對(duì)應(yīng) GP1=0,GP0=1。
每次中斷后:
GPIO=N
N= N XOR 3   ;目的:對(duì)應(yīng)的 GP1、GP0 求反,準(zhǔn)備下次使用。
試試看。
要點(diǎn):讓GP1、GP0 同時(shí)改變。
回復(fù)

使用道具 舉報(bào)

ID:140489 發(fā)表于 2021-11-25 09:29 | 顯示全部樓層
仿真試了下,一路方波正常,兩路波形就亂了
#include <pic.h>

__CONFIG(0x0054);

#define uchar unsigned char
#define uint unsigned int

uchar flag,flag1;

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GP0=0;
                                GP1=0;
        }
void timer0_init(void) //定時(shí)器0初始化使用系統(tǒng)默認(rèn)時(shí)鐘4M fosc/4 所以計(jì)數(shù)周期為1us
        {
                T0CS=0;    //timer0工作于定時(shí)器方式
                PSA=1;     //timer0不分頻
                T0IF=0;    //清timer0中斷標(biāo)志
                TMR0=224; /*置初值 20KHz的半個(gè)周期為25us*/
                T0IE=1;    //timer0中斷允許
                GIE=1;     //開(kāi)全局中斷
        }


void main(void)          //主程序
        {

                IO_init();         //引腳初始化函數(shù)
                timer0_init();     //定時(shí)器0初始化函數(shù)

                while(1)    //死循環(huán)
                {
                               if(flag)
                                        {
                                                GP0=1;
        //                                        GP1=!GP0;
                                        }
                                        else
                                        {
                                                GP0=0;
        //                                        GP1=!GP0;                               
                                        }

/*
                        if(flag1)
                                        {
                                                GP1=0;
                               
                                        }
                                        else
                                        {
                                                GP1=1;
                                                                               
                                        }  */                     
                }

        }

void interrupt isr(void)   //中斷子程序
        {

                T0IF=0;    //清中斷標(biāo)志
                                TMR0=224; //定時(shí)器0置初值25us
                 
                                flag = !flag;

        }  

51hei截圖20211125092516.jpg
回復(fù)

使用道具 舉報(bào)

ID:47286 發(fā)表于 2021-11-25 12:29 | 顯示全部樓層
老哥好 PIC一點(diǎn)都不懂 幫不上 我也60后 和您打個(gè)招呼
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-25 13:13 | 顯示全部樓層
lids 發(fā)表于 2021-11-25 09:29
仿真試了下,一路方波正常,兩路波形就亂了
#include

謝謝提供方法!剛剛測(cè)試了一下,編譯通不過(guò),將配置語(yǔ)句刪除,使用默認(rèn)的時(shí)鐘通過(guò)編譯,用示波器看了一下,單腳輸出頻率只有10KHZ且不穩(wěn)定,占空比似乎是50%但不穩(wěn)定左右飄忽,怎么調(diào)示波都不能很好的同步……
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-11-25 17:28 | 顯示全部樓層
xxll 發(fā)表于 2021-11-25 13:13
謝謝提供方法!剛剛測(cè)試了一下,編譯通不過(guò),將配置語(yǔ)句刪除,使用默認(rèn)的時(shí)鐘通過(guò)編譯,用示波器看了一下 ...

PIC12F683 的PDF手冊(cè)有么? 發(fā)一個(gè)上來(lái),我研究一下看看。畢竟有些東西受限于硬件,光看代碼可能忽略掉一些關(guān)鍵信息。
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-25 17:49 | 顯示全部樓層
188610329 發(fā)表于 2021-11-25 17:28
PIC12F683 的PDF手冊(cè)有么? 發(fā)一個(gè)上來(lái),我研究一下看看。畢竟有些東西受限于硬件,光看代碼可能忽略掉一 ...

12f683cn.pdf

3.14 MB, 下載次數(shù): 7

回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-25 18:57 | 顯示全部樓層
dzbj 發(fā)表于 2021-11-25 12:29
老哥好 PIC一點(diǎn)都不懂 幫不上 我也60后 和您打個(gè)招呼

兄弟好!
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-11-25 19:29 | 顯示全部樓層
手冊(cè)看了一下,發(fā)現(xiàn)一個(gè)被忽略的問(wèn)題。
這個(gè)片子,只有35條指令,其中對(duì)位的操作指令,只有4條,而這個(gè)片子速度還比較慢,周期比較長(zhǎng)。帶來(lái)的直接結(jié)果就是:
                      GP1=~GP1;//中斷后設(shè)引腳反相
                        GP0=~GP1;//使GP0與GP1反相            
這看似簡(jiǎn)單的兩個(gè)操作,實(shí)際上需要消耗非常多的時(shí)間來(lái)處理。
通過(guò)仔細(xì)分析這個(gè)片子擁有的35條指令,我認(rèn)為:
初使?fàn)顟B(tài)  GP0 = 0, GP1 = 1 之后。在翻轉(zhuǎn)的時(shí)候,使用:

GPIO ^= 0x03;  這一條指令來(lái)取代  你的:

                        GP1=~GP1;//中斷后設(shè)引腳反相
                        GP0=~GP1;//使GP0與GP1反相      

這兩條指令,是比較高效的方法。建議你嘗試一下。

回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-26 08:19 | 顯示全部樓層
188610329 發(fā)表于 2021-11-25 19:29
手冊(cè)看了一下,發(fā)現(xiàn)一個(gè)被忽略的問(wèn)題。
這個(gè)片子,只有35條指令,其中對(duì)位的操作指令,只有4條,而這個(gè)片 ...

按照你的方法試了一下,沒(méi)有波形輸出只有直流電壓。
其實(shí)這個(gè)真正的原因,我個(gè)人認(rèn)為不是操作快慢的問(wèn)題,而是CPU離開(kāi)中斷子程序輸出引腳信號(hào)立即再次翻轉(zhuǎn)的問(wèn)題。像前面我示出的一個(gè)例子,在子程序里延時(shí)即可得到想要的波形。
這個(gè)程序原意是:1。CPU給引腳付值然后延時(shí),CPU跳出再干別的事。等延時(shí)到CPU在回去給相關(guān)引腳重新付值,就這樣周而復(fù)始下去的,F(xiàn)在的問(wèn)題就是在正程時(shí)間的延時(shí)都給了逆程時(shí)間了。
如將子程序中指令位置上下調(diào)換,只影響逆程時(shí)長(zhǎng),不影響正程脈寬
TMR0=224;
T0IF=0;
GP1=!GP1;
GP0=!GP1;
這樣的正脈沖是4.8US,負(fù)脈寬是50.2US,頻率為19.9KHz;
GP1=!GP1;
GP0=!GP1;
TMR0=224;
T0IF=0;
這樣調(diào)換一下順序,正程脈寬仍然是4.8us,但負(fù)脈寬變成了54.4us,頻率降到16.8KHz;
TMR0=224;
T0IF=0;
GP1=!GP1;
TA=!GP1;
GP0=TA;
在這段里加入一個(gè)變量TA,正脈寬會(huì)變成5.48us,負(fù)脈寬縮小,頻率不變?nèi)允?9.Khz;
你看從這里能不能想出解決方案來(lái)!
回復(fù)

使用道具 舉報(bào)

ID:548551 發(fā)表于 2021-11-26 09:20 | 顯示全部樓層
我現(xiàn)在用得單片機(jī)剛好是PIC架構(gòu)得。我看了半天不知道理解對(duì)不對(duì)。你想GP1輸出的正占空比,GP0輸出的正占空比是GP0的負(fù)占空比時(shí)間,假如1現(xiàn)在的正占空比是10%,那么GP0輸出的正占空比就應(yīng)該是90%對(duì)吧。您是這意思么?
回復(fù)

使用道具 舉報(bào)

ID:342822 發(fā)表于 2021-11-26 09:38 | 顯示全部樓層
lids 發(fā)表于 2021-11-25 09:29
仿真試了下,一路方波正常,兩路波形就亂了
#include

一路方波正常很好~~加個(gè)7404反相器就成了互補(bǔ)波形了
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-26 09:41 | 顯示全部樓層
xqleft 發(fā)表于 2021-11-26 09:20
我現(xiàn)在用得單片機(jī)剛好是PIC架構(gòu)得。我看了半天不知道理解對(duì)不對(duì)。你想GP1輸出的正占空比,GP0輸出的正占空 ...

我要的就是一個(gè)引腳上正50%,負(fù)50%就這樣簡(jiǎn)單,要求是用定時(shí)器0實(shí)現(xiàn),頻率20KHZ
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2021-11-26 14:36 | 顯示全部樓層
還在折騰這個(gè)?
TMR0=0xE0(224),定時(shí)器就是256-224=32
如果你是用4MHZ時(shí)鐘,那么,定時(shí)器的中斷時(shí)間是不低于32uS的,你這還怎么達(dá)到?20KHZ的輸出?
TMR0=0xE0; /*置初值 20KHz的半個(gè)周期為25us*/..........這是怎么算出來(lái)的?
而且,PIC是沒(méi)有堆棧指令的,編譯器可能還要加幾條保存W和其它會(huì)改變的文件寄存器的指令
這樣一來(lái),你這個(gè)是肯定不會(huì)有20KHZ的頻率的
而且,在中斷程序中,盡量少用變量計(jì)算,沒(méi)有用過(guò)PIC的C,不知道PIC有沒(méi)有位,如果有位,就用位來(lái)判斷,定時(shí)器設(shè)定要高于20KHZ,TMR0的值要大于0xe7
先聲明一個(gè)位
void interrupt isr(void)   //中斷子程序
                {
                        TMR0=240; //定時(shí)器0置初值,先看結(jié)果,再慢慢調(diào)節(jié)
                        T0IF=0;    //清中斷標(biāo)志
                        if(ON)
                             {
                               GP0=1;
                                GP1=0;
                               ON=0;
                             }   
                       else
                             {
                               GP0=0;
                                GP1=1;
                               ON=1;
                             }                                
                }

回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-26 18:19 | 顯示全部樓層
Y_G_G 發(fā)表于 2021-11-26 14:36
還在折騰這個(gè)?
TMR0=0xE0(224),定時(shí)器就是256-224=32
如果你是用4MHZ時(shí)鐘,那么,定時(shí)器的中斷時(shí)間是不低于 ...

這位老師好!我把你的方案和數(shù)據(jù)測(cè)試結(jié)果匯報(bào)給你:時(shí)鐘4M時(shí),GP0正脈寬0.8us負(fù)脈寬75.2us頻率13KHz;
GP1正脈寬38.8us,負(fù)脈寬37.6us,頻率13KHZ

時(shí)鐘設(shè)置成8M時(shí):GP0正脈寬0.5us(500ns),負(fù)脈寬示波器沒(méi)報(bào),頻率26.3KHZ;
GP1正脈寬19.4us,負(fù)脈寬18.6us,頻率26.3KHz
老師從這二種時(shí)鐘數(shù)據(jù)看,只有GP1正負(fù)脈沖占空比能接近50%,而GP0正脈沖太窄,你看如何解決?
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2021-11-26 18:54 | 顯示全部樓層
xxll 發(fā)表于 2021-11-26 18:19
這位老師好!我把你的方案和數(shù)據(jù)測(cè)試結(jié)果匯報(bào)給你:時(shí)鐘4M時(shí),GP0正脈寬0.8us負(fù)脈寬75.2us頻率13KHz;
GP1 ...

你把完整的代碼上傳一下
GP0和GP1是一樣的調(diào)整,在時(shí)間上應(yīng)該是一致的,沒(méi)有理由只有一個(gè)行,一個(gè)不行的,要么就都不行,要么就都行
你也可以自己調(diào)試一下的呀,把GP1代碼刪除,或者把GP0換成其它的端口試一下
void interrupt isr(void)   //中斷子程序
                {
                        
                        T0IF=0;    //清中斷標(biāo)志
                        if(ON)
                             {
                               GP0=1;
                                GP1=0;
                               ON=0;
                             }   
                       else
                             {
                               GP0=0;
                                GP1=1;
                               ON=1;
                             }   
TMR0=240; //定時(shí)器0置初值,先看結(jié)果,這設(shè)置放后面                           
                }
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-26 20:44 | 顯示全部樓層
18434225 發(fā)表于 2021-11-26 18:45
從你這個(gè)圖可以看出,那個(gè)脈沖是你每次進(jìn)去之后GP0=~GP0取反的結(jié)果,后面變低是因?yàn)槟阌諫P1=!GP0,使其變低 ...

正半周25us+負(fù)半周25us,總周期是50us哪來(lái)的40KHZ,這個(gè)單片機(jī)20KHZ都可能做不督到,還40K
雙腳輸出互補(bǔ)的方波如果拿來(lái)驅(qū)動(dòng)逆變半橋,GP1=GP0想想是什么后果?再都為了試驗(yàn),前面說(shuō)過(guò)都試過(guò)了,沒(méi)有變化,是一樣的。這東西折騰很久了,不是我執(zhí)著,論個(gè)所以然,早就放棄了……
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-11-26 21:34 | 顯示全部樓層
老哥, 你說(shuō)…… ,會(huì)不會(huì)是因?yàn)椋?br />
ANSEL = 0; 這句沒(méi)寫的關(guān)系?

我琢磨了很久,你在頂樓說(shuō)的,刪除了GP1 = !GP0;  就沒(méi)輸出了, 你覺(jué)得不應(yīng)該,我也覺(jué)得不應(yīng)該,所以,我在想,是不是一開(kāi)始咱們就沒(méi)找對(duì)方向? 其實(shí)就是端口的初始化沒(méi)有做好? 所以沒(méi)有輸出?
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-27 09:08 | 顯示全部樓層
188610329 發(fā)表于 2021-11-26 21:34
老哥, 你說(shuō)…… ,會(huì)不會(huì)是因?yàn)椋?br />
ANSEL = 0; 這句沒(méi)寫的關(guān)系啊?

ANSEL寄存器是為模擬信號(hào)輸入設(shè)置寄存器和它沒(méi)關(guān)系,端口就這兩個(gè)寄存器TRISIO和GPIO
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-27 09:23 | 顯示全部樓層
xxll 發(fā)表于 2021-11-26 20:44
正半周25us+負(fù)半周25us,總周期是50us哪來(lái)的40KHZ,這個(gè)單片機(jī)20KHZ都可能做不督到,還40K
雙腳輸出互補(bǔ) ...

#include <pic.h>
#define uchar unsigned char
uchar ON;
void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO=0X00;
        }
void timer0_init(void) //定時(shí)器0初始化使用系統(tǒng)默認(rèn)時(shí)鐘4M fosc/4 所以計(jì)數(shù)周期為1us
        {
                T0CS=0;    //timer0工作于定時(shí)器方式
                PSA=1;     //timer0不分頻
                T0IF=0;    //清timer0中斷標(biāo)志
                TMR0=224; /*置初值 20KHz的半個(gè)周期為25us*/
                T0IE=1;    //timer0中斷允許
                GIE=1;     //開(kāi)全局中斷
        }

        void interrupt isr(void)   //中斷子程序
                {
                        TMR0=224; //定時(shí)器0置初值25us               
                        T0IF=0;    //清中斷標(biāo)志                                       
                if(ON)
                        {
        //                TMR0=224; //定時(shí)器0置初值25us               
        //                T0IF=0;    //清中斷標(biāo)志                       
                        GP2=0;
                        GP1=1;
                        ON=0;
                        }
                else
                        {
                //        TMR0=224; //定時(shí)器0置初值25us               
                //        T0IF=0;    //清中斷標(biāo)志
                        GP1=0;
                        GP2=1;
                        ON=1;                       
                        }
       
                //        GP0=~GP0;  //GP0位取反
                //        GP1=!GP0;  //使GP1引腳取反GP0               
               
                        /*在這里廢寢忘食3總天,一度引起孫子的奶奶發(fā)飆
                                也沒(méi)有折騰出正確的結(jié)果*/                                
                }  
void main(void)          //主程序
        {
                OSCCONbits.IRCF0=1;
                OSCCONbits.IRCF1=1;
                OSCCONbits.IRCF2=1;//此3條設(shè)置時(shí)鐘為8M
                IO_init();         //引腳初始化函數(shù)
                timer0_init();     //定時(shí)器0初始化函數(shù)
                GP1=1;
                GP2=0;
                while(1)    //死循環(huán)
                {
               
                       
                }
                       
        }
花括號(hào)里的順序誰(shuí)在前誰(shuí)就是窄脈沖,和TMR0、T0IF所在位置無(wú)關(guān),但和頻率高低有較大的關(guān)系。稍后我將發(fā)個(gè)統(tǒng)計(jì)表格上來(lái)供大家研究!

GAS0002副本.jpg
GAS0004副本.jpg
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2021-11-27 12:00 | 顯示全部樓層
xxll 發(fā)表于 2021-11-27 09:08
ANSEL寄存器是為模擬信號(hào)輸入設(shè)置寄存器和它沒(méi)關(guān)系,端口就這兩個(gè)寄存器TRISIO和GPIO

你試過(guò)增加ANSEL=0x00;這語(yǔ)句沒(méi)有?
ANSEL 是要先清除的!
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2021-11-27 12:25 | 顯示全部樓層
xxll 發(fā)表于 2021-11-27 09:08
ANSEL寄存器是為模擬信號(hào)輸入設(shè)置寄存器和它沒(méi)關(guān)系,端口就這兩個(gè)寄存器TRISIO和GPIO

還要添加一條:
CMCON0=0x07;
回復(fù)

使用道具 舉報(bào)

ID:27513 發(fā)表于 2021-11-27 19:56 | 顯示全部樓層
Y_G_G 發(fā)表于 2021-11-26 14:36
還在折騰這個(gè)?
TMR0=0xE0(224),定時(shí)器就是256-224=32
如果你是用4MHZ時(shí)鐘,那么,定時(shí)器的中斷時(shí)間是不低于 ...

關(guān)于這里的TMRO=224是因?yàn)闀r(shí)鐘是8M時(shí)設(shè)的值,(256-224)*0.5=16us在8M時(shí)鐘時(shí)CPU執(zhí)行中斷大約耗費(fèi)9us (后面也證實(shí)了),16+9=25
回復(fù)

使用道具 舉報(bào)

ID:624769 發(fā)表于 2021-11-27 20:17 | 顯示全部樓層
xxll 發(fā)表于 2021-11-27 09:08
ANSEL寄存器是為模擬信號(hào)輸入設(shè)置寄存器和它沒(méi)關(guān)系,端口就這兩個(gè)寄存器TRISIO和GPIO

從你發(fā)的手冊(cè)上看,

ANSEL 控制引腳是模擬輸入,還是數(shù)字輸出。
如果 有 位置1則為模擬輸入,如果該位置0則為數(shù)字輸出。
手冊(cè)上看,上電后 ANSEL 的初值不為0。
并且,手冊(cè)上還說(shuō),上電后端口初始化 ANSEL 需要 置 0 復(fù)位。
另外,和GPIO有關(guān)的寄存器,總共有11個(gè),
GPIO.png
此表中,沒(méi)有打陰影的部分,都是會(huì)影響GPIO的輸出的設(shè)置。
通過(guò)此表也能看到,ANSEL 不設(shè)置0的話,GPIO0~GPIO3 默認(rèn)為模擬輸入。
回復(fù)

使用道具 舉報(bào)

ID:342822 發(fā)表于 2021-11-27 22:34 | 顯示全部樓層
雖然占空比沒(méi)達(dá)到百分之50,但已經(jīng)是互補(bǔ)方波了 屏幕截圖(76).png



/* Main.c file generated by New Project wizard
*
* Created:   周六 11月 27 2021
* Processor: PIC12F683
* Compiler:  HI-TECH C for PIC10/12/16
*/

#include <pic.h>

__CONFIG(0x0054);

#define uchar unsigned char
#define uint unsigned int

uchar flag,flag1;

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO==0b00000000;

        }
void timer0_init(void) //定時(shí)器0初始化使用系統(tǒng)默認(rèn)時(shí)鐘4M fosc/4 所以計(jì)數(shù)周期為1us
        {
                T0CS=0;    //timer0工作于定時(shí)器方式
                PSA=1;     //timer0不分頻
                T0IF=0;    //清timer0中斷標(biāo)志
                TMR0=224; /*置初值 20KHz的半個(gè)周期為25us*/
                T0IE=1;    //timer0中斷允許
                GIE=1;     //開(kāi)全局中斷
        }


void main(void)          //主程序
        {

                IO_init();         //引腳初始化函數(shù)
                timer0_init();     //定時(shí)器0初始化函數(shù)

                while(1)    //死循環(huán)
                {
                               if(flag)
                                        {
                                                GPIO=0B00000001;

                                        }
                                        else
                                        {
                                                 GPIO=0B00000010;

                                        }



                }

        }

void interrupt isr(void)   //中斷子程序
        {

                T0IF=0;    //清中斷標(biāo)志
                                TMR0=224; //定時(shí)器0置初值25us

                                flag = !flag;

        }  

回復(fù)

使用道具 舉報(bào)

ID:342822 發(fā)表于 2021-11-28 00:10 | 顯示全部樓層
本帖最后由 taotie 于 2021-11-29 14:49 編輯

屏幕截圖(111).png

相差無(wú)幾
時(shí)鐘8Mhz,標(biāo)志判斷的內(nèi)容由死循環(huán)轉(zhuǎn)到中斷子程序中。
初值設(shè)置為225     方波頻率=20000hz


* Created:   周六 11月 27 2021
* Processor: PIC12F683
* Compiler:  HI-TECH C for PIC10/12/16
*/

#include <pic.h>

__CONFIG(0x0054);

#define uchar unsigned char
#define uint unsigned int

uchar flag,flag1;

void IO_init(void) /*端口初始化*/
        {
                TRISIO=0x00;
                GPIO==0b00000000;

        }
void timer0_init(void) //定時(shí)器0初始化使用系統(tǒng)默認(rèn)時(shí)鐘4M fosc/4 所以計(jì)數(shù)周期為1us
        {
                T0CS=0;    //timer0工作于定時(shí)器方式
                PSA=1;     //timer0不分頻
                T0IF=0;    //清timer0中斷標(biāo)志
                TMR0=225; /*置初值 20KHz的半個(gè)周期為25us*/
                T0IE=1;    //timer0中斷允許
                GIE=1;     //開(kāi)全局中斷
        }


void main(void)          //主程序
        {

                IO_init();         //引腳初始化函數(shù)
                timer0_init();     //定時(shí)器0初始化函數(shù)

                while(1)    //死循環(huán)
         {      

}
        }

void interrupt isr(void)   //中斷子程序
        {

               //T0IF=0;    //清中斷標(biāo)志
                TMR0=225; //定時(shí)器0置初值25us
{
                if(flag)
         {
                      GPIO=0B00000001;

                }
                         else
                     {
                         GPIO=0B00000010;

                      }

                        T0IF=0;

                }

                             flag = !flag;                       

        }  

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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