Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: 1 секунда на С
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
ZLOI
Здравствуйте, интересно бы увидеть фрагмент кода на С, который бы позволял на 16 пике с 4 МГц кварцем каждую секунду увеличивать значение какой-нибудь переменной на 1. Интересно, вдруг я делаю неправильно.
GVC
Цитата(ZLOI @ Apr 29 2008, 10:45) *
Здравствуйте, интересно бы увидеть фрагмент кода на С, который бы позволял на 16 пике с 4 МГц кварцем каждую секунду увеличивать значение какой-нибудь переменной на 1. Интересно, вдруг я делаю неправильно.


Покажите что и как вы делаете, ну а мы уже скажем так или не так делает.
Конфигурирование таймера и прерывания этож класскика жанра. Показуйте свой код ...
rezident
Цитата(ZLOI @ Apr 29 2008, 13:45) *
который бы позволял на 16 пике с 4 МГц кварцем каждую секунду увеличивать значение какой-нибудь переменной на 1.
Таймер разрядности менее, чем 32 можно программно расширить до 32-х разрядов. А с помощью 32-х разрядного уже можно отмерить интервал в 1с даже при тактовой 4ГГц.
И вообще, чем вас аппликухи у Microchip не устраивают?
ZLOI
Цитата(GVC @ Apr 29 2008, 18:59) *
Покажите что и как вы делаете, ну а мы уже скажем так или не так делает.
Конфигурирование таймера и прерывания этож класскика жанра. Показуйте свой код ...

Забыл подписаться, поэтому не отвечал.
Код
#include    <pic12F6x.h>

int time;

void interrupt Times(void)
{
    if (++time==3906)
        {
            unsigned char to_delay=0;
            while (++to_delay<6)
                {}
            time=0;
            _asm NOP _endasm
            time=0;//    
            time=0;//Вообщем надо как-то паузу сделать,
            TMR0=0;//по грамотному, а то вдруг компилер сменил и всё, не пашет.
            GPIO=!GPIO;
            }
    T0IF = 0;
}
main()
{
    int x;
    GPIO=0;
    CMCON=7;
    TRISIO=254;
    GPIO=0;
    GIE=1;
    T0IE=1;
    T0CS=0;
    PSA=1;
    TMR0=1;
    for(;;)    {}
}

Собственно сейчас у меня компилера нет поэтому протестить особо не могу, но по памяти, что-то типа такого делал. И работало оно как надо, по крайней мере за неделю ни на секунду не сдвинулось.
Алгоритм простой, таймер инкрементиться каждые 256 машинных циклов таймер вызывает прерывание и увеличивает переменную time на 1. Секунда проходит через 1000 000 машинных циклов или через 3906 прерываний и ещё 64 такта. Вот у меня и вопрос, как сделать чисто на С, чтобы любой другой компилятор поставил и всё работает. Хочется знаете, увидеть как делают мастера.

Цитата(rezident @ Apr 29 2008, 21:00) *
Таймер разрядности менее, чем 32 можно программно расширить до 32-х разрядов. А с помощью 32-х разрядного уже можно отмерить интервал в 1с даже при тактовой 4ГГц.

Знаю. Проблем со "сделать" нет. Не хочется быть умным программистом, который тупым кодом делает гениальные вещи. Хочется делать красиво. Вот Вы мне скажете. Я посмотрю и подумаю: "Ёлки палки, да ведь здесь же надо в таком направлении двигаться, такие книжки читать и т.д.".

P.S.
Сомневаюсь, что буду когда-нибудь использовать такие бешеные частоты smile.gif
rezident
Цитата(ZLOI @ Apr 30 2008, 15:49) *
Знаю. Проблем со "сделать" нет. Не хочется быть умным программистом, который тупым кодом делает гениальные вещи. Хочется делать красиво. Вот Вы мне скажете. Я посмотрю и подумаю: "Ёлки палки, да ведь здесь же надо в таком направлении двигаться, такие книжки читать и т.д.".
Если у вас уже есть таймерное прерывание, то в нем просто инкрементируйте какую-либо беззнаковую переменную на величину тика таймера, выраженную, например, в миллисекундах.
Код
#define TICK_TIMER 10UL  // тик таймера 10 мс

volatile unsigned long time;

void interrupt Times(void)
{
  time+=TICK_TIMER;
...
}
Переменная time "тикает" себе в фоне потихоньку.
Когда вам нужно сделать задержку в main-е, то делаете такую конструкцию
Код
void main (void)
{ unsigned long tmpTime1, tmpTime2;
...
  _disable_interrupt();
  tmpTime1=time;
  _enable_interrupt();
  do
  { _disable_interrupt();
    tmpTime2=time;
    _enable_interrupt();
  } while ((tmpTime2-tmpTime1)<1000UL); //задержка на 1000мс=1с
...
}

Запрет прерываний перед считыванием переменной time требуется только, если другим образом нельзя обеспечить атомарность операции ее чтения. Например, когда вы пытаетесь на 8-ми битном MCU оперировать 32-х битными переменными. Все используемые в примере переменные должны быть беззнаковыми. Переменная time обязательно должна иметь квалификатор volatile. При исчислении в миллисекундах 32-х разрядной переменной хватает для измерения интервалов времени длительностью свыше 1,5 месяца.
P.S.
Для выполнения каких-либо действий по отметкам времени можно поступать аналогично.
Код
void main (void)
{ unsigned long tmpTime1, tmpTime2;
...
  _disable_interrupt();
  tmpTime2=time;
  _enable_interrupt();
  if ((tmpTime2-tmpTime1)>=1000UL) // прошло больше 1000мс?
  { funcDo1sPeriod(); // да, вызываем функцию
    _disable_interrupt();
    tmpTime1=time;  // обновляем значение переменной заданного интервала
    _enable_interrupt();
  }
...
}

Еще раз обращаю внимание, что переменные должны быть беззнаковыми. В этом случае корректно обрабатывается ситуация переполнения их максимального значения при сравнении этих чисел.
GVC
Цитата(ZLOI @ Apr 30 2008, 12:49) *
Вот у меня и вопрос, как сделать чисто на С, чтобы любой другой компилятор поставил и всё работает. Хочется знаете, увидеть как делают мастера.


Принцип правильный, програмируете таймер на определённый интервал времени (не обязательно 256 машинных циклов, есть же делители у таймера wink.gif), в зависимости от требуемой дискреты (это добивается делителем для таймера а также значением загружаемым в счётчик таймера), например можно получить почти 1, 10, 100 мСек. Ну а далее в прерывании от этого таймера программно "считает" эти интервалы времени до требуемой вам величины.
Это чисто на си реализуемо просто.
А вот вся "обвязка" прерываний на си не имеет стандарта и в зависимости от компилятора вам всётаки прийдётся вносить изменения в обьявления векторов прерывания и обработчиков ... Такчто полной универсальности трудно добится, есть особенности у каждого компилятора.
ZLOI
Цитата(GVC @ Apr 30 2008, 23:37) *
Ну а далее в прерывании от этого таймера программно "считает" эти интервалы времени до требуемой вам величины.

Вот я про это и говорю, компиляторы могут по разному "считать" и поэтому лучше АСМ вставить. Просто цикл забабахать и всё.



Цитата(rezident @ Apr 30 2008, 23:05) *
Если у вас уже есть таймерное прерывание, то в нем просто инкрементируйте какую-либо беззнаковую переменную на величину тика таймера, выраженную, например, в миллисекундах.

Я говорил конкретно под 4 МГц. Просто нацело миллион на 256 не делится и мне кажется, что придётся отсчитывать конкретное количество циклов. Т.е. когда у нас предделитель перед WDT, то как я уже говорил 3906 прерываний и 64 такта длятся одну секунду. Если поставить предделитель перед таймером скажем 256, то секнда будет длится 15 прерываний и 16960 машинных циклов. Или нет? © Bill.

Впрочем спасибо за ответ, когда достану хайтек Иваныча, то попробую.
rezident
Цитата(ZLOI @ Apr 30 2008, 21:49) *
Я говорил конкретно под 4 МГц. Просто нацело миллион на 256 не делится и мне кажется, что придётся отсчитывать конкретное количество циклов. Т.е. когда у нас предделитель перед WDT, то как я уже говорил 3906 прерываний и 64 такта длятся одну секунду. Если поставить предделитель перед таймером скажем 256, то секнда будет длится 15 прерываний и 16960 машинных циклов. Или нет? © Bill.
Во-первых, я давал вам советы с точки зрения алгоритма без привязки к конкретному МК или компилятору.
Во-вторых, я не знаком с периферией PIC16, чтобы что-либо конкретно советовать по таймеру. У тех таймеров с которыми я работал кроме предделителя имеется режим счета с перезагрузкой. Т.е. таймер считает не до макс. значения, а до какого-то конкретного значения, задаваемого в регистре сравнения, после чего перескакивает в состояние 0. Поэтому установить более точную частоту прерываний не составляет особой сложности.
В-третьих, вы же не указали с какой точностью вам нужно отсчитывать секундные интервалы. Если вам небольшие интервалы для регистрации каких-то событий нужно отсчитывать это одно, а же если вы решили организовать RTC с точностью хода ±20 секунд/год это совершенно другой коленкор! laughing.gif
В-четвертых, если вы хотите быть программистом, то должны стремиться к самостоятельной разработке алгоритмов. Программисту достаточно понимания самой идеи и/или принципов, а разработка и программная реализация алгоритма это и есть собственно работа программиста. Ну уж а писать программу по готовому алгоритму это вовсе работа кодера, а не программиста. wink.gif
ZLOI
Цитата(rezident @ May 1 2008, 01:17) *
Во-первых, я давал вам советы с точки зрения алгоритма без привязки к конкретному МК или компилятору.

Я заметил.
Цитата(rezident @ May 1 2008, 01:17) *
Во-вторых, я не знаком с периферией PIC16, чтобы что-либо конкретно советовать по таймеру.

Думаю, не слишком много потеряли smile.gif
Цитата(rezident @ May 1 2008, 01:17) *
В-третьих, вы же не указали с какой точностью вам нужно отсчитывать секундные интервалы.

Цитата
каждую секунду увеличивать значение какой-нибудь переменной на 1

Цитата(rezident @ May 1 2008, 01:17) *
В-четвертых, если вы хотите быть программистом, то должны стремиться к самостоятельной разработке алгоритмов. Программисту достаточно понимания самой идеи и/или принципов, а разработка и программная реализация алгоритма это и есть собственно работа программиста. Ну уж а писать программу по готовому алгоритму это вовсе работа кодера, а не программиста. wink.gif

Ну вот алгоритм я сам и придумал, это не сложно. Апликухами я вообще почти не пользуюсь, от этого есть и минусы, но безусловно есть и плюсы, не похвалишься сотней устройств сделанных по чужим схемам, но начинаешь понимать многое сам.
_Ivan_33
эээ... while(1) {
delay_ms(1000);
a++;}
ZLOI
Цитата(_Ivan_33 @ May 1 2008, 17:36) *
эээ... while(1) {
delay_ms(1000);
a++;}

Вообще оригинальный ответ biggrin.gif
Я даже не думал, что Вы так словчите.
Но мне он не кажется корректным.
Если delay_ms это задержка на одну милисекунду, то это тоже неправильный код, поскольку ещё будет добавляться время от a++. А оно должны быть пару мкс. А пара микросекунд за год это уже полминуты набежало.
Хотелось бы узнать как delay_ms определяет какой у Вас кварц стоит.

Конечно я говорил о другом. Вся эта тема с таймером не должна занимать основное время МК, там ещё надо будет на ЖК выводить и другие операции. И правильное решение через прерывание.

P.S.
Ну и мотивация для создания темы была желание проверить, нужно ли знать ассемблер, чтобы решить такую задачу.
haker_fox
Цитата(ZLOI @ May 2 2008, 00:22) *
Вообще оригинальный ответ biggrin.gif
Я даже не думал, что Вы так словчите.
Но мне он не кажется корректным.
Если delay_ms это задержка на одну милисекунду, то это тоже неправильный код, поскольку ещё будет добавляться время от a++.

И не только от a++, надо полагать, что у Вас, кроме инкремента переменной и другая полезная работа выполняется, на которую тоже время нужно...
Цитата(ZLOI @ May 2 2008, 00:22) *
Хотелось бы узнать как delay_ms определяет какой у Вас кварц стоит.

Возможно это пример под GCC компилятор. Величина системной частоты передается через параметр в makefile.
Цитата(ZLOI @ May 2 2008, 00:22) *
Конечно я говорил о другом. Вся эта тема с таймером не должна занимать основное время МК, там ещё надо будет на ЖК выводить и другие операции. И правильное решение через прерывание.

Чтоже мешает реализовать все это через прерывания?
Если с учетом делителей таймера не подходит кварц, то можно выбрать другой. Либо настроить режим работы таймера по совпадению, если такой имеется в PIC'e. И инкрементировать переменную уже в прерывании.
Цитата(ZLOI @ May 2 2008, 00:22) *
Ну и мотивация для создания темы была желание проверить, нужно ли знать ассемблер, чтобы решить такую задачу.

Не нужно.
ZLOI
Цитата(haker_fox @ May 3 2008, 08:18) *
Чтоже мешает реализовать все это через прерывания?

Ничего я же давно это реализовал.
_Ivan_33
так там же на каждую команду расходуется несколько машинных циклов (период кварца) так что мне кажется что это не так важно...
r_dot
Цитата(ZLOI @ May 3 2008, 09:12) *
Ничего я же давно это реализовал.


Программист микроконтроллеров несколько отличается от просто программиста. smile.gif Поставь кварц на 4096 кГц и работай просто по прерыванию.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.