ATTiny84 и сдвиговый регистр не работают
Знаю, что это вопрос не совсем по Arduino, но я использую Arduino IDE и считаю, что она достаточно близка к цели. Итак, я работаю над проектом, в котором используются ATTiny84, два сдвиговых регистра SN74HC595N SIPO и сдвиговый регистр SN74HC165 PISO. Мне напечатали специальную печатную плату, и после нескольких попыток подключения всё заработало. Всё отлично работает на UNO R3, но когда я перешёл на ATTiny84, всё перестало работать. По сути, я мог один раз обновить сдвиговый регистр '595, и после этого он бы перестал реагировать.
Я немного повозился и сузил проблему до вывода данных из регистра '165. В схеме линия данных 165 подключена к PORTB2 (физический вывод 5), и когда я объявляю его как ВХОД, программа перестаёт работать. Сдвиговые регистры '595 работают нормально, если объявить PB2 как выход или использовать вообще другой вывод (например, PA5).
Сейчас я планирую перемонтировать 165-й и провести еще несколько тестов. Надеюсь, кто-то, кто разбирается в этом гораздо лучше меня, сможет объяснить, почему это происходит. Код ниже.
Все детали, которые я использую, взяты от digikey:
- 296-8251-5-ND ---- SN74HC165N
- 296-1600-5-ND ---- SN74HC595N
- ATTINY84A-PU-ND -- ATTINY84 MCU
#define SER PORTA0 // данные
#define RCLK PORTA2 // защелка
#define SRCLK PORTA1 // часы
// 165 регистр сдвига
#define CLK PORTB0 // часы - arduino 7 - ATTiny PORTB0
#define SHLD PORTB1 // сдвиг нагрузки - arduino 6 - ATTiny PORTB1
#define Qh PORTA5 // вывод данных - arduino 5 - ATTiny PORTB2 -- ЭТО ВЕЩНЫЙ ПИН
#define CLKINH PORTA3 // запрет тактовой частоты - arduino 4 - ATTiny PORTA3
// светодиод состояния
#define STATUS PORTA7
#define numCols 11
//uint8_t read[numCols];
//uint8_t oldRead[numCols];
int currentCol = 1;
#include <timer.h>
timer tim;
void setup() {
tim.setInterval(1000);
// 595
pinMode(SER, OUTPUT);
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
//165
pinMode(CLK, OUTPUT);
pinMode(SHLD, OUTPUT);
pinMode(Qh, INPUT);
pinMode(CLKINH, OUTPUT);
//светодиод состояния
pinMode(STATUS, OUTPUT);
// устанавливаем начальное состояние 165
digitalWrite(CLKINH, HIGH);
digitalWrite(CLK, LOW);
digitalWrite(SHLD, HIGH);
write595(0xAA); // просто чтобы что-то увидеть
}
void loop() {
for(int i=0; i<numCols; i++){
write595(currentCol);
currentCol = currentCol <<1;
//задержка(250);
}
currentCol = 1;
}
void write595(uint16_t num){
uint8_t MSB = num >> 8;
uint8_t LSB = num;
digitalWrite(RCLK, LOW);
shiftOut(SER, SRCLK, MSBFIRST, MSB);
shiftOut(SER, SRCLK, MSBFIRST, LSB);
digitalWrite(RCLK, HIGH);
}
// uint8_t read165(void){
// uint8_t данные = 0;
// // переключить сдвиг/загрузку для сохранения данных в регистре
// digitalWrite(SHLD, LOW);
// delayMicroseconds(5);
// digitalWrite(SHLD, HIGH);
// delayMicroseconds(5);
// // выгружаем эти данные и возвращаем их в программу
// digitalWrite(CLK, HIGH);
// digitalWrite(CLKINH, LOW);
// данные = shiftIn(Qh, CLK, MSBFIRST);
// digitalWrite(CLKINH, HIGH);
// вернуть данные;
// }
@user113684, 👍0
Обсуждение2 ответа
PORTB0, PORTA5 и т. д. не предназначены для использования с функциями Arduino pinMode, digitalRead и т. д. Они не определены для номеров выводов Arduino.
Это номера битовых индексов, которые можно использовать для непосредственного управления регистрами портов GPIO PORTA и PORTB.
Например, если вы хотите установить высокий уровень на порту GPIO PB3, можно использовать PORTB3 в выражении типа PORTB |= 1 << PORTB3; Многие из нас не используют именованные битовые поля специально для регистров GPIO, поскольку они не делают код более читабельным. Вместо этого мы просто используем 3 вместо PORTB3. Если уж на то пошло, эти макросы битовых индексов для портов GPIO скорее создали путаницу, чем устранили её.
В любом случае, поскольку это всего лишь номера битовых индексов, PORTB0 и PORTA0 оба равны 0, PORTB1 и PORTA1 оба равны 1, и этот шаблон повторяется до 7.
Немного изменив #define, теперь, возможно, будет легче увидеть конфликты:
// Конфликтующая пара; оба пытаются использовать вывод 0 Arduino при последующем использовании с pinMode() и т. д.
#define SER PORTA0 // данные
#define CLK PORTB0 // часы - arduino 7 - ATTiny PORTB0
// Конфликтующая пара: оба пытаются использовать вывод 1 Arduino
#define SRCLK PORTA1 // часы
#define SHLD PORTB1 // сдвиг нагрузки - arduino 6 - ATTiny PORTB1
// Конфликтующая пара, когда Qh — это PORTB2.
#define RCLK PORTA2 // защелка
#define Qh PORTA5 // вывод данных - arduino 5 - ATTiny PORTB2 -- ЭТО ВЕЩНЫЙ ПИН
// Пока ничего не конфликтует.
#define CLKINH PORTA3 // запрет тактовой частоты - arduino 4 - ATTiny PORTA3
Иногда удаётся обойтись без макросов PORTx# при использовании чего-то вроде ATtiny85, поскольку у него только один порт, PORTB, а сопоставление рассчитано на использование номеров бит PORTB в качестве номеров выводов Arduino. Но с ATtiny84, у которого несколько портов, это не сработает.
Вам необходимо ознакомиться с документацией к ядру Arduino, которое вы используете. Например, для ATtiny84A с ATtinycore нужно следовать этому:

Следуйте серо-голубым номерам «Пин-кодов Arduino». Существует два набора. Вам нужно выбрать один из них в зависимости от того, выбрали ли вы в меню платы вращение по часовой стрелке или против.
В конце концов, мне это удалось. Мне нужно было изменить схему подключения сдвигового регистра 165 и подключить его линию данных к PA5 (или контакту 5).
Оказалось, что изменение обозначения «PORTxn» (CW или CCW) не помогло, однако я вношу это изменение, поскольку оно определённо имеет смысл. Спасибо, Timemage!
Чтобы ответить на некоторые другие вопросы: Обычно я использую Serial.print для отладки, однако у ATTiny такой функции нет. Поэтому я добавил светодиод состояния на PA7. «timer.h» — это написанная мной библиотека, основанная на концепции «моргания без задержки». В ней есть один метод, который возвращает значение true по истечении заданного интервала. Это позволяет мне очень легко писать неблокирующий код.
Еще раз всем спасибо!
- При использовании Arduino Uno в качестве ISP: "Yikes! Invalid device signature" - плохое соединение, неверную конфигурацию или неверную версию avrdude?
- Связь ATtiny85 с компьютером через USB
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
- avrdude: ошибка проверки, первое несоответствие в байте 0x0000 : 0x00 != 0x16 с использованием USBasp
- Радиочастотное дистанционное управление с использованием VirtualWire на ATtiny85, работающем на частоте 8 МГц на внутреннем генераторе
- I2C с ATtiny85 на частоте 8 МГц с использованием библиотеки TinyWireM
- Эмуляция 1-проводных устройств
- Как перевести ATtiny/ATmega в режим глубокого сна (чтобы годами работать от батарей), но при этом обнаруживать нажатие кнопки?
добавить отладочный код... в его нынешнем виде вы не можете узнать, что делает программа, @jsotola
Добро пожаловать в SE/Arduino! Ознакомьтесь с [туром], чтобы узнать, как работает этот сайт, а также прочтите раздел «[спросить]» и другие страницы [помощи]. — «_Не работает_» не объясняет, что происходит. Вместо этого, пожалуйста, [отредактируйте] свой вопрос, добавив это. Заодно, пожалуйста, добавьте схему неработающей схемы., @the busybee
Схема определенно поможет. Что такое "timer.h"? Предоставьте ссылку на неё. Возможно, он использует "проблемный" вывод или ожидает определения ISR. В зависимости от того, какое ядро Arduino вы используете для ATtiny84, существуют (возможно) разные схемы нумерации выводов микроконтроллера. Кроме того, ваш цикл очень быстрый. Вы уверены, что увидите какие-либо видимые эффекты?, @6v6gt