|
Виж темите без отговор | Виж активните теми
Дата и час: Вто Юли 28, 2026 1:18 am
|
Страница 1 от 1
|
[ 15 мнения ] |
|
pic16f84a + 7seg + 2buttons
| Автор |
Съобщение |
|
DanielED
Ранг: Минаващ
Регистриран на: Сря Юни 25, 2008 11:47 pm Мнения: 44
|
 pic16f84a + 7seg + 2buttons
Здравейте, имам задача за правене. Условието е да имам микроконтролер, индикация и два бутона. Замислил съм да направя задачата така, че с натискенто на единия бутон, да се увеличава съдържанието на някакъв регистър и да се изобразява на индикацията, а другия бутон да намаля съдържанието на регистъра при натискане.
Почнах да пиша програмата, направих за единия бутон, по най-простия начин, чрез проверка, дали е натиснат бутона. Но за втория бутон, такава проверка не мога да направя или не се сещам как ще стане. Реших да пробвам с прекъсване, като по-удачен вариант. Но и там намирам проблем, има прекъсване, чрез единия извод на контролера - не ми върши работа. Другия вариант е да ползвам RB4 - RB7, които изводи също позволяват прекъсване. Тогава пък ще разваля конфигурацията на изводите за индикацията :\
Какво ще ме посъветвате?
|
| Пон Сеп 14, 2009 2:06 am |
|
 |
|
ji4ka
Ранг: Форумен бог
Регистриран на: Чет Фев 01, 2007 4:04 am Мнения: 1539
|
За бутоните не ти трябва прекъсване. Просто през 0.02сек проверяваш нивото на пиновете на които си вързал бутоните. А виж ,тия 0.02сек вече може да ги генерираш с прекъсване от тмр0 например. Но най-добре прегледай сайта на микрочип - там има много примери за работа с бутони и клавиатури.
|
| Пон Сеп 14, 2009 2:15 am |
|
 |
|
tolstolob
Ранг: Ориентиран
Регистриран на: Вто Фев 06, 2007 2:45 am Мнения: 263
|
Таймер0 е решението, точно както казва колегата по-горе. Дори не ти трябва прекъсване - в main() сложи един празен цикъл, в който чакай флага за прекъсване на таймера да се вдигне. Като се вдигне, зачисти го и почвай да си вършиш задачите - опреснявай индикацията и чети (и дебаунсвай ако искаш) бутоните. Функциите си ги напиши в 'non-preemtive' стил - ползвай стейт машини. После добавянето на нови задачи се улеснява, също и поддръжката.
За това, което се иска, аз бих използвал free run режим за таймера (т.е. не трябва да го зареждаш с някаква стойност) и време за препълване 4096us или 8192us.
|
| Пон Сеп 14, 2009 10:05 am |
|
 |
|
optron
Ранг: Ориентиран
Регистриран на: Чет Ное 20, 2008 1:49 pm Мнения: 276 Местоположение: Бургас
|
За твой късмет, вече съм правил нещо такова, само че беше таймер, а не брояч, но постановката е подобна.
При мен индикацията е динамична, с четири цифри. Аз правя така - при всяка стъпка от динамичната индикация правя проверка за бутон. В крайна сметка, човек не е толкова бърз, че да натисне и отпусне бутона за под 5 милисекунди. След това правя сравнение с регистър, в който съм запаметил последното състояние на бутоните. Така откривам дали имам преден или заден фронт на съответния вход. Нататък е лесно - инкрементиране и декрементиране.
Другата особеност на тази задача е да си направиш знакова таблица за изображенията на индикаторите. Ако знаеш как се правят таблици в ПИК, ще ти е лесно.
Ако не ти става ясно дотук, кажи, ще ти постна фрагменти от кода си.
_________________ Digitally yours: Optron
|
| Пон Сеп 14, 2009 11:25 am |
|
 |
|
DanielED
Ранг: Минаващ
Регистриран на: Сря Юни 25, 2008 11:47 pm Мнения: 44
|
Здравейте, погледнете дали правилно съм се справил:
 |  |  |  | Код: list p=16F84A; #include <P16F84A.inc>; __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
w EQU 0 f EQU 1 Speed EQU D'20'
Counter EQU H'C0' Flag EQU H'10' W_temp EQU H'E0' StatusT EQU H'0F' Cnt EQU H'20'
#define Int Flag,0 #define Up PORTA, 0 #define Down PORTA, 1
ORG H'0000' goto start
;-------------------------------------------
start bcf STATUS, RP0 clrf PORTA clrf PORTB bsf STATUS, RP0 clrf TRISB clrf TRISA movlw b'00011111' movwf TRISA movlw b'10010111' movwf OPTION_REG bcf STATUS, RP0 movlw b'10100000' movwf INTCON movlw Speed movwf Cnt goto main
;-------------------------------------------
Int_Service movwf W_temp swapf STATUS, w movwf StatusT btfss INTCON, T0IF goto end_int TMR0_int decfsz Cnt,f goto end_int bsf Int movlw Speed movwf Cnt end_int bcf INTCON, T0IF swapf StatusT, w movwf STATUS swapf W_temp,f swapf W_temp,w retfie
;-------------------------------------------
main bcf STATUS, RP0 clrf Counter
Count movf Counter,0 ; Display a 1 call bin2seg ; Convert number in W to the segment value movwf PORTB
check btfss Int goto check btfss Up btfss Down goto Add goto Sub
Add incf Counter bcf Int goto Count
Sub decf Counter bcf Int goto Count
bin2seg addwf PCL, 1 ; Jump into the lookup table retlw H'C0' ; Return segment code for 0 retlw H'F9' ; Return segment code for 1 retlw H'A4' ; Return segment code for 2 retlw H'B0' ; Return segment code for 3 retlw H'99' ; Return segment code for 4 retlw H'92' ; Return segment code for 5 retlw H'82' ; Return segment code for 6 retlw H'F8' ; Return segment code for 7 retlw H'80' ; Return segment code for 8 retlw H'98' ; Return segment code for 9 end |  |  |  |  |
Когато тествам на Протеус не се получава. Зарежда и извежда нулата само, но натискането с бутоните не се получава, въпреки, че там мисля трябва да работи(бутоните). Явно нещо с TMR0 не съм се справил добре.
|
| Вто Сеп 15, 2009 8:14 pm |
|
 |
|
optron
Ранг: Ориентиран
Регистриран на: Чет Ное 20, 2008 1:49 pm Мнения: 276 Местоположение: Бургас
|
Следният фрагмент не ти е правилен: Трябва да е:
И не е нужно да нулираш трис А, щом като после го зареждаш с литерала - това ще ти спести един цикъл, когато това е критично.
Ако правилно разбирам, ти работиш с индикатор с един разряд. Не съм преглеждал таблицата ти със сегментния код, приемам, че правилно е съставена. Пусни и схемата да видим дали всичко е наред.
_________________ Digitally yours: Optron
|
| Вто Сеп 15, 2009 8:49 pm |
|
 |
|
DanielED
Ранг: Минаващ
Регистриран на: Сря Юни 25, 2008 11:47 pm Мнения: 44
|
Ако го направя така както си го дал, ако е натиснат бутона за инкрементиране, следващата инструкция ще бъде за проверка на другия бутон и така няма да има преход към ADD или SUB, когато има натиснат бутон. Не е ли така?
Ето схемата:
|
| Вто Сеп 15, 2009 9:03 pm |
|
 |
|
a_stankov
Ранг: Новодошъл
Регистриран на: Съб Дек 06, 2008 9:22 am Мнения: 119 Местоположение: Пловдив
|
Тука на пръв поглед ми се набива едно нещо.Незнам дали си го симулирал на протеус но според мен така както е написано няма да
работи.Защото:
За да знае при прекъсване къде да направи преход.
|
| Вто Сеп 15, 2009 10:34 pm |
|
 |
|
tolstolob
Ранг: Ориентиран
Регистриран на: Вто Фев 06, 2007 2:45 am Мнения: 263
|
 Кратък курс по използване на '#define' :)
Чак за прекъсване не работата, затова ето и моите 5 стинки:
 |  |  |  | Код: ; a ; - ; f | | b ; g - ; e | | c ; -. dot ; d
#define bit_a 0 ;Тези ще си ги нагласиш спрямо индикатора си и това как е вързан към порта. #define bit_b 1 #define bit_c 2 #define bit_d 3 #define bit_e 4 #define bit_f 5 #define bit_g 6 #define bit_dot 7
#define seg_a (1 << bit_a) #define seg_b (1 << bit_b) #define seg_c (1 << bit_c) #define seg_d (1 << bit_d) #define seg_e (1 << bit_e) #define seg_f (1 << bit_f) #define seg_g (1 << bit_g) #define seg_dot (1 << bit_dot)
;--------------------- #define symbol_0 seg_a + seg_b + seg_c + seg_d + seg_e + seg_f ;"0" #define symbol_1 seg_b + seg_c ;"1" #define symbol_2 seg_a + seg_b + seg_d + seg_e + seg_g ;"2" #define symbol_3 seg_a + seg_b + seg_c + seg_d + seg_g ;"3" #define symbol_4 seg_b + seg_c + seg_f + seg_g ;"4" #define symbol_5 seg_a + seg_c + seg_d + seg_f + seg_g ;"5" #define symbol_6 seg_a + seg_c + seg_d + seg_e + seg_f + seg_g ;"6" #define symbol_7 seg_a + seg_b + seg_c ;"7" #define symbol_8 seg_a + seg_b + seg_c + seg_d + seg_e + seg_f + seg_g ;"8" #define symbol_9 seg_a + seg_b + seg_c + seg_d + seg_f + seg_g ;"9" #define symbol_A seg_a + seg_b + seg_c + seg_e + seg_f + seg_g ;"A" #define symbol_A seg_a + seg_b + seg_c + seg_e + seg_f + seg_g ;"A" #define symbol_b seg_c + seg_d + seg_e + seg_f + seg_g ;"b" #define symbol_c seg_d + seg_e + seg_g ;"c" #define symbol_C seg_a + seg_d + seg_e + seg_f ;"C" #define symbol_d seg_b + seg_c + seg_d + seg_e + seg_g ;"d" #define symbol_E seg_a + seg_d + seg_e + seg_f + seg_g ;"E" #define symbol_F seg_a + seg_e + seg_f + seg_g ;"F" ; Добави си още, ако е необходимо
; Предполагам, че високото ниво ти е натиснат бутон
main: BTFSC Up GOTO Add BTFSC Down GOTO Sub GOTO main ;нямаме натиснат бутон, циклим Add: CALL DebounceDelay BTFSS Up ;Провери дали още е натиснат бутона GOTO main ; INCF Counter,F ;Имаме натиснат бутон, вършим работа MOVF Counter,W CALL LoadDisplay BTFSC Up ;Чакаш, докато се отпусне бутона GOTO $-1 ; GOTO main
Sub: CALL DebounceDelay BTFSS Down GOTO main DECF Counter,F MOVF Counter,W BTFSC Down ;Чакаш, докато се отпусне бутона GOTO $-1 ; GOTO main
LoadDisplay: CALL SymbolTable MOVWF PORTB RETURN
; ; Напиши си подпрограмка за дилей (около 20ms) ; DebounceDelay: ;Може да е с таймер0 ;Може и да е прост софтуерен цикъл RETURN
SymbolTable: ANDLW 0x0F ;Тази маска обикновено те предпазва да не изхвърчиш от таблицата, ако подадеш кофти стойност - не е известно къде ще отидеш (ако има код след таблицата, намазваш яко ситуацията) ADDWF PCL,F RETLW symbol_0 RETLW symbol_1 RETLW symbol_2 RETLW symbol_3 RETLW symbol_4 RETLW symbol_5 RETLW symbol_6 RETLW symbol_7 RETLW symbol_8 RETLW symbol_9 RETLW symbol_A RETLW symbol_b RETLW symbol_c RETLW symbol_d RETLW symbol_E RETLW symbol_F
|  |  |  |  |
|
| Вто Сеп 15, 2009 11:13 pm |
|
 |
|
optron
Ранг: Ориентиран
Регистриран на: Чет Ное 20, 2008 1:49 pm Мнения: 276 Местоположение: Бургас
|
Всъщност си прав, но аз бях приел, че ползуваш негативна логика за бутоните. В схемата ти е позитивна. Но този ти вариант ограничава до два възможни варианта.
Аз бих го направил така: Това ми дава възможност да правя повече варианти. Все пак, и твоят вариант ще работи за конкретния проект.
Толстолоб дава доста обемист пример, според мен е безпредметно да се правят дефиниции на дефиниции. И неговото е решение, разбира се, при други обстоятелства може да се използва. Но той напомня нещо, което не се сетих - да проверяваш да не излизаш извън границите на таблицата си. Възможно е Протеуса така да се държи, защото ако програмния брояч бъде насочен някъде след енд-инструкцията, не е ясно как ще реагира процесорът. Та сложи си проверка за най-малка и най-голяма стойност за всеки случай. Все пак, при мен, когато правя симулации и ми се случи програмния брояч да задраска някъде след енд, тогава просто процесорът не прави нищо и броячът си върви. Мисля си, че е възможно просто да се превърти след като обходи цялата програмна памет и да започне отначало, при което ефектът ще е просто рестартиране на програмата. Но не обещавам, че точно така ще стане!
Още нещо - виждам, че следиш флага за прекъсване, значи ще трябва и да се грижиш за него. Имам предвид, че след като си обслужил прекъсването, трябва да нулираш флага. Преди това трябва поне веднъж да си прочел регистъра на порта, иначе флагът ще си остане вдигнат.
_________________ Digitally yours: Optron
|
| Сря Сеп 16, 2009 12:30 am |
|
 |
|
DanielED
Ранг: Минаващ
Регистриран на: Сря Юни 25, 2008 11:47 pm Мнения: 44
|
tolstolob, благодаря ти.
Пробвах програмата ти, но също като моята(след като я поправих и дадох начален адрес на прекъсването) при пускането на програмата сама почва да отброява...
|
| Сря Сеп 16, 2009 1:26 am |
|
 |
|
optron
Ранг: Ориентиран
Регистриран на: Чет Ное 20, 2008 1:49 pm Мнения: 276 Местоположение: Бургас
|
Нешо ти куца при логиката за бутоните. Трябва да изчакаш да се натисне бутон, проверяваш кой е, след това правиш инкрементиране или декрементиране, след което изчакваш да се отпусне бутонът. Ако не правиш някое от тези изчаквания, почва едно лудо броене в някоя посока, което няма и да го видиш при реална обстановка заради бързодействието на процесора.
_________________ Digitally yours: Optron
|
| Сря Сеп 16, 2009 1:34 am |
|
 |
|
tolstolob
Ранг: Ориентиран
Регистриран на: Вто Фев 06, 2007 2:45 am Мнения: 263
|
Оптроне, не си разбрал смисъла на цялата верига дефиниции, а именно - с промяна на едно битче да промениш целия сет от символи без да си мърдаш пръста. Причината за това - кода е взет от един проект, при който индикацията на макета беше вързана по един начин, а на платката - по съвсем различен.
Даниеле, примера, който съм дал, не ползва прекъсване - за това, което трябва да направиш изобщо не е нужно. Вече ако добавиш още един разряд индикация, нещата вече отиват към ползване на таймер. Не подценявай времето за дебаунс - трябва да има такова. В началото и аз го ядох, докато ми увре тиквата за тези 'подробности'.
Още нещо - с цел ловене на непредвидени преходи (обикновено при несъобразен скок при четене на таблици) е добре да се използва FILL директива, с която попълваш незаетите места от програмното пространство - или с преход към ресет вектора или към някакъв друг адрес, така че да изловиш нередността.
И още нещо - изхвърли го тоя протеус - така си създаваш двойна работа. Никога не съм ползвал това лайно и не мисля някога да го ползвам. Докато не видиш регистрите реално в контролера какви стойности приемат, реално работа не вършиш.
|
| Сря Сеп 16, 2009 9:26 am |
|
 |
|
DanielED
Ранг: Минаващ
Регистриран на: Сря Юни 25, 2008 11:47 pm Мнения: 44
|
Здравейте отново,
Програмата като я чета е абсолютно точна вече. Като я пусна на Протеус, нещо не му харесва.
В такъв случай, ако изключа Протеуса като помощна програма и използвам само дебъг, когато имам прекъсване в програмата как да го предизвикам в дебъг-а за да си продължи работата?
|
| Сря Сеп 16, 2009 8:25 pm |
|
 |
|
tolstolob
Ранг: Ориентиран
Регистриран на: Вто Фев 06, 2007 2:45 am Мнения: 263
|
И в дебъг интеръптите си работят както трябва - просто слагаш брейкпойнт и дебнеш
Можеш да сетнеш флаг за прекъсване и ръчно в съответния регистър.
|
| Сря Сеп 16, 2009 8:44 pm |
|
|
|
Страница 1 от 1
|
[ 15 мнения ] |
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 3 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|