:::


Browsing this Thread:   1 Anonymous Users






PIC16F877A外部中斷RB電平變化觸發請教
#1
新會員
新會員


查看用戶資訊
感謝進來的前輩指導。我是剛入門的菜鳥!
目前我想設計用按鈕外部觸發RB0-RB7電位變化中斷,下面程式目標是按鈕按下觸發中斷則LED顯示累加的數字。
目前狀況:程式下載到晶片後,會一直觸發中斷致使led顯示MONEY的數值一直刷新。
目標:RB0~RB7可以按下按鈕觸發外部中斷。
以下是程式碼,謝謝。

#include <pic.h>

__CONFIG(HS&WDTDIS&LVPDIS);

//---------------------------------------
//數碼管字形表,供顯示時查詢
const unsigned char LED[]=
{ //定義表格一定要使用const,這樣會做到程序存儲區中
0xc0,0xf9,0xa4,0xb0,//0~3
0x99,0x92,0x82,0xf8,//4~7
0x80,0x90,//8~9
};

#define P1 RB0 //定義獨立按鍵P1為RC0
#define P2 RB1 //定義獨立按鍵P2為RC1
#define P3 RB2 //定義獨立按鍵P3為RC2
#define P4 RB3 //定義獨立按鍵P4為RC3
unsigned int Money=0,Wanter;//投$、流量。

void delay(unsigned int count);
void interrupt ISR(void);

void main(void) //主函數,單片機開機後就是從這個函數開始運行
{
TRISE&=0XFC; //初始化RE為輸出方向
TRISD=0x00; //初始化RD為輸出方向
TRISB=0XFF; //初始化RB為輸入方向

PORTD=0xFF; //初始化RD的數值
PORTE=0xFD; //初始化RE的數值

RBIF=0;
RBIE=1;
GIE=0;//打開這個埠GIE全區中斷。RBIF端口B中斷

while(1) //死循環,單片機初始化後,將一直運行這個死循環
{
}
}

void interrupt ISR(void)
{
if(RBIE==1&&RBIF==1)
{

Money=Money+1;
PORTE=0xFE;
PORTD=LED[Money];
delay(500);
RBIF=0 ;
}
}



void delay(unsigned int count)
{
unsigned int a,i;
for(i=0;i<count;i++)
{
for(a=0;a<200;a++);
}
}

發表於: 2019/6/5 15:09
Twitter Facebook Google Plus Linkedin Del.icio.us Digg Reddit Mr. Wong 頂部


Re: PIC16F877A外部中斷RB電平變化觸發請教
#2
新會員
新會員


查看用戶資訊
你所使用的 pic16f877A 已經是蠻舊的型號了,
其中, 它的 interrupt-on-change 只有在 RB4 <-> RB7,
並不是全部的腳位! (4支腳位)
不過, 在 RB0 腳位還有一 "外部中斷" 可使用,
但是它在一時間內只能設定為 上緣 或 下緣.

對 PIC16F877A 來說,
RBIF 的清除需要額外讀 PORTB 一次來更新 RB 狀態,
倒不是有什麼特別原因, 單單只是當時的設計是這樣.
(請在清除 RBIF 前做讀 PORTB 更新狀態的動作)
相關資料請查看 PIC16F877A 或 PIC16F87xA 的手冊,
位於 I/O PORT 中的 PORTB 內之敘述.

對於您所貼出的 code 中,
GIE=0;//打開這個埠GIE全區中斷。RBIF端口B中斷
請記得把它再更改回 GIE=1;
這樣測試時才能正常進入中斷功能.

另外, 因為是 interrupt-on-change 的中斷類型,
建議中斷內不需要 delay 這動作,
應該只在 上緣/下緣 兩處會有中斷動作,
測試時, 使用較長的按壓時間來測試,
這樣應該可以分辨的出兩處分別動作的情況.

再一個另外, 可使用 PORTB 的 RBPU 弱提升,
它是弱提升至 VDD 的設計,
用於 I/O 腳位無任何外部連接時穩定腳位輸入狀態,
在 PIC16F877A 中,
是 清除 OPTION_REG 的第7位元 來致能弱提升.
(當然您也可以自行連接使用想用的外部電阻做提升)

------------------------------------------------------------------------
#include <pic.h>

__CONFIG(HS&WDTDIS&LVPDIS);

//---------------------------------------
//數碼管字形表,供顯示時查詢
const unsigned char LED[]=
{ //定義表格一定要使用const,這樣會做到程序存儲區中
0xc0,0xf9,0xa4,0xb0,//0~3
0x99,0x92,0x82,0xf8,//4~7
0x80,0x90,//8~9
};

#define P1 RB0 //定義獨立按鍵P1為RC0
#define P2 RB1 //定義獨立按鍵P2為RC1
#define P3 RB2 //定義獨立按鍵P3為RC2
#define P4 RB3 //定義獨立按鍵P4為RC3
unsigned int Money=0,Wanter;//投$、流量。

void delay(unsigned int count);
void interrupt ISR(void);

void main(void) //主函數,單片機開機後就是從這個函數開始運行
{
TRISE&=0XFC; //初始化RE為輸出方向
TRISD=0x00; //初始化RD為輸出方向
TRISB=0XFF; //初始化RB為輸入方向

PORTD=0xFF; //初始化RD的數值
PORTE=0xFD; //初始化RE的數值

OPTION_REG &= 0x7F; /* 致能使用 *RB_PU */
OPTION_REG &= 0x7F; /* 致能使用 *RB_PU */
PORTB = PORTB; /* 更新 PORTB 的記錄狀態 */
RBIF=0;
RBIE=1;
GIE=1;//打開這個埠GIE全區中斷。RBIF端口B中斷

while(1) //死循環,單片機初始化後,將一直運行這個死循環
{
}
}

void interrupt ISR(void)
{
if(RBIE==1&&RBIF==1)
{
PORTB = PORTB; /* 更新 PORTB 的記錄狀態 */

Money=Money+1;
PORTE=0xFE;
PORTD=LED[Money];
/* delay(500); */ //不做 delay
RBIF=0 ;
}
}



void delay(unsigned int count)
{
unsigned int a,i;
for(i=0;i<count;i++)
{
for(a=0;a<200;a++);
}
}

#include <pic.h>

__CONFIG(HS&WDTDIS&LVPDIS);

//---------------------------------------
//數碼管字形表,供顯示時查詢
const unsigned char LED[]=
//定義表格一定要使用const,這樣會做到程序存儲區中
0xc0,0xf9,0xa4,0xb0,//0~3
0x99,0x92,0x82,0xf8,//4~7
0x80,0x90,//8~9
};

#define P1 RB0 //定義獨立按鍵P1為RC0
#define P2 RB1 //定義獨立按鍵P2為RC1
#define P3 RB2 //定義獨立按鍵P3為RC2
#define P4 RB3 //定義獨立按鍵P4為RC3
unsigned int Money=0,Wanter;//投$、流量。

void delay(unsigned int count);
void interrupt ISR(void);

void main(void//主函數,單片機開機後就是從這個函數開始運行
{
  
TRISE&=0XFC//初始化RE為輸出方向
  
TRISD=0x00//初始化RD為輸出方向
  
TRISB=0XFF//初始化RB為輸入方向

  
PORTD=0xFF//初始化RD的數值
  
PORTE=0xFD//初始化RE的數值

  
OPTION_REG &= 0x7F;   /*   致能使用 *RB_PU   */
  
OPTION_REG &= 0x7F;   /*   致能使用 *RB_PU   */
  
PORTB PORTB;   /*   更新 PORTB 的記錄狀態   */
  
RBIF=0;
  
RBIE=1;
  
GIE=1;//打開這個埠GIE全區中斷。RBIF端口B中斷

  
while(1//死循環,單片機初始化後,將一直運行這個死循環
  
{
  }
}

void interrupt ISR(void)
{
  if(
RBIE==1&&RBIF==1)
  {
    
PORTB PORTB;   /*   更新 PORTB 的記錄狀態   */

    
Money=Money+1;
    
PORTE=0xFE;
    
PORTD=LED[Money];
/*    delay(500);   */  //不做 delay
    
RBIF=;
  }
}



void delay(unsigned int count)
{
  
unsigned int a,i;
  for(
i=0;i<count;i++)
  {
    for(
a=0;a<200;a++);
  }
}

發表於: 2019/6/9 14:35
Twitter Facebook Google Plus Linkedin Del.icio.us Digg Reddit Mr. Wong 頂部


Re: PIC16F877A外部中斷RB電平變化觸發請教
#3
版主
版主


查看用戶資訊
感謝網友 him 的解答,him 果然是高手,問題都解得很清楚,謝謝。

參於中斷裡的 PORTB = PORTB 這個動作是很重要的。因為是使用 IOP 的中動方式,所以 PORTB<7:4> 任何一隻腳有準位上的改變時就會產生 IOP 的中斷。但下一次的中斷也是要做準位地變化的偵測。
所以在離開中斷時就須做個假讀取的動作將目前 PB7:PB4 的狀態讀進來到內部的 D-Type Latch 與輸入腳位一起送到 XOR Gate 比較,以便於下一次的準位變化偵測。


PORTB = PORTB; /* 更新 PORTB 的記錄狀態 */
RBIF=0;
RBIE=1;
GIE=1;//打開這個埠GIE全區中斷。RBIF端口B中斷


void interrupt ISR(void)
{
if(RBIE==1&&RBIF==1)
{
PORTB = PORTB; /* 更新 PORTB 的記錄狀態 */

Money=Money+1;
PORTE=0xFE;
PORTD=LED[Money];
/* delay(500); */ //不做 delay
RBIF=0 ;
}
}

發表於: 2019/6/10 11:35
Twitter Facebook Google Plus Linkedin Del.icio.us Digg Reddit Mr. Wong 頂部


Re: PIC16F877A外部中斷RB電平變化觸發請教
#4
新會員
新會員


查看用戶資訊
感謝版友回答,研究到現在發現除了程式外,學習板的配置也有問題。
目前重新設計電路板的部份,時間會較久,晚點再來回覆心得。^^
謝謝

發表於: 2019/6/18 9:08
Twitter Facebook Google Plus Linkedin Del.icio.us Digg Reddit Mr. Wong 頂部







You can view topic.
You cannot start a new topic.
You cannot reply to posts.
You cannot edit your posts.
You cannot delete your posts.
You cannot add new polls.
You cannot vote in polls.
You cannot attach files to posts.
You cannot post without approval.
You cannot use topic type.
You cannot use HTML syntax.
You cannot use signature.
You cannot create PDF files.
You cannot get print page.

[進階搜尋]