Новичок
Регистрация: 05.12.2012
Сообщений: 11
Репутация: 11
![]() |
XC8 вер.2.46 MPLAB IDE PIC16F684 Уровень — Начинающий.
Задача - мигать четырьмя светодиодами с разной частотой. Реализовано на подсчёте прерываний от таймера TMR0. Код: ============================ /* * File: Base_PIC16F684.c * Author: efimius * * Created on June 24, 2024, 2:07 PM */ // CONFIG // PIN 2-LEDS button,PIN 11-MOTOR button,PIN 3=MUSIC button #pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: CLKOUT function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is MCLR) #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = OFF // Brown Out Detect (BOR enabled) #pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is enabled) #pragma config FCMEN =OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled) #define OPTION_REG &= 0x7F #define WPUA = 0x00 #define _XTAL_FREQ 4000000 #define MOTOR PORTCbits.RC5 //PIN #5 Launch DC motor #define LIGHT_Y PORTCbits.RC3 //PIN #7 Controls yellow leds #define LIGHT_B PORTCbits.RC2 //PIN #8 Controls blue leds #define LIGHT_G PORTCbits.RC1 //PIN #9 Controls green leds #define LIGHT_R PORTCbits.RC0 //PIN #10 Controls red leds #define MUSIC PORTCbits.RC4 //PIN #6 Controls music chip #define BUT3 PORTAbits.RA5 //PIN #2) TOGGLE BUTTON log "0" or log "1" #define BUT2 PORTAbits.RA2 //PIN #11 TOGGLE BUTTON log "0" or log "1" #define BUT1 PORTAbits.RA4 //PIN #3 TOGGLE BUTTON log "0" or log "1" #include <xc.h> #include <stdio.h> #include <stdlib.h> int tickMOT=0; int tickR=0; int tickG=0; int tickB=0; int tickY=0; //======================================= void ROTATE(void) { tickMOT++; if(tickMOT<=2)MOTOR=1; else if(tickMOT>=3){MOTOR=0;tickMOT=0;} } //============================================== void SONG(void) { if(BUT1==1) // IF toggle button3 is "ON" (log"1") { MUSIC=0; //Than set log "0" on PIN 10. launch music } else MUSIC=1; } //===================================== void __interrupt() LEDS() { INTCONbits.T0IF=0; //Reset interrupt flag to 0 tickR++; //Increment counter interrupts f0r RED tickG++; //Increment counter interrupts f0r GREEN tickB++; //Increment counter interrupts f0r BLUE tickY++; //Increment counter interrupts f0r YELLOW { if (tickR == 4000){LIGHT_R=!LIGHT_R; tickR=0;} //Toggle pin LIGHT_R if (tickG == 3000){LIGHT_G=!LIGHT_G; tickG=0;} //Toggle pin LIGHT_G if (tickB == 2000){LIGHT_B=!LIGHT_B; tickB=0;} //Toggle pin LIGHT_B if (tickY == 1000){LIGHT_Y=!LIGHT_Y; tickY=0;} //Toggle pin LIGHT_Y } } //================================================== =========void main(void void main(void) { ANSEL=0x00000000; //Disconnect analog iputs TRISA=0x11111111; //TRISA input TRISC=0x00000000; //TRISC output PORTA=0x11111111; //PORTA input PORTC=0x00000000; //PORTC output CMCON0=0x00000000; ADCON0bits.ADON=0; INTCONbits. GIE=1; //Enable all interrupts INTCONbits.T0IF=0; //reset interrupt flag INTCONbits.T0IE=1; //Enables TMR0 interruptOPTION_REGbits. OPTION_REGbits.T0CS=0; //CLOCK- internal instruction cycle OPTION_REGbits.PSA=1; //Pre scaler OPTION_REGbits.PS0=1; OPTION_REGbits.PS1=1; OPTION_REGbits.PS2=1; while(1); } На настоящий момент всё работает, но переключаются только синий и жёлтый светодиоды. На RC0 и RC1 логический "0". Буду благодарен за любой совет. Cbase.jpg
Последний раз редактировалось Admin; 22.07.2024 в 17:54.
|
||
Оценка
|
Знаток
Регистрация: 06.01.2010
Адрес: Львов
Сообщений: 229
Репутация: 112
![]() ![]() |
Не в прерывании дело (хотя я туда не заглянул, полез сначала проверять инициализацию, ибо там обычно ошибки у большинства, в том числе и у меня). Компараторы не отключены. Судя по схеме, Вы их не используете. Должно быть так:
CMCON0 = 7. А у Вас пишется почему-то 0. И ещё: ADCON0 = 0 (весь регистр, а не только один бит). Т.е. надо указать опору от VDD, а не от пина Vref, и выключить модуль АЦП. Чтобы было меньше проблем, советую делать инициализацию не точечно, а полностью пройтись по всем регистрам, влияющим на настройку, и всё явно прописать в коде. И глобальный конфиг тоже проверять. И ещё не понятно, зачем в схеме стоит ULN. Питать светодиоды можно и прямо от портов. Но если вместо светодиодов будут впоследствии мощные нагрузки - тогда да, оправдано.
Последний раз редактировалось Guaho; 22.07.2024 в 18:34.
|
||
Оценка
|
Новичок
Регистрация: 05.12.2012
Сообщений: 11
Репутация: 11
![]() |
Цитата:
Не в прерывании дело (хотя я туда не заглянул, полез сначала проверять инициализацию, ибо там обычно ошибки у большинства, в том числе и у меня). Компараторы не отключены. Судя по схеме, Вы их не используете. Должно быть так:
CMCON0 = 7. А у Вас пишется почему-то 0. И ещё: ADCON0 = 0 (весь регистр, а не только один бит). Т.е. надо указать опору от VDD, а не от пина Vref, и выключить модуль АЦП. Чтобы было меньше проблем, советую делать инициализацию не точечно, а полностью пройтись по всем регистрам, влияющим на настройку, и всё явно прописать в коде. И глобальный конфиг тоже проверять. И ещё не понятно, зачем в схеме стоит ULN. Питать светодиоды можно и прямо от портов. Но если вместо светодиодов будут впоследствии мощные нагрузки - тогда да, оправдано. CMCON0=0x00000111; ADCON0=0; Но пока не работает, по-прежнему только синий и жёлтый, может с интераптом я чего-то напутал в логике. Буду думать. Насчёт ULN, вы правы, должно быть по восемь запараллеленых светодиодов. PIC не потянет. Спасибо вам за вашу подсказку, буду думать дальше. Думаю с таймером что-то, потому что запрещал GIE, т.е. интеррапт и спокойно выводил на RC1 RC2 RC3 RC4 нули и единицы. |
||
Оценка
|
Знаток
Регистрация: 06.01.2010
Адрес: Львов
Сообщений: 229
Репутация: 112
![]() ![]() |
Если вне прерывания состояния проблемных светодиодов можно изменить - значит, переиферийные модули (АЦП, компараторы и прочее) не мешают выводу. Кроме того, два светодиода из 4-х меняют состояние - значит, вход в прерывание происходит. Код работы со светодиодами - одинаков, ничто не предвещает беды))
Посмотрите свой глобальный конфиг: #pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSC oscillator: CLKOUT function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN) - включен выход тактовой частоты на пине RA4, а там (да и вообще) это не нужно (линия кнопки). #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled) - Вот это ещё раз проверьте, точно ли отключен сторожевой таймер. А в целом, навскидку, действительно непонятно, в чём проблема (я тоже начинающий). Тогда воспользуйтесь симулятором - это верное средство, не раз выручало. Поставьте точку останова в место инкремента счётчиков светодиодов и смотрите их состояние. Если не трудно, отпишитесь потом, в чём была проблема, самому интересно стало) Да, и ещё (уже не по теме). Не увидел в коде фрагмента подавления дребезга клавиатуры (возможно, Вы просто его не привели). Штука обязательная, в реальном железе без этого будет проблема с управлением.
Последний раз редактировалось Guaho; 23.07.2024 в 07:27.
|
||
Оценка
|
Новичок
Регистрация: 05.12.2012
Сообщений: 11
Репутация: 11
![]() |
Любопытная вещь. изменил в ISR порядок счётчиков по возрастанию:
{ if (tickR == 1000){LIGHT_R=!LIGHT_R; tickR=0;} //Toggle pin LIGHT_R if (tickG == 2000){LIGHT_G=!LIGHT_G; tickG=0;} //Toggle pin LIGHT_G if (tickB == 3000){LIGHT_B=!LIGHT_B; tickB=0;} //Toggle pin LIGHT_B if (tickY == 4000){LIGHT_Y=!LIGHT_Y; tickY=0;} //Toggle pin LIGHT_Y } И всё заработало, как задумано, все светодиоды разноцветно мигают, казалось бы радуйся, но осадочек остался. Почему порядок возрастания счётчиков исправил ситуацию? Число в счётчиках не имеет значения, главное, чтобы они в ISR располагались по возрастанию. Даже при равенстве чисел в счётчиках, мигают только синий и жёлтый. Надеюсь, что гуру объяснят. |
||
Оценка
|
Знаток
Регистрация: 06.01.2010
Адрес: Львов
Сообщений: 229
Репутация: 112
![]() ![]() |
Не поленитесь, верните всё назад и прогоните код в симуляторе (в MPLAB-е). И посмотрите, что происходит с регистрами и счётчиками. Это самый надёжный вариант. Кроме того, в железе схема может повести себя иначе, чем в Протеусе, поэтому на последний нельзя 100%-но полагаться. И главное - что это? Повторюсь, симулятор MPLAB избавит Вас от гаданий. Но навскидку можно предположить, что это проблема RMW (http://www.knutselaar.eu/pdf/ReadModifyWrite.pdf) Похоже, изменение одних битов порта влияет на другие биты, потому перестановка команд и меняет дело. Я ловил такое как-то в железе (Протеусом не пользуюсь). Хорошим подходом для контроллеров среднего подсемейства является хранение образа порта в отдельном регистре. Все модификации битов Вы проводите только с этим регистром, а затем, в конце прерывания, выводите образ в физический порт. Ради интереса попробуйте этот вариант. Фактически здесь всего одна дополнительная команда, но этот подходит надёжно страхует от RMW. Я уже давно только так и работаю с портами.
А для манипуляций с битами можно использовать макросы, или, что ещё удобнее - использовать битовые структуры и объединения. |
||
Оценка
|
Обратная связь РадиоЛоцман Вверх |