Здравствуйте. Ещё одна проблемка у меня, при симуляции проекта.
Attiny13a
MicroCore
Ошибка в Proteus
PC=0x002E. [AVR WATCHDOG] Incorrect watchdog timer setup sequence. [U1]
Нельзя исправить?
Здравствуйте. Ещё одна проблемка у меня, при симуляции проекта.
Attiny13a
MicroCore
Ошибка в Proteus
PC=0x002E. [AVR WATCHDOG] Incorrect watchdog timer setup sequence. [U1]
Нельзя исправить?
Наверное, можно, но нужно знать что там у Вас за
Мне рекомендовали, на форуме, использовать MicroCore
Сейчас скачала DIY ATtiny
В Proteus заработало
Как узнать?)
Ну, как, код посмотреть.
На миллис ругается
uint32_t tmr;
bool tmr_flag;
void setup() {
// put your setup code here, to run once:
}
void loop() {
if (tmr_flag && millis() - tmr >= 2000) {
tmr_flag = false;
}
}
Дык надо код millis смотреть. Он там есть в адд-оне
Замените строки в файле
packages\MicroCore\hardware\avr\2.2.0\cores\microcore\millis.S
строки
.section .init8
ldi r16, 1<<WDTIE
out WDTCR, r16
sei
На строки
.section .init8
ldi r16, (1<<WDTIF) | (1<<WDTIE) | (1<<WDCE) | (1<<WDE)
out WDTCR, r16
ldi r16, (1<<WDTIF) | (1<<WDTIE) | (0<<WDCE) | (0<<WDE)
out WDTCR, r16
sei
Хотя для изменения WDTIE особая запись не требуется. Вероятно это глюк протеуса. (Похожий глюк есть и в 328).
Tiny13 какой частотой тактируется?
Ядро DIY ATtiny врёт с millis() при 1,2 мгц.
Спасибо, попробую.
9,6 МГц
вдруг кто будет перечитывать: такой код не имеет смысла. он не делает, то, что как бы задумано, потому и не работает.
скорее всего имелось ввиду вот так:
WDTCSR = (WDTCSR & ~((1<<WDCE) | (1<<WDE))) | (1<<WDTIF) | (1<<WDTIE);
А так в Proteus нормально моделируются прерывания от WDT. Но проблема в том, что штатный макрос wdt_enable(period); для AVR не приводит к изменению регистра WDTCSR так, как нужно, и приходится писать свою функцию. Например что-то вроде
wdt_reset();
cli();
MCUSR &= ~(1<<WDRF);
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = 0b01100000; // 4s
sei();
(для AVR 382p)
тогда все моделируется
Этот код был проверен на работоспособность. И он работает как задумано.
Задумано было внесение изменений в ядро. Чтобы один и тот же ИМЕЮЩИЙСЯ и РАБОТАЮЩИЙ на железе скетч, одинаково выполнялся и в Proteus и на железе. Без этих изменений, он не запускался в Proteus.
Да, как альтернатива можно было не трогать ядро и внести изменения в скетч, с учетом особенностей Proteus.
Так пишется лишь для наглядности, при инициализации, когда регистры и так равны 0.
Этот код был проверен на работоспособность.
Вы его не поняли. Он имел в виду, что код
| (0 << нечто)
не имеет никакого смысла от слова совсем, т.к. он не делает ничего. Скорее всего, компилятор его выбрасывает. Тогда зачем его писать и перегружать чтение программы.
при инициализации, когда регистры и так равны 0.
Этот код никак не влияет на регистры. Вообще никак. Он ничего не делает. Он просто загромождает программу.
Этот код никак не влияет на регистры. Вообще никак. Он ничего не делает
Ну так я и пишу
пишется лишь для наглядности,
Просто, чтобы показать тек. состояние регистров.
Я иногда так делаю, но чаще не делаю))
Тогда зачем его писать
В исходном тексте было написано
ldi r16, (1<<WDTIF) | (1<<WDTIE) | (0<<WDCE) | (0<<WDE)
И как уже написал Дим-мычъ, нулевые значения указаны для наглядности, что они сброшены.
Но на ответ меня сподвигло не замечание, что так писать “не красиво”, а замечание “Потому и не работает“
#include <avr/io.h> // Подключение библиотеки для работы с регистрами ввода-вывода
#include <avr/interrupt.h> // Подключение библиотеки для работы с прерываниями
volatile unsigned long timer_millis = 0; // Глобальная переменная для хранения миллисекунд
// Обработчик прерывания по переполнению таймера 0
ISR(TIM0_OVF_vect) {
timer_millis++; // Увеличиваем счетчик миллисекунд при каждом переполнении таймера
}
// Функция настройки таймера
void setup_timer() {
// Настройка предделителя таймера 0
// Для частоты 9.6 МГц с предделителем 64
// CS02=0, CS01=1, CS00=1 - предделитель 64
TCCR0B = (1<<CS01) | (1<<CS00); // Установка битов CS01 и CS00 для предделителя 64
// Разрешение прерывания по переполнению таймера 0
TIMSK0 = (1<<TOIE0); // Установка бита TOIE0 для разрешения прерывания
sei(); // Разрешение глобальных прерываний
}
// Пользовательская функция millis()
unsigned long millis_custom() {
// Корректировка значения для преобразования в миллисекунды
// Частота прерываний = 9600000/64/256 = 58.59 Гц
// Коэффициент коррекции = 1000/58.59 ≈ 17
return timer_millis * 17; // Возвращаем время в миллисекундах
}
// Объявление глобальных переменных
uint32_t tmr; // Переменная для хранения времени отсчета
bool tmr_flag = false; // Флаг состояния таймера
// Функция setup() - выполняется один раз при старте
void setup() {
setup_timer(); // Инициализация таймера
tmr = millis_custom(); // Запоминаем начальное время
}
// Функция loop() - выполняется в бесконечном цикле
void loop() {
// Проверяем, прошло ли 2000 миллисекунд (2 секунды)
if (millis_custom() - tmr >= 2000) {
tmr = millis_custom(); // Обновляем время отсчета
tmr_flag = !tmr_flag; // Инвертируем состояние флага
// Здесь можно добавить код, который должен выполняться каждые 2 секунды
}
}
может поможет…
unsigned long millis_custom() { // Корректировка значения для преобразования в миллисекунды // Частота прерываний = 9600000/64/256 = 58.59 Гц // Коэффициент коррекции = 1000/58.59 ≈ 17 return timer_millis * 17; // Возвращаем время в миллисекундах }
timer_millis изменяется в прерывании, поэтому такой код не катит)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
volatile unsigned long timer_millis = 0;
volatile uint16_t timer_accumulator = 0;
ISR(TIM0_OVF_vect) {
// Для 9.6 МГц с предделителем 64:
// Частота таймера: 9600000 / 64 = 150000 Гц
// Период прерывания: 256 тактов
// Накопление для 1 мс: 150 тактов (150000 / 1000)
timer_accumulator += 256;
if (timer_accumulator >= 150) {
timer_accumulator -= 150;
timer_millis++;
}
}
void setup_timer() {
TCCR0B = (1<<CS01) | (1<<CS00); // Предделитель 64
TIMSK0 = (1<<TOIE0); // Разрешить прерывание по переполнению
sei(); // Разрешить глобальные прерывания
}
unsigned long millis_custom() {
unsigned long temp;
ATOMIC_BLOCK(ATOMIC_FORCEON) {
temp = timer_millis;
}
return temp;
}
uint32_t tmr;
bool tmr_flag = false;
void setup() {
setup_timer();
tmr = millis_custom();
}
void loop() {
if (millis_custom() - tmr >= 2000) {
tmr = millis_custom();
tmr_flag = !tmr_flag;
}
}
?)