Матрица фоторезистора имеет те же значения.

Я студент второго курса системного инженера, и мне нужно сделать проект для занятий. У меня есть матрица фоторезисторов 4x4, которая подключается к аналогово-цифровому мультиплексору, подключенному к Arduino Uno. Данная установка помещается в коробку с крышкой. Крышка имеет отверстие посередине матрицы. Я хочу рассчитать угол источника света в зависимости от показаний фоторезисторов. По сути, я хочу воссоздать спутниковый датчик солнца. У меня следующая проблема: все фоторезисторы подряд имеют одинаковое показание, даже если я пытаюсь изолировать один из них и посветить на него. В колонке все работает хорошо.

Это моя схема на двухслойной печатной плате: (C0-C15, SIG, S0-S3, EN — контакты мультиплексора CD74HC4067)
Печатная плата Схема схемы

Кроме того, это мой код:

//Выводы управления мультиплексором
int s0 = 11;
int s1 = 10;
int s2 = 9;
int s3 = 8;

//Мультиплексор в "SIG" приколоть
int SIG_pin = 0;
float values[4][4] = {0.0};

void setup(){
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);

  Serial.begin(9600);
}

void loop(){

  //Проходим и читаем все 16 значений
  for(int i = 0; i < 4; ++i)
      for(int j = 0; j < 4; ++j){
        values[i][j] = readMux(i);
        delay(500);
      }

  Serial.println("-----Matrix-----");
  for(int i = 0; i < 4; ++i){
      for(int j = 0; j < 4; ++j){
        Serial.print(values[i][j]);
        Serial.print(" ");
        delay(100);
    }
    Serial.println();
  }
  Serial.println();
  Serial.print(calculateAngle());
  Serial.println();
  delay(1000);
}

float calculateAngle(){
  const int dx[] = {-2, -1, 1, 2, -2, -1, 1, 2, -2, -1, 1, 2, -2, -1, 1, 2};
  const int dy[] = {-2, -2, -2, -2, -1, -1, -1, -1, 1, 1, 1, 1, 2, 2, 2, 2};
  float x = 0, y = 0;

  for(int i = 0; i < 16; ++i){
    x += dx[15 - i] * values[i / 4][i % 4];
    y += dy[15 - i] * values[i / 4][i % 4];
  }
  Serial.print(x);
  Serial.print(" ");
  Serial.print(y);
  Serial.print(" ");
  return atan2(y, x) * 180 / 3.14;
}

float readMux(int channel){
  int controlPin[] = {s0, s1, s2, s3};

  int muxChannel[16][4]={
    {0,0,0,0}, //канал 0
    {1,0,0,0}, //канал 1
    {0,1,0,0}, //канал 2
    {1,1,0,0}, //канал 3
    {0,0,1,0}, //канал 4
    {1,0,1,0}, //канал 5
    {0,1,1,0}, //канал 6
    {1,1,1,0}, //канал 7
    {0,0,0,1}, //канал 8
    {1,0,0,1}, //канал 9
    {0,1,0,1}, //канал 10
    {1,1,0,1}, //канал 11
    {0,0,1,1}, //канал 12
    {1,0,1,1}, //канал 13
    {0,1,1,1}, //канал 14
    {1,1,1,1}  //канал 15
  };
  DDRB = 0;
  //проходим по 4-м знакам
  for(int i = 0; i < 4; i ++)
    DDRB |= (1 << i) & muxChannel[channel][i]; // быстрее, чем digitalWrite(controlPin[i], muxChannel[channel][i]);
  delay(100);
  //читаем значение на выводе SIG
  int val = analogRead(SIG_pin);
  //конвертируем значение в напряжение
  float voltage = (val * 5.0) / 1024.0;
  //возвращаем напряжение
  return voltage;
}

Пример фиктивного прочтения:

-----Matrix-----
0.13 0.14 0.13 0.12 
3.14 3.17 3.12 2.96 
0.12 0.12 0.11 0.12 
2.77 2.81 2.83 2.77 

Что я делаю не так? Я допустил ошибку в своем коде или соединил все вместе? Спасибо за любую помощь!

, 👍0


1 ответ


Лучший ответ:

0

Вероятно, это потому, что вы на самом деле не устанавливаете контакты MUX. Регистры DDRx задают Dнаправление D выводов порта. 1 означает, что вывод, соответствующий этому биту, установлен как выход. Ноль означает, что он установлен как вход. Выходное состояние вывода контролируется регистрами PORTx. Если биты DDRx установлены на вход, а биты PORTx установлены на 1, тогда активируется внутренний подтягивающий резистор.

При настройке вы устанавливаете все контакты MUX на OUTPUT и LOW, поэтому DDRB с 1 и PORTB с нулями. Затем в readMux() вы просто устанавливаете биты в DDRB через (слишком сложную) строку:

DDRB |= (1 << i) & muxChannel[channel][i];

Итак, вы переключаете контакты между OUTPUT+LOW и INPUT+NO_PULLUP. Вместо этого вам следует выполнить запись в регистр PORTB, который управляет состоянием вывода выводов порта B.

Кроме того, запись канала мультиплексирования можно сделать намного проще. Когда вы посмотрите на свой массив в readMux(), вы можете заметить, что шаблоны каналов представляют собой просто двоичное число. Итак, у вас есть следующий номер канала для шаблонной связи:

channel  0 --> binary 0000 --> decimal 0
channel  1 --> binary 0001 --> decimal 1
channel  2 --> binary 0010 --> decimal 2
channel  3 --> binary 0011 --> decimal 3
...
channel 10 --> binary 1010 --> decimal 10
...

Поэтому вместо того, чтобы использовать приведенную выше сложную строку, вы можете просто записать номер канала в 4 целевых бита PORTB:

PORTB |= channel & 0b00001111;

Для этого даже не нужен цикл for. & Часть 0b00001111 предназначена только для сокращения номера канала, чтобы всегда использовались только первые 4 бита регистра (удерживая его в диапазоне от 0 до 15).

,

Так что это решило одну из проблем. Основная из них заключалась в том, что я читал всего 4 канала 4 раза вместо всех 16, поэтому значения были одинаковыми. Огромное спасибо за помощь и за оптимизацию кода!, @Iustinian Serban