Отговори на тема  [ 15 мнения ] 
pic16f84a + 7seg + 2buttons 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Юни 25, 2008 11:47 pm
Мнения: 44
Мнение pic16f84a + 7seg + 2buttons
Здравейте, имам задача за правене. Условието е да имам микроконтролер, индикация и два бутона. Замислил съм да направя задачата така, че с натискенто на единия бутон, да се увеличава съдържанието на някакъв регистър и да се изобразява на индикацията, а другия бутон да намаля съдържанието на регистъра при натискане.

Почнах да пиша програмата, направих за единия бутон, по най-простия начин, чрез проверка, дали е натиснат бутона. Но за втория бутон, такава проверка не мога да направя или не се сещам как ще стане. Реших да пробвам с прекъсване, като по-удачен вариант. Но и там намирам проблем, има прекъсване, чрез единия извод на контролера - не ми върши работа. Другия вариант е да ползвам RB4 - RB7, които изводи също позволяват прекъсване. Тогава пък ще разваля конфигурацията на изводите за индикацията :\

Какво ще ме посъветвате?


Пон Сеп 14, 2009 2:06 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Чет Фев 01, 2007 4:04 am
Мнения: 1539
Мнение 
За бутоните не ти трябва прекъсване. Просто през 0.02сек проверяваш нивото на пиновете на които си вързал бутоните. А виж ,тия 0.02сек вече може да ги генерираш с прекъсване от тмр0 например. Но най-добре прегледай сайта на микрочип - там има много примери за работа с бутони и клавиатури.


Пон Сеп 14, 2009 2:15 am
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 2:45 am
Мнения: 263
Мнение 
Таймер0 е решението, точно както казва колегата по-горе. Дори не ти трябва прекъсване - в main() сложи един празен цикъл, в който чакай флага за прекъсване на таймера да се вдигне. Като се вдигне, зачисти го и почвай да си вършиш задачите - опреснявай индикацията и чети (и дебаунсвай ако искаш) бутоните. Функциите си ги напиши в 'non-preemtive' стил - ползвай стейт машини. После добавянето на нови задачи се улеснява, също и поддръжката.
За това, което се иска, аз бих използвал free run режим за таймера (т.е. не трябва да го зареждаш с някаква стойност) и време за препълване 4096us или 8192us.


Пон Сеп 14, 2009 10:05 am
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Чет Ное 20, 2008 1:49 pm
Мнения: 276
Местоположение: Бургас
Мнение 
За твой късмет, вече съм правил нещо такова, само че беше таймер, а не брояч, но постановката е подобна.
При мен индикацията е динамична, с четири цифри. Аз правя така - при всяка стъпка от динамичната индикация правя проверка за бутон. В крайна сметка, човек не е толкова бърз, че да натисне и отпусне бутона за под 5 милисекунди. След това правя сравнение с регистър, в който съм запаметил последното състояние на бутоните. Така откривам дали имам преден или заден фронт на съответния вход. Нататък е лесно - инкрементиране и декрементиране.
Другата особеност на тази задача е да си направиш знакова таблица за изображенията на индикаторите. Ако знаеш как се правят таблици в ПИК, ще ти е лесно.
Ако не ти става ясно дотук, кажи, ще ти постна фрагменти от кода си.

_________________
Digitally yours: Optron


Пон Сеп 14, 2009 11:25 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Юни 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
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Чет Ное 20, 2008 1:49 pm
Мнения: 276
Местоположение: Бургас
Мнение 
Следният фрагмент не ти е правилен:
Код:
check   btfss   Int
      goto   check
      btfss   Up
      btfss   Down
      goto   Add
      goto   Sub

Трябва да е:
Код:
check   btfss   Int
      goto   check
      btfss   Up
      goto   Add
      btfss   Down
      goto   Sub

И не е нужно да нулираш трис А, щом като после го зареждаш с литерала - това ще ти спести един цикъл, когато това е критично.
Ако правилно разбирам, ти работиш с индикатор с един разряд. Не съм преглеждал таблицата ти със сегментния код, приемам, че правилно е съставена. Пусни и схемата да видим дали всичко е наред.

_________________
Digitally yours: Optron


Вто Сеп 15, 2009 8:49 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Юни 25, 2008 11:47 pm
Мнения: 44
Мнение 
Ако го направя така както си го дал, ако е натиснат бутона за инкрементиране, следващата инструкция ще бъде за проверка на другия бутон и така няма да има преход към ADD или SUB, когато има натиснат бутон. Не е ли така?


Ето схемата:


Прикачени файлове:
pic.JPG
pic.JPG [ 137.11 KiB | Прегледано 1463 пъти ]
Вто Сеп 15, 2009 9:03 pm
Профил
Ранг: Новодошъл
Ранг: Новодошъл

Регистриран на: Съб Дек 06, 2008 9:22 am
Мнения: 119
Местоположение: Пловдив
Мнение 
Тука на пръв поглед ми се набива едно нещо.Незнам дали си го симулирал на протеус но според мен така както е написано няма да
работи.Защото:

Код:
ORG      H'0000'
goto     start       
         
           след него добави

ORG      H'0004'
goto     Int_Service 


За да знае при прекъсване къде да направи преход.


Вто Сеп 15, 2009 10:34 pm
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 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
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Чет Ное 20, 2008 1:49 pm
Мнения: 276
Местоположение: Бургас
Мнение 
DanielED написа:
Ако го направя така както си го дал, ако е натиснат бутона за инкрементиране, следващата инструкция ще бъде за проверка на другия бутон и така няма да има преход към ADD или SUB, когато има натиснат бутон. Не е ли така?
Всъщност си прав, но аз бях приел, че ползуваш негативна логика за бутоните. В схемата ти е позитивна. Но този ти вариант ограничава до два възможни варианта.
Аз бих го направил така:
Код:
check   btfss   Int
      goto   check
      btfsc   Up
      goto   Add
      btfsc   Down
      goto   Sub
Това ми дава възможност да правя повече варианти. Все пак, и твоят вариант ще работи за конкретния проект.

Толстолоб дава доста обемист пример, според мен е безпредметно да се правят дефиниции на дефиниции. И неговото е решение, разбира се, при други обстоятелства може да се използва. Но той напомня нещо, което не се сетих - да проверяваш да не излизаш извън границите на таблицата си. Възможно е Протеуса така да се държи, защото ако програмния брояч бъде насочен някъде след енд-инструкцията, не е ясно как ще реагира процесорът. Та сложи си проверка за най-малка и най-голяма стойност за всеки случай. Все пак, при мен, когато правя симулации и ми се случи програмния брояч да задраска някъде след енд, тогава просто процесорът не прави нищо и броячът си върви. Мисля си, че е възможно просто да се превърти след като обходи цялата програмна памет и да започне отначало, при което ефектът ще е просто рестартиране на програмата. Но не обещавам, че точно така ще стане!
Още нещо - виждам, че следиш флага за прекъсване, значи ще трябва и да се грижиш за него. Имам предвид, че след като си обслужил прекъсването, трябва да нулираш флага. Преди това трябва поне веднъж да си прочел регистъра на порта, иначе флагът ще си остане вдигнат.

_________________
Digitally yours: Optron


Сря Сеп 16, 2009 12:30 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Юни 25, 2008 11:47 pm
Мнения: 44
Мнение 
tolstolob, благодаря ти.

Пробвах програмата ти, но също като моята(след като я поправих и дадох начален адрес на прекъсването) при пускането на програмата сама почва да отброява...


Сря Сеп 16, 2009 1:26 am
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Чет Ное 20, 2008 1:49 pm
Мнения: 276
Местоположение: Бургас
Мнение 
Нешо ти куца при логиката за бутоните. Трябва да изчакаш да се натисне бутон, проверяваш кой е, след това правиш инкрементиране или декрементиране, след което изчакваш да се отпусне бутонът. Ако не правиш някое от тези изчаквания, почва едно лудо броене в някоя посока, което няма и да го видиш при реална обстановка заради бързодействието на процесора.

_________________
Digitally yours: Optron


Сря Сеп 16, 2009 1:34 am
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 2:45 am
Мнения: 263
Мнение 
Оптроне, не си разбрал смисъла на цялата верига дефиниции, а именно - с промяна на едно битче да промениш целия сет от символи без да си мърдаш пръста. Причината за това - кода е взет от един проект, при който индикацията на макета беше вързана по един начин, а на платката - по съвсем различен.
Даниеле, примера, който съм дал, не ползва прекъсване - за това, което трябва да направиш изобщо не е нужно. Вече ако добавиш още един разряд индикация, нещата вече отиват към ползване на таймер. Не подценявай времето за дебаунс - трябва да има такова. В началото и аз го ядох, докато ми увре тиквата за тези 'подробности'.
Още нещо - с цел ловене на непредвидени преходи (обикновено при несъобразен скок при четене на таблици) е добре да се използва FILL директива, с която попълваш незаетите места от програмното пространство - или с преход към ресет вектора или към някакъв друг адрес, така че да изловиш нередността.

И още нещо - изхвърли го тоя протеус - така си създаваш двойна работа. Никога не съм ползвал това лайно и не мисля някога да го ползвам. Докато не видиш регистрите реално в контролера какви стойности приемат, реално работа не вършиш.


Сря Сеп 16, 2009 9:26 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Сря Юни 25, 2008 11:47 pm
Мнения: 44
Мнение 
Здравейте отново,
Програмата като я чета е абсолютно точна вече. Като я пусна на Протеус, нещо не му харесва.
В такъв случай, ако изключа Протеуса като помощна програма и използвам само дебъг, когато имам прекъсване в програмата как да го предизвикам в дебъг-а за да си продължи работата?


Сря Сеп 16, 2009 8:25 pm
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 2:45 am
Мнения: 263
Мнение 
И в дебъг интеръптите си работят както трябва - просто слагаш брейкпойнт и дебнеш :)
Можеш да сетнеш флаг за прекъсване и ръчно в съответния регистър.


Сря Сеп 16, 2009 8:44 pm
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 15 мнения ] 

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 3 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни