Форум по микроконтроллерам: pic12f629 b обработка прерывания - Форум по микроконтроллерам

Перейти к содержимому

Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

pic12f629 b обработка прерывания

#1 Пользователь офлайн   yeye77 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 5
  • Регистрация: 17 Май 17

Отправлено 18 Май 2017 - 13:21

Здравствуйте!
Пытаюсь освоить программирование МК. Написал первую прогу - помигал светодиодами, понажимал кнопками. Работает. Хочу написать прогу под следующую схему: нажатие кнопки - включение светодиода, дальнейшее нажатие с плавным увеличением яркости. Для этого необходимо использование прерываний и ШИМ. На прерывании у меня получилась первая затычка, не могу понять почему не работает.

#include <xc.h>
#include <pic.h>
#pragma config BOREN = OFF, MCLRE = OFF, PWRTE = ON, WDTE = OFF, FOSC = INTRCIO
#define _XTAL_FREQ 4000000
#define LEDG GPIO2
#define LEDR  GPIO1
#define knopka GPIO4
#define knopka2 GPIO5

unsigned char cnt=0;
void interrupt isr(void)
{ 
	if(GPIF)
	{
		cnt++;
		GPIF=0;
	}
}
void main() 
{
    GIE = 0;
	PEIE = 0;
    GPIE = 0;

    //TRISIO = 0x8;
    CMCON = 0x07;
    TRISIO = 0b111001;
    GPIO = 0;
    IOCB4 = 1;
    
    PEIE = 1;
	GIE  = 1;
    GPIE = 1;
    while (1)
    {
        if (cnt==2)
        {__delay_ms(100); LEDG=1; LEDR=0; __delay_ms(100);}
        if (cnt==4)
        {__delay_ms(100); LEDG=0; LEDR=1; __delay_ms(100); cnt=0;}
    }
}

0

#2 Пользователь офлайн   Alex 

  • Убиватель МК
  • PipPipPipPip
  • Группа: Пользователи
  • Сообщений: 1 886
  • Регистрация: 15 Февраль 11

Отправлено 18 Май 2017 - 23:58

Цитата

На прерывании у меня получилась первая затычка, не могу понять почему не работает
Какая затычка ? Что не работает ?
Не говорите что мне делать, и я не скажу куда Вам идти !
0

#3 Пользователь офлайн   boatcall 

  • Знаток
  • PipPip
  • Группа: Пользователи
  • Сообщений: 70
  • Регистрация: 29 Октябрь 14
  • ГородКрасноярск

Отправлено 19 Май 2017 - 08:07

Смотрел по диагонали, но снимать флаг прерывания GPIO Change Interrupt у PIC надо по-другому, хотя-бы так:

Просмотр сообщенияyeye77 (18 Май 2017 - 13:21) писал:

...
void interrupt isr(void)
{ 
	if( GPIE && GPIF )
	{
		cnt++;
		GPIO;
	}
}
...


Т.е. нужно просто обратиться к порту, читать, записать, что угодно, в общем. В даташите они пишут:

Цитата

The user, in the Interrupt Service Routine, clears the interrupt by:
a) Any read or write of GPIO. This will end the mismatch condition, then,
b)Clear the flag bit GPIF.

Может в Microchip что-то поменяли, но на ранних PIC только чтением порта флаг прерывания снимался, писать GPIF=0 было вообще необязательно, как теперь в нынешних с этим обстоит, не знаю, может быть так теперь GPIF = 0 ; нужно писать обязательно, но чтение порта нужно делать по-любому.

Сообщение отредактировал boatcall: 19 Май 2017 - 08:17

0

#4 Пользователь офлайн   yeye77 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 5
  • Регистрация: 17 Май 17

Отправлено 19 Май 2017 - 10:41

Спасибо за отклик.
Alex, под неработой подразумевал отсутствие реакции на нажатие кнопки.
boatcall, странно, видимо чтение флага перепутал с чтением портов, добавил то, что вы посоветовали, заработало. Но работает странно, доходит до определенного кол-ва нажатий кнопки и горит только один светодиод. Видимо нужно добавлять задержки. Можно ли их добавлять в подпрограмму обработки прерываний? Как лучше это решить? И вообще, правильно ли будет совместить обработку прерываний от кнопки и таймера с учетом поставленной задачи?

Еще принципиальный вопрос. В поиске решения читал много мнений, касающегося подпрограммы обработки прерываний. Считается, что в подпрограмме лучше ничего не делать кроме чтения/записи и сброса флагов, остальные вычисления/действия производить вне этой подпрограммы. Так ли это?
0

#5 Пользователь офлайн   Alex 

  • Убиватель МК
  • PipPipPipPip
  • Группа: Пользователи
  • Сообщений: 1 886
  • Регистрация: 15 Февраль 11

Отправлено 19 Май 2017 - 11:26

попробуйте так :
        if (cnt>=4)
        {__delay_ms(100); LEDG=0; LEDR=1; __delay_ms(100); cnt=0;}
        else if (cnt>=2)
        {__delay_ms(100); LEDG=1; LEDR=0; __delay_ms(100);}

Возможно, значение счётчика перескакивает за значение 4 до того, как программа доходит до условия.
И на будущее, примите за правило вставлять в условия сравнения операторы "больше" или "меньше", если не нужно явное сравнение на равенство.
Не говорите что мне делать, и я не скажу куда Вам идти !
0

#6 Пользователь офлайн   yeye77 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 5
  • Регистрация: 17 Май 17

Отправлено 19 Май 2017 - 12:31

Интересно. Для четкой фиксации нажатий кнопок я использовал след.конструкцию:
if (knopka==1 && cnt==0)
        {__delay_ms(20); LEDG=1; __delay_ms(20);  LEDR=0; 
        __delay_ms(20); while(knopka);
        cnt++;
        }


Работает как надо. Но состыковать это с ШИМ у меня не получилось (ШИМ честно содрал с раб.кода. Просто ШИМ без обработки кнопок работает). При первом нажатии диод загорается. Однако согласно задумке, инкрементации яркости и гашения светодиода не происходит. Ниже листинг:

#include <xc.h>
#pragma config BOREN = OFF, MCLRE = OFF, PWRTE = ON, WDTE = OFF, FOSC = INTRCIO
#define _XTAL_FREQ 4000000
#define LEDG GPIO2
#define LEDR  GPIO1
#define knopka GPIO4

unsigned int t1value = 65535;
unsigned char cnt;
float ff;
// Interrupt service routine
void interrupt isr(void)
{ 
if(T0IF)
	{
		TMR0 = 217;
		TMR1H = (t1value>>8)&0xFF;
		TMR1L = (t1value&0xFF);
		LEDG = 1;	// Pin on
		TMR1ON = 1;
		T0IF = 0;
	}
	if(TMR1IF)
	{
		TMR1ON = 0;
		LEDG = 0;	// pin off
		TMR1IF = 0;
	}
}
void pwm_init(void)
{
	// Timer 0
	OPTION_REG = 0xD7;		// 0b 1101 0111  T0CS=0, PSA=0, 1:256
	TMR0 = 217;		// (Fosc/4)/(256*39) = 100Hz
	T0IF = 0;
	T0IE = 1;

	// Timer 1
	T1CON = 0x00;			// 0b 0000 0000
	TMR1H = (t1value>>8)&0xFF;	//  Timer for 10KHz multiples
	TMR1L = (t1value&0xFF);
	TMR1IF = 0;
	TMR1IE = 1;
}
void pwm_on(void)
{
	PEIE = 1;
	GIE  = 1;
}
void pwm_off(void)
{
GIE = 0;
PEIE = 0;
}

void main() 
{
    TRISIO = 0b111001;
    GPIO = 0;
    //LEDR=1;
    int prir=600;
    //float ff;
    //int l;
    cnt=0;
    pwm_init();
    while (1)
    {
        if (knopka==1 && cnt==0)
          {__delay_ms(20);
           pwm_on();
          __delay_ms(20);
          while(knopka);
          cnt++;
        }
        if (knopka==1 && cnt>1)    
          {__delay_ms(20);
          ff=cnt%10;
          if (ff==0){
            LEDR=1;
            __delay_ms(500); 
            LEDR=0;
          }
          while(knopka);
          __delay_ms(20);
          cnt++;
        }
        if (cnt==6)
        {    LEDG=0;
             pwm_off();
        }
        t1value = 65535-(prir*cnt);
        __delay_ms(100);
    }
}



Поэтому пытаюсь кнопки через обработчик прерываний.

Сообщение отредактировал yeye77: 19 Май 2017 - 14:29

0

#7 Пользователь офлайн   boatcall 

  • Знаток
  • PipPip
  • Группа: Пользователи
  • Сообщений: 70
  • Регистрация: 29 Октябрь 14
  • ГородКрасноярск

Отправлено 22 Май 2017 - 05:38

Читать полностью лениво, но всё-же, для начала опишите обработчик прерываний подобным образом:

...
void interrupt isr(void)
{
if(T0IE && T0IF)
        {
...
        }
        if(TMR1IE && TMR1IF)
        {
...
        }
}
...


Не забывайте, что при отпускании кнопки, так-же происходит "дребезг":
if (knopka==1 && cnt==0)
        {
        __delay_ms(20); // Кнопка нажата
        ...
        while(knopka);
        __delay_ms(20); // Кнопка отпущена
        ...
        cnt++;
        }


Чтобы добиться самому полного понимания алгоритма программы, нарисуйте блок-схему программы, не упуская такие детали типа "дребезг", прерывания и.т.д.

Сообщение отредактировал boatcall: 22 Май 2017 - 05:52

0

#8 Пользователь офлайн   yeye77 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 5
  • Регистрация: 17 Май 17

Отправлено 22 Май 2017 - 15:41

Спасибо за помощь!
Сделал, вроде получилось, и даже работает как задумал. Нажатие включает диод, далее увеличение яркости до 10 нажатий, затем плавное уменьшение до 20 нажатий, больше выключение. Обработку прерываний использовал только для ШИМ (нажатие кнопки обрабатывается без него). Код, в общем, тот же.
Теперь хочу слегка изменить задачу: долгое нажатие отключает/включает диод, короткое - инкрементирует/декрементирует. Как лучше реализовать? Использовать таймер, но оба таймера отведены для ШИМ?
0

#9 Пользователь офлайн   boatcall 

  • Знаток
  • PipPip
  • Группа: Пользователи
  • Сообщений: 70
  • Регистрация: 29 Октябрь 14
  • ГородКрасноярск

Отправлено 22 Май 2017 - 16:15

Просмотр сообщенияyeye77 (22 Май 2017 - 15:41) писал:

...Использовать таймер, но оба таймера отведены для ШИМ?

Использовать TMR0, разумеется. Я в своё время делал как-то так. TMR0 был настроен на 250мс ( непринципиально, пересчитаете под себя ). В прерывании инкрементировалась глобальная переменная pass. По её значению можно было судить о количестве прерываний, а следовательно о времени после обнуления, при pass=1 прошло 250мс, при pass=2 прошло 500мс, при pass=3 прошло 750мс и.т.д. Выбиралось условное время "длительного" нажатия, к примеру 2с ( pass=8 ). Тогда в главном цикле будет что-то такое:
...
void interrupt isr(void)
{
if(T0IE && T0IF)
        {
...
        pass ++ ; // Прошли очередные 250мс
        }
        if(TMR1IE && TMR1IF)
        {
...
        }
}
...

if (knopka==1 && cnt==0)
        {
        pass = 0; // Обнуляем количество проходов
        __delay_ms(20); // Кнопка нажата
        ...
        while( knopka && pass <= 8 );// Проверка опускания кнопки, или "длительного нажатия". 
                                     // При pass >= 8 выход 
                                     // из цикла
        if( pass >= 8 )
        {
        ...// было длительное нажатие, делаем что-то
        }
        // Иначе, отпускание кнопки до таймаута
        __delay_ms(20); // Кнопка отпущена
        ...
        }
...

Полагаю, основную мысль я пояснил. Не сомневаюсь, что есть ещё варианты, я делал так, потому-что у меня тоже других таймеров уже не было. Такой подход в целом удобен тем, что из TMR0 делается некий генератор системных тиков. Если сделать его период, к примеру 1мс, то очень многие вещи из "человеческого диапазона", легко реализуются, т.к. таких переменных, как pass, может быть несколько, но дискрета будет единой, зато предсказуемой.

Сообщение отредактировал boatcall: 22 Май 2017 - 16:16

0

#10 Пользователь офлайн   yeye77 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 5
  • Регистрация: 17 Май 17

Отправлено 22 Май 2017 - 17:28

Спасибо за оперативный ответ. Мысль понятна.
До Вашего ответа хотел испробовать вариант со счетчиком без таймера, такой:

cnt2=0;
while(knopka)
{
cnt2++;
}


и далее расчет/угадывание его приемлемого значения. Но Ваш вариант кажется более удобным.

while( knopka && pass <= 8 ); - здесь включение pass в условие разве не лишнее, т.к. его наращивание в таймере не зависит от длительности удержания кнопки?

Пока оба варианта не заработали :)

Сообщение отредактировал yeye77: 22 Май 2017 - 17:29

0

#11 Пользователь офлайн   mf323 

  • Знаток
  • PipPip
  • Группа: Пользователи
  • Сообщений: 83
  • Регистрация: 27 Январь 13
  • ГородУфа

Отправлено 22 Май 2017 - 19:49

Опрос кнопки с частотой в 20ms и никакого дребезга никогда не будет. Всегда использую один и тот же принцип. По факту изменения (нажатия/отжатия) затираешь таймер (свою переменную). А сам таймер работает всегда и независимо от чего-либо, то есть тупо инкрементируется раз в 20ms (и скажем на FF самоостанавливается), после него проверяешь нажата или отжата, считай разветляешься на две области, и в каждой из них сравниваешь на совпадение текущее значение таймера и твоей константы. Совпало, делаешь дело, или проходишь мимо(через 20ms следующая такая проверка). То есть всё просто, один таймер считает сколько нажата и он же сколько отжата. Правда я не знаю как это будет выглядеть на си, поскольку пишу на асме, но главное просто осознать сам принцип и отбросить ненужное.
0

Поделиться темой:


Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

1 человек читают эту тему
0 пользователей, 1 гостей, 0 скрытых пользователей