Освещение, активируемое движением
Я пытаюсь следовать этому руководству, чтобы осветить темный лестница со светодиодными лентами, активируемыми движением. Если мое понимание руководства верное, по сути, работа Arduino заключается в том, чтобы включать или выключать транзисторы в нужное время, чтобы запретить/разрешить достаточное напряжение на светодиодных лентах на лестнице.
Я собрал несколько световых полосок и припаял микроконтроллер к плате с соответствующими компонентами и был готов протестировать устройство. Автор руководства любезно создал это видео, демонстрирующее ожидаемое поведение устройства при запуске: индикаторы должны мигать, как показано, а затем выключаться, ожидая активации от датчика движения. Однако, когда я пытаюсь воспроизвести это, мои огни просто включаются и никогда не выключаются, не исчезают и не мигают.
Консультируясь с часто задаваемыми вопросами в руководстве, я попытался переориентировать свои транзисторы, думая, что, возможно, я перевернул их. Это не имело никакого эффекта.
Затем я попытался убедиться, что мой микропроцессор работает и правильно запрограммирован. Я изменил код в разделе настройки, добавив следующие команды:
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
for(int i=0; i<10; i++){
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(2000);
}
Намерение состояло в том, чтобы встроенный светодиод на плате несколько раз мигал во время запуска. Пока плата была подключена к компьютеру, она действительно замигала после того, как я нажал кнопку «Загрузить». При подключении к блоку питания от платы он не мигает (хотя светодиоды для лестницы включаются, как я описал).
Мне кажется, что микропроцессор просто не получает питание или неправильно подключен к плате. Однако я сделал все возможное, чтобы проверить все соединения и не могу найти никаких проблем. Это мой первый проект такого типа, и я не знаю, что еще попробовать. Будем очень признательны за любые рекомендации по устранению неполадок.
Прошу прощения за длинное сообщение, но я хотел обязательно включить всю необходимую информацию. Спасибо за прочтение!
Ниже приведены изображения печатной платы и схемы из руководства, которые, надеюсь, соответствуют тому, как я на самом деле соединил компоненты.
Вот код из руководства плюс мой мигающий цикл. Оригинал доступен на гитхабе автора.
##Shift_Stairs.ino
#include <math.h>
#include <SPI.h>
//#включить <MemoryFree.h>
//#include "expoDutyCycles.h"
// Контакт данных - MOSI (atmega168/328: контакт 11. Mega: 51)
// Тактовый контакт — SCK (atmega168/328: контакт 13. Mega: 52)
const int ShiftPWM_latchPin=10;
const bool ShiftPWM_invertOutputs = 0; // если invertOutputs равно 1, выходы будут активны на низком уровне. Полезно для светодиодов RGB с общим анодом.
#include <ShiftPWM.h> // включаем ShiftPWM.h после установки пинов!
const int SWITCH_PIN = A0;
const int PHOTORESISTOR_PIN = A2;
const int MOTION_SENSOR_TOP_PIN = 2;
const int MOTION_SENSOR_BOTTOM_PIN = 3;
const unsigned char maxBrightness = 255;
const unsigned char pwmFrequency = 75;
const int numRegisters = 2;
const int NUMLEDs = 9;
const int MOTION_SENSOR_WARMUP_TIME = 10;
const int ON_TIME = 10000; /* The duration between turn on and turn off. */
const int LIGHT_THRESHOLD = 300; /* Anything below this sensor value will enable lights */
/* These are used to detect rising edges in the absence of interrupts.
Using interrupts with ShiftPWM crashes the program. */
unsigned char lastReadTopPin = LOW;
unsigned char lastReadBotPin = LOW;
volatile unsigned char topActivated = false;
volatile unsigned char bottomActivated = false;
unsigned long lastMotionTime = 0;
const char BOTTOM_TO_TOP = 1;
const char TOP_TO_BOTTOM = 2;
/* For sake of the animation, stores the direction of propegation.
Set when animation is active, cleared when animation is done. */
char directionTriggered = 0;
const unsigned long BRIGHTNESS_SM_PERIOD = 2000; /* in μs */
unsigned long lastBrightnessSM = 0;
/* LED 0 is on the top of stairs */
unsigned char brightnesses[NUMLEDs] = {0};
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
for(int i=0; i<10; i++){
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(2000);
}
pinMode(ShiftPWM_latchPin, OUTPUT);
SPI.setBitOrder(LSBFIRST);
// SPI_CLOCK_DIV2 лишь немного быстрее отправляет последний байт.
// Передача SPI и вычисления перекрываются для других байтов.
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.begin();
Serial.begin(9600);
/* Turn on pullup resistor for switch */
digitalWrite(SWITCH_PIN, HIGH);
ShiftPWM.SetAmountOfRegisters(numRegisters);
ShiftPWM.Start(pwmFrequency,maxBrightness);
// Выводим информацию о частоте прерываний, продолжительности и нагрузке на вашу программу
ShiftPWM.SetAll(0);
ShiftPWM.PrintInterruptLoad();
// Затухание всех выходных данных
for(int j=0;j<maxBrightness;j++){
ShiftPWM.SetAll(j);
delay(3);
}
// Исключаем все выходные данные
for(int j=maxBrightness;j>=0;j--){
ShiftPWM.SetAll(j);
delay(3);
}
}
void loop()
{
/* Detect rising edge with polling. Interrupts crash the program. */
unsigned char pinRead = digitalRead(MOTION_SENSOR_TOP_PIN);
if(pinRead == HIGH && lastReadTopPin == LOW){
topActivated = true;
}
lastReadTopPin = pinRead;
/* Detect rising edge with polling. Interrupts crash the program. */
pinRead = digitalRead(MOTION_SENSOR_BOTTOM_PIN);
if(pinRead == HIGH && lastReadBotPin == LOW){
bottomActivated = true;
}
lastReadBotPin = pinRead;
/* Resets flags */
if(topActivated){
if(directionTriggered == 0){
directionTriggered = TOP_TO_BOTTOM;
}
lastMotionTime = millis();
topActivated = false;
}
if(bottomActivated){
if(directionTriggered == 0){
directionTriggered = BOTTOM_TO_TOP;
}
lastMotionTime = millis();
bottomActivated = false;
}
/* State machine */
if(micros() - lastBrightnessSM > BRIGHTNESS_SM_PERIOD){
brightnessSM();
lastBrightnessSM = micros();
}
}
/**
Returns true if switch is in "1" position.
*/
boolean switchPressed(){
return !digitalRead(SWITCH_PIN);
}
###brightnessSM.ino
enum brightnessStates {
sFullyOn,
sOff,
sTurningOn,
sTurningOff,
sOverrideSwitch
};
int brightnessState = sOff;
void brightnessSM(){
/* Actions */
switch(brightnessState){
case sFullyOn:
break;
case sOff:
break;
case sTurningOn:{
/* Increase brightness of lights. This for loop goes from -NUMLEDs to 0 or
0 to NUMLEDs depending on the direction of propegration. */
char startLight = -1 * (directionTriggered - 1) * (NUMLEDs - 1);
char endLight = -1 * (directionTriggered - 2) * (NUMLEDs - 1);
for(char l = startLight; l <= endLight; l++){
/* Turn on the next LED only if the ones before it
are on*/
if(brightnesses[abs(l)] != maxBrightness){
brightnesses[abs(l)] += 5;
ShiftPWM.SetOne(abs(l), brightnesses[abs(l)]);
break;
}
/* Turn on the next LED only if the one before it is partially on */
// if(brightnesses[abs(l)] != maxBrightness){
// if(l == startLight || (brightnesses[abs(l - 1)] > maxBrightness*3/10)){
// яркость[abs(l)] += 1;
// ShiftPWM.SetOne(abs(l), expoDutyCycles[brightnesses[abs(l)]]);
// }
// }
}
break;
}
case sTurningOff:{
/* Decrease brightness of lights. This for loop goes from -NUMLEDs to 0 or
0 to NUMLEDs depending on the direction of propegration. */
char startLight = -1 * (directionTriggered - 1) * (NUMLEDs - 1);
char endLight = -1 * (directionTriggered - 2) * (NUMLEDs - 1);
for(char l = startLight; l <= endLight; l++){
/* Turn on the next LED only if the ones before it
are on*/
if(brightnesses[abs(l)] != 0){
brightnesses[abs(l)] -= 5;
ShiftPWM.SetOne(abs(l), brightnesses[abs(l)]);
break;
}
/* Turn on the next LED only if the one before it is partially on */
// если(яркости[abs(l)] != 0){
// if(l == startLight || (brightnesses[abs(l - 1)] < maxBrightness*9/10)){
// яркость[abs(l)] -= 1;
// ShiftPWM.SetOne(abs(l), expoDutyCycles[brightnesses[abs(l)]]);
// }
// }
}
break;
}
case sOverrideSwitch:
break;
}
/* Transitions */
switch(brightnessState){
case sFullyOn:
if(millis() - lastMotionTime > ON_TIME){
brightnessState = sTurningOff;
}
if(switchPressed()){
transitionToOverrideSwitch();
}
break;
case sOff:
if(directionTriggered != 0){
if(analogRead(PHOTORESISTOR_PIN) < LIGHT_THRESHOLD){
brightnessState = sTurningOn;
}
else {
directionTriggered = 0;
}
}
if(switchPressed()){
transitionToOverrideSwitch();
}
break;
case sTurningOn:{
/* If all the lights are on then proceed */
unsigned char allOn = true;
for(unsigned char l = 0; l < NUMLEDs; l++){
if(brightnesses[l] != maxBrightness){
allOn = false;
break;
}
}
if(allOn){
brightnessState = sFullyOn;
}
if(switchPressed()){
transitionToOverrideSwitch();
}
break;
}
case sTurningOff:{
/* If all the lights are off then proceed */
unsigned char allOff = true;
for(unsigned char l = 0; l < NUMLEDs; l++){
if(brightnesses[l] != 0){
allOff = false;
break;
}
}
if(allOff){
directionTriggered = 0;
brightnessState = sOff;
}
if(switchPressed()){
transitionToOverrideSwitch();
}
break;
}
case sOverrideSwitch:
if(switchPressed() == false){
/* Switch all LEDs off */
for(char l = 0; l < NUMLEDs; l++){
ShiftPWM.SetOne(l, 0);
brightnesses[l] = 0;
}
directionTriggered = 0;
brightnessState = sOff;
}
break;
}
}
void transitionToOverrideSwitch(){
brightnessState = sOverrideSwitch;
/* Switch all LEDs on */
for(unsigned char l = 0; l < NUMLEDs; l++){
ShiftPWM.SetOne(l, maxBrightness);
brightnesses[l] = maxBrightness;
}
}
@Eidan Jacob, 👍2
Обсуждение1 ответ
Лучший ответ:
Изображение печатной платы (PCB), размещенное в предыдущем вопросе, содержит множество примеров того, что обычно называют Холодная пайка. Эти типы соединений ненадежны и иногда не обеспечивают электрического соединения. И зачастую их невозможно визуально проверить. первые 2 минуты этого видео демонстрируют, как можно комбинировать нагрев и флюс для исправления соединений холодной пайки, включающих печатную плату и сквозной штифт.
(Я могу отредактировать/изменить следующее, поскольку мы сужаем решение этой проблемы. Цель состоит в том, чтобы сделать хороший вопрос и ответ для обмена стеками.)
Симптом:
- При подключении к ПК проект ведет себя так, как ожидалось. Это предполагает, что кабель к ПК (вероятно, от USB/CDC к последовательному порту) содержит заземление, вход, выход и питание. Ожидаемое поведение — включение и выключение светодиодов.
- Проект не работает при отключении от ПК и питается от внешнего блока питания. Только горят светодиоды.
Рассмотрите возможность проверки питания процессора или, что еще лучше, процессора. При описанной в вопросе проблеме может быть обрыв пути питания от внешнего блока питания к процессору. Проверьте все паяные соединения, связанные с подключением входа питания Arduino к печатной плате. Вероятно, процессор (Arduino) был включен во время программирования через контакты заземления и питания кабеля последовательного порта. После того, как этот кабель был удален, процессор мог не получать питание и, возможно, не работал, в то время как плата питалась только от внешнего источника.
- Мой светодиодный дисплей выходит из строя из за того что выход MSGEQ7 застрял
- avrdude: stk500_getsync(): not in sync: resp=0x00
- Ошибка "avrdude:stk500_recv(): programmer is not responding" при загрузке скетча в Arduino Pro Mini
- Как остановить SoftwareSerial от получения данных и повторно включить его в какой-то другой момент?
- Библиотека FastLED: Как настроить яркость одного пикселя в абсолютном масштабе?
- Сторожевой таймер застрял в цикле перезапуска? (мигает зеленый светодиод)
- Arduino Pro Mini (версия 3.3 V) диапазон входного напряжения / допуск
- Arduino 16 МГц только с 3,3 В?
Проверьте ориентацию Arduino. Это вверх ногами? Проверьте также напряжение между контактами, помеченными GND и VCC., @Edgar Bonet
Спасибо за ответ. Я читаю 12 В на контактах, что кажется хорошим. Я почти уверен, что ориентация правильная, но я еще раз проверю., @Eidan Jacob
Судя по схемам, похоже, что в (поддельной) версии платы, которую я использовал, разъем FTDI ориентирован наоборот, но остальные контакты совпадают. У меня есть несколько запасных частей, так что я могу попробовать перевернуть, если ничего не работает., @Eidan Jacob
Спасибо, изображения добавлены, код будет следовать. Я был бы рад добавить что-нибудь еще, что вы считаете полезным., @Eidan Jacob
Где именно вы измеряли 12В? Вы измеряли между Vcc и землей Arduino? 12В было бы плохо., @chrisl
что произойдет, если вы запустите минимальный скетч, например мигание встроенным светодиодом?, @jsotola
схема не имеет сброса ... выходы всегда включены ... это означает, что выход может быть в любом состоянии при включении питания ... можно начать с простого скетча, чтобы побитить входные сигналы ... установить контакты 10, 11, 13 LOW, переключить контакт 13 LOW-HIGH-LOW шестнадцать раз, чтобы сдвинуть все нули, переключить контакт 10 LOW-HIGH-LOW для передачи сдвинутых данных на выходы... задержка на одну секунду... установить контакт 11 HIGH и повторите действия с контактом 13 и контактом 10 ... это должно выключить все светодиоды, а затем снова включить их ... контакт 11 - данные, контакт 13 - часы последовательного переключения, контакт 10 - выходная защелка Часы, @jsotola
Я могу заставить встроенный светодиод мигать, когда Arduino подключен к компьютеру и я загружаю скетч. На Arduino ничего не происходит, когда я подключаю блок питания к печатной плате. Код был проверен другими пользователями, которые успешно следовали руководству, поэтому я был бы очень удивлен, если бы это было источником проблемы. Когда у меня будет возможность, я попробую вашу идею., @Eidan Jacob
ваша схема похожа на https://wokwi.com/projects/301213976182653448, @jsotola
Твоя пайка выглядит ужасно. Недостаточно тепла, нет флюса, не прогрета деталь перед подачей припоя... что-то. Прежде чем беспокоиться о многом другом, я бы выяснил, что с этим не так, потому что до тех пор это может просто свести с ума любого, кто попытается помочь вам., @timemage