Перейти к содержанию
    

Микроконтроллеры для начинающих

Привет всем. Наверняка уже много раз этот вопрос поднимался, но не знаю как и где искать.

 

Программирую атмегу по интерфейсу JTAG. В программе я могу эти 4 ноги, занятые JTAGом, использовать как обычные входы/выходы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Привет всем. Наверняка уже много раз этот вопрос поднимался, но не знаю как и где искать.

 

Программирую атмегу по интерфейсу JTAG. В программе я могу эти 4 ноги, занятые JTAGом, использовать как обычные входы/выходы?

 

При отладке программ нельзя, а в рабочем режиме имеется возможность. В регистрах MCUCSR или MCUCR имеется хитрый бит JTD, переключением которого можно эти порты использовать в рабочем режиме. Правда его переключение довольно своеобразное, как пишут в руководстве необходимо произвести запись бита дважды за четыре такта...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При отладке программ нельзя, а в рабочем режиме имеется возможность. В регистрах MCUCSR или MCUCR имеется хитрый бит JTD, переключением которого можно эти порты использовать в рабочем режиме. Правда его переключение довольно своеобразное, как пишут в руководстве необходимо произвести запись бита дважды за четыре такта...

 

Спасибо, попробую :beer:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте, снова есть смешной (для сколь-нибудь опытных разработчиков) вопрос:

 

Снова про AVR, работаю в атмел студии 7.

Ниже привожу проект, который должен включать Порт B на 10 секунд, потом вЫключать на 10 секунд, снова включать и так далее.

Использую для этого таймер1 (16 бит).

 

Задача - понять как правильно использовать аппаратный таймер для создания, допустим, 30 своих независимых друг от друга программных таймеров с произвольными моментами включения и сброса для каждого из них в зависимости от состояния, допустим, какой-либо переменной в программе. Пока экспериментирую с одной переменной. МК работает на частоте 8МГц, от внутреннего источника, - как был, я его не калибровал и не знаю как это делать и надо ли вообще.. Делитель 256.

 

#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned int n_count=0;

void preset()
{
    DDRB = 0b11111111; // 0xFF
    PORTB = 0b11111111; // 0x00
    
        DDRD = 0b00001111; // 0xFF
        PORTD = 0b00000000; // 0x00
    
    DDRA = 0b00000000; 
    PORTA = 0b11111111; // 0x00
}

void timer_ini(void)    //функция инициализации таймера
{
    TCCR1B |= (1<<WGM12); //установка режима работы CTC (сброс по совпадению)
    TIMSK1 |= (1<<OCIE1A); //устанавливаем бит разрешения прерывания первого счётчика по совпадению с OCIR1A (H и L)
    OCR1AH = 0b00001100; //записываем в регистр OCR1A число 3125 (при работе на частоте 8 МГц это будет давать прерывание каждые 0,1 сек) 
    OCR1AL = 0b00110101; //
    TCCR1B |= (1<<CS12); //установка делителя 256
     
}

ISR(TIMER1_COMPA_vect) //Прерывание по достижению таймером значения регистра OCR1A (H и L)
{
n_count++;
if (n_count>=200)    {n_count=0;}
}

int main(void)
{
    preset();
    timer_ini();    
    sei(); //глобальное разрешение прерываний
    
    while(1)
    {
        if ((n_count>0)&&(n_count<100)) {PORTB = 0b11111111;}
else 
    if ((n_count>100)&&(n_count<=200)) {PORTB = 0b00000000;};        
    }
}

 

И вот мой Порт В включается и выключается, - ДА, примерно каждые 10 секунд. Как измерил? - положил рядом с включаемым светодиодом свой телефон с запущенным секундомером. И Вот такой подсчёт времени в микроконтроллере даёт погрешность примерно 1 секунду в минуту. А за 4 минуты - МК уже врёт на 4 секунды - убегает вперёд относительно времени, которое на смартфоне...

 

Тогда я переставил код из бесконечного цикла в тело прерывания. Так МК убегает вперёд на 12 секунд за 10 минут... Это слишком большая погрешность.. Как быть? Это нормально и вызвана непостоянностью рабочей частоты? Погрешность эту можно как-то сократить? А если я 30 таких таймеров запилю - мне их все в этом же прерывании обрабатывать будет нормально или они, возможно, не будут успевать обрабатываться за прерывание?

 

Буду рад, примеру простого но более или менее точного программного таймера.

 

И ещё вопрос из фьюзов кроме CKDIV8 ещё какие-то влияют на рабочую частоту МК, если он работает от внутреннего генератора? То есть в моём случае есть всего 2 варианта частоты, - с включенным CKDIV8 это 1МГц, а с выключенным CKDIV8 это 8МГц и третьего не дано? Атмега644, если это важно.

Изменено пользователем lyric

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я бы не стал слишком сильно доверять телефонному секундомеру... Но если вы хотите опираться на него как на эталон, попробуйте поварьировать данные в регистре OCR1A. Одна единица этого регистра изменит ваши 10 сек на 3,2 мсек.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно, у вас лишняя единица где-то еще.

 

Значение для таймера считается без единицы. В вашем случае:

timer_value = ([10] мс * 8000 [кГц] / 256) - 1 = 3124.

Эта ошибка уже добавляет лишние 320 мкс на одну секунду или 192 мс на 10 минут.

 

Вероятно, на следующем уровне иерархии, когда обрабатываете свои счетчики, допускаете ту же ошибку.

 

Как быть? Это нормально и вызвана непостоянностью рабочей частоты? Погрешность эту можно как-то сократить?

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

Но это в том случае, если используете внешний кварцевый резонатор или генератор. Если внутренний RC-генератор, то все может быть иначе. Но проверить можно в AtmelStudio в режиме симуляции. Там есть возможность замерить интервалы работы участков кода. Только необходимо упростить пример, уменьшив значение, загружаемое в счетчик. Накопление погрешностей можно отследить. Все остальное будет из-за несовершенства RC-генератора. Его можно откалибровать, насколько помню. См. документацию.

 

А если я 30 таких таймеров запилю - мне их все в этом же прерывании обрабатывать будет нормально или они, возможно, не будут успевать обрабатываться за прерывание?

Это надо проверять, кто ж вам ответит. Но перегрузить прерывание, происходящее раз в 100 мс — это надо очень постараться.

 

 

И ещё вопрос из фьюзов кроме CKDIV8 ещё какие-то влияют на рабочую частоту МК, если он работает от внутреннего генератора? То есть в моём случае есть всего 2 варианта частоты, - с включенным CKDIV8 это 1МГц, а с выключенным CKDIV8 это 8МГц и третьего не дано? Атмега644, если это важно.

Далее идет делитель CLKPR, который может дальше поделить эту частоту.

Изменено пользователем x736C

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Smoky, x736C

 

Большое спасибо, Ваши советы и замечания помогли. Ну и кроме того я сделал прерывание каждые 5 миллисекунд (вместо каждых 100), и инкрементируемую переменную указал volatile вместо unsigned. теперь секундомер смартфона один в один бьёт с тем, что отсчитывает МК, - на глаз никак не отличить. По моим расчётам погрешность за каждую секунду теперь составляет 2 микросекунды, а за 10 минут, соответственно, - 1,2 миллисекунды. Итого удалось уменьшить погрешность примерно в 10000 раз, неплохо :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте.

Снова есть вопросы по AVR.

 

В программе сделал динамическую семисегментную индикацию через SPI, индикация вызывается в прерывании таймера каждые 2 миллисекунды.

И написал так же функцию, которая опрашивает все 8 каналов АЦП (без прерывания по окончанию преобразования). Эта функция вызывается в основном цикле, опрашивает 1 канал за такт. Для первых двух каналов АЦП в этой функции производятся довольно тяжёлые математические вычисления (оверсемплинг, фильтрация, аппроксимация по 2 точкам, коррекция) в переменных типа FLOAT. Ну и на время этих вычислений я запрещаю прерывания, соответственно индикаторы мерцают... А хотелось бы чтобы они горели с постоянной яркостью.

 

1а) Если НЕ запрещать прерывания, то прерывания могут испортить переменные в ОЗУ, которые в обработчике этого прерывания никак не участвуют?

 

1б) Если могут испортить - то, получается, мне в каждом куске основного цикла где есть работа с типами int16_t, int32_t, float - всегда запрещать прерывания?

 

2) В Atmel Studio 7, если использовать стандартные функции работы с EEPROM, то функция записи/обновления переменной в EEPROM сама отключает прерывания на время своей работы? Или это надо вручную перед вызовом этой функции запретить прерывания, а после выполнения функции - снова разрешать? В обработчике прерывания эти переменные так же не используются. Сейчас без запрета прерываний всё работает вроде, но боюсь что мне просто везёт, а хотелось бы знать наверняка. Можно ли где-то посмотреть сам текст этих стандартных функций работы с EEPROM? В хедер-файле EEPROM.h этого кода нет.

Изменено пользователем lyric

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Узел EEPROM — это отдельная схема на кристалле микроконтроллера, она тактируется собственным тактовым генератором, поэтому всё делает сама и не зависит ни от чего. Также, после её озадачивания записью и до завершения всех процессов она включает помпу, повышающую напряжение питания, потому что для работы с ячейками памяти такого типа требуется относительно высокое напряжение, т.е. начинает потреблять указанный в паспорте существенный и дополнительный к общему ток на указанный в паспорте же интервал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Plain

 

это значит что в моём случае запрещать прерывания не нужно ни при расчёте АЦП ни при записи EEPROM?

 

В обработчике прерывания таймера есть только то что касается индикации, и инкремент трёх переменных для создания программных таймеров в основном цикле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ни при записи EEPROM?
Прерывание может не только менять данные, но и нарушать временнЫе интервалы между командами. При записи в ЭСППЗУ нужно сделать две записи в регистр EECR, между которыми не должно быть больше четырех тактов процессора. Естественно, если после первой записи произойдет прерывание - ни о каких четырех тактах речь идти уже не будет. Поэтому вот именно перед первой записью в EECR прерывания должны быть запрещены, а после второй их уже можно разрешать.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прерывание может не только менять данные, но и нарушать временнЫе интервалы между командами. При записи в ЭСППЗУ нужно сделать две записи в регистр EECR, между которыми не должно быть больше четырех тактов процессора. Естественно, если после первой записи произойдет прерывание - ни о каких четырех тактах речь идти уже не будет. Поэтому вот именно перед первой записью в EECR прерывания должны быть запрещены, а после второй их уже можно разрешать.

 

А если я использую стандартные функции работы с EEPROM, которые содержаться в компиляторе Атмел Студии, - всё равно вручную запрещать прерывания? Функция eeprom_update_word() сама этого не делает? Где-то можно посмотреть её код?

Изменено пользователем lyric

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если я использую стандартные функции работы с EEPROM, которые содержаться в компиляторе Атмел Студии, - всё равно вручную запрещать прерывания?
Если она не запрещает прерывания - надо делать это вручную.

Функция eeprom_update_word() сама этого не делает? Где-то можно посмотреть её код?
Самое простое - в листинге дизассемблера.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если она не запрещает прерывания - надо делать это вручную.

Самое простое - в листинге дизассемблера.

 

Не запрещает. Придётся писать свою функцию записи/обновления EEPROM, видимо.

Спасибо за помощь, с EEPROM понятно :a14: .

 

Подскажите пожалуйста ещё на эти вопросы:

 

1а) Если НЕ запрещать прерывания, то прерывания могут испортить переменные в ОЗУ, которые в обработчике этого прерывания никак не участвуют?

 

1б) Если могут испортить - то, получается, мне в каждом куске основного цикла где есть работа с типами int16_t, int32_t, float - всегда запрещать прерывания?

 

Какие ответы? :rolleyes:

Изменено пользователем lyric

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...