реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> прерывания PIC
HarieR
сообщение May 5 2010, 07:25
Сообщение #1





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



Помогите нубу с прерываниями, плиз. По нажатию кнопки RB0 (pic16f887) должно измениться состояние светодиодов на порту PORTD. Все вроде должно работать, ан-нет. Прошу помощи у PIC-гуру smile.gif . Ниже код:
Код
unsigned short counter;
void interrupt()
{
  if(INTCON.INTF)
  {
      counter++;
        if (counter > 8)
        {
          PORTD=~PORTD; //PORTD - меняем состояние на противопол  
          counter=0;
        }
    INTCON.INTF=0;
   }
}// interrupt

void Init()
{
   TRISB=0b00000001; //RB0 - вход
   TRISD=0b00000000; //PORTD - все выходы
   PORTD=0b00000000; //PORTD - не горят          
   OPTION_REG = 0x87;  
   INTCON.INTE=1; //включаем прерыв на порту RB0    
   INTCON.GIE=1;   //разрешаем все прерывания  
}// Init

void main()
{
   Init();
   while(1)
  {          
   }
}
Go to the top of the page
 
+Quote Post
Vlad27
сообщение May 5 2010, 07:57
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 95
Регистрация: 31-07-05
Из: Полоцк Беларусь
Пользователь №: 7 227



Перепишите строку PORTD=~PORTD; на PORTD=^0xFF;
Не забывайте что при обращении к порту выполняется операция <чтение-модификация-запись>.
Как вариант, добавить переменную static volatile unsigned char temp=0;
temp ^= 0xFF;
PORTD = temp;
Ну, надеюсь, мысль понятна.

Сообщение отредактировал Vlad27 - May 5 2010, 08:18
Go to the top of the page
 
+Quote Post
xemul
сообщение May 5 2010, 07:58
Сообщение #3



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Устранение дребезга
Или Вы предполагали, что counter этим и занимается?
Go to the top of the page
 
+Quote Post
HarieR
сообщение May 5 2010, 08:42
Сообщение #4





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



переписал с учетом советов:
Код
static volatile unsigned char temp=0;
void interrupt()
{
     if(INTCON.INTF)
     {
      if (PORTB.F0==1)
      {
       delay_ms(20);
       if(PORTB.F0==1)
       {
        temp = 0xFF;
        PORTD = temp; // инверсия уровней на выводах PORTD
       }
      }
      INTCON.INTF=0;
     }
}// interrupt
void Init()
{
     TRISB=0b00000001;
     TRISD=0b00000000;
     PORTD=0b00000001;          
     OPTION_REG = 0x87;  
     INTCON.INTE=1;    
     INTCON.GIE=1;      
}// Init
void main()
{
     Init();
     while(1) {}
}

не работает laughing.gif
Go to the top of the page
 
+Quote Post
xemul
сообщение May 5 2010, 08:57
Сообщение #5



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(HarieR @ May 5 2010, 12:42) *
переписал с учетом советов:
...
не работает laughing.gif

Где и какие советы Вы учли, не понял.
Ваш код может сделать только PORTD = 0xFF, но не наоборот. Уберите temp за ненадобностью (PORTD и так объявлен volatile) и напишите PORTD ^= 0xFF, как советовали, или PORTD = ~PORTD - в Вашем случае (TRISD=0b00000000;) без разницы.
delay_ms() в прерывании (да и вообще) - имхо, моветон.
Go to the top of the page
 
+Quote Post
Vlad27
сообщение May 5 2010, 09:06
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 95
Регистрация: 31-07-05
Из: Полоцк Беларусь
Пользователь №: 7 227



Не делайте таких обработчиков прерываний, прерывания должны обрабатывться по-возможности быстро.
Лучше устанавливайте флаг, а задержку реализуйте в main.
Код
static volatile unsigned char temp=0;
static unsigned char flag;
void interrupt()
{
     if(INTCON.INTF)
     {
         temp ^= 0xFF;
         PORTD = temp; // инверсия уровней на выводах PORTD
         flag = 1;
         INTCON.INTF=0;
     }
}// interrupt

void main() {
   Init();
   while(1) {
     if (flag == 1) {
       flag = 0;
       delay_ms(20);
     }
   }
}
Go to the top of the page
 
+Quote Post
xemul
сообщение May 5 2010, 09:39
Сообщение #7



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Буфер для вывода имеет смысл вводить, если требуется какая-либо синхронизация вывода или TRIS меняется в процессе. Здесь же достаточно:
Код
#define TRISD_MASK 0b01010101 // для разнообразия
#define PORTD_INVERSION_MASK (0b00001010 & ~TRISD_MASK) // инвертируем 1 и 3 биты

PORTD ^= PORTD_INVERSION_MASK;


static unsigned char flag; должен быть volatile, иначе if (flag == 1) { flag = 0; ... } в примере будет соптимизировано напрочь.
Go to the top of the page
 
+Quote Post
HarieR
сообщение May 5 2010, 09:51
Сообщение #8





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



сделал без флагов, обработки дребезга и т.д.
Код
void interrupt()
{
     if(INTCON.INTF)
     {
        
         PORTD=~PORTD;
    
         INTCON.INTF=0;
     }
}// interrupt
void Init()
{
     TRISB=0b00000001;
     TRISD=0b00000000;
     OPTION_REG = 0x87;  
     INTCON.INTE=1;      
     INTCON.GIE=1;      
}// Init
void main() {

   Init();
   while(1) { }
   }
}

результат 0
Go to the top of the page
 
+Quote Post
xemul
сообщение May 5 2010, 10:00
Сообщение #9



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(HarieR @ May 5 2010, 13:51) *
сделал без флагов, обработки дребезга и т.д.
...
результат 0

Сразу не заметил. Вы уверены, что
void interrupt()
компилятору достаточно, чтобы сообразить, что это подпрограмма обработки прерываний?
Go to the top of the page
 
+Quote Post
HarieR
сообщение May 5 2010, 10:03
Сообщение #10





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



да, с прерыванием по TOIF все работает
Go to the top of the page
 
+Quote Post
Vlad27
сообщение May 5 2010, 10:26
Сообщение #11


Частый гость
**

Группа: Свой
Сообщений: 95
Регистрация: 31-07-05
Из: Полоцк Беларусь
Пользователь №: 7 227



Цитата(HarieR @ May 5 2010, 13:03) *
да, с прерыванием по TOIF все работает

То есть, прерывание INT не возникает? В таком случае тупой вопрос, как кнопка подключена?
Go to the top of the page
 
+Quote Post
xemul
сообщение May 5 2010, 10:28
Сообщение #12



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(HarieR @ May 5 2010, 14:03) *
да, с прерыванием по TOIF все работает

Гуманный компилятор - экономит пальцы и клавиатуру.
Если проверяете в железе, то остаётся вариант - очень_чётная_кнопка, которая принципиально выдаёт только чётное число импульсов дребезга.
Ой, ещё одно (странное) предположение - на RB0 нет резистора привязки к gnd или vcc, но тогда прерывания должны легко генериться наводкой от пальца.
Не пробовали проверить в симуляторе?
Go to the top of the page
 
+Quote Post
HarieR
сообщение May 5 2010, 10:37
Сообщение #13





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



подключена нормально, на минус через резистор. Тестовые программы работают, эта - нет
Go to the top of the page
 
+Quote Post
xemul
сообщение May 5 2010, 10:44
Сообщение #14



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(HarieR @ May 5 2010, 14:37) *
подключена нормально, на минус через резистор. Тестовые программы работают, эта - нет

"Нормально" в этом случае будет: vcc - R - RB0 - btn - gnd, а не RB0 - R - btn - gnd.
Или включите внутреннюю привязку для RB0 (RBPU = 0 в OPTION, WPUB = 1).
Go to the top of the page
 
+Quote Post
HarieR
сообщение May 7 2010, 10:11
Сообщение #15





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



добавил две волшебные строчки, программа ожила:
ANSEL = 0;
ANSELH = 0;
теперь рабочий код такой:
Код
void interrupt()
{
     if(INTCON.INTF)
     {

         PORTD=~PORTD;

         INTCON.INTF=0;
     }
}// interrupt
void Init()
{
     ANSEL  = 0;
      ANSELH = 0;
     TRISB=0b00000001;
     TRISD=0b00000000;
     OPTION_REG = 0x87;
     INTCON.INTE=1;
     INTCON.GIE=1;
}// Init
void main() {

   Init();
   while(1) { }
   }

подтяжка RB0 к gnd через 10k и внутренняя подтяжка PORTB отключена: /RPBU=1.
Вопрос: каким образом могли повлиять на работу регистры ANSEL и ANSELH?
Go to the top of the page
 
+Quote Post
Guest_@Ark_*
сообщение May 7 2010, 10:45
Сообщение #16





Guests






Цитата
Вопрос: каким образом могли повлиять на работу регистры ANSEL и ANSELH?

Непосредственным. Эти регистры задают режимы работы портов - аналоговый или цифровой. После старта (сброса) - устанавливается аналоговый режим. Нужно правильно настраивать порты, прежде чем ими пользоваться.
Go to the top of the page
 
+Quote Post
HarieR
сообщение May 7 2010, 11:03
Сообщение #17





Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075



Спасибо большое всем за помощь!


вешаю кнопку на RB4 и меняю программу, чтобы прерывание срабатывало с нее:
Код
void interrupt()
{
     if(INTCON.RBIF)
     {

         PORTD=~PORTD;

         INTCON.RBIF=0;
     }
}// interrupt
void Init()
{
     ANSEL  = 0;
     ANSELH = 0;
     TRISB=0b00010000;
     TRISD=0b00000000;
     OPTION_REG = 0b10000111;
     INTCON.RBIE=1;
     INTCON.GIE=1;
}// Init
void main() {

   Init();
   while(1) { }
   }

не работает! в чем ошибка, пните плиз

Сообщение отредактировал HarieR - May 7 2010, 11:04
Go to the top of the page
 
+Quote Post
evc
сообщение May 7 2010, 13:35
Сообщение #18


Местный
***

Группа: Свой
Сообщений: 206
Регистрация: 17-03-07
Из: Москва
Пользователь №: 26 266



Посмотрите регистр IOCB. Стр. 49/ds


--------------------
УЭР
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 16:45
Рейтинг@Mail.ru


Страница сгенерированна за 0.01524 секунд с 7
ELECTRONIX ©2004-2016