Проблемы с загрузкой кода в ATTiny84 с помощью Sparkfun AVR Pocket Programmer и ATTinyCore
Я возвращаюсь к программированию с помощью Arduino и построил спиннер от первого лица, вдохновленный инструкцией от MakersBox. Я использую карманный программатор SparkFun AVR и ATTiny84 (внутренняя частота 8 МГц) с ATTinyCore в качестве менеджера платы.
Несколько дней назад мне удалось безошибочно загрузить код с помощью программатора USBTinyISP (ATTinyCore) FAST для компонентов, работающих на частоте >= 2 МГц, но он перестал работать. Теперь отображается следующая ошибка:
avrdude: Version 6.3-20201216
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2014 Joerg Wunsch
System wide configuration file is "C:\Users\Franklin Marquette\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.5.2/avrdude.conf"
Using Port : usb
Using Programmer : usbtiny
Setting bit clk period : 0.3
avrdude: usbdev_open(): Found USBtinyISP, bus:device: bus-0:\\.\libusb0-0001--0x1781-0x0c9f
AVR Part : ATtiny84
Chip Erase delay : 15000 us
PAGEL : P00
BS2 : P00
RESET disposition : possible i/o
RETRY pulse : SCK
serial program mode : yes
parallel program mode : yes
Timeout : 200
StabDelay : 100
CmdexeDelay : 25
SyncLoops : 32
ByteDelay : 0
PollIndex : 3
PollValue : 0x53
Memory Detail :
Block Poll Page Polled
Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack
----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
eeprom 65 6 4 0 no 512 4 0 4000 4500 0xff 0xff
flash 65 6 32 0 yes 8192 64 128 4500 4500 0xff 0xff
signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00
lock 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
lfuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
hfuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
efuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00
Programmer Type : USBtiny
Description : USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/
avrdude: programmer operation not supported
avrdude: Setting SCK period to 1 usec
avrdude: initialization failed, rc=-1
Double check connections and try again, or use -F to override
this check.
avrdude done. Thank you.
Failed programming: uploading error: exit status 1
СЕЙЧАС, если я загружаю с помощью "USBtinyISP (ATtinyCore) SLOW, для новых частей или частей с частотой 1 МГц" вариант программатора, код загружается. Но в 8 раз медленнее. Я загрузил скетч Blink в отдельный ATTiny84 на макетной плате, и подключенный светодиод оставался включенным в течение ~ 7,75 с, хотя он был запрограммирован на 1 с.
Я понятия не имею, что происходит, и был бы очень признателен за любую помощь, которую я могу получить. Спасибо!
Для справки код приведен ниже.
/*
Not all Attiny cores support the tone() function. Try this one
https://github.com/SpenceKonde/ATTinyCore
// АТМЕЛ ATTINY84 / АРДУИНО
//
// +-\/-+
// ВКК 1| |14 ЗАЗЕМЛЕНИЕ
// (D 0) PB0 2| |13 АРЕФ (Д 10)
// (D 1) PB1 3| |12 ПА1 (Д 9)
// ПБ3 4| |11 ПА2 (Д 8)
// ШИМ INT0 (D 2) PB2 5| |10 ПА3 (Д 7)
// ШИМ (D 3) PA7 6| |9 ПА4 (Д 6)
// ШИМ (D 4) PA6 7| |8 PA5 (D 5) ШИМ
*/
#include <EEPROMex.h>
#include <avr/pgmspace.h>
#include "font.h"
#include "textAndShapes.h"
const int charHeight = 8;
const int charWidth = 5;
int rows= 8; // Всего светодиодов подряд
int LEDS[] = {0, 1, 2, 3, 4, 5, 7, 6};
bool STATES[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW};
char charArray[6]; // содержит символы для отображения
unsigned long lastTimeUs; // время (нас) обнаружения магнита
unsigned long revTimeUs; // время (нас) последнего полного оборота
unsigned long dwellTimeUs; // время (мкс) между сменами светодиодов (в зависимости от скорости вращения)
volatile unsigned long revolutions = 0; // отслеживаем количество оборотов с момента последнего запуска
long totalRevolutions; // отслеживание общего количества оборотов (хранится в EEPROM)
bool spinning = true; // отслеживать сброс времени & считает
unsigned long startTimeUs; // время (в мкс) начала текущего вращения
int mode; // текущий режим работы, хранится в EEPROM
int modes = 8; // количество доступных режимов
// 0 -> текст "Привет, мир!"
// 1 -> об/мин
// 2 -> время в секундах
// 3 -> количество вращений
// 4 -> количество вращений (всего)
// 5 -> "Лилли Пад"; шаблон
// 6 -> форма 1 (сердце)
// 7 -> форма 2 (улыбка)
byte ledPin = 0;
byte magPin = 0; // Датчик на эффекте Холла, подтянутый, переходит в низкий уровень, когда проходит магнит
byte magPullUp = 10; // Контакт A0/D10
byte touchPin = 1; // Нажать кнопку A1/D9
byte touchPullUp = 9;
volatile boolean rotationFlag = false; // изменено ISR
void setup(){
// настраиваем входы
pinMode(touchPin, INPUT);
digitalWrite(touchPullUp, HIGH);
pinMode(magPin, INPUT);
digitalWrite(magPullUp, HIGH);
// устанавливаем другие светодиоды
for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
pinMode(LEDS[LED], OUTPUT);
digitalWrite(LEDS[LED], STATES[LED]);
}
// Настройка прерывания
GIMSK = bit (PCIE0); // разрешение прерывания смены контакта
PCMSK0 = bit (PCINT0); // Включить прерывание на PCINT0 (D10)
sei(); // разрешает прерывания
// получить сохраненный режим из eeprom
mode = EEPROM.read(0);
if (mode >= modes) {
mode = 0; // первый раз может быть очень большим
}
// получаем сохраненное количество оборотов из eeprom
totalRevolutions = EEPROMReadlong(1);
if (totalRevolutions < 0 || totalRevolutions > 999999UL){ // первый раз будет -1.
totalRevolutions = 0;
EEPROMWritelong(1, 0);
}
// показываем, что мы живы и какой режим активен
blipLEDs();
lastTimeUs = micros();
}
void loop(){
int sigFigs = 6; // количество значащих цифр для отображения
unsigned long curTimeUs;
int seconds;
unsigned int rpm;
checkButton();
if (((micros() - lastTimeUs) > 1000000UL)){ // меньше 1 об/сек
if (spinning){
spinning = false;
totalRevolutions = totalRevolutions + revolutions;
EEPROMWritelong(1, totalRevolutions);
revolutions = 0;
clearArray();
blipLEDs();
}
else {
//digitalWrite(LEDS[mode], LOW);
}
}
if (mode == 5){ // шаблон кувшинки, показать независимо от магнита.
for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
digitalWrite(LEDS[LED], HIGH);
delay(1);
digitalWrite(LEDS[LED], LOW);
}
for(int LED=(sizeof(LEDS)/sizeof(int))-1; LED >= 0; LED--){
digitalWrite(LEDS[LED], HIGH);
delay(1);
digitalWrite(LEDS[LED], LOW);
}
}
else if (rotationFlag){ // мы крутимся!
rotationFlag = false;
if (!spinning){
spinning = true;
startTimeUs = micros();
}
curTimeUs = micros();
revTimeUs = curTimeUs - lastTimeUs;
dwellTimeUs = revTimeUs * 3UL / 360UL; // 3 градуса
seconds = (curTimeUs - startTimeUs) / 1000000UL;
rpm = 60000 * 1000 / revTimeUs;
lastTimeUs = curTimeUs;
clearArray();
if (mode == 0){
strcpy (charArray, text);
//sprintf(charArray, "%lu", stayTimeUs);
}
else if (mode == 1){
sprintf(charArray, "%d", rpm);
sigFigs = 2;
}
else if (mode == 2){
sprintf(charArray, "%d", seconds);
}
else if (mode == 3){
sprintf(charArray, "%lu", revolutions);
}
else if (mode == 4){
sprintf(charArray, "%lu", totalRevolutions + revolutions);
}
else if (mode == 6){ // форма 1 (сердце)
for(int k=0; k< sizeof(shape_1);k++){
if (rotationFlag){
break;
}
char b = pgm_read_byte_near(&(shape_1[k]));
for (int j=0; j<charHeight; j++) {
digitalWrite(LEDS[j], bitRead(b, 7-j));
}
dwellTimeUs = revTimeUs * 4UL / 360UL; // 5 градусов
delayMicroseconds(dwellTimeUs);
}
}
else if (mode == 7){ // форма 2 (улыбка)
for(int k=0; k< sizeof(shape_2);k++){
if (rotationFlag){
break;
}
char b = pgm_read_byte_near(&(shape_2[k]));
for (int j=0; j<charHeight; j++) {
digitalWrite(LEDS[j], bitRead(b, 7-j));
}
dwellTimeUs = revTimeUs * 4UL / 360UL; // 5 градусов
delayMicroseconds(dwellTimeUs);
}
}
// Текст в верхней половине
if (mode < 5) {
int digits = 0;
for(int k=0; k< sizeof(charArray);k++){
char c = charArray[k];
if (rotationFlag){
break;
}
if(c){
if (digits < sigFigs){
printLetter(c);
//цифры += 1;
}
else{
printLetter('0');
}
digits += 1;
}
}
// Обработка отображения в нижней части
clearArray();
if(1 && (revTimeUs < 200000)){
char * ptr = (char *) pgm_read_word (&string_table[mode]);
//символьный буфер [6]; // должно быть достаточно большим!
strcpy_P (charArray, ptr);
// ждать его . . .
while((micros() < (lastTimeUs + revTimeUs / 2)) && !rotationFlag){};
// покажи это
for (int k=sizeof(charArray)-1; k>=0; k--){
if (rotationFlag){
break;
}
printLetterLower(charArray[k]);;
}
}
}
}
}
ISR(PCINT0_vect){ // обнаружен магнит
if (!digitalRead(magPullUp)){
rotationFlag = true; // Увеличиваем изменчивые переменные
revolutions += 1;
}
}
void dwellDelay(){ // избегайте сбоев при первом вращении с ошибочным значением
if (dwellTimeUs > 2000){
dwellTimeUs = 2000;
}
if (dwellTimeUs < 100){
dwellTimeUs = 100;
}
delayMicroseconds(dwellTimeUs);
}
void printLetter(char ch){
// https://github.com/reger-men/Arduion-POV-clock/blob/master/clock.ino
// убедитесь, что символ находится в пределах границ алфавита (определяется файлом font.h)
// если это не так, сделать его пустым символом
if (ch < 32 || ch > 126){
ch = 32;
}
// вычесть символ пробела (преобразует число ASCII в номер индекса шрифта)
ch -= 32;
// пройтись по каждому байту массива символов
for (int i=0; i<charWidth; i++) {
char b = pgm_read_byte_near(&(font[ch][i]));
for (int j=0; j<charHeight; j++) {
digitalWrite(LEDS[j], bitRead(b, 7-j));
}
dwellDelay();
}
//очистить светодиоды
for (int i = 0; i < rows; i++)
digitalWrite(LEDS[i] , LOW);
dwellDelay();
}
void printLetterLower(char ch){
// убедитесь, что символ находится в пределах границ алфавита (определяется файлом font.h)
// если это не так, сделать его пустым символом
if (ch < 32 || ch > 126){
ch = 32;
}
// вычесть символ пробела (преобразует число ASCII в номер индекса шрифта)
ch -= 32;
// пройтись по каждому байту массива символов
for (int i=charWidth-1; i>-1; i--) {
char b = pgm_read_byte_near(&(font[ch][i]));
for (int j=0; j<charHeight; j++) {
digitalWrite(LEDS[j+1], bitRead(b,j));
}
dwellDelay();
}
//очистить светодиоды
for (int i = 0; i < rows; i++)
digitalWrite(LEDS[i] , LOW);
// пробел между буквами
dwellDelay();
}
bool touched(){
// возвращает true, если коснулись, false, если нет. Светить светодиодом до тех пор, пока касание не будет отпущено
bool touchVal = digitalRead(touchPullUp);
if (!touchVal){
while(!digitalRead(touchPullUp)){ // дождитесь отпускания касания
delay(10);
digitalWrite(LEDS[mode], LOW);
}
//цифровая запись(LEDS[0], LOW);
return (true);
}
else{
return (false);
}
}
void checkButton(){
// проверяем кнопку смены режима и отображаем текущий режим
if (touched()){
mode += 1;
if (mode >= modes){
mode = 0;
}
EEPROM.write(0, mode);
blipLEDs();
}
}
void blipLEDs(){
// что-то, чтобы показать, что мы живы
for(int LED=0; LED<(sizeof(LEDS)/sizeof(int)); LED++){
digitalWrite(LEDS[LED], HIGH);
delay(10);
digitalWrite(LEDS[LED], LOW);
}
for(int LED=sizeof(LEDS)/sizeof(int); LED>mode; LED--){
digitalWrite(LEDS[LED], HIGH);
delay(10);
digitalWrite(LEDS[LED], LOW);
}
digitalWrite(LEDS[mode], HIGH);
}
void EEPROMWritelong(int address, long value) {
//Эта функция запишет 4 байта (32 бита) в eeprom в
// указанный адрес на адрес + 3.
//https://playground.arduino.cc/Code/EEPROMReadWriteLong
// Декомпозиция из длинного в 4 байта с использованием битового сдвига.
//Один = самый значимый -> Четыре = младший значащий байт
byte four = (value & 0xFF);
byte three = ((value >> 8) & 0xFF);
byte two = ((value >> 16) & 0xFF);
byte one = ((value >> 24) & 0xFF);
// Записываем 4 байта в память eeprom.
EEPROM.write(address, four);
EEPROM.write(address + 1, three);
EEPROM.write(address + 2, two);
EEPROM.write(address + 3, one);
}
long EEPROMReadlong(long address){
//Прочитать 4 байта из памяти eeprom.
long four = EEPROM.read(address);
long three = EEPROM.read(address + 1);
long two = EEPROM.read(address + 2);
long one = EEPROM.read(address + 3);
// Возвращаем перекомпонованную длинную с помощью битового сдвига.
return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}
void clearArray(){
for(int i=0; i<sizeof(charArray); i++){ // очистить массив
charArray[i] = 0;
}
}
@fmarquet, 👍2
Обсуждение1 ответ
Лучший ответ:
Когда вы впервые получаете один из этих чипов, он всегда внутренне настроен на понижение частоты внутреннего генератора на 8. Таким образом, он по-прежнему работает на физической частоте 8 МГц, но фактическая тактовая частота чипа составляет 1 МГц.
Если вы сообщите IDE, что это версия с частотой 8 МГц (делитель отключен), потребуется примерно в 8 раз больше времени для запуска любой задержки (именно поэтому вы видите импульс светодиода 7,75 с, а не 1 с).
Чтобы решить эту проблему, установите в IDE нужные параметры микросхемы (внутренний генератор 8 МГц*), затем нажмите "Записать загрузчик" На самом деле это не установит загрузчик, так как этот чип его не использует, но он установит внутренние предохранители, чтобы делитель тактовой частоты был выключен, и он работал на частоте 8 МГц, как и ожидалось.
Обратите внимание, что программатор по-прежнему должен быть установлен на низкую скорость (почему он говорит «МЕДЛЕННО, для новых [выделено мной] или частей с частотой 1 МГц»), когда вы делаете " Записать загрузчик" так как в противном случае чип будет работать слишком медленно на частоте 1 МГц, чтобы получать команды на скорости программатора по умолчанию (другая причина ошибки rc=-1, помимо плохой проводки).
Обратите внимание, что иногда программатор также не работает, если к какому-либо из контактов для программирования подключены светодиоды или переключатели. Вы удаляете чип перед программированием или он все еще подключен к схеме? Если второе, также попробуйте изолировать его перед программированием.
*Убедитесь, что вы не выбираете какие-либо параметры внешних часов, если вы не знаете, что делаете. Это приведет к поломке вашего чипа, если у вас нет внешнего источника тактового сигнала такого типа или высоковольтного программатора. Я не знаю, как они работают, но это особый (дорогой) вариант, в котором используется более высокое, чем обычно, напряжение для переопределения настроек предохранителя, даже если чип не синхронизируется.
- Управляемая вводом переменная счетчика спорадически увеличивается, если определенные функции вызываются в Setup()
- avrdude: ошибка проверки, первое несоответствие в байте 0x0000 : 0x00 != 0x16 с использованием USBasp
- Arduino IDE не будет использовать выбранный порт
- avrdude ser_open() can't set com-state
- При использовании Arduino Uno в качестве ISP: "Yikes! Invalid device signature" - плохое соединение, неверную конфигурацию или неверную версию avrdude?
- ATtiny85 и DHT11 - Датчик всегда возвращает 0
- Поскольку double и float представляют один и тот же тип данных (обычно), что предпочтительнее?
- Где параметры avrdude определяются в Arduino IDE?
Я, наверное, что-то упускаю. Я просто укажу, что выбор платы/опций задает ожидания IDE для компиляции кода и устанавливает конфигурацию, которую он запишет, если вы сделаете «запись загрузчика». Если вы сообщите IDE, что у вас конфигурация с частотой 8 МГц, когда на самом деле у вас конфигурация с частотой 1 МГц, ваши задержки будут в 8 раз больше, а ваши последовательные скорости — 1/8. Я не знаю, как это связано с невозможностью загрузки. Максимальная скорость интернет-провайдера составляет либо 1/4, либо 1/6 фактической тактовой частоты. Вы не можете использовать тактовую частоту ISP 1 МГц с чипом с тактовой частотой 1 МГц. Вы делаете это? без понятия., @timemage