while (1) { // Place your code here if(rx_counter1 != 0) //если еще не все символы, из входного буфера, прочитанные функцией getchar { tmp = getchar1(); // tmp = входной символ (уменьшаем на 1 rx_counter1)
putchar1(tmp^string_in[index_str]); // Xor и отправляем на выход
if (index_str == 19) index_str=0; else index_str++; }; };
Устройство подключено через СОМ порт к ПК. С ПК отправляю массив символов (нажатием кнопки) на UART нашего МК. Программа берет по одному символу из массива с ПК и делает операцию Xor с каким-то элементом массива string_in (который записан в памяти МК). Если входной массив с ПК больше чем массив string_in, то index_str обнуляется. И данные для операции Xor берутся сначала массива string_in. После чего возвращает на ПК (по UART) измененный массив символов.
Что нужно добавить в код, чтобы, когда с ПК отправляется новый массив символов, МК сбрасывал в 0 значение моей переменной index_str?
Наколько я понял, максимальная длина массива 16. Допустим, вы передали 10 элементов. Как МК узнает, что передан один массив из 10 элементов или 2 массива по 5? В данном коде просто никак - он поместит все 10 в один массив и будет ожидать 11-го элемента. Как-бы Вы сами узнали?
Вам нужно, например, передавать фактическую длину массива, или делать временную задержку между посылкой разных массивов. Во втором случае можно после приема каждого символа включать таймер, который будет считать, скажем, до 1000. Если таймер не досчитал до 1000 и принят новый символ, то считается, что он принадлежит к тому-же массиву. Таймер следует каждый раз обнулять по приему символа. Как только таймер досчитает до 1000, значит массив принят полностью и следует обнулять index_str и готовиться принимать другой массив. Если разрешить прерывание по переполнению таймера, то обнулять переменную можно в подпрограмме обработки прерывания таймера. В ней-же следует останавливать таймер. Он включися опять после приема след. символа.
Chip type : ATmega64 Clock frequency : 8,000000 MHz
interrupt [TIM1_OVF] void timer1_ovf_isr(void) { // Reinitialize Timer 1 value //Начальное значение Таймера 1 при запуске: ??? (почему эти значения) TCNT1H=0x0B; TCNT1L=0xDC; // Place your code here index_str=0; // должно выполнятся при переполнении таймера? }
void main(void) { //… // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 125,000 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // OC1C output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: On // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off // Compare C Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x03; // Clock value: 125,000 kHz //Начальное значение Таймера 1 при запуске: ??? (почему эти значения) //в прерывании interrupt [TIM1_OVF] void timer1_ovf_isr(void) такие же значения TCNT1H=0x0B; TCNT1L=0xDC; //.. // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x04; //при переполнении таймера 1, запуск прерывания interrupt [TIM1_OVF] void timer1_ovf_isr(void) ETIMSK=0x00; //что это??? //.. while (1) { // Place your code here if(rx_counter1 != 0) //если еще не все символы, из входного буфера, прочитанны функцией getchar { tmp = getchar1(); // tmp = входной символ (уменьшаем на 1 rx_counter1)
putchar1(tmp^string_in[index_str]);
if (index_str == 19) index_str=0; //это же должно присходить, если дольше 1сек не поступают входные символы. else index_str++; }; }
Подскажите, пожалуйста: 1. Данные TCNT1H=0x0B; TCNT1L=0xDC; взял с «потолка», какие у меня должны быть значения таймера? Что бы таймер переполнялся через 1 секунду (если данные не поступают по UART). 2. Как обнулять таймер при каждом входе в if(rx_counter1 != 0)…?
Правильнее буде оформлять данные в пакеты с разделителями. Один из простых вариантов -- SLIP, на нём основан Wake от Леонида Ивановича. Ещё тут -- viewtopic.php?f=20&t=36709 С некоторым отклоненем, зато с готовым софтом под Win для работы и отладки.
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Cпасибо за комментарий. Т.к. пишу на C# под ПК, то создал свой интерфейс используя SerialPort – класс
А вот с задачей написания прошивки для МК (ATmega64) столкнулся впервые. Мне нужно, что бы по окончанию приема или передачи данных через UART происходило установление в ноль переменной (которую сам объявил).
Сейчас приходится выключать/включать устройство, что бы установились первоначальные параметры.
Пожалуйста, подскажите, как сделать на ATmega64 включение/отключение таймера?
Таймер будет считать до 1 секунды, если за это время не будет передана/принята никакая инфрмация через UART, то переменная index_str должна стать равной нулю.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
while (1) { // Place your code here if(rx_counter1 != 0) //если еще не все символы, из входного буфера, прочитанные функцией getchar { tmp = getchar1(); // tmp = входной символ (уменьшаем на 1 rx_counter1)
putchar1(tmp ^ string_in[index_str]); // Xor 1 символ и отправляем на выход if (index_str == 19) index_str=0; else index_str++; }; //else // index_str=0; //if (UDR1 == 0) index_str=0; if (tx_counter1 == 0) if (rx_counter1 == 0) index_str=0; }; }
При такой программе всегда index_str=0.
Ser60 предложил очень разумное решение. Нужно на каждой итерации
Таймер будет обнуляться чаще чем 1 раз в секунду. Но, если условие перестанет выполнятся длительное время (1 секунду или больше), прерывание переполнения таймера сбросит index_str = 0.
Подскажите, пожалуйста, код для запуска (обнуления) таймера?
Как всегда меня опередили пока спал... Ну раз уж написал, отправлю.
1. Если МК тактируется от 8 мгц и требуется переполмение таимера Timer1 через секунду, то коэффициент деления должен быть 8000000. Используя прескейлер 1:1024 получаем, что таймер должен считать до 8000000 / 1024 = 7812 = 0x1E84. Именно это число надо поместить в регистр ICR1 до входа в основной цикл программы. ICR1 = 0x1E84
2. Используем таймер в режиме CTC (режим 1100). Это достигается так: TCCR1A = 0 TCCR1B = 0x18
3. Разрешаем прерывания от таймера и обнуляем его флаг: TIMSK1 = 1 TIFR1 = 0
4. Разрешаем прерывания глобально: #asm("sei")
5. В программе обработки прерываний таймера: а. Останавливаем таймер, отключая от него тактирующую частоту TCCR1B = 0x18 б. обнуляем Вашу переменную index_str=0;
Все предыдущие операции надо сделать до входа в основной цикл программы. В основном цикле по приему символа из UART:
1. Обнуляем таймер TCNT1 = 0 2. Запускаем таймер, подав на него частоту от прескейлера 1:1024 TCCR1B = 0x1D Строго говоря, запуск необходим только 1 раз по приему первого элемента массива, но повторный запуск не повредит (он просто будет проигнорирован). Но если хотите, можно запускать только 1 раз: if (index_str==0) TCCR1B = 0x1D
Я-бы в основном цикле код в блоке if (rx_counter1 != 0) оформил-бы как прерывание от UART по приему символа. В этом случае процессор можно поместить в сон, нечего ему работать высунув язык. Пробуждение будет по приему символа или переполнению таймера.
Идея в том, что прерывание от UART, похоже, приоритетней чем прерывание от Timer 1. Поэтому, банально обнуляю нужную переменную в таймере. Согласен, это метод некрасивый. Т.к. если буду обрабатывать массив данных долго (внутри МК), то переменная index_str может не вовремя обнулиться. Поэтому начинаю медитировать, на Ваше решение.
Ser60 писал(а):
Как всегда меня опередили пока спал... Ну раз уж написал, отправлю. ... Я-бы в основном цикле код в блоке if (rx_counter1 != 0) оформил-бы как прерывание от UART по приему символа. В этом случае процессор можно поместить в сон, нечего ему работать высунув язык. Пробуждение будет по приему символа или переполнению таймера.
Прерывание от UART по приему символа разрешить не забыли? Если нет - поставьте точку останова в отладчике (внутрисхемном) в нагале программы приема символа с UART и посмотрите что принимается.
... Добавлено позже. Посмотрел код - конечно забыли. А где ISR от Таймера, что я писал, и где его инициализация?
...поставьте точку останова в отладчике (внутрисхемном) в нагале программы приема символа с UART и посмотрите что принимается.
Пользуюсь только CV. Недавно начал читать про VMLAB. Установил AVRStudio5.1, но она с CV (2008 года) не хочет работать. Поэтому, пожалуйста, уточните: что значит внутрисхемный отладчик?
Ser60 писал(а):
...А где ISR от Таймера, что я писал, и где его инициализация?
Извините, недопонял сразу. Вот исправленный вариант (он то же не рабочий).
Вложения:
Комментарий к файлу: новая версия Mytest_m64d1.c [11.57 KiB]
Скачиваний: 295
А у Вас вместо TIMSK1 стоит TIMSK. Поставьте эти строчки вместе и выкиньте весь остальной код связанный с таймерами: помимо Timer1 Вы других не используете, ну и не трогайте их регистры.
Прерывание UART надо по окончании приема. У Вас код в обработчике не того прерывания.
Еще выкиньте весь код запрета/разрешения прерываний иz getchar1 и putchar1. Сейчас он не нужен.
Чем Вы программируете МК? Внутрисхемный отладчик/программатор (например AVR Dragon) к IDE не имеет отношения. Но если Вы не знаете, что это такое, скорее всего им и не пользуетесь. Тогда забудьте про него.
Нет, не так. Вам нужно запускать таймер по окончании приему символа, как я писал, а не по окончании передачи, как у Вас сейчас. Давайте начнем с малого. Вернитесь к первоначальному коду, где обработка производится в основном цикле. Я написал внизу как он должен выглядеть. Весь этот код надо вставить в самый конец main(). Вы правы, регистры в Mega64 действительно называются TIMSK и TIFR. В TIMSK надо загружать 4, чтобы разрешить прерывания по переполнению таймера.
Код:
ICR1 = 0x1E84; // настройки таймера до входа в основной цикл TCCR1A = 0; TCCR1B = 0x18; TIMSK = 4; TIFR = 0;
while (1) { if (rx_counter1 != 0) //если еще не все символы из входного буфера прочитанны { tmp = getchar1(); // tmp = входной символ (уменьшаем на 1 rx_counter1)
putchar1(tmp^string_in[index_str]); // Xor и отправляем на выход
////////////////////////////////////////////////// Пока вернулся к самому первому варианту и добавил пару строк:
Код:
interrupt [TIM1_OVF] void timer1_ovf_isr(void) { // Reinitialize Timer 1 value TCNT1H=0x0B; //задержка таймера TCNT1L=0xDC; //около 0,5 сек // Place your code here index_str = 0; TIMSK=0x00; }
void main(void) { //… while (1) { // Place your code here if(rx_counter1 != 0) //если еще не все символы, из входного буфера, прочитанные функцией getchar { TIMSK=0x00; // Reinitialize Timer 1 value TCNT1H=0x0B; TCNT1L=0xDC;
tmp = getchar1(); // tmp = входной символ (уменьшаем на 1 rx_counter1)
putchar1(tmp ^ string_in[index_str]); // Xor 1 символ и отправляем на выход if (index_str == 19) index_str=0; else index_str++; } else TIMSK=0x04; //при переполнении таймера 1, запуск прерывания interrupt [TIM1_OVF] void timer1_ovf_isr(void) }; }
Теперь около 2Мб входного потока шифрует, потом глючит (иногда). Как думаете, это из-за программа прошивки или из-за интерфейса на ПК (может моя программа на ПК слишком быстро передает данные)?
Вложения:
Комментарий к файлу: Файл из ТС с мелкими доработками Mytest_m64c1.c [11.25 KiB]
Скачиваний: 301
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 29
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения