Отговори на тема  [ 72 мнения ]  Отиди на страница 1, 2, 3, 4, 5  Следваща
Zilog - Z8 Encore! F083A Series - Timer & Button 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Съб Ное 22, 2014 7:23 pm
Мнения: 48
Мнение Zilog - Z8 Encore! F083A Series - Timer & Button
Здравейте !

Бих искал да помоля за помощ, относно следния казус: Имам бутон (с pull-up resistor) и диод, това което искам е като натисна бутона диодът да светне за 5s и да спре, след което отново същата процедура да се повтаря и т.н. Със кодът, който е по-долу и лог. анализатора, получавам най-различни стойности след натискане на бутона: Width - 2.006s, Frequency - 0.2374Hz, Period - 4.212 ; Width - 2.809, Frequency - 0.2932, Period - 3.411 ; Width - 4.414, Frequency - 0.1994, Period - 5.015.

Бях пускал една тема за таймера на този микроконтролер и мисля, че нещата ги схванах, имам в предвид, че таймера е нагласен точно - 200ms * 25 прекъсвания = 5s.

W (Width) = 5.015s, f (Frequency) = 99.69mHz, T (Period) = 10.03s. - Това са стойностите с лог. анализатора, при 5s, но както slav40.com ми изясни в предишната тема, зависи какъв е осцилатора.

Според спецификацията, този е default-ния и оттам идва разликата за която питам :) Но, тя е малка, докато сега с програмата с бутона се получават доста различни стойности и не мога да си обясня какво се случва... :rolleyes: :rolleyes: :rolleyes:

Internal precision RC oscillator

• 119 kHz or 20 MHz
• ± 4% accuracy when trimmed
• No external components required
• Unlock and write Oscillator Control Register (OSCCTL) to enable and select oscillator at either 20 MHz or 119 kHz



Код:

#include <ez8.h> /* Този хедър позволява да достъпваме вътрешните регистри като всички останали, чрез имената им. */
#include "stdtypes.h"

#define BUTTON_PRESSED (0)
#define BUTTON_RELEASED (1)

extern void PortConfig(void);
extern void InterruptConfig(void);
extern void TimerConfig(void);
extern boolean ReadButton(void);

int main(void)
{
   PortConfig();
   InterruptConfig();
   TimerConfig();
   
   while(1);
}

void interrupt Timer0_ISR(void) _At TIMER0
{
   static uint8 Delay_Counter_5s = 0;
   
   Delay_Counter_5s++;
   
   if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
   {/* Да */
      do
      {
         PAOUT |= 1 << 1; /* Включи светодиода */
      }while(25 == Delay_Counter_5s);
   }
   
   if(25 == Delay_Counter_5s)
   {
      PAOUT &= ~(1 << 1); /* Изключи светодиода */
      
      Delay_Counter_5s = 0; /* Нулираме брояча */
   }
}

void PortConfig(void)
{
   PADD &= ~(1 << 1); /* За да конфигурираме извод PA1 като изход, трябва да нулираме бит 1 на регистър PADD */
   
   PBDD |= 1 << 0; /* Kонфигурираме извод PB0 като вход */
}

void InterruptConfig(void)
{
   IRQCTL |= 1 << 7; /* Прекъсванията се разрешават с глобалния бит IRQE в регистър IRQCTL. Бит IRQE
   се установява в 1 */
   
   IRQ0ENL |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
   
   IRQ0ENH |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
}

void TimerConfig(void)
{
   T0H = 0x00; /* Записваме старшата част на числото -> Регистрите съдържат първоначалната стойност от която брои таймера */
   T0L = 0x00; /* Записваме младшата част на числото -> Регистрите съдържат първоначалната стойност от която брои таймера */
   
   T0RH = 0x7A; /* Записваме старшата част -> Регистрите съдържат макс. 16-бит броячна стойност до която брои таймера и тя е 65535 */
   T0RL = 0x12; /* Записваме младшата част -> Регистрите съдържат макс. 16-бит броячна стойност до която брои таймера и тя е 65535 */
   
   /* Системна честота - 20MHz => Честота на таймера - 20MHz / 128 (prescaler) = 156250Hz => Периода на таймера - 1 / 156250 = 0.0000064s
   или 6.4us => Таймера се увеличава с 1 на всеки 6.4us. Ние имаме 16 битов таймер, който брои до 65535 ---> Максималното време за което,
   може да имаме прекъсване е: 65535 * 0.0000064 = 420ms (приблизително). За 5s ми трябва число кратно на 5 и по-малко от 420ms (0.42s) =>
   За да получа 200ms, брояча трябва да изброи: 200 000 / 6.4 = 31 250 пъти (периода). Това ми е коефициента на таймера, демек ще брои
   от 0 до 31 250. */
   
   T0CTL0 = 0x00; /* Непрекъснат режим */
   T0CTL1 = 0xB9; /* Коефициент на деление 128 и стартиране на таймера */
}

boolean ReadButton(void)
{
   return (PBIN & (1 << 0)) ? BUTTON_RELEASED : BUTTON_PRESSED;
}



Благодаря!


Вто Юли 10, 2018 2:07 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Ное 25, 2005 11:41 am
Мнения: 1680
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Абе кой е тоя "даскал", де то Ви учи да пишете код в прекъсване?
Че и while(..)... 8O 8O 8O

ЗАПОМНИ:

Цитат:
:idea: КОД НЕ СЕ ПИШЕ В ПРЕКЪСВАНЕ!!! :idea:



Сега ми обясни, какво очакваш да правят двата if-a в прекъсването, че май си посещавал лекции по Pascal, пък после си се появил за домашното по C....?


Вто Юли 10, 2018 4:43 pm
Профил ICQ WWW
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Съб Ное 22, 2014 7:23 pm
Мнения: 48
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Ами всъщност, никога не съм учил програмиране в училище/университета (то си личи), но от известно време в мен се породи идея, че искам да се занимавам точно с това. Започнах да учи С, после си взех и микроконтролера. Принципно следвам различни примери, описани в една книга, но това е без значение, защото идеята ми е сега да направя нещо елементарно без да го има в книгата и т.н. Очевидно, след като не се справям, питам за помощ : )

Еми мисля, че е описано това което правят или поне това което аз мисля, че правят : )

Код:

if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
   {/* Да */
      do
      {
         PAOUT |= 1 << 1; /* Включи светодиода */
      }while(25 == Delay_Counter_5s); /* Стой тук 5s */
   }
   
   if(25 == Delay_Counter_5s) /* Ако изтекат 5-те секунди (25 прекъсвания * 200ms = 5s) */
   {
      PAOUT &= ~(1 << 1); /* Изключи светодиода */
      
      Delay_Counter_5s = 0; /* Нулираме брояча */
   }



Вто Юли 10, 2018 5:15 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Съб Ное 22, 2014 7:23 pm
Мнения: 48
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Това е добавката с 10ms delay, само нз, какво да сложа в ISR-а, просто не разбирам за какво трябва да се проверява...

Код:

#include <ez8.h> /* Този хедър позволява да достъпваме вътрешните регистри като всички останали, чрез имената им. */
#include "stdtypes.h"

#define DELAY_CONSTANT_10_MSEC (5052)

#define BUTTON_PRESSED (0)
#define BUTTON_RELEASED (1)

extern void PortConfig(void);
extern void InterruptConfig(void);
extern void TimerConfig(void);
extern boolean ReadButton(void);
extern void Delay(uint32 delay);

int main(void)
{
   PortConfig();
   InterruptConfig();
   TimerConfig();
   
   while(1)
   {
      static uint8 Delay_Counter_5s = 0;
   
      Delay_Counter_5s++;
      
      if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
      {/* Да */
         Delay(DELAY_CONSTANT_10_MSEC); /* Изчакване 10ms */
         
         if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
         {/* Да */
            do
            {
               PAOUT |= 1 << 1; /* Включи светодиода */
            }while(25 == Delay_Counter_5s);
         }
         
      }
      
      if(25 == Delay_Counter_5s)
      {
         PAOUT &= ~(1 << 1); /* Изключи светодиода */
      
         Delay_Counter_5s = 0; /* Нулираме брояча */
      }
   }
}

void interrupt Timer0_ISR(void) _At TIMER0
{
   
}

void PortConfig(void)
{
   PADD &= ~(1 << 1); /* За да конфигурираме извод PA1 като изход, трябва да нулираме бит 1 на регистър PADD */
   
   PBDD |= 1 << 0; /* Конфигурираме извод PB0 като вход */
}

void InterruptConfig(void)
{
   IRQCTL |= 1 << 7; /* Прекъсванията се разрешават с глобалния бит IRQE в регистър IRQCTL. Бит IRQE
   се установява в 1 */
   
   IRQ0ENL |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
   
   IRQ0ENH |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
}

void TimerConfig(void)
{
   T0H = 0x00; /* Записваме старшата част на числото -> Регистрите съдържат първоначалната стойност от която брои таймера */
   T0L = 0x00; /* Записваме младшата част на числото -> Регистрите съдържат първоначалната стойност от която брои таймера */
   
   T0RH = 0x7A; /* Записваме старшата част -> Регистрите съдържат макс. 16-бит броячна стойност до която брои таймера и тя е 65535 */
   T0RL = 0x12; /* Записваме младшата част -> Регистрите съдържат макс. 16-бит броячна стойност до която брои таймера и тя е 65535 */
   
   /* Системна честота - 20MHz => Честота на таймера - 20MHz / 128 (prescaler) = 156250Hz => Периода на таймера - 1 / 156250 = 0.0000064s
   или 6.4us => Таймера се увеличава с 1 на всеки 6.4us. Ние имаме 16 битов таймер, който брои до 65535 ---> Максималното време за което,
   може да имаме прекъсване е: 65535 * 0.0000064 = 420ms (приблизително). За 5s ми трябва число кратно на 5 и по-малко от 420ms (0.42s) =>
   За да получа 200ms, брояча трябва да изброи: 200 000 / 6.4 = 31 250 пъти (периода). Това ми е коефициента на таймера, демек ще брои
   от 0 до 31 250. */
   
   T0CTL0 = 0x00; /* Непрекъснат режим */
   T0CTL1 = 0xB9; /* Коефициент на деление 128 и стартиране на таймера */
}

boolean ReadButton(void)
{
   return (PBIN & (1 << 0)) ? BUTTON_RELEASED : BUTTON_PRESSED;
}

void Delay(uint32 delay)
{
   for(; delay > 0; delay--);
}



Вто Юли 10, 2018 6:18 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Съб Ное 22, 2014 7:23 pm
Мнения: 48
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Виждам, че си пишете някакви общи нещица (шегички), няма лошо, ама нали идеята е някой да ми обясни и помогне да се справя с задачката или бъркам ? След коментара на itso.t, пооправих кода, обаче никой нищо не каза, не съм сигурен дали въобще някой взима темата ми на сериозно или не ?

Благодаря!


Вто Юли 10, 2018 9:33 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Сря Юли 11, 2007 10:16 am
Мнения: 1730
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Ами не е ОК това решение. Дори съм сигурен, че ще забие в момента в който натиснеш бутона. По принцип - добре направи, че изкара кода от прекъсването, но все пак трябваше да си оставиш в него някой друга глобална променлива например, която да инкрементваш/декрементваш и да следиш нейните стойности в основния while цикъл.


Вто Юли 10, 2018 10:05 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Ное 25, 2005 11:41 am
Мнения: 1680
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Споко де, много сме сериозни даже!
Гледам, и някой други колеги не са разбрали, че НЕ СЕ ПИШЕ код в прекъсването от такъв тип, ама с тях ще се разправям друг път ... :P :P :P

Той тоя код, в тоя си вид няма как да работи както го искаш по ред причини...

Та така:

1. В това прекъсване място има само:

Код:
Delay_Counter_5s++;


2. Ей това:

Код:
}while(25 == Delay_Counter_5s); /* Стой тук 5s */


всъщност работи точно наобратно, справка тук:

https://www.tutorialspoint.com/cprogramming/c_do_while_loop.htm

3. В момента работи така:

Като натиснеш бутона (ако имаш късмет да не е на 25-тото прекъсване), светодиода ще светне. Ще започне да свети обаче някъде между 1 и 25 прекъсване, и ще угасне на 25-тото, освен ако не продължаваш да държиш бутона натиснат. Тогава ще си зависне и ще си свети... Времето на светене е винаги различно, защото го светваш по различно време (както казах между прекъсване 1 и 25), а го гасиш винаги на 25. Демек, началното условие не е точно дефинирано.

4. Ей така може и да работи:

Код:
if((BUTTON_PRESSED == ReadButton()) && (btn_prev_state == BUTTON_NOT_PRESSED)) /* Бутонът натиснат ли е ? */
   {/* Да */
      Delay_Counter_5s = 0;
      btn_prev_state = BUTTON_PRESSED;
   }
   
   if(25 <= Delay_Counter_5s) /* Ако изтекат 5-те секунди (25 прекъсвания * 200ms = 5s) */
   {
      PAOUT &= ~(1 << 1); /* Изключи светодиода */
      btn_prev_state = BUTTON_NOT_PRESSED;
     
      Delay_Counter_5s = 0; /* Нулираме брояча */
   }


4. За домашно:

а) - направи необходимите дефиниции и декларации за да работи модифицирания код;
б) - изкарай логиката (двата if-a) извън прекъсването;
в) - направи таймера да прекъсва на 1 мс;
г) - използвай 32 битова глобална променлива за Delay_Counter_5s.


Вто Юли 10, 2018 10:38 pm
Профил ICQ WWW
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Яну 01, 2012 8:04 pm
Мнения: 2663
Местоположение: София / Велико Търново
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Код:

BOOL buttonIF = FALSE;
unsigned char period_cnt = 0;

void interrupt ISR (void)
{
   if(buttonchangeflag) // ако прекъсването идва от бутона
    if(!button_input){ // ако бутона е натиснат (ниско ниво)
     buttonIF = TRUE;
     buttonchangeflag = FALSE;
    }
}


   if(timerinterrupt) // ако прекъсването идва от таймера
    if(period_cnt) // ако брояча на периоди е по-гоолям от 0-ла
     period_cnt++; // го инкрементираме

}

void StartChronometer(void)
{
  TOH = 0x00;
  TOL = 0x00;
  period_cnt = 1; // 0-ла е семафор да не брои изобщо. 1-ца е първото състояние

}
void ProcessButtons(void)
{
  if(ButtonIF){
   StartChronometer();
   LED = ON;
   ButtonIF = FALSE;  // бутона е обработен
  }
}

void ScheduleTasks(void)
{
if(period_cnt == (25+1)){ // 25 x 200ms = 5s
   LED = OFF;
   period_cnt = 0; // нулираме брояча на периоди. Така няма и да брои. Направил съм го да брои до 26 защото броим от 1.
                        // понеже когато е нула го ползвам за семафор да не брои изобщо. Би могло да се напише и period_cnt > 25.
                        // това е в случай, че основният цикъл на програмата върви бавно и има опасност да се инкрементира още
                        // поне веднъж.
}


void main (void)
{
   PortConfig();
   InterruptConfig();
   TimerConfig();

   while(1){

     ProcessButtons();
     ScheduleTasks();
   }
}


и такова while(1); без {} не пиши ! Не пиши и функции (били те и void) без скоби: () , ако не сложиш скоби на void функция, тя няма да се изпълни.

_________________
https://github.com/slav4ocom/


Сря Юли 11, 2018 1:14 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Чет Фев 03, 2005 2:21 am
Мнения: 12765
Местоположение: София
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
От коментарите оставам с впечатление, че ако 10 човека напишат горния код за бутона, светодиода и таймера, ще има минимум 10 различни версии... :D

Редакция:
Знам че подобно нещо е меко казано майтап за старите кучета програмисти, и едва ли им се занимава, ама защо не постнете някакъв код, да се види какви са "добрите практики"?
Таймерче, бутон, дебоунс, светодиод. Съвсем общо - не за конкретен микроконтролер...


Сря Юли 11, 2018 3:21 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Фев 26, 2006 6:52 pm
Мнения: 11265
Местоположение: Добрич
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
itso.t написа:
От коментарите оставам с впечатление, че ако 10 човека напишат горния код за бутона, светодиода и таймера, ще има минимум 10 различни версии... :D


тц... 10 човека това са поне 150 версии ;-)

Цитат:
ама защо не постнете някакъв код, да се види какви са "добрите практики"?


нямаш проблем - key_drv.* драйверче за всякакви клавиатур (матрични, нематрични) и не е за конкретен контролер ;-)


Сря Юли 11, 2018 3:37 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Чет Фев 03, 2005 2:21 am
Мнения: 12765
Местоположение: София
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
miro_atc написа:
нямаш проблем - key_drv.* драйверче за всякакви клавиатур (матрични, нематрични) и не е за конкретен контролер ;-)

Е, имах предвид нещо по-семпло и изчистено. Според мен, авторът на темата ще се "загуби" в хилядите условия за условно компилиране, и няма да вникне в същността.


Сря Юли 11, 2018 3:47 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Съб Ное 22, 2014 7:23 pm
Мнения: 48
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Май единствено itso.t, slav4o.com и relsys се опитват да ми помогнат, другите си чешат езиците, само не мога да разбера, защо това трябва да се случва в моята тема. Разбирам, че всички сте много начетени, че както се изрази itso.t това са свръх елементарни неща за вас, ама хайде ако обичате да престанете да спамите, ако няма да ми помогнете. Благодаря предварително !

Към relsys:

Благодаря за поправките, за while(25 == Delay_Counter_5s); /* Стой тук 5s */ си абсолютно прав, че работи на обратно. Относно кода, който си постнал, извинявам се, ама ми е малко объркващо. Написах си домашното и преправих програмата, обаче, нещата отново не се случват. И защо, трябва да променям таймера на 1ms, нали ми трябват 25 прекъсвания * 200ms ?

Код:

if((BUTTON_PRESSED == ReadButton()) && (btn_prev_state == BUTTON_NOT_PRESSED)) // btn_prev_state == BUTTON_NOT_PRESSED - Това е същото като BUTTON_RELEASED == ReadButton(), нали ? Не го разбирам, съжалявам...
   {/* Да */
      Delay_Counter_5s = 0; // Тук защо, нулираме брояча, не трябва ли да се нулира само в долният if ? Тук би следвало да включим диода или бъркам ?
      btn_prev_state = BUTTON_PRESSED; // Това стана ясно, че не го разбирам...
   }
   
   if(25 <= Delay_Counter_5s) /* Ако изтекат 5-те секунди (25 прекъсвания * 200ms = 5s) */
   {
      PAOUT &= ~(1 << 1); /* Изключи светодиода */
      btn_prev_state = BUTTON_NOT_PRESSED; // Това стана ясно, че не го разбирам...
     
      Delay_Counter_5s = 0; /* Нулираме брояча */
   }



Код:

#define BUTTON_PRESSED  (0)
#define BUTTON_RELEASED (1)

boolean ReadButton(void)
{
   return (PBIN & (1 << 0)) ? BUTTON_RELEASED : BUTTON_PRESSED;
}





Към slav4o.com:

Благодаря за съветите и за кода, но честно да ти кажа твоя код още повече ме пообърка :rolleyes: :rolleyes: :rolleyes: Наистина е супер, с коментари и всичко, просто се обърках тотално.

Благодаря на всички отново, извинявам се ако някой се е засегнал и разбира се, се извинявам за глупавите въпроси, които задавам и задавам... ( :



Код:

#include <ez8.h> /* Този хедър позволява да достъпваме вътрешните регистри като всички останали, чрез имената им. */
#include "stdtypes.h"

static uint32 Delay_Counter_5s = 0;


#define DELAY_CONSTANT_10_MSEC (5052)

#define BUTTON_PRESSED  (0)
#define BUTTON_RELEASED (1)

extern void PortConfig(void);
extern void InterruptConfig(void);
extern void TimerConfig(void);
extern boolean ReadButton(void);
extern void Delay(uint32 delay);

int main(void)
{
   PortConfig();
   InterruptConfig();
   TimerConfig();
   
   while(1)
   {
      if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
      {/* Да */
         Delay(DELAY_CONSTANT_10_MSEC); /* Изчакване 10ms */
         
         if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
         {/* Да */
            PAOUT |= 1 << 1; /* Включи сетодиода */
         }
         
         if(25 <= Delay_Counter_5s)
         {
            PAOUT &= ~(1 << 1); /* Изключи светодиода */
            
            Delay_Counter_5s = 0; /* Нулираме брояча */
         }
      }
   }
}

void interrupt Timer0_ISR(void) _At TIMER0
{   
   Delay_Counter_5s++;
}

void PortConfig(void)
{
   PADD &= ~(1 << 1); /* За да конфигурираме извод PA1 като изход, трябва да нулираме бит 1 на регистър PADD */
   
   PBDD |= 1 << 0; /* Kонфигурираме извод PB0 като вход */
}

void InterruptConfig(void)
{
   IRQCTL |= 1 << 7; /* Прекъсванията се разрешават с глобалния бит IRQE в регистър IRQCTL. Бит IRQE
   се установява в 1 */
   
   IRQ0ENL |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
   
   IRQ0ENH |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
}

void TimerConfig(void)
{
   T0H = 0x00; /* Записваме старшата част на числото -> Регистрите съдържат първоначалната стойност от която брои таймера */
   T0L = 0x00; /* Записваме младшата част на числото -> Регистрите съдържат първоначалната стойност от която брои таймера */
   
   T0RH = 0x7A; /* Записваме старшата част -> Регистрите съдържат макс. 16-бит броячна стойност до която брои таймера и тя е 65535 */
   T0RL = 0x12; /* Записваме младшата част -> Регистрите съдържат макс. 16-бит броячна стойност до която брои таймера и тя е 65535 */
   
   /* Системна честота - 20MHz => Честота на таймера - 20MHz / 128 (prescaler) = 156250Hz => Периода на таймера - 1 / 156250 = 0.0000064s
   или 6.4us => Таймера се увеличава с 1 на всеки 6.4us. Ние имаме 16 битов таймер, който брои до 65535 ---> Максималното време за което,
   може да имаме прекъсване е: 65535 * 0.0000064 = 420ms (приблизително). За 5s ми трябва число кратно на 5 и по-малко от 420ms (0.42s) =>
   За да получа 200ms, брояча трябва да изброи: 200 000 / 6.4 = 31 250 пъти (периода). Това ми е коефициента на таймера, демек ще брои
   от 0 до 31 250. */
   
   T0CTL0 = 0x00; /* Непрекъснат режим */
   T0CTL1 = 0xB9; /* Коефициент на деление 128 и стартиране на таймера */
}

boolean ReadButton(void)
{
   return (PBIN & (1 << 0)) ? BUTTON_RELEASED : BUTTON_PRESSED;
}

void Delay(uint32 delay)
{
   for(; delay > 0; delay--);
}



Сря Юли 11, 2018 4:41 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Чет Фев 03, 2005 2:21 am
Мнения: 12765
Местоположение: София
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Моят съвет е да разделиш цялата задача на малки такива.

Оправи кода така че на всеки да кажем 5 секунди да променяш изхода към който е свързан светодиода в 0, 1, 0 и.т.н.
Следваща стъпка - направи четенето на бутона с дебоунс на сигнала. Когато имаш валиден сигнал, да пали светодиода. Например, направи процеса да е бавен, да кажем 0.5 или 1 секунда за валиден входен сигнал. Така ще можеш да тестваш визуално дали се светодиода светва при кратко натискане.
Горното е по-удобно да се гледа на осцилоскоп, а и ще можеш да работиш с по-нормални времена, но не си споменал дали разполагаш с такъв.
За финал - сглоби кода от 1 и 2 за да получиш това което искаш.

Нагоре беше споменато периода генериран от таймера да е на някакъв кратък интервал. Това дава куп възможности. От една страна. можеш да го използваш за дебоунс. Можеш елементарно да направиш всякакви закъснения (имаше такива в кода). Е, за 5 скунди ще трябва броячът да е 16 битов, но общо взето е все тая. Един байт повече RAM.


Сря Юли 11, 2018 6:17 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Яну 01, 2012 8:04 pm
Мнения: 2663
Местоположение: София / Велико Търново
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Така както съм го направил бутона се чете в прекъсване и вдига флаг ако е в ниско ниво т.е. натиснат. Флага на бутона се обработва извън прекъсването. При това таймера се нулира и се стартира броенето. Дебоунс не мисля, че е необходим - ако има няколко задействания на бутона, ще важи времето от последното задействане. Все пак може да се сложи дебоунс :
Код:

void ProcessButtons(void)
{
  if(ButtonIF){
   if(!period_cnt) // ако брояча на периоди е 0-ла (не сме стартирали хронометъра), го стартираме (избягваме повторен рестарт преди 5те сек)
    StartChronometer();
   LED = ON;
   ButtonIF = FALSE;  // бутона е обработен
  }
}



Бутонът може да го четеш в основния цикъл, без прекъсване:
Код:

#derfine BUTTONPRESSED !(PBIN & (1 << 0))

void main (void)
{


   while(1){
   
     if(BUTTONPRESSED)
        StartChronometer();

   }

}

_________________
https://github.com/slav4ocom/


Сря Юли 11, 2018 8:34 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Съб Ное 22, 2014 7:23 pm
Мнения: 48
Мнение Re: Zilog - Z8 Encore! F083A Series - Timer & Button
Към itso.t:

Човече, аз уж това и направих, просто при сглобката нещо бъркам или вече нз и аз:

1. Искам 5s:

Код:

void InterruptConfig(void)
{
   IRQCTL |= 1 << 7; /* Прекъсванията се разрешават с глобалния бит IRQE в регистър IRQCTL. Бит IRQE
   се установява в 1 */
   
   IRQ0ENL |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
   
   IRQ0ENH |= 1 << 5; /* Достатъчно е да установим единия от двата или и двата бита. Младши бит 5 e за
   разрешаване на прекъсване от Таймер0. Всеки източник на прекъсване има локален механизъм за разрешаване. Този
   механизъм също се използва за задаване и на софтуерен приоритет на прекъсванията. Тъй като имаме само един
   източник на прекъсване в програмата, е без значение какво ниво на приоритет ще изберем. */
}



void TimerConfig(void)
{
   T0H = 0x00;
   T0L = 0x00;
   
   T0RH = 0x7A;
   T0RL = 0x12;
   
   /* Системна честота - 20MHz => Честота на таймера - 20MHz / 128 (prescaler) = 156250Hz => Периода на таймера - 1 / 156250 = 0.0000064s
   или 6.4us => Таймера се увеличава с 1 на всеки 6.4us. Ние имаме 16 битов таймер, който брои до 65535 ---> Максималното време за което,
   може да имаме прекъсване е: 65535 * 0.0000064 = 420ms (приблизително). За 5s ми трябва число кратно на 5 и по-малко от 420ms (0.42s) =>
   За да получа 200ms, брояча трябва да изброи: 200 000 / 6.4 = 31 250 пъти (периода). Това ми е коефициента на таймера, демек ще брои
   от 0 до 31 250. */
   
   T0CTL0 = 0x00; /* Непрекъснат режим */
   T0CTL1 = 0xB9; /* Коефициент на деление 128 и стартиране на таймера */
}



static uint8 Delay_Counter_5s = 0;
   
Delay_Counter_5s++; // За този ред се разбрахме, че ще стои в интеръпта...
   
   if (25 == Delay_Counter_5s)
   {
      PAOUT ^= 1 << 1; /* Превключване на нивото на извод PA1 */
     
      Delay_Counter_5s = 0;
   }



Горният код е тестван и диода се превключва от 0 в 1 и т.н.през 5s : )



Следва кода на бутона и delay-а, заради трептенията на пластината:

Код:

#define DELAY_CONSTANT_10_MSEC (5052)

#define BUTTON_PRESSED  (0)
#define BUTTON_RELEASED (1)

-------------------------------

if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
      {/* Да */
         Delay(DELAY_CONSTANT_10_MSEC); /* Изчакване 10ms */
         
         if(BUTTON_PRESSED == ReadButton()) /* Бутонът натиснат ли е ? */
         {/* Да */
            PAOUT |= 1 << 1; /* Включи сетодиода */
         }

-------------------------------

boolean ReadButton(void)
{
   return (PBIN & (1 << 0)) ? BUTTON_RELEASED : BUTTON_PRESSED;
}

void Delay(uint32 delay)
{
   for(; delay > 0; delay--);
}





И така 2 кода работещи перфектно отделно и при сглобката - гредааа ?! Бутонът се чете, изчаква се 10ms, после пак четем бутона и ако нивото е ниско, превключваме диода, може би сега по-някакъв начин трябва с таймера да кажа на диода да изчака 5s и после да угася диода. Но, как ? Уж имам правилен код за 5s, но нещо се бъркам...

Към slav4o.com:

Благодаря ти наистина за усилията, кода и всичко, просто аз искам да си оправя моя код и почти съм сигурен, че нещо малко ми липсва, не разбирам или вече нз какво да кажа и аз...



Извинявам се, ако досаждам вече ! ( :


Сря Юли 11, 2018 10:29 pm
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 72 мнения ]  Отиди на страница 1, 2, 3, 4, 5  Следваща

Кой е на линия

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


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

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