Здравствуйте, уважаемые. Давно хотел сделать для себя устройство с механической разверткой. Собрал статор, ротор. Светодиодов не очень много, всего 24, но мне достаточно. Используемый МК - Atmega328p на 16МГц, регистры 74HC595. Программирую на CodeVision 3.12. С железом проблем нет. Есть трудности с программной частью. И именно по ней требуется помощь. Для начала сделал вывод по столбцам и тупой задержкой с помощью delay_us. Конкретно в моем случае задержка после выводка каждого столбца была 850мкс. Все работало. Потом решил сделать расчет времени задержки на таймерах и без delay_us. Задумка была такая - по INT0 начинается отсчет 16-битного таймера Т1 до следующего срабатывания INT0. На ноге с INT0 сидит ИК-диод и дает "ноль" в определенной точке вращение ротора, как в большинстве подобных схем. При каждом срабатывании INT0 делается расчет времени необходимого для вывода ОДНОГО столбца изображения. Всего 48 столбцов. Результат расчета помещается в 8-битный таймер Т2 и при его переполнении выводится очередной столбец изображения. Для Т1 выбран предделитель 64 (250кГц), для Т2 - 256 (62,5кГц). И вот где-то на этапе вычислений я либо не замечаю ошибки, либо не учитываю какую-то тонкость программирования МК. Ротор делает 10-12 оборотов в секунду, поэтому переполнения Т1 быть не должно. В результате получаю следующее - вывод всего изображения происходит где-то за 2-3 "предполагаемых" переполнения таймера2, т.е. примерно за 20 градусов от полного круга. Привожу полный код программы с подробными комментариями. Надеюсь на вашу помощь. Спойлер
Код:
unsigned char nachalo, n3, n4, b_tmp, num_ris, stolbec; unsigned char image_end; // дорисовали картинку до конца (1) или нет (0) unsigned char kw_t2; // вычисляемый интервал для вывода одного столбца рисунка
// External Interrupt 0 service routine interrupt [EXT_INT0] void ext_int0_isr(void) { // между прерываниями INT0 засекается количество тиков Таймера1 // затем это число делится на количество столбцов рисунка и пересчитывается на частоту Таймера2 kw_t2=((TCNT1H<<8) + TCNT1L)/192; // расчет времени отводимого для вывода одного столбца // ((TCNT1*(1/250000))/(1/62500))/IMAGE_COL = // = (TCNT1 * 62500) / (250000 * IMAGE_COL) = // = TCNT1 / (4 * IMAGE_COL) = TCNT1 / 192
TCNT1H=0x0; // сброс счетчика Таймера1 TCNT1L=0x0; TCNT2=255-kw_t2; // установка счетчика Таймера2 image_end=0; // сбросим флаг достижения конца рисунка stolbec=0; // выводим с первого столбца nachalo=1; // можно начинать вываодить картинку }
// External Interrupt(s) initialization // INT0: On // INT0 Mode: Falling Edge // INT1: On // INT1 Mode: Falling Edge // Interrupt on any change on pins PCINT0-7: Off // Interrupt on any change on pins PCINT8-14: Off // Interrupt on any change on pins PCINT16-23: Off EICRA=(0<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00); EIMSK=(0<<INT1) | (1<<INT0); EIFR=(0<<INTF1) | (1<<INTF0); PCICR=(0<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);
// Analog Comparator initialization // Analog Comparator: Off ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0); ADCSRB=(0<<ACME); // Digital input buffer on AIN0: On // Digital input buffer on AIN1: On DIDR1=(0<<AIN0D) | (0<<AIN1D);
Sync=0; Latch=0; nachalo=0; num_ris=0; image_end=0; kw_t2=130; // начальное значение для времени 10 оборотов в секунду while (1) { // еще что-то
if ((nachalo==1)&&(image_end==0)) { // Если разрешен вывод очередного столбца и не достигли конца рисунка, то // заполняю регистры для одного столбца for (n3=0; n3<3; n3++) // у меня 3 регистра { b_tmp=risunki[num_ris][stolbec][n3]; for (n4=0; n4<8; n4++) { // побитовый вывод начиная со старшего разряда if ((b_tmp & 0b10000000) != 0) Data=1; else Data=0; Sync=1; // Тактовый импульс для регистров Sync=0; b_tmp=b_tmp<<1; } } Latch=1; // защелкнем ригистры Latch=0; nachalo=0; // Столбец отрисовали if (stolbec<(IMAGE_COL-1)) stolbec++; // Если вывели последний столбец, то больше выводить не надо до прерывания INT0 else image_end=1; }// if nachalo }// while }// main
И вот где-то на этапе вычислений я либо не замечаю ошибки, либо не учитываю какую-то тонкость программирования МК.
А как ты можешь заметить ошибку, если не видишь значений? Что конкретно у тебя насчитывает таймер-1, что он вычисляет как значение для таймера-2? Заведи массив на все 48 строк, чтобы за время "рисования" запомнить все значения TCNT1 в момент INT0 и вычисленного kw_t2 для каждой строки. И выведи эти значения по окончанию всего цикла рисования, хотя бы через UART на консоль. Потребуется 48 * (2 + 1 ) = 144 байта памяти для массива.
mas123, спасибо что откликнулся на зов помощи. Проблематично вывести на консоль что-то с вращающейся штуковины, а если остановить, то и расчетов никаких не будет. Можно разве что в EEPROM записать и потом глянуть. "отсутствие" переполнения Т1 я предполагал потому что частота вращения не менее 10 оборотов в секунду, а максимальное значение Т1 достигнет только при оборотах меньше 4 в секунду. Проведу рекомендованные мероприятия и отпишусь по результатам.
P.S. Расчет kw_t2 делается один раз за оборот и используется для вывода каждого столбца изображения.
Проблематично вывести на консоль что-то с вращающейся штуковины, а если остановить, то и расчетов никаких не будет.
Эммммм, не вижу НИКАКОЙ проблемы даже по двум причинам: - вывод стоит делать после прохождения одного круга. Выполнен один проход, буфер заполнен - всё, можно выводить цифры и пофигу уже на дальнейшее кручение.
- вывод в UART на прерываниях. Тут-то что мешать будет "кручению"? Если только не намудрить в функции обработки прерывания передатчика UART...
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
а если сделать проще - по переполнению (или по любому другому событию) зажигать определённый светодиод в глобусе, тогда будет виден не только факт, но и момент события.
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
В общем я сделал так. В своей "тупой" (которая использует delay) выводилке изображения подобрал задержку и по ней выставил скорость двигателя 15 оборотов в секунду. Было 27. Затем в программе, листинг которой я опубликовал тут, добавил запись в EEPROM МК 20 значений подряд TCNT1 и kw_t2, но сначала выжидал 4 секунды для стабилизации скорости вращения. И был удивлен тем, что всегда старший байт счетчика в EEPROM был нулевым, а kw_t2 всегда был больше 2. Косяк мой был в том, что я читал сначала старший байт счетчика, а потом младший. А надо строго наоборот. После этого цифирки стали соответствовать друг другу. И тут я предположил, что компилятор не учитывает правила работы при чтении регистров счетчика. И заменил строку: kw_t2=((TCNT1H<<8) + TCNT1L)/192;
на вот такую комбинацию: kw_t2=TCNT1L; kw_t2=((TCNT1H<<8) + kw_t2)/192;
и заработало, блин. Я неделю бился с этой проблемой. Это уже второй косяк на который я напоролся понадеевшись на корректность CVAVR. Первый был связан с кривым генератором начального кода для инициализации ватчдога на atmege328. Только изредка почему-то пропускает INT0. Не могу пока понять почему.
Специально пишу через отдельную переменную для наглядности. Можно и kw_t2 = TCNT1 / 192; Компиляторы умеют правильно вычитывать двухбайтные значения из TCNTх, ADC,...
Только изредка почему-то пропускает INT0. Не могу пока понять почему.
В смысле "пропускает"? Либо на входе сигнал "плохой", либо в этот момент прерывания запрещены. Повесь отдалочный светодиод и мигай им при входе в обработчик INT0.
В смысле "пропускает"? Либо на входе сигнал "плохой", либо в этот момент прерывания запрещены. Повесь отдалочный светодиод и мигай им при входе в обработчик INT0.
Прерывания у меня вообще не запрещаются в этом коде, ну разве что аппаратно в переполнении счетчика Т2. Происходит следующее, если нет сработки INT0, то все светодиоды гаснут и я фиксирую "моргание". Буду с этим разбираться. Спасибо за участие в топике
Я пробовал. Выяснилось, что cvavr не знает такого регистра
их можно и познакомить : в папке inc найди файл от своего МК и допиши про TCNT1W (по аналогии с ADCW) должно прокатить я к меге 8 так дописывал, правда там он описан был в верхней части (не через дефайны)
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 48
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения