Матрица фоторезистора имеет те же значения.
Я студент второго курса системного инженера, и мне нужно сделать проект для занятий. У меня есть матрица фоторезисторов 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
Что я делаю не так? Я допустил ошибку в своем коде или соединил все вместе? Спасибо за любую помощь!
1 ответ
Лучший ответ:
Вероятно, это потому, что вы на самом деле не устанавливаете контакты 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).
- Как перезапустить счетчик в программе с помощью кнопки в настройке LDR Tripwire
- Подключение нескольких TFT-панелей к Arduino Uno через SPI?
- Arduino nano KiCad символы
- Проблема с кодом для мультиплексора SDA/SCL TC9548A и датчиков HMC58 83L.
- Проблема с мультиплексором CD74HC4067 при высоких значениях.
- Проблема с подключением 2 8-разрядных сдвиговых регистров 74HC595 в каскадном соединении
- Почему светодиоды заметно мерцают?
- Измерение скорости автомобиля между двумя точками: какой датчик использовать и как преодолевать расстояние?
Так что это решило одну из проблем. Основная из них заключалась в том, что я читал всего 4 канала 4 раза вместо всех 16, поэтому значения были одинаковыми. Огромное спасибо за помощь и за оптимизацию кода!, @Iustinian Serban