|
|
  |
Микроконтроллеры для начинающих, AVR, PIC, FUJITSU |
|
|
|
Sep 22 2017, 06:03
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Привет всем. Наверняка уже много раз этот вопрос поднимался, но не знаю как и где искать.
Программирую атмегу по интерфейсу JTAG. В программе я могу эти 4 ноги, занятые JTAGом, использовать как обычные входы/выходы?
|
|
|
|
|
Sep 22 2017, 06:56
|

Местный
  
Группа: Свой
Сообщений: 401
Регистрация: 7-05-10
Из: Оренбург
Пользователь №: 57 135

|
Цитата(lyric @ Sep 22 2017, 12:03)  Привет всем. Наверняка уже много раз этот вопрос поднимался, но не знаю как и где искать.
Программирую атмегу по интерфейсу JTAG. В программе я могу эти 4 ноги, занятые JTAGом, использовать как обычные входы/выходы? При отладке программ нельзя, а в рабочем режиме имеется возможность. В регистрах MCUCSR или MCUCR имеется хитрый бит JTD, переключением которого можно эти порты использовать в рабочем режиме. Правда его переключение довольно своеобразное, как пишут в руководстве необходимо произвести запись бита дважды за четыре такта...
--------------------
Лень, оттвори дверь, сгоришь - а хоть и сгорю, но не оттворю.
|
|
|
|
|
Sep 22 2017, 07:22
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Цитата(Smoky @ Sep 22 2017, 13:56)  При отладке программ нельзя, а в рабочем режиме имеется возможность. В регистрах MCUCSR или MCUCR имеется хитрый бит JTD, переключением которого можно эти порты использовать в рабочем режиме. Правда его переключение довольно своеобразное, как пишут в руководстве необходимо произвести запись бита дважды за четыре такта... Спасибо, попробую
|
|
|
|
|
Oct 6 2017, 11:22
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Здравствуйте, снова есть смешной (для сколь-нибудь опытных разработчиков) вопрос: Снова про 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 - Oct 6 2017, 12:54
|
|
|
|
|
Oct 6 2017, 17:33
|
Профессионал
    
Группа: Участник
Сообщений: 1 273
Регистрация: 3-03-06
Пользователь №: 14 942

|
Возможно, у вас лишняя единица где-то еще. Значение для таймера считается без единицы. В вашем случае: timer_value = ([10] мс * 8000 [кГц] / 256) - 1 = 3124. Эта ошибка уже добавляет лишние 320 мкс на одну секунду или 192 мс на 10 минут. Вероятно, на следующем уровне иерархии, когда обрабатываете свои счетчики, допускаете ту же ошибку. Цитата(lyric @ Oct 6 2017, 14:22)  Как быть? Это нормально и вызвана непостоянностью рабочей частоты? Погрешность эту можно как-то сократить? Такой погрешности быть не должно. То есть на глаз, если положить рядом секундомер, интервалы должны быть неотличимы. Но это в том случае, если используете внешний кварцевый резонатор или генератор. Если внутренний RC-генератор, то все может быть иначе. Но проверить можно в AtmelStudio в режиме симуляции. Там есть возможность замерить интервалы работы участков кода. Только необходимо упростить пример, уменьшив значение, загружаемое в счетчик. Накопление погрешностей можно отследить. Все остальное будет из-за несовершенства RC-генератора. Его можно откалибровать, насколько помню. См. документацию. Цитата(lyric @ Oct 6 2017, 14:22)  А если я 30 таких таймеров запилю - мне их все в этом же прерывании обрабатывать будет нормально или они, возможно, не будут успевать обрабатываться за прерывание? Это надо проверять, кто ж вам ответит. Но перегрузить прерывание, происходящее раз в 100 мс — это надо очень постараться. Цитата(lyric @ Oct 6 2017, 14:22)  И ещё вопрос из фьюзов кроме CKDIV8 ещё какие-то влияют на рабочую частоту МК, если он работает от внутреннего генератора? То есть в моём случае есть всего 2 варианта частоты, - с включенным CKDIV8 это 1МГц, а с выключенным CKDIV8 это 8МГц и третьего не дано? Атмега644, если это важно. Далее идет делитель CLKPR, который может дальше поделить эту частоту.
Сообщение отредактировал x736C - Oct 6 2017, 17:37
|
|
|
|
|
Oct 10 2017, 07:51
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Smoky, x736C Большое спасибо, Ваши советы и замечания помогли. Ну и кроме того я сделал прерывание каждые 5 миллисекунд (вместо каждых 100), и инкрементируемую переменную указал volatile вместо unsigned. теперь секундомер смартфона один в один бьёт с тем, что отсчитывает МК, - на глаз никак не отличить. По моим расчётам погрешность за каждую секунду теперь составляет 2 микросекунды, а за 10 минут, соответственно, - 1,2 миллисекунды. Итого удалось уменьшить погрешность примерно в 10000 раз, неплохо
|
|
|
|
|
Aug 23 2018, 03:06
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Здравствуйте. Снова есть вопросы по AVR.
В программе сделал динамическую семисегментную индикацию через SPI, индикация вызывается в прерывании таймера каждые 2 миллисекунды. И написал так же функцию, которая опрашивает все 8 каналов АЦП (без прерывания по окончанию преобразования). Эта функция вызывается в основном цикле, опрашивает 1 канал за такт. Для первых двух каналов АЦП в этой функции производятся довольно тяжёлые математические вычисления (оверсемплинг, фильтрация, аппроксимация по 2 точкам, коррекция) в переменных типа FLOAT. Ну и на время этих вычислений я запрещаю прерывания, соответственно индикаторы мерцают... А хотелось бы чтобы они горели с постоянной яркостью.
1а) Если НЕ запрещать прерывания, то прерывания могут испортить переменные в ОЗУ, которые в обработчике этого прерывания никак не участвуют?
1б) Если могут испортить - то, получается, мне в каждом куске основного цикла где есть работа с типами int16_t, int32_t, float - всегда запрещать прерывания?
2) В Atmel Studio 7, если использовать стандартные функции работы с EEPROM, то функция записи/обновления переменной в EEPROM сама отключает прерывания на время своей работы? Или это надо вручную перед вызовом этой функции запретить прерывания, а после выполнения функции - снова разрешать? В обработчике прерывания эти переменные так же не используются. Сейчас без запрета прерываний всё работает вроде, но боюсь что мне просто везёт, а хотелось бы знать наверняка. Можно ли где-то посмотреть сам текст этих стандартных функций работы с EEPROM? В хедер-файле EEPROM.h этого кода нет.
Сообщение отредактировал lyric - Aug 23 2018, 03:16
|
|
|
|
|
Aug 23 2018, 05:43
|
Гуру
     
Группа: Участник
Сообщений: 6 776
Регистрация: 5-03-09
Из: Москва
Пользователь №: 45 710

|
Во-первых, прерывания сами по себе ничего не портят, это просто условное ветвление программы, а во-вторых, в прерываниях надо делать только то, что в них действительно нуждается.
Узел EEPROM — это отдельная схема на кристалле микроконтроллера, она тактируется собственным тактовым генератором, поэтому всё делает сама и не зависит ни от чего. Также, после её озадачивания записью и до завершения всех процессов она включает помпу, повышающую напряжение питания, потому что для работы с ячейками памяти такого типа требуется относительно высокое напряжение, т.е. начинает потреблять указанный в паспорте существенный и дополнительный к общему ток на указанный в паспорте же интервал.
|
|
|
|
|
Aug 23 2018, 05:56
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Plain
это значит что в моём случае запрещать прерывания не нужно ни при расчёте АЦП ни при записи EEPROM?
В обработчике прерывания таймера есть только то что касается индикации, и инкремент трёх переменных для создания программных таймеров в основном цикле.
|
|
|
|
|
Aug 23 2018, 08:44
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Цитата(Сергей Борщ @ Aug 23 2018, 14:55)  Прерывание может не только менять данные, но и нарушать временнЫе интервалы между командами. При записи в ЭСППЗУ нужно сделать две записи в регистр EECR, между которыми не должно быть больше четырех тактов процессора. Естественно, если после первой записи произойдет прерывание - ни о каких четырех тактах речь идти уже не будет. Поэтому вот именно перед первой записью в EECR прерывания должны быть запрещены, а после второй их уже можно разрешать. А если я использую стандартные функции работы с EEPROM, которые содержаться в компиляторе Атмел Студии, - всё равно вручную запрещать прерывания? Функция eeprom_update_word() сама этого не делает? Где-то можно посмотреть её код?
Сообщение отредактировал lyric - Aug 23 2018, 08:44
|
|
|
|
|
Aug 23 2018, 09:16
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (lyric @ Aug 23 2018, 11:44)  А если я использую стандартные функции работы с EEPROM, которые содержаться в компиляторе Атмел Студии, - всё равно вручную запрещать прерывания? Если она не запрещает прерывания - надо делать это вручную. QUOTE (lyric @ Aug 23 2018, 11:44)  Функция eeprom_update_word() сама этого не делает? Где-то можно посмотреть её код? Самое простое - в листинге дизассемблера.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 23 2018, 10:55
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250

|
Цитата(Сергей Борщ @ Aug 23 2018, 16:16)  Если она не запрещает прерывания - надо делать это вручную. Самое простое - в листинге дизассемблера. Не запрещает. Придётся писать свою функцию записи/обновления EEPROM, видимо. Спасибо за помощь, с EEPROM понятно  . Подскажите пожалуйста ещё на эти вопросы: Цитата(lyric @ Aug 23 2018, 10:06)  1а) Если НЕ запрещать прерывания, то прерывания могут испортить переменные в ОЗУ, которые в обработчике этого прерывания никак не участвуют?
1б) Если могут испортить - то, получается, мне в каждом куске основного цикла где есть работа с типами int16_t, int32_t, float - всегда запрещать прерывания? Какие ответы?
Сообщение отредактировал lyric - Aug 23 2018, 10:56
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|