lyric 0 22 сентября, 2017 Опубликовано 22 сентября, 2017 · Жалоба Привет всем. Наверняка уже много раз этот вопрос поднимался, но не знаю как и где искать. Программирую атмегу по интерфейсу JTAG. В программе я могу эти 4 ноги, занятые JTAGом, использовать как обычные входы/выходы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Smoky 0 22 сентября, 2017 Опубликовано 22 сентября, 2017 · Жалоба Привет всем. Наверняка уже много раз этот вопрос поднимался, но не знаю как и где искать. Программирую атмегу по интерфейсу JTAG. В программе я могу эти 4 ноги, занятые JTAGом, использовать как обычные входы/выходы? При отладке программ нельзя, а в рабочем режиме имеется возможность. В регистрах MCUCSR или MCUCR имеется хитрый бит JTD, переключением которого можно эти порты использовать в рабочем режиме. Правда его переключение довольно своеобразное, как пишут в руководстве необходимо произвести запись бита дважды за четыре такта... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 22 сентября, 2017 Опубликовано 22 сентября, 2017 · Жалоба При отладке программ нельзя, а в рабочем режиме имеется возможность. В регистрах MCUCSR или MCUCR имеется хитрый бит JTD, переключением которого можно эти порты использовать в рабочем режиме. Правда его переключение довольно своеобразное, как пишут в руководстве необходимо произвести запись бита дважды за четыре такта... Спасибо, попробую :beer: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 6 октября, 2017 Опубликовано 6 октября, 2017 (изменено) · Жалоба Здравствуйте, снова есть смешной (для сколь-нибудь опытных разработчиков) вопрос: Снова про 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, если это важно. Изменено 6 октября, 2017 пользователем lyric Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Smoky 0 6 октября, 2017 Опубликовано 6 октября, 2017 · Жалоба Я бы не стал слишком сильно доверять телефонному секундомеру... Но если вы хотите опираться на него как на эталон, попробуйте поварьировать данные в регистре OCR1A. Одна единица этого регистра изменит ваши 10 сек на 3,2 мсек. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x736C 0 6 октября, 2017 Опубликовано 6 октября, 2017 (изменено) · Жалоба Возможно, у вас лишняя единица где-то еще. Значение для таймера считается без единицы. В вашем случае: timer_value = ([10] мс * 8000 [кГц] / 256) - 1 = 3124. Эта ошибка уже добавляет лишние 320 мкс на одну секунду или 192 мс на 10 минут. Вероятно, на следующем уровне иерархии, когда обрабатываете свои счетчики, допускаете ту же ошибку. Как быть? Это нормально и вызвана непостоянностью рабочей частоты? Погрешность эту можно как-то сократить? Такой погрешности быть не должно. То есть на глаз, если положить рядом секундомер, интервалы должны быть неотличимы. Но это в том случае, если используете внешний кварцевый резонатор или генератор. Если внутренний RC-генератор, то все может быть иначе. Но проверить можно в AtmelStudio в режиме симуляции. Там есть возможность замерить интервалы работы участков кода. Только необходимо упростить пример, уменьшив значение, загружаемое в счетчик. Накопление погрешностей можно отследить. Все остальное будет из-за несовершенства RC-генератора. Его можно откалибровать, насколько помню. См. документацию. А если я 30 таких таймеров запилю - мне их все в этом же прерывании обрабатывать будет нормально или они, возможно, не будут успевать обрабатываться за прерывание? Это надо проверять, кто ж вам ответит. Но перегрузить прерывание, происходящее раз в 100 мс — это надо очень постараться. И ещё вопрос из фьюзов кроме CKDIV8 ещё какие-то влияют на рабочую частоту МК, если он работает от внутреннего генератора? То есть в моём случае есть всего 2 варианта частоты, - с включенным CKDIV8 это 1МГц, а с выключенным CKDIV8 это 8МГц и третьего не дано? Атмега644, если это важно. Далее идет делитель CLKPR, который может дальше поделить эту частоту. Изменено 6 октября, 2017 пользователем x736C Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 10 октября, 2017 Опубликовано 10 октября, 2017 · Жалоба Smoky, x736C Большое спасибо, Ваши советы и замечания помогли. Ну и кроме того я сделал прерывание каждые 5 миллисекунд (вместо каждых 100), и инкрементируемую переменную указал volatile вместо unsigned. теперь секундомер смартфона один в один бьёт с тем, что отсчитывает МК, - на глаз никак не отличить. По моим расчётам погрешность за каждую секунду теперь составляет 2 микросекунды, а за 10 минут, соответственно, - 1,2 миллисекунды. Итого удалось уменьшить погрешность примерно в 10000 раз, неплохо :rolleyes: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 23 августа, 2018 Опубликовано 23 августа, 2018 (изменено) · Жалоба Здравствуйте. Снова есть вопросы по AVR. В программе сделал динамическую семисегментную индикацию через SPI, индикация вызывается в прерывании таймера каждые 2 миллисекунды. И написал так же функцию, которая опрашивает все 8 каналов АЦП (без прерывания по окончанию преобразования). Эта функция вызывается в основном цикле, опрашивает 1 канал за такт. Для первых двух каналов АЦП в этой функции производятся довольно тяжёлые математические вычисления (оверсемплинг, фильтрация, аппроксимация по 2 точкам, коррекция) в переменных типа FLOAT. Ну и на время этих вычислений я запрещаю прерывания, соответственно индикаторы мерцают... А хотелось бы чтобы они горели с постоянной яркостью. 1а) Если НЕ запрещать прерывания, то прерывания могут испортить переменные в ОЗУ, которые в обработчике этого прерывания никак не участвуют? 1б) Если могут испортить - то, получается, мне в каждом куске основного цикла где есть работа с типами int16_t, int32_t, float - всегда запрещать прерывания? 2) В Atmel Studio 7, если использовать стандартные функции работы с EEPROM, то функция записи/обновления переменной в EEPROM сама отключает прерывания на время своей работы? Или это надо вручную перед вызовом этой функции запретить прерывания, а после выполнения функции - снова разрешать? В обработчике прерывания эти переменные так же не используются. Сейчас без запрета прерываний всё работает вроде, но боюсь что мне просто везёт, а хотелось бы знать наверняка. Можно ли где-то посмотреть сам текст этих стандартных функций работы с EEPROM? В хедер-файле EEPROM.h этого кода нет. Изменено 23 августа, 2018 пользователем lyric Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 220 23 августа, 2018 Опубликовано 23 августа, 2018 · Жалоба Во-первых, прерывания сами по себе ничего не портят, это просто условное ветвление программы, а во-вторых, в прерываниях надо делать только то, что в них действительно нуждается. Узел EEPROM — это отдельная схема на кристалле микроконтроллера, она тактируется собственным тактовым генератором, поэтому всё делает сама и не зависит ни от чего. Также, после её озадачивания записью и до завершения всех процессов она включает помпу, повышающую напряжение питания, потому что для работы с ячейками памяти такого типа требуется относительно высокое напряжение, т.е. начинает потреблять указанный в паспорте существенный и дополнительный к общему ток на указанный в паспорте же интервал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 23 августа, 2018 Опубликовано 23 августа, 2018 · Жалоба Plain это значит что в моём случае запрещать прерывания не нужно ни при расчёте АЦП ни при записи EEPROM? В обработчике прерывания таймера есть только то что касается индикации, и инкремент трёх переменных для создания программных таймеров в основном цикле. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 220 23 августа, 2018 Опубликовано 23 августа, 2018 · Жалоба запрещать прерывания не нужно Естественно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 23 августа, 2018 Опубликовано 23 августа, 2018 · Жалоба ни при записи EEPROM?Прерывание может не только менять данные, но и нарушать временнЫе интервалы между командами. При записи в ЭСППЗУ нужно сделать две записи в регистр EECR, между которыми не должно быть больше четырех тактов процессора. Естественно, если после первой записи произойдет прерывание - ни о каких четырех тактах речь идти уже не будет. Поэтому вот именно перед первой записью в EECR прерывания должны быть запрещены, а после второй их уже можно разрешать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 23 августа, 2018 Опубликовано 23 августа, 2018 (изменено) · Жалоба Прерывание может не только менять данные, но и нарушать временнЫе интервалы между командами. При записи в ЭСППЗУ нужно сделать две записи в регистр EECR, между которыми не должно быть больше четырех тактов процессора. Естественно, если после первой записи произойдет прерывание - ни о каких четырех тактах речь идти уже не будет. Поэтому вот именно перед первой записью в EECR прерывания должны быть запрещены, а после второй их уже можно разрешать. А если я использую стандартные функции работы с EEPROM, которые содержаться в компиляторе Атмел Студии, - всё равно вручную запрещать прерывания? Функция eeprom_update_word() сама этого не делает? Где-то можно посмотреть её код? Изменено 23 августа, 2018 пользователем lyric Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 23 августа, 2018 Опубликовано 23 августа, 2018 · Жалоба А если я использую стандартные функции работы с EEPROM, которые содержаться в компиляторе Атмел Студии, - всё равно вручную запрещать прерывания?Если она не запрещает прерывания - надо делать это вручную. Функция eeprom_update_word() сама этого не делает? Где-то можно посмотреть её код?Самое простое - в листинге дизассемблера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lyric 0 23 августа, 2018 Опубликовано 23 августа, 2018 (изменено) · Жалоба Если она не запрещает прерывания - надо делать это вручную. Самое простое - в листинге дизассемблера. Не запрещает. Придётся писать свою функцию записи/обновления EEPROM, видимо. Спасибо за помощь, с EEPROM понятно :a14: . Подскажите пожалуйста ещё на эти вопросы: 1а) Если НЕ запрещать прерывания, то прерывания могут испортить переменные в ОЗУ, которые в обработчике этого прерывания никак не участвуют? 1б) Если могут испортить - то, получается, мне в каждом куске основного цикла где есть работа с типами int16_t, int32_t, float - всегда запрещать прерывания? Какие ответы? :rolleyes: Изменено 23 августа, 2018 пользователем lyric Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться