Cvavr вопрос по Си

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
Arik
Встал на лапы
Сообщения: 137
Зарегистрирован: Сб апр 04, 2009 04:12:23

Cvavr вопрос по Си

Сообщение Arik »

Здравствуйте столкнулся с проблемой! Пишу программу сканирующую три вывода микроконтроллера тини 2313 Пишу на Си

Код: Выделить всё

 while(1)
 {
      if(PINB.1<1)allarm1();       
      if(PINB.2<1)allarm2();
      if(PINB.3<1)allarm3();
 };  
если на одном из выводов удерживать низкий уровень, то срабатывает соответствующая подпрограмма allarm(1-3) но мне не нужно чтобы подпрограмма выполнялась постоянно, пока удерживается низкий уровень на выводе. Как сделать чтобы подпрограмма сработала один раз и не срабатывала повторно если низкий уровень всё еще присутствует на выводе, но сканирование оставшихся выводов продолжалось? Спасибо!
Реклама
Аватара пользователя
adrenocrome
Потрогал лапой паяльник
Сообщения: 365
Зарегистрирован: Вт окт 21, 2008 15:03:06
Откуда: moscow
Контактная информация:

Сообщение adrenocrome »

заведи лишнюю переменную,в неё пиши флаг отработки подпрограммы. Отработала - пиши в флаг 1 например.
Реклама
Аватара пользователя
Danko
Сверлит текстолит когтями
Сообщения: 1287
Зарегистрирован: Пн окт 13, 2008 11:45:54
Откуда: РФ, Крым, г.Бахчисарай
Контактная информация:

Сообщение Danko »

А если за время обработки Alarm3 на 1 входе была "1" и к моменту опроса опять установился "0".

Лучше читать сразу весь порт отбрасывать ненужные биты а из нужных выбирать комбинацию "0" на одном на двух и т.д.
и соответственно вызывать нужную Alarm()
Аватара пользователя
Yellow Tiger
Сверлит текстолит когтями
Сообщения: 1148
Зарегистрирован: Вт июл 08, 2008 12:24:17

Re: Cvavr вопрос по Си

Сообщение Yellow Tiger »

Arik писал(а):Как сделать чтобы подпрограмма сработала один раз и не срабатывала повторно ...
Для этого нужно обнаруживать не уровень, а смену уровня - то есть, не только читать состояние порта с кнопками, но и помнить предыдущее значение и сравнивать с ним побитным XOR'ом - единички в результате побитного XOR'а покажут какие биты изменились, а единички в только что прочитанном покажут, в каких битах переход был с нуля на единичку (ну, а в остальных - ...).
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
xelos
Потрогал лапой паяльник
Сообщения: 336
Зарегистрирован: Пн мар 20, 2006 13:05:08
Контактная информация:

Сообщение xelos »

либо прерывания использовать...

1. прерывание по таймеру - анализ входных битов идет периодично и от того, что задетектировали - вызывать соответствующую процедуру. проблема - если уже находимся в процедуре обработки и вызываем новую - кол-во вложенных вызовов ограничено стеком.

2. либо прерывания на изменение порта ввода, если есть такая возможность. проблема та же, что и в первом случае.

все зависит от конкретной задачи. но проблема вложенных вызовов может быть критичной.
Я просто верю в то, что рушить догмы - лучший способ не стареть.
Реклама
Vov123
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

if(PINB.1)alarm1();
else
no_alarm1();
Реклама
Аватара пользователя
Yellow Tiger
Сверлит текстолит когтями
Сообщения: 1148
Зарегистрирован: Вт июл 08, 2008 12:24:17

Re: Cvavr вопрос по Си

Сообщение Yellow Tiger »

Автор привел такой код:
Arik писал(а):

Код: Выделить всё

      if(PINB.1<1)allarm1();
Как сделать чтобы подпрограмма сработала один раз и не срабатывала повторно если низкий уровень всё еще присутствует на выводе...?
Зачем советовать тот же принцип? Ведь и работать будет также:
Vov123 писал(а):

Код: Выделить всё

if(PINB.1)
    alarm1();
else
    no_alarm1();
Единственное отличие в том, что вызов alarm() будет не по нулю, а по единице на входе.
Vov123
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

Да и кодик условный и не для вас.
Можно написать проще-используйте оператор ELSE

До меня дошло-сомневаетесь в правильности.
Так вот,если без ELSE,то принажатии кнопки произойдёт вызов функции,но и при отпускании кнопки alarm будет продалжать "гудеть".
Но при использовании оператора ELSE при отпускании кнопки произойдёт вызов другой функции "alarm-off".
Интересно,кто-же мешает вам это проверить,хотя бы в проте?

Вот поиграйтесь.
Вложения
2313.rar
(36.23 КБ) 160 скачиваний
YKolomiets
Родился
Сообщения: 13
Зарегистрирован: Чт апр 02, 2009 10:06:25

Сообщение YKolomiets »

Предлагаю так:
unsigned char x1, x2, x3;
x1=x2=x3=1;
while(1)
{
if(PINB.1<1)
{
if(x1)
{
allarm1();
x1=0;
}
}
else
{
x1=1;
}
if(PINB.2<1)allarm2();
тоже самое что и выше но с х2
if(PINB.3<1)allarm3();
тоже самое что и выше но с х3
};
По строки подряд идут не могу отредактировать.
Аватара пользователя
Yellow Tiger
Сверлит текстолит когтями
Сообщения: 1148
Зарегистрирован: Вт июл 08, 2008 12:24:17

Сообщение Yellow Tiger »

Vov123 писал(а):Вот поиграйтесь.
Благодарю, нет нужды. Работать этот код будет именно так, как не хочет автор вопроса, а именно - пока кнопка нажата, будет, как из пулемета, вызываться функция alarm(), и связано это, как я уже говорил, с тем, что предложенный код устроен так же, как и тот, который хотел заменить автор вопроса.
Еще раз, чего хотел спрашивавший:
Arik писал(а):срабатывает соответствующая подпрограмма allarm(1-3) но мне не нужно чтобы подпрограмма выполнялась постоянно, пока удерживается низкий уровень на выводе. Как сделать чтобы подпрограмма сработала один раз и не срабатывала повторно если низкий уровень всё еще присутствует на выводе, но сканирование оставшихся выводов продолжалось? Спасибо!
P.S. Не сразу заметил вот это:
Vov123 писал(а):но и при отпускании кнопки alarm будет продалжать "гудеть"
Можно узнать, кто будет вызывать функцию alarm() в этом коде:

Код: Выделить всё

if(PINB.1<1)allarm1();
когда отпущенная кнопка сделает проверку "(PINB.1<1)" ложной - Пушкин?
YKolomiets писал(а):Предлагаю так:

Код: Выделить всё

unsigned char x1, x2, x3;
x1=x2=x3=1;
while(1) 
{
   if(PINB.1<1)
   {
        if(x1)
        {
          allarm1();
          x1=0;
         }
        }
       else
       {
         x1=1;
        }
       ...
 };
То же самое, что с побитным XOR'ом, только значительно длиннее, медленнее, запутаннее и с массой ненужных переменных.
Аватара пользователя
__Alexander
Потрогал лапой паяльник
Сообщения: 335
Зарегистрирован: Вт сен 11, 2007 10:27:08
Откуда: Киев

Сообщение __Alexander »

Тут без автора вопроса никак не обойтись, хотя по ходу ему этот вопрос уже не актуален. :))

Хотел было вопрос задать, а могу только усложнить задачу: А кто сказал, что подпрограмма alarm должна возвращаться в while??? После возврата она начнет заново выполняться. А может автору это не нужно? Вошла в alarm, выполняется там в while(1), но при этом сканирование продолжается, и при нажатии другой клавиши, передаем указатель адреса функции обратно и обрабатываем...? Ну как? Может этого хотел автор?
Vov123
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

Надо было поиграться-поманипулировать оператором ELSE.
Тогда бы не стал вспоминать писателей и задавать глупых вопросов.
Хотя чего я пристал?Обещаю торжественно обходить вас стороной и прошу тех же действий от вас.
Аватара пользователя
Arik
Встал на лапы
Сообщения: 137
Зарегистрирован: Сб апр 04, 2009 04:12:23

Сообщение Arik »

Всем спасибо за участие! Раскрою вопрос более конкретно!функция Allarm() содержит АТ команду для GSM модема а сканируемые порты это датчики - движения, подьема гаража и шума. Так вот при срабатывании датчика шума к примеру должна быть отправлена смс с текстом шум.
Моделирую в протеусе и получаю такую картину - если сработал датчик подьема гаража, то смс с текстом подьем отправляется без остановки снова и снова! В реальной жизни это сразу приведет к зависанию модема! Вот мне и нужно чтоб помогли с кодом так, чтобы отправлялось только один раз, даже если датчик остается в активном состоянии.

P.S. Например пришла смс с текстом шум но нет другой смс движение или подьем значит можно не паниковать! Может это дети бомбочками балуются :)
Аватара пользователя
Yellow Tiger
Сверлит текстолит когтями
Сообщения: 1148
Зарегистрирован: Вт июл 08, 2008 12:24:17

Сообщение Yellow Tiger »

Vov123 писал(а):Тогда бы не стал ... задавать глупых вопросов.
Ты не понял - это был не вопрос, это был намёк! Подсказка. Изображение

Ладно, мастер "операторов" Else, дам еще один шанс...

1. Пишем простенькую программку, чтобы проверить будет ли вызываться что-либо в теле оператора if, если его условие не выполняется, а "оператора" ELSE не предусмотрено:

Код: Выделить всё

//=== Global definitions
void    InitDevices( void );    //Init controller perifery

void main(void)
{
        InitDevices();
        
        while (1)
        {
            if (!PINB.0) // if PB.0's pressed
                    PINB.1 = 1;
        };
}
2. Подключаем к PB.0 кнопку, а к PB.1 - осцилл
3. Запускаем - экран заполнится уровнем "1", нажимаем кнопку - на экране появляется меандр, отпускаем кнопку - меандр исчезает, снова нажимаем - меандр появляется (см. кнопку 1 на Control Panel):
Изображение
4. Сравниваем поведение программы в контроллере с этими словами:
Yellow Tiger писал(а):пока кнопка нажата, будет, как из пулемета, вызываться функция alarm()
, а затем с этими:
Vov123 писал(а):если без ELSE,то ... и при отпускании кнопки alarm будет продалжать "гудеть"
и делаем выводы. Изображение

P.S. Если добавить "оператор" else, то в поведении тиньки относительно нажатий кнопки нифига не изменится...:

Код: Выделить всё

        while (1)
        {
            if (!PINB.0) // if PB.0's pressed
                    PINB.1 = 1;
            else
                    #asm("nop");
        };
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Сообщение ARV »

что-то мне ход дискуссии стал напоминать соседнюю тему известного автора a...mm-а : едва ли не в первом ответе был дан верный совет, однако на протяжении многих последующих постов все идет и идет обсасывание неверных вариантов...

решение "в лоб":

Код: Выделить всё

#define f_1 0b00000001
#define f_2 0b00000010
#define f_3 0b00000100

unsigned char flags = 0;

while(1){
   // проверка первого варианта f_1
   if(!(PINB & f_1)){
      // если в пине 0, то проверим, не было ли уже такого ранее?
      if(!(flag & f_1)){
         // если флажок не установлен, то вызываем свою функцию
         alarm1();
         // и устанавливаем флаг обработки события
         flag |= f_1;
      }
   } else flag &= ~f_1; // если в пине 1, то сбросим флажок этого события

   // далее аналогично для обработки состояний f_2 и f_3
}
логичнее и оптимальнее было бы функцию выдачи сообщения сделать одну, а не три, передавать в нее "сработавший" пин, а внутри нее анализировать состояние флажков и устанавливать их при необходимости, а так же выводить сообщение, соответствующее переданному пину...

что-то типа такого:

Код: Выделить всё

void alarm(unsigned char pin){
   if(flag & pin) return; // если флаг уже стоит - сразу выход
   flag |= pin;
   switch(pin){
   case f_1: SMS_SEND("караул!!!");
   case f_2: SMS_SEND("грабят!!!");
   case f_3: SMS_SEND("насилуют");
   default:  SMS_SEND("ошибка!");
   }      
}
разумеется, и это не самое элегантное решение, но не буду же я все сам за вас делать? :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
Барсик
Друг Кота
Сообщения: 3459
Зарегистрирован: Ср сен 27, 2006 16:18:57

Сообщение Барсик »

А флаг, как мне кажется, лучше сбрасывать по прошествию некоторого времени. А то если будет "трах-бах-бах-бубух", то придётся ещё и с дребезгом датчика бороться.
Сделать из одного таймера системные часы, чтобы возникало прерывание, например, раз в миллисекунду.

В программе написать:

Код: Выделить всё

#define MAX_ALARM1_TIME 5000 // 5 секунд
unsigned int alarm1_time = 0; // счётчик времени
В теле функции alarm написать:

Код: Выделить всё

if(!alarm1_time)
{
    sendSms(?????);
    alarm1_time = MAX_ALARM1_TIME
}
А в обработчике прерывания от таймера уменьшать счётчик времени:

Код: Выделить всё

if(alarm1_time)
    alarm1_time--;
Аватара пользователя
__Alexander
Потрогал лапой паяльник
Сообщения: 335
Зарегистрирован: Вт сен 11, 2007 10:27:08
Откуда: Киев

Сообщение __Alexander »

ARV писал(а): что-то типа такого:

Код: Выделить всё

   void alarm(unsigned char pin){
   if(flag & pin) return; // если флаг уже стоит - сразу выход
   flag |= pin;
   switch(pin){
   case f_1: SMS_SEND("караул!!!");
   case f_2: SMS_SEND("грабят!!!");
   case f_3: SMS_SEND("насилуют");
   default:  SMS_SEND("ошибка!");
   }      
}
разумеется, и это не самое элегантное решение, но не буду же я все сам за вас делать? :)))
И отличается этот код от приведенного автором только тем, что при установленном флаге выходим сразу. А автор хочет продолжать сканирование остальных кнопок.

Я бы сделал так:

char pins, pinslast;
pins = ((PINB >> 1) & $0x07;
....
pinlast = pins;

И собственно все. Смотрим pins и сравниваем с его предыдущим состоянием pinslast. Допустим приняли 4 (типа PIN.3 нажат), смотрим, что pinlast равно 1, значит что PIN.1 был уже нажат и предпринимаем соответсвующие действия.

Если приняли 7, значит нажали все три клавиши, и тоже думаем что лучше сделать... может послать одну СМС с тремя словами сразу?

А вобще решений немеряно. Каждое имеет место. И мы не совсем дискутируем, а предлагаем как бы поступил каждый из нас. И на выяснение чей же код чучше, может уйти тысячи лет. :))
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18546
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Сообщение ARV »

__Alexander писал(а):И отличается этот код от приведенного автором только тем, что при установленном флаге выходим сразу. А автор хочет продолжать сканирование остальных кнопок.
уважаемый, вы бы хоть подумали 5 минут, прежде чем это писать... я предлагаю вариант замены функциё alarm1()...alarm3(), введенных автором топика, а анализ пинов осуществляется "снаружи" примерно по тому алгоритму, что я и предложил. в этом случае единожды сработавший пин обрабатывается так же один раз, а остальные продолжают сканироваться.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
__Alexander
Потрогал лапой паяльник
Сообщения: 335
Зарегистрирован: Вт сен 11, 2007 10:27:08
Откуда: Киев

Сообщение __Alexander »

ARV писал(а):уважаемый, вы бы хоть подумали 5 минут, прежде чем это писать...
Забей.

Я многое чего не понимаю, допустим даже вот такое:

Почему функция strlen, которая возвращает длину строки, при указании жесткого размера строки выдает на три байта больше?

Типа такого:

chat Str[] = "YO";
chat Str1[2] = "YO";

так вот на strlen(Str1) выдает что байт аж 5!
Я тоже прежполагаю, что служебные символы компилятор может добавлять сам, но почему три? Че-то тут не то.
Когда нить разберусь, а может быть это и RTFM. :))

PS. Компилятор IAR
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»