PIC мк. Эксперимент №8. Использование таймера TMR1.

Задача: получить импульсы с частотой 1Гц.

Исходный материал: PIC16f628a и простенькая devboard + proteus.

Продолжаем разбираться с работой таймеров пиков, на этот раз исследуем работу с 16 битным таймером timer1. Сначала немного теории работы:

Таймер может работать как счетчик или таймер, для таймера выделено два 8 битных регистра TMR1H и TMR1L. Контролируется таймер регистром T1CON:


T1CKPS<1:0>: Timer1 выбор коэффициента деления частоты
11 = 1:8
10 = 1:4
01 = 1:2
00 = 1:1
T1OSCEN: включение внутреннего генератора
1 = включен
0 = выключен
T1SYNC:  синхронизация внешнего генератора
TMR1CS = 1
1 = не синхронизировать
0 = синхронизировать внешний генератор
TMR1CS = 0
бит игнорируется
TMR1CS: выбор генератора
1 = внешний источник тактирования на пине RB6/T1OSO/T1CKI/PGC (по возрастающему импульсу)
0 = внутреннее тактирование (FOSC/4)
TMR1ON: бит включения
1 = включен
0 = выключен

Для получения импульсов с частотой 1 Гц будем использовать кварц 32.768 кГц.

Небольшой рассчет:

Fosc  =  32.768 kHz

F0sc/4 = 8192 Hz

После предделителя F = 1024 Hz

один тик = 0.0009765625 секунды

0.5/0.0009765625  = 512

Таймер до переполнения делает 65536 тиков: 65536 – 512 = 65024

Значит конфигурация таймера будет

TMR1H = 0b11111110; TMR1L = 0x00;

Ну и собственно код программы:


#include &amp;lt;htc.h&amp;gt;
#define _XTAL_FREQ 32768

__CONFIG(WDTDIS &amp;amp; UNPROTECT &amp;amp; MCLREN &amp;amp; LVPDIS);

void main() {
__delay_ms(100); //небольшая задержка
TRISB = 0x00;
PORTB = 0x00;
T1CKPS1 = 1;
T1CKPS0 = 1; // предделитель = 8

T1OSCEN = 0; //выключаем внутренний генератор
TMR1CS = 0; // Fosc/4
GIE = 1;&amp;nbsp;&amp;nbsp; // глобальные прерывания
PEIE = 1;&amp;nbsp; // прерывания перефирии
TMR1IE = 1; // прерывание по переполнению TMR1
TMR1ON = 1; // включаем таймер

TMR1H = 0b11111110; TMR1L = 0x00;&amp;nbsp; //инициализация таймера со значения 65024

for (;;) {
 //бесконечный цикл
 }

}

interrupt isr() {

if (TMR1IF) {
TMR1H = 0b11111110; TMR1L = 0x00;
RB5 = !RB5;
TMR1IF = 0;&amp;nbsp; //сброс флага
}

}

Результат моделирования в протеусе:

Исходники здесь

PIC мк. Эксперимент №8. Использование таймера TMR1.: 53 комментария

  1. еще непонятно как выбрать коэффициент предделителя 1:4
    в даташите написано:
    11 = 1:8 //мы просто ставим T1CKPS0 = 1;
    00 = 1:1 // ставим T1CKPS0 = 0;
    10 = 1:4 // здесь непонятно…

  2. 0.5/0.0009765625 = 512

    Таймер до переполнения делает 65536 тиков: 65536 — 512 = 65024

    Откуда здесь взялось 0.5??? Где взять формулы для расчеты выходной частоты ?? Раскажите пожалуйста поподробнее. Например если было бы нужно получить 10Гц частоту. Спасибо!

  3. >>Откуда здесь взялось 0.5???

    Частота 1Гц, значит период 1с, чтобы получить такой период, нам нужно дергать ногой каждые полсекунды(0.5)

    >>Раскажите пожалуйста поподробнее. Например если было бы нужно получить 10Гц частоту. Спасибо!

    Если кварц такой же (32.768КГц), то:
    Fosc = 32.768 kHz

    F0sc/4 = 8192 Hz

    После предделителя F = 1024 Hz

    один тик = 0.0009765625 секунды

    0.05с/0.0009765625 приблизительно = 51

    То есть нам нужно, чтобы до переполнения осуществился 51 тик, значи:
    65536 – 51 = 65485

    65485 = 0b11111111 11001101
    Значит настройка таймера:
    TMR1H = 0xFF; TMR1L = 0b11001101;

  4. Еще вопросик где в протеусе найти оссцилограф???? и можно ли, настроив таймер один раз через переменные на один порт или разные порты выводит разные частоты просто домножив настроенную? такой некий синтезатор частоты?

  5. Еще вопросик где в протеусе найти оссцилограф????

    Есть там слева такой значок – Virtual Instruments, вот он в том разделе
    virt_instr

    и можно ли, настроив таймер один раз через переменные на один порт или разные порты выводит разные частоты просто домножив настроенную? такой некий синтезатор частоты?

    Не совсем понятно, что конкретно нужно, но если я правильно понял, то так просто не выйдет. Как вариант таймер настраивается один раз, а в коде постоянно проверяется значение регистров, если нужная первая величина достигнута, то меняем состояние на пине 1, если достигунто второе значение, то меняем значение на пине 2, ну и т.д. А вообще лучше поподробнее расписать задачу, тогда будет точнее.

  6. Спасибо осцилограф нашел. сейчас пытаюсь написать программу. Необходим синтезатор частоты. в зависимости от переключения кнопки на выходе нужны разные частоты. 4 и я подумал можно ли выставив один раз нужную частоту потом ее с помощью переменной увеличивать в зависимости от нажатой кнопки? или другой вариант можно ли перенастроивать регистры каждый раз под нужную частоту после проверки состояния нажатой кнопки?

    Немного условий использоввать буду pic16f628a и 10 МГц резонатор в качестве в качастве внешнего источника тактирования. Настраивать буду Таймер 1

    • 10 МГц резонатор скорее всего не заведется так как в доке DS33023 раздел 12.6 черным по белому написано “Максимальная частота резонатора 200 КГц”…

  7. или другой вариант можно ли перенастроивать регистры каждый раз под нужную частоту после проверки состояния нажатой кнопки?

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

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

  8. Хотел спросить про саму структуру таймера. Мы устанавливаем кол-во тиков. сбрасываем флаг в ноль и ждем??? Я правильно понял мы грубо говоря подсчитываем кол-во раз когда флаг сбросился а именно наступило переполнение. и с каждым переполнением мы инвертируем состояние ножки? с 1 на ноль? я все правильно понял?
    Если это так то как изначально выстаить эту нужно что на ней должно быть?

  9. Мы инвертируем состояние ножки независимо от того единица там или 0, а в остальном все правильно.
    Изначально, что пожелаете то и выставляйте, это не принципиально, у нас ширина импульса 50%.

  10. Еще вопросик почему вычитание происходит из 65536, ведь если брать двух байтовую переменную типа long то у нее счет (0 до 65535)???? и еще вопрос бесконечный цикл For в него не включен проверка флага? что он делает?

  11. Еще вопросик почему вычитание происходит из 65536, ведь если брать двух байтовую переменную типа long то у нее счет (0 до 65535)????

    Да, вы правы, тут я ошибся, надо от 65535 вычитать, я просто привык, что общее число тиков составит 65536, включая ноль.

    и еще вопрос бесконечный цикл For в него не включен проверка флага? что он делает?

    Это стандартный бесконечный цикл, без него программа исполнится один раз и остановится, а нам нужна ведь постоянная работа 🙂

  12. Проверка флага включена в обработчик прерываний, так гораздо эффективнее.

    interrupt isr() {
     
    if (TMR1IF) {
    TMR1H = 0b11111110; TMR1L = 0x00;
    RB5 = !RB5;
    TMR1IF = 0;  //сброс флага
    }
     
    }
  13. Написал программу по вашему примеру на три частоты. Скомпилирровал с помощью HI-TECH 9,50 LP . в протеусе все идеально работает, но в железе на выходе стабильно единица. складывается впечатление что он не инвертирует выход. либо как то зацикливается до этого момента.

  14. У меня 3 вопроса, я пильзуюсь 628а кристаллом, пишу только на ассемблере, си понимаю в слабенько
    1) как выставить TMR1 как счетчик или как таймер?
    2) как оценивать что таймер/счетчик переполнен (надо постоянно опрашивать флаг переполнения?)
    3) что означает строчка RB5 = !RB5; вослицательный знак это инверсия?

  15. 1) как выставить TMR1 как счетчик или как таймер?
    Установите TMR1CS в 1 и считать будете импульсы на ноге B6.
    2) как оценивать что таймер/счетчик переполнен (надо постоянно опрашивать флаг переполнения?)
    Либо так, либо просто включить прерывание по переполнению (флаг TMR1IF)
    3) что означает строчка RB5 = !RB5; вослицательный знак это инверсия?
    Совершенно верно 🙂

  16. Спасибо за ответ.
    1) Допустим я включил прерывания что мне это даст? когда таймер переполниться я могу чтобы программа перепрыгнула в нужное место? и как указать это место?
    2) Я хочу чтобы таймер считал от внутреннего генератора импульсы а не от внешенего

  17. 1) Допустим я включил прерывания что мне это даст? когда таймер переполниться я могу чтобы программа перепрыгнула в нужное место? и как указать это место?
    Не знаю как в асме, но в си вы просто заводите обработчик прерываний, если оно произошло, то программа немедленно переходит к обработчику и выполняет код из него, потом возвращается к нормальной работе.
    2) Я хочу чтобы таймер считал от внутреннего генератора импульсы а не от внешенего
    По идее вам нужно еще включать T1OSCEN, но тут утверждать не буду, никогда не работал с этим.

  18. Пишу программу для управления шаговым двигателем, драйвер ULN2003 подключил к ножкам МК. От него требуется последовательно каждые 25мкс посылать импульс на одну из ног драйвера, последовательно подает напряжение на обмотки ШД. С направлением вращения разобрался, таймер настроил, при срабатывании флага переполнения инкрементирую переменную, чтобы потом остановить таймер при достижении определенного количества посланных импульсов, например 1000.

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

    • Что-то я слабо понимаю что конкретно требуется, посылать определенное количество импульсов через 25 мкс, потом остановиться на определенное время, потом послать другое количество импульсов с таким же интервалом?

  19. Да именно так, интервал тот же 25мкс посылаем 200 импульсов к примеру ШД сдвинулся на 2 миллиметра останавливаем таймер, делаем небольшую задержку еще 200 импульсов, снова задержка и так далее. потом задержку и в обратную сторону, вариантов может быть много. у меня не получается пока в while делаю проверку переменной, если достигла нужного числа останавливаю таймер, обнуляю переменную и он стоит, дальше не запускатся висит в while и все

  20. вот пример кода правда компилятор другой для 18 серии пика. Мне главное суть понять почему он не работает как надо:

    while (1) // Бесконечный цикл
    { if (but==10) {T0CONbits.TMR0ON = 0; }

    T0CONbits.TMR0ON = 1;
    //Delay10KTCYx(50);
    if (but==20) {T0CONbits.TMR0ON = 0; }
    //Delay10KTCYx(50);
    T0CONbits.TMR0ON = 1;

    if (but==30) {T0CONbits.TMR0ON = 0; but=0;}

    }

    • Код какой-то бессмысленный. Вы не успели выключить таймер как сразу его выключаете.
      Давайте распишите четко по пунктам что должно происходить на словах, например:
      1. Прерывание от таймера на 25 мкс, посылаем импульс.
      2. Повторяем п1 пока не пошлем 10 импульсов.
      3. Ничего не делаем 200 мс
      и т.д.

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

        • ImpulsesCount = 10;
          while(1)
          {
          if (but == ImpulsesCount) && (!ImpulseFlag)
          {
          ImpulsesCount = новое значение для количества импульсов;
          but = 0;
          ImpulseFlag = 1;
          }
          
          }
          
          interrupt isr()
          {
          
          if (T0IF)
          {
          if (!ImpulseFlag)
          {
          but++;
          ваша_функция_посылки_импульса();
          }
           else
            {
              //тут разбираетесь с задержкой когда ничгео не должно происходить
              ImpulseFlag = 0;
            }
          
          T0IF = 0;
          }
          
          
          }
          
  21. А куда в этом варианте вставить строчку включения и выключения таймера, и получается у меня будет несколько таких while????? или все внутри оного

    • Проверьте мой прошлый пост, я там случайно раньше времени отправить нажал.

      Два таких while() физически невозможны – это первое
      Зачем вам выключать таймер? Каким образом вы тогда понимаете, что нужное время перед следующим действием прошло? – это второе

      P.S. Если все равно ничего не ясно, пишите все по пунктам.

  22. Спасибо за помощь буду разбираться. Таймер я выключаю чтобы остановить подачу напряжения на обмотки. Я привязался к с срабатываю флага переполнения, как только он сработал начинается последовательное посыл импульса на порт микроконтроллера.

    if (INTCONbits.TMR0IF == 1 && INTCONbits.TMR0IE == 1)
    {
    TMR0L = 0xEE; // Загрузка значения в младший байт
    TMR0H = 0x85; // Загрузка значения в старший байт
    but++;
    INTCONbits.TMR0IF = 0; // Сброс флага прерывания ТС0

    if (PORTBbits.RB4==1) {

    switch(step1){
    default:
    step1=0;
    case 0:
    PORTBbits.RB0 = 1; PORTBbits.RB1=0; PORTBbits.RB2=0; PORTBbits.RB3=0;
    break;
    case 1:
    PORTBbits.RB0 = 0; PORTBbits.RB1=1; PORTBbits.RB2=0; PORTBbits.RB3=0;
    break;
    case 2:
    PORTBbits.RB0 = 0; PORTBbits.RB1=0; PORTBbits.RB2=1; PORTBbits.RB3=0;
    break;
    case 3:
    PORTBbits.RB0 = 0; PORTBbits.RB1=0; PORTBbits.RB2=0; PORTBbits.RB3=1;
    break;
    }
    step1++;
    }

    else
    switch(step2){
    default:
    step2=0;
    case 0:
    PORTBbits.RB0 = 0; PORTBbits.RB1=0; PORTBbits.RB2=0; PORTBbits.RB3=1;
    break;
    case 1:
    PORTBbits.RB0 = 0; PORTBbits.RB1=0; PORTBbits.RB2=1; PORTBbits.RB3=0;
    break;
    case 2:
    PORTBbits.RB0 = 0; PORTBbits.RB1=1; PORTBbits.RB2=0; PORTBbits.RB3=0;
    break;
    case 3:
    PORTBbits.RB0 = 1; PORTBbits.RB1=0; PORTBbits.RB2=0; PORTBbits.RB3=0;
    break;
    }
    step2++;

    }

    return; // Выход из функции обработки
    }

    Так порт RB4 я настроил на переключения направления вращения, задержка между посылками определенного количества импульсов я буду настраивать используя функцию задержки delays.h

  23. Здравствуйте. Немного и вот только снова сеть за отладку программы. Изменились условия. Теперь у меня в наличии есть шаговый двигатель с редуктором и блок управления к нему, с микроконтроллера теперь необходимо посылать только пачки импульсов и один управляющий сигнал для изменения направления вращения. Программа состоит в том чтобы при нажатии кнопки МК послал 8500 импульсов, и ожидал следующего что бы послать следующую пачку импульсов.
    Программа построина так: Есть обработчик прерываний в нем я задаю частоту с которой мне необходимо посылать импульсы, а так же виду подсчет их. Я создал там переменную которая инкрементируеться как только срабатывает флаг переполнения таймера, то есть происходит один тик. Как только количество импульсов равно 8500, таймер выключается. Управление запуском таймера прописано в основном цикле, и по идеи таймер должен включаться только по нажатию кнопки, но на практике оказалось что при включении питания таймер посылает пачку импульсов и потом выключается в ожидании когда я нажму кнопку. Как можно исключить это событие. Мне нужно чтобы при включении он импульсы не посылал а посылал их только после нажатия кнопки?????????????? Вот код, где в нем ошибка:

    #pragma interrupt Int_Handle // Обработка прерываний высокого уровня
    void Int_Handle (void) // Функция обработки прерываний
    {

    if (INTCONbits.TMR0IF == 1 && INTCONbits.TMR0IE == 1)
    {
    INTCONbits.TMR0IF = 0; // Сброс флага прерывания ТС0
    TMR0L = 0xEF; // Загрузка значения в младший байт
    TMR0H = 0xFF; // Загрузка значения в старший байт
    but++;

    PORTBbits.RB6=!PORTBbits.RB6;

    if (but==8500) {T0CONbits.TMR0ON = 0; but=0;}
    else
    {T0CONbits.TMR0ON = 1;}

    }
    return; // Выход из функции обработки
    }

    void main (void) // Основная функция
    {
    OSCCON = 0b01110000;
    OSCTUNE = 0b01000000;
    TRISB = 0b10110000; // Настройка порта B на выход
    TRISC = 0b00000011; // Настройка порта C на выход

    PORTBbits.RB3=1;
    ADCON1 = 0x0f;

    // Настройка прерываний: разрешение, приоритет
    RCONbits.IPEN = 1; // Включить приоритеты прерываний
    INTCON2bits.TMR0IP = 1; // Высокий приоритет прерывания Timer0
    INTCONbits.TMR0IE = 1; // Разрешение прерываний от Timer0
    INTCONbits.TMR0IF = 0; // Сброс флага прерывания
    INTCONbits.GIEH = 1; // Разрешить приём всех прерываний
    INTCONbits.GIEL = 0; // Запретить прерывания низкого уровня

    //T0CONbits.TMR0ON = 1; // Запуск таймера-счётчика Timer0

    // Использование функции настройки
    OpenTimer0 (TIMER_INT_ON & // Включение прерывания от таймера
    T0_16BIT & // Режим 16 бит
    T0_SOURCE_INT & // Внутренний источник тактирования
    T0_PS_1_256); // Предделитель 1:256

    while (1) // Бесконечный цикл

    {if (PORTCbits.RC1==0) {p1=1;} else {p1=0;}
    if (p1==1) { if (T0CONbits.TMR0ON ==0) {T0CONbits.TMR0ON =1; p1=0;}
    }
    }

    //{;}
    }

    И еще вопрос, я частоту послыки импульсов задаю с помощью двух регистров, вписывая в них значения в моем случаи примерно 2кГц, и это частота фиксированна, а как можно сделать чтобы она увеличивалась бы до определенного значения, проще говоря разгонялась, н опри этом оставалась одинаковое количество посланных мною импульсов????
    Зарание большое спасибо!

    • Пожалуйста, распишите по пунктам ваши вопросы и по пунктам что вы хотите сделать, и код вставьте в тэги у меня на данный момент ну очень мало свободного времени, чтобы его тратить еще и на то, чтобы понять вопрос.

  24. Виноват. По пунктам. Для решения моей задачи необходимо чтобы импульсы посылались пачкой по 8500 на драйвер ШД, причем они должны идти только при определенном событии, в моем случаи нажатие кнопки. Нажали кнопку, ушла пачка импульсов ждем следующего нажатия. Сейчас ситуация такая, при включении питания МК посылает неконтролируемую пачку импульсов, а потом уже начинает работать как надо, как можно это исключить?????? Чтобы таймер посылал импульсы только по нажатию кнопки????

    Второй важный вопрос, как можно организовать плавный увеличение частоты посылки импульсов. Сейчас она примерно 2кГц, и при старте шумит, как можно программно При нажатие кнопки посылать импульсы с возрастающей частотой, чтобы обеспечить плавный разгон?.
    Спасибо!

    • Так вы в начале вашей главной функции включили таймер, естественно, что какая то пачка полетит, вставьте функцию преднастройки таймера в обработчик нажатия кнопки и все будет как хотите.

      По второму вопросу, что значит шумит? выбросы есть какие-то?
      Мне кажется тут можно двумя вариантами решить проблему:
      1. Емкость на землю – если шумы на высокой частоте пролазят.
      2. В зависимости от значения переменной but просто уменьшаете значение в регистрах таймера, в итоге организовывается дискретное увеличение частоты.

  25. void Int_Handle (void);     // Задание прототипа функции
      unsigned int but=0; 
      unsigned int p0=0; 
      unsigned int p1=0;
    
    
    #pragma code HIGH_INT_VECTOR = 0x8 // Код помещается в ячейку 0x08
    void high_ISR (void)        // Функция с переходом на функцию обработки
    {
        _asm                    // Начало ассемблерной вставки
            goto Int_Handle       // Переход по метке High_Int
        _endasm                 // Окончание ассемблерной вставки
    }
    #pragma code                // Окончание блока кода
    
    #pragma interrupt Int_Handle      // Обработка прерываний высокого уровня
    void Int_Handle (void)           // Функция обработки прерываний 
    {
        
    
        if (INTCONbits.TMR0IF == 1 &amp;&amp; INTCONbits.TMR0IE == 1)
        {
    INTCONbits.TMR0IF = 0;   // Сброс флага прерывания ТС0
            TMR0L = 0xEF;            // Загрузка значения в младший байт
            TMR0H = 0xFF;            // Загрузка значения в старший байт
            but++;
       
    PORTBbits.RB6=!PORTBbits.RB6;
    
    if (but==8500) {T0CONbits.TMR0ON = 0; but=0;} 
    else 
    {T0CONbits.TMR0ON = 1;}
    
    }
        return;                      // Выход из функции обработки
    }
     
    void main (void)                 // Основная функция
    {
         OSCCON = 0b01110000;
        OSCTUNE = 0b01000000;
       TRISB = 0b10110000;                   // Настройка порта B на выход
       TRISC = 0b00000011;                   // Настройка порта C на выход
        
       PORTBbits.RB3=1;   
       ADCON1 = 0x0f;
        
        // Настройка прерываний: разрешение, приоритет 
        RCONbits.IPEN = 1;           // Включить приоритеты прерываний
        INTCON2bits.TMR0IP = 1;      // Высокий приоритет прерывания Timer0 
        INTCONbits.TMR0IE = 1;       // Разрешение прерываний от Timer0
        INTCONbits.TMR0IF = 0;       // Сброс флага прерывания
        INTCONbits.GIEH = 1;         // Разрешить приём всех прерываний
        INTCONbits.GIEL = 0;         // Запретить прерывания низкого уровня 
    
        //T0CONbits.TMR0ON = 1;        // Запуск таймера-счётчика Timer0
    
                                     // Использование функции настройки
      OpenTimer0 (TIMER_INT_ON &amp;   // Включение прерывания от таймера
                  T0_16BIT &amp;       // Режим 16 бит
                  T0_SOURCE_INT &amp;  // Внутренний источник тактирования
                  T0_PS_1_256);    // Предделитель 1:256
    
       while (1) // Бесконечный цикл
    
    {if (PORTCbits.RC1==0) {p1=1;} else {p1=0;}
    if (p1==1) { if (T0CONbits.TMR0ON ==0) {T0CONbits.TMR0ON =1; p1=0; }
    }
    }
    
    //{;}
    } 
  26. Попробовал пользовать ваш код с таймером на 676 пике кварц 4000000. Так вот нестыкрвка получается с реальным временем. При настройки таймера до переполнения на 100 us он в реальности мне выдает 120 us примерно. Предполагаю что 20us берутся за счет компелированного кода проверки флага в перывании. Или я что то не правильно делаю.

          • #include  //PIC16F676
            #include 
            __CONFIG(MCLREN &amp; WDTDIS &amp; HS &amp; UNPROTECT);  // Program config. word 1
            #define _XTAL_FREQ 4000000
            
            interrupt isr(){ 
                if (TMR1IF) {
            	TMR1IF = 0;  //сброс флага
                TMR1H = 0b11111111;    TMR1L = 0b10011011; //TMR1L = 0b10101111 === 80us
                RC5=~RC5;
               } 
            } 
            
            void main (void) {
            	__delay_ms(5);
               T1CKPS1 = 0;                      //Не используем делитель TMR1
               T1CKPS0 = 0;
               T1OSCEN = 0;                      //Выключаем внутренний генератор
               TMR1CS = 0;                       // Fosc/4
               //T1CON=0b00001001;					
               //TMR1H = 0b01111111; TMR1L = 0b10011011;       //
            
            GIE = 1;                             //Включаем глобальные прерывания
            PEIE = 1;                           // прерывания перефирии
            TMR1IE = 1;                       // Разрешение прерывания по переполнению TMR1
            TMR1ON = 1;                       // Включение модуля таймера TMR1
                ANSEL = 0;       //Отключаем аналоговые входы, иначе с в портах будут 0
                TRISC = 0x00;   // Порт В на выход
                PORTC = 0x00;   // Выключаем все выходы порта C
                RC5 = 0; 
                PORTC = 0b00000000; 
            
            for(;;)       							// Запускаем бесконечный цикл
             {	    
            RC4=~RC4;
            __delay_ms(5);
            }  
            }  //main end
            
            • Попробовал замоделить ваш проект и получил такие же результаты. Странно, я всегда думал, что увеличение таймер всегда происходит за один цикл (F/4).
              Адекватные результаты удается получить при кварце в 16 МГц, тогда цифра уже близится к 100 (естественно с правильным переконфигурированием регистров таймера).
              P.S. оператор ~делает побитовую инверсию и применяется для портов в основном, для одного бита есть !

    • Блин теги автоматом скрывает квадратная скобка code закрывающая кв. скобка, кв. скобка /code кв. скобка.
      Я ваш код уже засунул в теги, ща попытаюсь осмыслить

  27. С Прошлой задачей я разобрался! С помощью timer 0 посылаю пачку импульсов по нажатию кнопки и жду следующего нажатия. Все окей. Теперь немного усложнилось условие. 2 шаговика нужно использовать. Решил для них использовать timer1 timer2. Написал по аналогии код, проверил в протеусе, все работает. Прошил контроллер и облом… Он перестал реагировать на нажатие кнопки!!!!!!!
    На моей платке 2 кнопки и я хочу управлять 2-мя шаговиками, но блин они не реагируют на нажатие кнопки, смотрю осцилографом импульсов нету!!!!!! Плата рабочая так как когда настраиваю timer 0, все работает. Что я мог упустить в настройках таймера??? почему он не реагирует на кнопку???. Когда программно меняю проверку нажатие кнопки и получеться что она всегда зажата, импульсы благополучно идут. но на однократное нажатие не реагирует. В чем может быть у меня ошибка:

    #include  // Подключение библиотеки МК PIC18F2520
    #include  // Подключение библиотеки timers
    #include 
    #pragma config OSC = INTIO67 // Внешний источник тактовых импульсов
    #pragma config WDT = OFF // Отключить сторожевой таймер
    #pragma config LVP = OFF // Отключить низковольтное программирование
    
    void Int_Handle (void); // Задание прототипа функции
    unsigned int but0=0;
    unsigned int but1=0;
    unsigned int p0=0; 
    unsigned int p1=0;
    
    
    
    #pragma code HIGH_INT_VECTOR = 0x8 // Код помещается в ячейку 0x08
    void high_ISR (void) // Функция с переходом на функцию обработки
    {
    _asm // Начало ассемблерной вставки
    goto Int_Handle // Переход по метке High_Int
    _endasm // Окончание ассемблерной вставки
    }
    #pragma code // Окончание блока кода
    
    #pragma interrupt Int_Handle // Обработка прерываний высокого уровня
    void Int_Handle (void) // Функция обработки прерываний 
    {
    
    if (PIR1bits.TMR1IF == 1 &amp;&amp; PIE1bits.TMR1IE == 1)
    {
    PIR1bits.TMR1IF = 0; // Сброс флага прерывания ТС1
    TMR1L = 0x7E; // Загрузка значения в младший байт
    TMR1H = 0xF9; // Загрузка значения в старший байт 
    PORTBbits.RB1=!PORTBbits.RB1; 
    but0++;
    if (but0==800) {T1CONbits.TMR1ON =0; but0=0;} 
    }
    //return; // Выход из функции обработки
    
    //***************************************//
    if (PIR1bits.TMR2IF == 1 &amp;&amp; PIE1bits.TMR2IE == 1)
    {
    PIR1bits.TMR2IF = 0; // Сброс флага прерывания ТС2
    PR2 = 0x4E; // Загрузка значения в младший байт
    TMR2 = 0x00; // Загрузка значения в старший байт 
    PORTBbits.RB3=!PORTBbits.RB3; 
    but1++;
    if (but1==800) {T2CONbits.TMR2ON =0; but1=0;} 
    }
    //return; // Выход из функции обработки
    }
    
    void main (void) // Основная функция
    {
    OSCCON = 0b01110000;
    OSCTUNE = 0b01000000;
    TRISB = 0b00000000; // Настройка порта B на выход
    TRISC = 0b00000011; // Настройка порта C на выход
    ADCON1 = 0x0f;
    // Настройка прерываний: разрешение, приоритет //
    RCONbits.IPEN = 1;
    INTCONbits.GIEH = 1; // Разрешить приём всех прерываний
    INTCONbits.GIEL = 0; // Запретить прерывания низкого уровня 
    PIE1bits.TMR1IE = 1; // Рзрешение прерываний от Timer1
    PIR1bits.TMR1IF = 0; // Сброс флага прерывания 
    PIE1bits.TMR2IE = 1;	 // Рзрешение прерываний от Timer2
    PIR1bits.TMR2IF = 0; // Сброс флага прерывания
    //IPR1bits.TMR1IP = 1;
    
    //*******************Настройки Timer1*********//
    
    T1CONbits.RD16 = 1; // Режим 16 бит 
    T1CONbits.T1RUN = 0; // Не используеться читаеться как "0" 
    T1CONbits.T1CKPS1 = 1; // Задание коэффициента деления 1:8
    T1CONbits.T1CKPS0 = 1; // Второй торой bit коэффициента деления
    T1CONbits.T1OSCEN = 1; // Включение тактового генератора 
    T1CONbits.T1SYNC = 1; // Не синхронизировать внешний тактовый сигнал 
    T1CONbits.TMR1CS = 0; // Внутренний источник тактирования
    T1CONbits.TMR1ON = 0; // Запуск таймера-счётчика Timer1
    
    //*******************Настройки Timer2*********//
    
    T2CONbits.T2OUTPS0 = 1; // 3 бит коэффициента деления выходного делителя 
    T2CONbits.T2OUTPS1 = 1; // 4 бит коэффициента деления выходного делителя 
    T2CONbits.T2OUTPS2 = 1; // 5 бит коэффициента деления выходного делителя 
    T2CONbits.T2OUTPS3 = 1; // 6 бит коэффициента деления выходного делителя 1:16
    T2CONbits.T2CKPS1 = 1; // Коэффициент деления предделителя 1:16
    T2CONbits.T2CKPS0 = 0;
    T2CONbits.TMR2ON = 0;	// Запуск таймера-счётчика Timer2
    while (1) // Бесконечный цикл
    {
    if (PORTCbits.RC0==0) {Delay10KTCYx(0);p0=1;} else {p0=0;}
    if (PORTCbits.RC1==0) {Delay10KTCYx(0);p1=1;} else {p1=0;}
    
    if (p0==1) {T1CONbits.TMR1ON = 1; p0=0;}
    if (p1==1) {T2CONbits.TMR2ON = 1; p1=0;}
    }
    } 
    
    

    И второй вопрос. если потом я захочу в программе управлять шаговикам последовательно, то есть нужно будет ставить задержку между посылками импульсов на разные шаговики, можно ли это время устанавливать с помощью функции (delays.h)??? Грубо говоря нажатие кнопки, посылка пачки импульсов одному шаговика, потом проходит время 5-10с и программно посылается вторая пачка импульсов с другого таймера на другой шаговик, можно ли эту задержку делать с помощью функции (delays.h)???

    Зарание большое спасибо!

    • По первому вопросу снова трудно понять и код и что требуется от него, но мне не нравится как кнопки юзаются. Их бы по хорошему тоже в прерывания поместить, что будет если во время нажатия сработает прерывание по таймеру?

      А второй, ну а кто вам запрещает? просто точность будет хуже по ходу и все. Но я бы на таймере наверное делал это, послал пачку импульсов, дальше таймер перенастроил на отсчет интервала нужного и по его достижении либо перенастроил этот же таймер либо пустил второй.

  28. Буду думать как переделать часть где идет проверка кнопки. Тогда вопрос у меня правильно выставлены биты настройки для timer1 и timer2?????

    • Как минимум TOSCEN надо в 0, но при TMR1CS = 0, на работу он влиять не будет.
      А про остальные биты настройки – разбивайте программу на части и проверяйте все ли работает так как того хотите вы. А то что я тут говорю, это все вилами по воде писано.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.