Отговори на тема  [ 75 мнения ]  Отиди на страница 1, 2, 3, 4, 5  Следваща
мултифункционален бутон + PWM 
Автор Съобщение
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Юни 21, 2011 9:51 pm
Мнения: 46
Местоположение: Bulgaria
Мнение мултифункционален бутон + PWM
от няколко седмици се боря да направя един контролер за 2 RGB лампи и една и една обикновенна :)

за целата ми трябва да направя бутон който да различва click, double click and hold работа с MPLAB под С

това е кода до който стигнах последно но така не работи бутона изобщо не засича. Тръгнал съм да го правя със инттерупт защото искам да вкарам и функция която да превърта плавно цветовете .
Код:
#include <htc.h>
#include <pic.h>
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000
#endif

unsigned char but;
unsigned char mode;

#define BUTTON RB5
#define MAX_DB_CNT 20/2

volatile unsigned char PB_dbstate;
volatile unsigned char PB_change;

void main()
{
TRISA = 0b00000000;
TRISB = 0b11110000;
PORTA = 0b10000000;
PORTB = 0b00000000;
CMCON = 7;
T0CS=1;
PSA=1;
PB_dbstate=1;
PB_change=0;
mode=1;
but=1;
T0IE = 1;
ei();
   for(;;)
   {
   if (PB_change==1)
      {
      but++;
      PB_change=0;
      if(but==6){but=1;}
      }
   if (PB_change==2)
      {
      mode++;
      PB_change=0;
      if (mode==4){mode=1;}
      }
   if (PB_change==3)
      {
      PB_change=0;
      if(RA7==1){RA7=0;}else{RA7=1;}
      }

       if (mode==1){                   
      switch(but)
      {

         case 1:// if screen == 1 run this code!
         PORTB = 0b00101110;
         break;

         case 2:// if screen == 2 run this code!
         PORTB = 0b00101100;
         break;

         case 3:// if screen == 2 run this code!
         PORTB = 0b00101000;
         break;
         case 4:// if screen == 2 run this code!
         PORTB = 0b00100010;
         break;
         case 5:// if screen == 2 run this code!
         PORTB = 0b00100110;
         break;
   
      }
         }
  if (mode==2){                   
      switch(but)
      {

         case 1:// if screen == 1 run this code!
         PORTA = 0b00001100;
         RB0=1;
         break;

         case 2:// if screen == 2 run this code!
         PORTA = 0b00001100;
         RB0=0;
         break;

         case 3:// if screen == 2 run this code!
         PORTA = 0b00001000;
         RB0=0;
         break;
         case 4:// if screen == 2 run this code!
         PORTA = 0b00000000;
         RB0=1;
         break;
         case 5:// if screen == 2 run this code!
         PORTB = 0b00000100;
         RB0=1;
         break;
   
      }
         }
         
   }   
}

void interrupt isr(void)
{
volatile unsigned char t0_cnt=0;
volatile unsigned char db_cnt=0;
volatile unsigned char long_cnt=0;
volatile unsigned char double_cnt=0;
volatile unsigned char flag=0;

TMR0 += 256-250+3;
T0IF =0;

++t0_cnt;
if (++t0_cnt==2000/250)
   {
   t0_cnt= 0;
   ++double_cnt;
   if (BUTTON == PB_dbstate)
      {
      t0_cnt=0;
      long_cnt=0;
      }
   else
      {
      ++db_cnt;
      ++long_cnt;
      
      if (db_cnt== MAX_DB_CNT)
         {
         PB_dbstate = !PB_dbstate;
         db_cnt=0;
         PB_change=1;
         ++flag;
         if(flag==2&&double_cnt<250)
            {
            flag=0;
            double_cnt=0;
            PB_change=2;
            }
         if(flag==2)
            {
            flag=0;
            double_cnt=0;
            }
         }
      if (long_cnt==200)
         {
         long_cnt=0;
         PB_change=3;
         }
      
      }
   }
}









много съм го закъсал , вече направих кутия за трафа и за контролера , направих и дистанционно което да го ползвам за бутон, направих и водоустоичивите лампи. Мислех че кода няма да ми е толквоа проблем но уви.... та моля някой да даде едно рамо , че немошах да си намеря протеус зада ги тествам направо на машината и трябва постоянно да свалям и закачам което направо вече ме побърква. Чипа е 16f627a


Последна промяна pachuka на Вто Юни 28, 2011 10:29 am, променена общо 1 път



Сря Юни 22, 2011 12:06 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Сря Юли 11, 2007 10:16 am
Мнения: 1730
Мнение 
Не съм ти гледал целия код, и не съм се мъчил да разбирам какво си правил, но на пръв поглед виждам в прекъсването, че
Код:
t0_cnt
никога няма да стане повече от 2, и съответно няма да влезе в нито едно условие. На всяко викане на прекъсването t0_cnt = 0. Ако я направиш статична въпросната променлива, може и да има някакъв шанс.


Сря Юни 22, 2011 12:20 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Юни 21, 2011 9:51 pm
Мнения: 46
Местоположение: Bulgaria
Мнение 
даа бе защо съм ги оставил там а не при другите , още утре ще пробвам как ще е като ги извадя от там.

Но изобщо в правилна насока ли съм , някой правил ли е енещо подобно, по много техники се наблюдават такива бутони :)


Сря Юни 22, 2011 12:42 am
Профил
Ранг: Популярен
Ранг: Популярен

Регистриран на: Сря Яну 25, 2006 12:47 pm
Мнения: 305
Местоположение: Varna
Мнение 
Колега, тази тема е за "Академия".

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


Сря Юни 22, 2011 9:31 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Юни 21, 2011 9:51 pm
Мнения: 46
Местоположение: Bulgaria
Мнение 
на теория ми е ясно как трябва да стане , но писането на кода ми куца.


Съб Юни 25, 2011 4:54 pm
Профил
Ранг: Ориентиран
Ранг: Ориентиран

Регистриран на: Вто Фев 06, 2007 2:45 am
Мнения: 263
Мнение 
Koпи & пейст (с допълнението за double-click) от друга подобна тема. Не гарантирам тръгване от раз, щото е нахвърляно набързо.
Само трябва да измислиш как да викаш OneButtonTask() циклично.
Код:
// Таймерите: 0 = спрян, > 0 = работещ

#define TASK_PERIOD_MS                  10      // Период на OneButtonTask().
#define DEBOUNCE_TIME                   (50 / TASK_PERIOD_MS)    // Дебаунс време
#define DOUBLE_CLICK_TIME               (500 / TASK_PERIOD_MS)   // Време между две натискания, което минава за double-click
#define BTN_PRESSED                     0       // или 1, зависи как е вързан бутона
#define pBUTTON                         pA2     // тук си дефинираш пина, на който си вързал бутона.


typedef enum {
    IDLE,           // бутона е отпуснат
    DEBOUNCING,     // бутона е натиснат и тече дебаунс
    DEBOUNCED,      // бутона е натиснат, дебаунс времето е изтекло, състоянието на бутона е потвърдено
    DOUBLE_CLICKED,
    CANCELLED,      // бутона е отпуснат преди да е изтекло дебаунс времето
    RELEASING       // чакаме бутона да се отпусне
} TStates;


static TStates      еState = IDLE;

void OneButtonTask(void)
{
    static UInt16      debounceTimer = 0;
    static UInt16      doubleClickTimer = 0;

    switch (еState)
    {
    case IDLE:
        {
            if (BTN_PRESSED == pBUTTON)
            {
                // Стартираме дебаунс
                debounceTimer = DEBOUNCE_TIME;
                еState = DEBOUNCING;
            }

            break;
        }

    case DEBOUNCING:
        {
            // Натиснат ли е все още бутона?
            if (BTN_PRESSED == pBUTTON)
            {
                // Да. Дебаунс времето изтекло ли е?
                if (0 == debounceTimer)
                {
                    // Да, имаме натискане
                    еState = DEBOUNCED;
                }
            }
            else
            {
                // Бутона е отпуснат по време на дебаунс
                еState = CANCELLED;
            }

            break;
        }

    case DEBOUNCED:
        {
            // Тук можеш да свършиш каквото трябва при еднократно натискане на бутона
            // .....
            //
           
            // Стартираме таймера за double-click, само ако е изтекъл doubleClickTimer.
            if (0 == doubleClickTimer)
            {
                еState = RELEASING;
                doubleClickTimer = DOUBLE_CLICK_TIME;
            }
            else
            {
                еState = DOUBLE_CLICKED;
                doubleClickTimer = 0;
            }

            break;
        }

    case DOUBLE_CLICKED:
        {
            // Тук си при двоен клик.
            // .....
            //
           
            еState = RELEASING;
            break;
        }

    case CANCELLED:
        {
            // Тук можеш да свършиш нещо в случай, че бутона се отпусне преждевременно. Удобно е при дълъг дебаунс
            // .....

            еState = RELEASING;
            break;
        }

    case RELEASING:
        {
            // Бутона отпуснат ли е?
            if (BTN_PRESSED != pBUTTON)
            {
                // Да, почваме отначало
                еState = IDLE;
            }
           
            break;
        }

    default:
        {
            // По принцип тук не трябва да се влиза никога, но кой знае... :)
            еState = IDLE;
            break;
        }
    }

    // Накрая придвижваме таймерите
    if (0 < debounceTimer)
    {
        debounceTimer--;
    }

    if (0 < doubleClickTimer)
    {
        doubleClickTimer--;
    }
}


edit: Опс, намерих грешка. По-добре е таймерите в случая да са с 2 стейта.


Последна промяна tolstolob на Нед Юни 26, 2011 1:11 pm, променена общо 3 пъти



Нед Юни 26, 2011 12:48 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Пет Ное 25, 2005 11:41 am
Мнения: 1680
Мнение 
@tolostolob +1

Все едно аз съм го писал тоя код. Като покажа на някой обаче код написан в такъв стил, нещо не могат да го разберат. Толкова ли е сложно и неразбираемо? Според мен, стейт машините са най-разбираемия начин за описване на дадена задача.


Нед Юни 26, 2011 10:38 am
Профил ICQ WWW
Ранг: Ориентиран
Ранг: Ориентиран

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


Нед Юни 26, 2011 1:19 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Юни 21, 2011 9:51 pm
Мнения: 46
Местоположение: Bulgaria
Мнение 
@tolstolob благодаря много ако го бях видял по рано твоя отговор щях да си спестя доста нерви. Но успях да се спрява и сам с бутона :) с което съм горд. ето го и целяи код може на някой да е полезен


Код:
#include <htc.h>
#include <pic16f627a.h>

/***** CONFIGURATION *****/
// ext reset, no code or data protect, no brownout detect,
// no watchdog, power-up timer enabled, 4MHz int clock


// Pin assignments
#define rele 7 // releto na  RA7
/***** GLOBAL VARIABLES *****/
unsigned char sGPB; // shadow copy of GPIO
volatile unsigned char flag=0;
volatile unsigned char but=0;
volatile unsigned char mode=0;
/***** MAIN PROGRAM *****/
void main()
{
// Initialisation
// setup ports
PORTA= 0;
PORTB = 0; // start with LED off
sGPB = 0; // update shadow
TRISB = 0b11110000; // configure LED pin
TRISA = 0b00000000;
CMCON =7;
mode=3;
but=1;
OPTION_REG = 0b11010111;
// configure Timer0:
//--0----- timer mode (T0CS = 0)
//----0--- prescaler assigned to Timer0 (PSA = 0)
//-----111 prescale = 256 (PS = 111)
// -> increment every 256 us
// configure interrupts
T0IE = 1; // enable Timer0 interrupt
ei(); // enable global interrupts
// Main loop
for (;;) {
// continually copy shadow GPB to port
RA7 = sGPB;
if (mode>=4){mode=1;}
if (mode==1){                   
  switch(but)
  {

   case 1:// if screen == 1 run this code!
   PORTB = 0b00101110;
   break;

   case 2:// if screen == 2 run this code!
   PORTB = 0b00101100;
   break;

   case 3:// if screen == 2 run this code!
   PORTB = 0b00101000;
   break;
   case 4:// if screen == 2 run this code!
   PORTB = 0b00100010;
   break;
   case 5:// if screen == 2 run this code!
   PORTB = 0b00100110;
   break;
   case 6:// if screen == 2 run this code!
   but=1;
   break;

  }
   }
  if (mode==2){                   
  switch(but)
  {

   case 1:// if screen == 1 run this code!
   PORTA = 0b00001100;
   RB0=1;
   break;

   case 2:// if screen == 2 run this code!
   PORTA = 0b00001100;
   RB0=0;
   break;

   case 3:// if screen == 2 run this code!
   PORTA = 0b00001000;
   RB0=0;
   break;
   case 4:// if screen == 2 run this code!
   PORTA = 0b00000000;
   RB0=1;
   break;
   case 5:// if screen == 2 run this code!
   PORTA = 0b00000100;
   RB0=1;
   break;
    case 6:// if screen == 2 run this code!
   but=1;
   break;

  }
   }
   if (mode==3)
   {
////////////////////////////////////////////////////////////////
/////////ТУК ДА PWM ФУНКЦИЯТА ЗА РЕДУВАНЕ НА ЦВЕТОВЕТЕ/////////   
//////////////////////////////////////////////////////////////
   }


} // repeat forever
}


/***** INTERRUPT SERVICE ROUTINE *****/
void interrupt isr(void)
{
static unsigned int t0_cnt=0;
static unsigned int dc_cnt=0;
static unsigned int hold_cnt=0;
// handle Timer0 interrupt
T0IF = 0;
   dc_cnt++;
if(dc_cnt==32){dc_cnt=31;}
if (RB5==0)
   {
   t0_cnt++;
   hold_cnt++;
   }
else if (RB5==1)
   {
   if(hold_cnt>=20)
      {
      flag=0;
      sGPB ^= 1;
      hold_cnt=t0_cnt=dc_cnt=0;
      }   

   else if(t0_cnt>=3 && flag==1 && dc_cnt<10)
      {
      flag=0;
      mode++;
      hold_cnt=t0_cnt=dc_cnt=0;
      }
   else if(t0_cnt>=3&&dc_cnt>10)
      {
      flag=1;
      hold_cnt=t0_cnt=dc_cnt=0;
      }
   if (flag==1&&dc_cnt>10)
      {
      flag=0;
      but++;
      hold_cnt=t0_cnt=dc_cnt=0;
      }
   else
      {

      hold_cnt=t0_cnt=0;
      }
   }

}



НО сега ми идва другия проблем. За да е всичко готово ми се иска там където е "mode==3" да се пускат да се връткат всички възможни цветове едновременно и на двата RGBta
демек
RA2=RB1= зелено
RA3=RB2= червено
RB0=RB3 = синьо

та моляви дайте едно бързо рамо че съм си дал срок до петък да е готово всичко и да ги монтирам :)
PIC а е 16f627a

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


Код:
   while( 1 )                  // Loop forever...
   {
   GPIO2 = 1;               // Start pulse
   for(pulse = 0; pulse < duty; pulse++);      // Lengthen pulse if < duty
   GPIO2 = 0;               // End pulse
   for(pulse = 0; pulse < (freq - duty); pulse++);   // Continue until frequency
   duty++;                  // Increment Duty cycle
   }


Вто Юни 28, 2011 2:13 am
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Юни 21, 2011 9:51 pm
Мнения: 46
Местоположение: Bulgaria
Мнение 
Изображение

искам да постигна този ефект. някой можели поне да разясни малко как трябва да стане защото миголяма мешавица в главата .

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


Сря Юни 29, 2011 3:52 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30684
Местоположение: София
Мнение 
Мммм какво конкретно те мъчи, трябват ти 3 PWM, аз не бих изпрал точно пик за целта но при тебе вече е факт. Остава ти въпроса с преливането на цветовете което може да стане по два начина, по сложния да измислиш алгоритъм който да мени едновременно трите PWM в желаната от теб комнинация, другия по лесен ако си решил да имаш примерно 64 стъпки на промяна да си зададеш табличните стойности и да ги въртиш. може и нещо междинно, да се движиш по таблични стойности, но да апроксимираш между тях, така ще имаш повече стъпки и плавност. Тук апроксимацията трябва да с епомисли дали винаги ще е линейна, или по скоро дали винаги ще е един тип функция без значение линейна или не.
Като знам колко много флаш имат тия пикове може и да не ти стигне :)


Сря Юни 29, 2011 7:38 am
Профил
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Съб Сеп 17, 2005 5:07 pm
Мнения: 813
Местоположение: Сливен
Мнение 
Що бе Тони ако иска точно това от картинката .. ми то се вижда алгоритъма ..колко флаш ще иде за пускане на един таймер и в прекъсването му според зададените стойности да клатиш 3 те крака .
Май Цецо преди беше се бъзикал с един пикльо 12-ка на тази тема.
Е ако имаше 3 PWM щеше да е прекалено лесно ама нали за това сме пикоборци .. да ни е трудно :D


Сря Юни 29, 2011 9:22 am
Профил ICQ
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Нед Окт 19, 2008 7:26 pm
Мнения: 672
Мнение 
Правих и аз нещо за RGB ... ама не се сещам вече за какво беше и как изглеждаше.
Спомням си че плавно се смесваха цветовете, и имаше условие да не с включват трите диода заедно, нещо пазене на батерииката ... . Мисля че основното беше това :
Код:
#include "D:\3_led\main.h"
char flag,tmr1,i,j;
#bit rtmr=flag.0
#bit gtmr=flag.1
#bit btmr=flag.2
#bit xxxx=flag.3
//#use fast_io(ALL)   
#int_RTCC
void  RTCC_isr(void)
{
set_RTCC(200);
tmr1++;
if(tmr1==1){
   output_low(PIN_A2);
   if(rtmr)output_high(PIN_A0);
   output_low(PIN_A1);
            };
if(tmr1==2){
   output_low(PIN_A0);
   if(gtmr)output_high(PIN_A1);
   output_low(PIN_A2);
            };
if(tmr1>=3){
   output_low(PIN_A1);
   if(btmr)output_high(PIN_A2);
   output_low(PIN_A0);
   tmr1=0;
         };
}

#int_TIMER1
void  TIMER1_isr(void)
{
set_timer1(0);
//rtmr=1,gtmr=1,btmr=1;
}



void main()
{

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);setup_wdt(WDT_18MS);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   setup_comparator(NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_RTCC);
//   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);

   // TODO: USER CODE!!
while(1){
restart_wdt();
rtmr=1,gtmr=0,btmr=0;
delay_ms(500);
for(i=1,j=15;i<=15;i++,j--){
   gtmr=1;
   rtmr=0;
   delay_ms(i);
   rtmr=1;
   gtmr=0;
   delay_ms(j);
};
rtmr=0,gtmr=1,btmr=0;
delay_ms(500);
for(i=1,j=15;i<=15;i++,j--){
   gtmr=0;
   btmr=1;
   delay_ms(i);
   btmr=0;
   gtmr=1;
   delay_ms(j);
};
rtmr=0,gtmr=0,btmr=1;
delay_ms(500);
for(i=1,j=15;i<=15;i++,j--){
   btmr=0;
   rtmr=1;
   delay_ms(i);
   btmr=1;
   rtmr=0;
   delay_ms(j);
};
};
}


Прикачени файлове:
3_led.rar [32.55 KiB]
138 пъти

_________________
Вниманиене съмвишист....ИЙ.
Сря Юни 29, 2011 9:34 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Сеп 26, 2004 9:21 pm
Мнения: 30684
Местоположение: София
Мнение 
valioman написа:
Що бе Тони ако иска точно това от картинката .. ми то се вижда алгоритъма ..колко флаш ще иде за пускане на един таймер и в прекъсването му според зададените стойности да клатиш 3 те крака .
Май Цецо преди беше се бъзикал с един пикльо 12-ка на тази тема.
Е ако имаше 3 PWM щеше да е прекалено лесно ама нали за това сме пикоборци .. да ни е трудно :D


Е ако иска точно това от картинката нещата са прости, там се мени само едният ШИМ, но не знам какво преливане би се получило, иначе по тоя начин може д астане мног опо плавно значително по лесно, може и 10 битов да е ШИМ.


Сря Юни 29, 2011 12:41 pm
Профил
Ранг: Минаващ
Ранг: Минаващ

Регистриран на: Вто Юни 21, 2011 9:51 pm
Мнения: 46
Местоположение: Bulgaria
Мнение 
точно това искам от катинката, преливане само най голямата яркост на цветовете. гледам че му викат дъга или rainbow само къде аз искам да има и бяло. във youtybe е пълно със готови таквиа проекти с пикчета 12фххх
таймера ми е на лице не е проблем да вкарам в него една променлива "x" която да се мени от 0до 255 за желано от мен време.

но как да задам на самия пин тая стойност ако напиша RB1=255; и RB2=120; свети само с максимална мощност RB2
та май това ми е проблема алгоритъма ще го измисля за връткането, но дори и таблично да го направя както предлага тони пак незнам как да задам да свети примерно наполовина единия лед.


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

Кой е на линия

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


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

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