會員登陸
帳號:

密碼:

記住我



忘記密碼?

現在註冊!
網站導航
最新下載
訪問統計 (自2012/5/3)


正在流覽:   1 名訪客





PIC16F877A外部中斷RB電平變化觸發請教
新會員
註冊日期:
6月05日 13:34:09
所屬群組:
註冊會員
文章: 2
等級: 1; EXP: 2
HP : 0 / 0
MP : 0 / 0
離線
感謝進來的前輩指導。我是剛入門的菜鳥!
目前我想設計用按鈕外部觸發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++);
}
}

6月05日 15:09:15
轉換PDF檔 列印


Re: PIC16F877A外部中斷RB電平變化觸發請教
新會員
註冊日期:
2018/08/22 16:17
所屬群組:
註冊會員
文章: 3
等級: 1; EXP: 10
HP : 0 / 2
MP : 1 / 9
離線
你所使用的 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=0 ;
  }
}



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

6月09日 14:35:03
轉換PDF檔 列印


Re: PIC16F877A外部中斷RB電平變化觸發請教
版主
註冊日期:
2004/04/30 10:53
來自 CAE, Microchip
所屬群組:
站務管理者
註冊會員
MICROCHIP
文章: 14850
等級: 73; EXP: 60
HP : 1089 / 1815
MP : 4950 / 82417
離線
感謝網友 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 ;
}
}

6月10日 11:35:33
轉換PDF檔 列印


Re: PIC16F877A外部中斷RB電平變化觸發請教
新會員
註冊日期:
6月05日 13:34:09
所屬群組:
註冊會員
文章: 2
等級: 1; EXP: 2
HP : 0 / 0
MP : 0 / 0
離線
感謝版友回答,研究到現在發現除了程式外,學習板的配置也有問題。
目前重新設計電路板的部份,時間會較久,晚點再來回覆心得。^^
謝謝

6月18日 09:08:21
轉換PDF檔 列印






無法在此發表文章
可以在此觀看文章
無法回覆文章
無法編輯自己的文章
無法刪除自己的文章
無法發起投票調查
無法在此投票
無法上傳附加檔案
無法不經審核直接發表文章

[進階搜尋]


搜尋
Microchip連結
產品技術問題產品技術支援專線:0800-717718 台北02-25088600 新竹03-5778366 Ext. 8600 高雄07-2137830 MicrochipDIRECT 專線: 07-2137830
Powered by XOOPS © 2001-2012 The XOOPS Project