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

|
Помогите нубу с прерываниями, плиз. По нажатию кнопки RB0 (pic16f887) должно измениться состояние светодиодов на порту PORTD. Все вроде должно работать, ан-нет. Прошу помощи у PIC-гуру  . Ниже код: Код 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) { } }
|
|
|
|
|
May 5 2010, 08:42
|
Группа: Участник
Сообщений: 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) {} } не работает
|
|
|
|
|
May 5 2010, 08:57
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(HarieR @ May 5 2010, 12:42)  переписал с учетом советов: ... не работает  Где и какие советы Вы учли, не понял. Ваш код может сделать только PORTD = 0xFF, но не наоборот. Уберите temp за ненадобностью (PORTD и так объявлен volatile) и напишите PORTD ^= 0xFF, как советовали, или PORTD = ~PORTD - в Вашем случае (TRISD=0b00000000;) без разницы. delay_ms() в прерывании (да и вообще) - имхо, моветон.
|
|
|
|
|
May 5 2010, 09:06
|
Частый гость
 
Группа: Свой
Сообщений: 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); } } }
|
|
|
|
|
May 5 2010, 09:39
|
    
Группа: Свой
Сообщений: 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; ... } в примере будет соптимизировано напрочь.
|
|
|
|
|
May 5 2010, 09:51
|
Группа: Участник
Сообщений: 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
|
|
|
|
|
May 5 2010, 10:00
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(HarieR @ May 5 2010, 13:51)  сделал без флагов, обработки дребезга и т.д. ... результат 0 Сразу не заметил. Вы уверены, что void interrupt() компилятору достаточно, чтобы сообразить, что это подпрограмма обработки прерываний?
|
|
|
|
|
May 5 2010, 10:03
|
Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075

|
да, с прерыванием по TOIF все работает
|
|
|
|
|
May 5 2010, 10:26
|
Частый гость
 
Группа: Свой
Сообщений: 95
Регистрация: 31-07-05
Из: Полоцк Беларусь
Пользователь №: 7 227

|
Цитата(HarieR @ May 5 2010, 13:03)  да, с прерыванием по TOIF все работает То есть, прерывание INT не возникает? В таком случае тупой вопрос, как кнопка подключена?
|
|
|
|
|
May 5 2010, 10:28
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(HarieR @ May 5 2010, 14:03)  да, с прерыванием по TOIF все работает Гуманный компилятор - экономит пальцы и клавиатуру. Если проверяете в железе, то остаётся вариант - очень_чётная_кнопка, которая принципиально выдаёт только чётное число импульсов дребезга. Ой, ещё одно (странное) предположение - на RB0 нет резистора привязки к gnd или vcc, но тогда прерывания должны легко генериться наводкой от пальца. Не пробовали проверить в симуляторе?
|
|
|
|
|
May 5 2010, 10:37
|
Группа: Участник
Сообщений: 10
Регистрация: 5-05-10
Пользователь №: 57 075

|
подключена нормально, на минус через резистор. Тестовые программы работают, эта - нет
|
|
|
|
|
May 7 2010, 10:11
|
Группа: Участник
Сообщений: 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?
|
|
|
|
Guest_@Ark_*
|
May 7 2010, 10:45
|
Guests

|
Цитата Вопрос: каким образом могли повлиять на работу регистры ANSEL и ANSELH? Непосредственным. Эти регистры задают режимы работы портов - аналоговый или цифровой. После старта (сброса) - устанавливается аналоговый режим. Нужно правильно настраивать порты, прежде чем ими пользоваться.
|
|
|
|
|
May 7 2010, 11:03
|
Группа: Участник
Сообщений: 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
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|