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);

// вернуть данные;
// }

, 👍0

Обсуждение

добавить отладочный код... в его нынешнем виде вы не можете узнать, что делает программа, @jsotola

Добро пожаловать в SE/Arduino! Ознакомьтесь с [туром], чтобы узнать, как работает этот сайт, а также прочтите раздел «[спросить]» и другие страницы [помощи]. — «_Не работает_» не объясняет, что происходит. Вместо этого, пожалуйста, [отредактируйте] свой вопрос, добавив это. Заодно, пожалуйста, добавьте схему неработающей схемы., @the busybee

Схема определенно поможет. Что такое "timer.h"? Предоставьте ссылку на неё. Возможно, он использует "проблемный" вывод или ожидает определения ISR. В зависимости от того, какое ядро Arduino вы используете для ATtiny84, существуют (возможно) разные схемы нумерации выводов микроконтроллера. Кроме того, ваш цикл очень быстрый. Вы уверены, что увидите какие-либо видимые эффекты?, @6v6gt


2 ответа


3

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 нужно следовать этому:

Схема распиновки ATtinycore для ATtiny84, ATtiny44 и ATtiny24

Следуйте серо-голубым номерам «Пин-кодов Arduino». Существует два набора. Вам нужно выбрать один из них в зависимости от того, выбрали ли вы в меню платы вращение по часовой стрелке или против.

,

-1

В конце концов, мне это удалось. Мне нужно было изменить схему подключения сдвигового регистра 165 и подключить его линию данных к PA5 (или контакту 5).

Оказалось, что изменение обозначения «PORTxn» (CW или CCW) не помогло, однако я вношу это изменение, поскольку оно определённо имеет смысл. Спасибо, Timemage!

Чтобы ответить на некоторые другие вопросы: Обычно я использую Serial.print для отладки, однако у ATTiny такой функции нет. Поэтому я добавил светодиод состояния на PA7. «timer.h» — это написанная мной библиотека, основанная на концепции «моргания без задержки». В ней есть один метод, который возвращает значение true по истечении заданного интервала. Это позволяет мне очень легко писать неблокирующий код.

Еще раз всем спасибо!

,