Easyelectronics.ru

Электроника для всех
Текущее время: 22 янв 2021, 23:27

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/5шт. два слоя. $5/5шт. четыре слоя
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Ответить на тему  [ Сообщений: 9 ] 
Автор Сообщение
 Заголовок сообщения: [Решено]Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 24 май 2020, 01:08 
Только пришел

Зарегистрирован: 27 янв 2012, 22:38
Сообщения: 14
Откуда: Уфа
Всем доброго времени суток! Понадобилось мне в сжатые сроки написать простенькую программку для tiny13. В Си я ни в зуб ногой, но с общими принципами знаком, поэтому решил осваивать синтаксис "по ходу пьесы", поэтапно реализовывая отдельные функции и проверяя правильность их работы в симуляторе и в железе. Глубинного понимания принципа работы нет, только надёрганные тут и там из примеров куски, да остатки воспоминаний ассемблерного курса для АВРок, пройденного на этом сайте много лет назад. Отсюда, вероятно, корни нижеописанной проблемы.
Итак, на данный момент "родил" такой остов программы:

Код:
#include <avr/io.h>
#define F_CPU 128000UL
#include <util/delay.h>
#include <avr/interrupt.h>

// Объявляем переменные
char key_press = 0;
char timer_start = 0;
unsigned char indic = 0;

unsigned int counter_global = 0;
unsigned int counter_sec = 0;
char counter_periodic = 2;

// Обработчики прерываний

// Прерывание по INT0
ISR (INT0_vect)
{
//PORTB ^= 0b00000100;
}

ISR(TIM0_COMPB_vect)
{
   if (counter_periodic > 0)
   {counter_periodic--;
   goto label1;}
      indic = 1;
      counter_periodic = 2;
   //PORTB ^= 0b00000100;
   label1:
   if (timer_start == 1) // Таймер запущен?
   {
      if (counter_global > 0) counter_global--; // Декремент обоих счетчиков, пока не дойдут до нуля
      if (counter_sec > 0) counter_sec--;
   }
    TCNT0=0;                     // сбрасываем счётный регистр
}

int main(void)
{
    // отключаем компаратор
    ACSR |= (1 << ACD);
   
   DDRB = (1<<PINB0)|(0<<PINB1)|(1<<PINB2)|(0<<PINB3)|(1<<PINB4); // PBO - выход на пульт; PB1 - вход кнопки с подтяжкой, PB2 - выход на светодиод; PB3 - вход контроль без подтяжки; PB4 - выход на пульт.
   PORTB = 0b00000010; // На выходах нули, входы PB1 с подтягом к питанию, PB3 без подтяга
   
   GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
   MCUCR = 0b00000011; // при перепаде из 0 в 1 (отпускание кнопки)

    // режим таймера CTC
    TCCR0A |= (1 << WGM01);
   
    // делитель частоты таймера 1024
    TCCR0B |= (1 << CS02)|(1 << CS00);
   
    // разрешаем прерывание от таймера                     
    TIMSK0 |= (1 << OCIE0B);                   
   
    // значение регистра сравнения (1000мс)         
    OCR0A = 125;                                 

sei();
   
    while(1)
    {
   //    PORTB=0b00000100;
   //   _delay_ms(200);
   //   PORTB=0b00000000;
   //   _delay_ms(200);
   
   //   PORTB ^= 0b00000100;

   //indic = 1;
   if (indic != 0)
   {
   PORTB ^= 0b00000100; // мигнём светодиодом для отладки
   //_delay_ms(500);
   //PORTB ^= 0b00000100;
   indic = 0; // сбросим флаг
   }
   }
}

Оно кривое и недоделанное, поэтому особо вникать тут не во что. Изучал прерывания по нажатию кнопки и по совпадению таймера. Речь как раз о втором. Примерно каждую секунду генерируется прерывание по таймеру, и в его обработчике происходит декремент переменных счётчиков. Каждые несколько секунд (определяется переменной counter_periodic, по достижению ей нуля) устанавливается переменная-флаг indic, состояние которой должно обрабатываться в основном цикле и там же сбрасываться. Для проверки накидал простенькое условие
if (indic != 0)
{
PORTB ^= 0b00000100; // мигнём светодиодом для отладки
indic = 0; // сбросим флаг
}
Но почему-то условие if (indic != 0) никогда не выполняется, при том, что в отладчике я чётко вижу, что переменной в обработчике прерываний присваивается значение 1. Пробовал варианты if (indic > 0), менял тип переменной с unsigned char на int - те же грабли. Причём, если именно в главном цикле сделать присвоение indic = 1; (закомментированная строчка выше условия), то оно выполняется как надо и в симуляторе и в железе, отладочный светодиод моргает. У меня два предположения почему так: либо компилятор что-то там наоптимизировал, либо я неправильно работаю с переменной в качестве флага или неверно задаю её тип. Смотрел ассемблерный выхлоп компилятора, ничего не понял) Кто в теме, подскажите где я накосячил и почему не выполняется условие? Заранее спасибо!


Последний раз редактировалось astron 24 май 2020, 01:41, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 24 май 2020, 01:11 
Старожил

Зарегистрирован: 19 мар 2013, 19:37
Сообщения: 2900
Откуда: Санкт-Петербург
volatile.
Если не разберётесь – пишите, поясню подробнее.

ЗЫ: и лучше замените goto на else, а то сейчас кто-нибудь в обморок упадёт :-D


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 24 май 2020, 01:31 
Только пришел

Зарегистрирован: 27 янв 2012, 22:38
Сообщения: 14
Откуда: Уфа
aamonster писал(а):
volatile.
Если не разберётесь – пишите, поясню подробнее.

ЗЫ: и лучше замените goto на else, а то сейчас кто-нибудь в обморок упадёт :-D


Охщи... А вот и "подводные камни написания кода на си для avr". Подчитал матчасть относительно volatile, попробовал - работает! Спасибо!) И ведь смутно осознавал, глядя на ассемблерный листинг, что что-то тут не так, раз компилятор активно использует STS/LDS и неохотно пользуется стеком. Явно ведь может подпортить данные.
Цитата:
goto на else

Извините за г..нокод, я ещё только осваиваюсь)
Огромное спасибо за подсказку, своим умом я бы тут точно не допёр!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 24 май 2020, 01:45 
Старожил

Зарегистрирован: 19 ноя 2012, 19:52
Сообщения: 643
Вместо volatile можно добавить барьер памяти
Код:
asm volatile ("" ::: "memory");

в начало цикла.

В отличии от volatile, барьер памяти не отключает оптимизатор, и позволяет получить более компактный/быстрый код.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 24 май 2020, 01:48 
Только пришел

Зарегистрирован: 27 янв 2012, 22:38
Сообщения: 14
Откуда: Уфа
caxap писал(а):
Вместо volatile можно добавить барьер памяти
Код:
asm volatile ("" ::: "memory");

в начало цикла.

В отличии от volatile, барьер памяти не отключает оптимизатор, и позволяет получить более компактный/быстрый код.


Спасибо, почитаю про барьер памяти тоже.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: [Решено]Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 25 май 2020, 09:43 
Старожил
Аватара пользователя

Зарегистрирован: 14 июн 2015, 17:41
Сообщения: 2741
Откуда: Русь, Новороссийск
Дополню варианты:


Избегаем volatile

Случай 1

Если AVR и avr-gcc и хотите чего-то ждать (крутиться в цикле), то сделайте например так:

Код:
#define barrier() asm volatile ("" ::: "memory")

struct data
{
        int ready;
        int one;
        int two;
        int three;
};

struct data my_data;

ISR(XXX_vect)
{
        my_data.one = 0;
        my_data.two = 1;
        my_data.three = 2;
       
        /* флаг ready должен быть выставлен после обновления всей структуры. сейчас avr-gcc не переставляет инструкции и я _не_ использую вложенных прерывания, но кто знает, что будет завтра? */
        barrier();

        my_data.ready = 1;
}

int main(void)
{
        while (my_data.ready)
                /* ждем выставления ready из прерывания */
                barrier();

        return 0;
}


Случай 2

А если я хочу перечитывать КОНКРЕТНУЮ переменную, а не всё, используемое в данной функции? Как правило перечитывать всё подряд бессмысленно.

Код:
/* здесь и сейчас получаю state, так как потом уже будет поздно */
int state = *(volatile int*)ptr;

switch(state) {
...
}


или другой пример

Код:
int G_flags;

#define SET_FLAG(A_FLAG) do { *(volatile int*)&G_flags |= A_FLAG;} while(0);



Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: [Решено]Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 25 май 2020, 11:14 
Старожил

Зарегистрирован: 19 ноя 2012, 19:52
Сообщения: 643
P.S. Для полноты картины. Многие считают, что ключевое слово volatile в C/C++ также обеспечивает атомарность обращения. Это не так от слова совсем. Нужно руками выключать прерывания при обращении к многобайтовым переменным. volatile в C/C++ лишь означает "эта переменная имеет side-эффекты" и все компиляторы реализуют это просто отключением оптимизатора везде, где хоть как то задействована эта переменная, на всякий случай.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: [Решено]Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 25 май 2020, 13:09 
Старожил

Зарегистрирован: 19 мар 2013, 19:37
Сообщения: 2900
Откуда: Санкт-Петербург
Да, подтверждаю мнение поправивших меня коллег, барьеры памяти примерно всегда лучше, на десктопе вообще только так делается (Mutex, Critical section и т.п.). Но в них врубиться сложнее, так что для начала volatile сойдёт (и для вашего конкретного случая, когда есть только одна общая переменная, годится).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: [Решено]Программа на C для Tiny13, прошу помощи
СообщениеДобавлено: 25 май 2020, 16:05 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 3051
Код:
#include <avr/cpufunc.h>
...
_MemoryBarrier();

Разницы никакой. Но там, где есть готовые стандартные макросы, лучше использовать их имхо.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 9 ] 


Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB