메뉴 전체보기

회원메뉴

DIY 태양 램프 > 게시판

본문 바로가기

쇼핑몰 검색

NO. 3440
제목 : DIY 태양 램프
2026-09-28 10:32

소개: DIY 태양 램프


소개: DIY 태양 램프


저는 항상 램프를 만들고 싶었고, 이미 놀라운 디자인이 많이 있습니다. 최근에 Leora Studio의 자연에서 영감을 받은 램프에 대한 블로그를 발견했습니다. 그들의 램프는 아름다운 유기적 형태와 알고리즘 디자인을 사용하여 즉시 제 주목을 끌었습니다. 저는 그 모습이 마음에 들어서 비슷한 것을 만들고 싶었습니다.

그러나 현실이 다가왔습니다. 저는 그렇게 복잡한 디자인을 재현할 기술이 없다는 것을 빠르게 깨달았습니다. 그래서 그들을 복사하는 대신, 훨씬 더 간단한 방법으로 자연에서 영감을 받기로 결정했습니다.

그때 저는 태양에서 영감을 받은 램프 아이디어를 생각해냈습니다. 저는 태양의 코로나에서 영감을 받은 흐르는 파도 패턴과 함께 따뜻하게 빛나는 오렌지색 빛을 상상했습니다. 최종 결과가 제가 머릿속에 그린 그림과 일치할지 확신이 없었지만, 꽤 잘 나온 것 같습니다.

이 Instructables에서는 첫 스케치부터 완성된 제작까지 이 램프를 만드는 전체 과정을 안내하겠습니다. 모든 것이 계획대로 진행되지는 않았고, 그 과정에서 많은 실수와 교훈이 있었습니다. 그럼 시작해봅시다.




STEP 1. 준비물


준비물


준비물


  1. 밀키 화이트 PLA+ 필라멘트
  2. Attiny1614
  3. Ds3231 RTC 모듈
  4. TM1637 0.56" 4자리 7세그먼트 LED 디스플레이 모듈 - 시계 콜론 포함 화이트
  5. TTP223 터치 스위치 - 3개
  6. 퍼프보드
  7. 7805 5V 전압 조절기
  8. 14핀 SMD To DIP PCB
  9. DC 잭
  10. AO3400 모스펫 - 3개
  11. 100uF 25V 커패시터 - 3개
  12. 100nF 커패시터 - 2개
  13. 2.2uF 커패시터
  14. 100옴 저항 - 3개
  15. 10k 저항 - 3개
  16. 남성 및 여성 헤더 핀
  17. 2핀 JST 남성 직선 커넥터 2.54mm 피치 - 4개
  18. 2핀 JST 2.54mm 여성 와이어 포함 - 4개
  19. 3핀 JST 남성
  20. 3핀 JST 여성 와이어 포함
  21. 4핀 JST 남성 직선 2.54mm 피치
  22. 4핀 JST 2.54mm 여성 와이어 포함
  23. 12V 3A 어댑터
  24. 2mm 아크릴 시트
  25. 틴트 필름
  26. M3 6mm 나사 - 10개
  27. M2 6mm 나사 - 4개
  28. 스프레이 페인트 화이트
  29. 하이드로 딥핑 필름
  30. 하이드로그래픽 프린팅 활성제
  31. 클리어 코트 스프레이




STEP 2. 램프 쉐이드 모델링


램프 쉐이드 모델링


램프 쉐이드 모델링


이 프로젝트의 가장 중요한 부분인 램프 쉐이드부터 시작하겠습니다. 앞서 언급했듯이, 저는 태양의 코로나에서 영감을 받아 흐르는 물결 모양의 능선을 가진 구체를 만들고 싶었습니다. 목표는 태양 주위에서 볼 수 있는 유기적인 패턴을 포착하면서도 간단하고 우아하게 보이도록 하는 것이었습니다.

쉐이드를 디자인하기 위해 저는 무료이고 오픈 소스이며 온라인에서 많은 튜토리얼이 제공되는 Blender를 선택했습니다. 저는 완전 초보자였기 때문에 이 프로젝트는 Blender를 처음부터 배우는 방법이 되었습니다. 몇 개의 튜토리얼을 보고 AI 챗봇의 도움을 조금 받은 후, 여러 가지 디자인을 만들어본 끝에 이 디자인으로 결정하게 되었습니다.

최종 쉐이드를 모델링한 방법은 다음과 같습니다.

  1. 기본 형태 조각하기

부드러운 곡선을 얻기 위해 고해상도 UV 구체로 시작했습니다.

편집 모드에서 구체의 상단에서 하단까지 이어지는 수직 엣지 루프를 선택했습니다. Checker Deselect 도구를 사용하여 빠르게 다른 엣지 루프를 선택했습니다.

그런 다음 S를 눌러 외부로 스케일을 조정했습니다. 이렇게 해서 부드러운 구체가 고르게 간격을 둔 능선이 있는 형태로 변형되었습니다.

  1. 기하학 비틀기

앞서 언급한 유기적이고 부드러운 움직임을 램프에 주기 위해 곡선을 형성해야 했습니다. 구체의 상단 부분을 선택하고 비례 편집을 활성화하여 나머지 메시가 부드럽게 따라가도록 했습니다. 그런 다음 R을 눌러 회전하고 Z를 눌러 그 회전을 Z축에 엄격하게 고정했습니다.

  1. 장착 구멍 만들기

쉐이드가 베이스에 안전하게 맞아야 했기 때문에 치수를 정확하게 맞춰야 했습니다.

실린더를 추가하고 지름을 정확히 100 mm로 설정했습니다. 이 실린더는 쉐이드 바닥에 완벽한 크기의 장착 구멍을 만들기 위해 불리언 컷으로 사용되었습니다.

마지막으로 디자인에 만족했을 때, STL 파일을 내보냈습니다.




STEP 3. 기초 모델링


기초 모델링


다음으로, 모든 전자기기와 배선을 수용할 수 있는 램프의 간단한 베이스가 필요합니다. 이 부분은 빠르고 사용하기 쉬운 Tinkercad에서 모델링하기로 결정했습니다.

디자인을 구성하는 동안, 베이스 앞쪽에 작은 시계를 추가하면 정말 멋질 것 같다는 생각이 들었습니다. 시계 디스플레이를 위한 완벽한 공간을 잘라내고, 다른 구성 요소를 위한 모든 필요한 구멍과 장착 슬롯도 함께 만들었습니다.

항상 그렇듯이, 아래에 모든 STL 파일을 첨부하고, 파일을 쉽게 가져오고 원하는 대로 변경할 수 있도록 제 Tinkercad 프로젝트에 대한 직접 링크를 포함할 것입니다.




STEP 4. 3D 프린팅


3D 프린팅


3D 프린팅


3D 프린팅


3D 프린팅


3D 프린팅


3D 프린팅


3D 프린팅


3D 프린팅


이 단계는 일이 계획대로 진행되지 않았던 단계였습니다.

램프 쉐이드를 위해, 저는 Vase Mode, 즉 Cura에서 Spiralize Outer Contour로 알려진 모드에서 인쇄하고 싶었습니다. 이 모드에서는 프린터가 아래에서 위로 연속적인 나선형으로 인쇄하여 속이 비어 있는 단일 벽 모델을 만듭니다.

얇은 벽이 빛을 훨씬 더 잘 확산시키기 때문에 램프에 완벽합니다. 또한 Z 이음새, 덩어리, 실타래 및 조명 기구 내부에 빛을 넣었을 때 매우 눈에 띄게 되는 기타 표면 결함을 제거합니다.

최고의 결과를 얻기 위해, 저는 우유빛 흰색 PLA+ 필라멘트 한 롤을 구입하고 잠자리에 들기 전에 인쇄를 시작했습니다. 인쇄가 몇 시간 걸릴 것이기 때문에, 저는 아침에 완성된 램프 쉐이드를 보게 될 것이라고 생각했습니다.

하지만... 그런 일은 일어나지 않았습니다.

인쇄는 약 90% 완료되었지만, 상단 부분이 완전히 실패하여 노즐에 거대한 필라멘트 덩어리가 남아 있었습니다.

조금의 좌절감 후, 저는 Cura로 돌아가서 레이어 미리보기를 확인했습니다. 그때 문제가 무엇인지 알게 되었습니다. 모델의 상단 근처에서, Vase Mode에서 레이어 사이에 큰 간격이 있었습니다. 인쇄가 계속되지 못한 이유는 분명했습니다.

Adaptive Layers를 활성화하고, 레이어 높이를 증가시키고, 몇 가지 다른 설정을 실험하면서 문제를 해결하려고 꽤 오랜 시간을 보냈지만, 아무것도 효과가 없었습니다.

이 문제를 해결할 방법을 아는 분이 계시다면, 아래에 댓글을 남겨주시면 정말 감사하겠습니다. Vase Mode에서 이 디자인을 제대로 인쇄하는 방법을 배우고 싶습니다.

결국, 저는 포기하고 일반 설정을 사용하여 쉐이드를 인쇄했습니다. 성공적으로 인쇄되었지만, 결과는 그리 좋지 않았습니다. 램프가 켜졌을 때 Z 이음새와 기타 작은 결함이 명확하게 보입니다. 두 방법 간의 차이는 꽤 눈에 띕니다.

다행히도, 다른 모든 부품은 문제 없이 인쇄되었습니다.




STEP 5. 지지대를 제거하세요.


지지대를 제거하세요.


이 단계는 제목이 말하는 것과 정확히 일치합니다.

모든 부품이 인쇄된 후, 나는 플러시 커터와 펜치를 사용하여 지지 재료를 조심스럽게 제거했습니다.




STEP 6. 베이스 수중 도장하기


베이스 수중 도장하기


베이스 수중 도장하기


베이스 수중 도장하기


모든 것을 흰색 필라멘트로 인쇄한 후, 결과물에 완전히 만족하지 못했습니다. 램프 쉐이드는 멋져 보였지만, 전체 프로젝트는 대비가 부족했습니다. 그냥... 흰색이었어요.

원래 계획은 베이스를 검은색이나 갈색으로 간단히 칠하는 것이었습니다. 그러다가 갑자기 하이드로 딥핑이 생각났습니다. 오랫동안 시도해보고 싶었던 것이었지만, 유튜브 비디오에서만 본 적이 있었습니다.

그래서 온라인에 접속해 하이드로 딥핑 필름을 찾기 시작했습니다. 카본 파이버, 나무, 대리석, 위장무늬 등 선택할 수 있는 디자인이 정말 많았습니다.

처음에는 나무 결 마감과 대리석 마감 중에서 결정하지 못했습니다. 그러다가 대리석 패턴을 둘러보게 되었고, 수백 가지의 다양한 디자인이 있다는 것을 깨달았습니다. 솔직히 하나를 선택하는 것이 예상보다 더 어려웠습니다.

옵션을 스크롤하는 데 너무 많은 시간을 보낸 후, 결국 간단한 검은색 대리석 패턴으로 결정했습니다. 이 디자인이 램프에 깔끔하고 고급스러운 느낌을 주면서 흰색 램프 쉐이드를 더욱 돋보이게 할 것이라고 생각했습니다.

필름 링크




STEP 7. 기초 준비하기


기초 준비하기


이것이 제가 수중 딥핑을 시도하는 첫 번째 경험이었기 때문에, 시작하기 전에 과정을 이해하고 싶었습니다. 그래서 기본을 익히기 위해 정말 유용하고 간단명료한 튜토리얼 비디오를 온라인에서 시청하기 시작했습니다.

제가 선택한 수중 딥핑 필름은 대리석 패턴이 제대로 나타나기 위해 흰색 베이스 코트를 필요로 했습니다. 그래서 3D 프린트된 베이스의 표면을 매끄럽게 하고 페인트가 잘 붙도록 하기 위해 가볍게 샌딩했습니다.

먼지를 제거한 후, 흰색 스프레이 페인트를 몇 번 가볍게 칠하고 완전히 건조시켰습니다.




STEP 8. 하이드로 딥핑 필름 자르기


하이드로 딥핑 필름 자르기


하이드로 딥핑 필름 자르기


다음으로, 전체 베이스를 덮을 수 있을 만큼 큰 하이드로 딥핑 필름 조각을 잘랐습니다. 베이스를 필름 위에 가이드로 놓고 모든 면에 약간의 여유 재료를 남겨서 부품을 완전히 감쌀 수 있도록 했습니다.

제가 즉시 눈치챈 한 가지는 필름이 얼마나 섬세한가 하는 점이었습니다. 필름은 매우 얇고 쉽게 접히거나 주름이 생기거나 서로 붙을 수 있으므로 조심스럽게 다뤄야 합니다. 약간의 인내가 필요했지만, 필름이 크기에 맞게 잘린 후에는 다음 단계로 준비가 되었습니다.




STEP 9. 딥 해보자!


딥 해보자!


딥 해보자!


딥 해보자!


딥 해보자!


딥 해보자!


딥 해보자!


딥 해보자!


딥 해보자!


이제 내가 기다려온 순간이 왔다.

내가 가진 가장 큰 플라스틱 용기를 잡고 물로 채웠다. 돌아보면, 조금 더 큰 용기를 사용했어야 했지만, 이것이 내가 사용할 수 있는 최선이었다.

나는 조심스럽게 수면 위에 하이드로 딥핑 필름을 놓았다. 필름이 매우 섬세하기 때문에 부드럽게 다뤄야 하며, 그렇지 않으면 쉽게 주름이 생기거나 접힐 수 있다. 물 위에 놓은 후, 필름이 완전히 수분을 흡수할 수 있도록 약 1분 정도 두었다.

중요한 점은 필름의 올바른 면이 물을 향해야 한다는 것이다. 대부분의 필름은 아래쪽을 향해야 하는 광택 있는 면이 있다. 확실하지 않다면, 작은 양의 활성제를 사용해 모서리를 테스트할 수 있다.

다음으로, 나는 필름 전체에 고르게 활성제를 분사했다. 몇 초 안에 필름은 떠 있는 잉크 층으로 변했다. 더 큰 용기를 사용하고 있다면, 활성제를 적용한 후 패턴이 너무 퍼지지 않도록 필름 주위에 간단한 프레임을 놓을 수 있다.

그 다음은 흥미진진한 부분이었다. 나는 천천히 각도를 주어 베이스를 물에 담갔다. 부품이 완전히 잠기자, 남은 필름을 치운 후 부품을 다시 꺼냈다.

솔직히, 나는 무엇을 기대해야 할지 전혀 몰랐다. 첫 시도에서 잘 될지 조금 회의적이었다.

하지만 부품을 물에서 꺼내는 순간... 와우! 내가 상상했던 것보다 훨씬 더 좋았다. 대리석 패턴이 아름답게 나왔다. 조금 더 큰 용기를 사용했다면 측면에 더 나은 커버리지를 얻었을지도 모르지만, 첫 시도로는 결과에 정말 만족했다.

마지막 단계는 흐르는 물에 부품을 헹궈 표면에 남아 있는 끈적한 잔여물을 씻어내는 것이었다. 완전히 건조시킨 후, 마감 처리를 보호하기 위해 투명 스프레이 페인트를 몇 겹 덧칠했다.




STEP 10. 전자기기


전자기기


전자기기


전자기기


조명을 위해, 나는 세 가지 다른 LED 스트립을 선택했습니다: 차가운 흰색, 따뜻한 흰색, 그리고 주황색. 하지만 내가 받은 주황색은 실제로는 약간 호박색처럼 보입니다. 주요 아이디어는 실제 태양광을 모방하는 것이었습니다. 여러분이 아시다시피, 태양의 진정한 색은 실제로 흰색입니다. 왜냐하면 태양은 무지개의 모든 색을 거의 고르게 방출하기 때문입니다. 지구에서 태양이 노란색, 주황색 또는 빨간색으로 보이는 것은 우리의 대기가 짧은 파란색 파장의 빛을 우리의 눈에 도달하기 전에 산란시키기 때문입니다.

한때, RGB LED를 사용했어야 했는지 고민했습니다. 그렇게 했다면 더 많은 색상 옵션을 제공했겠지만, 제어가 더 복잡해졌을 것입니다.

다음 주요 하드웨어는 시계를 위한 4자리 7세그먼트 디스플레이입니다. 밝기, 빛 혼합 및 시간을 제어하기 위해 세 개의 터치 스위치를 사용하고 있습니다. 나머지 회로에는 세 개의 LED 스트립을 구동하기 위한 세 개의 MOSFET, 정확한 시간 유지를 위한 RTC 모듈, 5V 전압 조정기 및 몇 가지 기본 수동 부품이 포함됩니다.

모든 것의 중심에는 ATtiny1614 마이크로컨트롤러가 있습니다. 이 프로젝트에 완벽하게 적합하다고 생각합니다. 왜냐하면 작고, 저렴하며, 저전력이고, 5V에서 잘 작동하며, 단일 와이어 UPDI 프로그래밍을 지원하기 때문입니다. 나는 자동 비누 디스펜서 프로젝트에서 ATtiny 마이크로컨트롤러를 사용한 적이 있으며, 그들은 믿을 수 없을 만큼 신뢰할 수 있었습니다. 사실, 그 프로젝트에서 배터리를 아직 충전할 필요가 없었습니다.

나는 이 빌드를 위해 맞춤형 PCB를 설계할 계획이 아니었기 때문에 SMD-to-DIP 어댑터와 함께 ATtiny1614의 14핀 버전을 사용하고 있습니다. 대신, 모든 것이 퍼프보드 조각에 납땜되어 있습니다.

조립과 향후 유지보수를 쉽게 하기 위해, 모든 주요 구성 요소에 대해 영구적으로 납땜하는 대신 커넥터를 사용했습니다.




STEP 11. 모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 것을 납땜하기


모든 구성 요소가 준비되었으므로, 드디어 전자 장치를 조립할 시간입니다.

커스텀 PCB를 사용하지 않았기 때문에, 전체 회로를 퍼프보드 한 조각에 구축했습니다. 되돌아보면, 끝날 무렵에 공간이 꽤 좁아졌기 때문에 약간 더 큰 보드를 선택했어야 했습니다.

ATtiny1614, 전압 조절기, MOSFET, 저항기 및 나머지 구성 요소를 퍼프보드에 납땜하는 것부터 시작했습니다. RTC 모듈은 원래 직각 헤더 핀과 함께 제공되었지만, 인클로저 안에 잘 맞지 않아, 납땜하기 전에 직선 헤더 핀으로 교체했습니다.

커넥터를 납땜할 때, 쌍으로 납땜하거나 일치하는 커넥터에 꽂힌 상태에서 납땜하는 것이 좋다는 것을 알게 되었습니다. 그렇지 않으면, 열로 인해 플라스틱이 부드러워져 핀이 이동하거나 정렬이 어긋날 수 있습니다.

다음으로, 터치 스위치, 7세그먼트 디스플레이, DC 전원 잭 및 세 개의 LED 스트립을 포함한 모든 외부 구성 요소에 대한 커넥터를 납땜했습니다. 와이어를 영구적으로 납땜하는 대신 커넥터를 사용하면 램프를 조립하고 분해하며 필요할 경우 수리하는 것이 훨씬 쉬워집니다.

배선을 깔끔하게 유지하기 위해, 세 개의 터치 스위치의 VCC 및 GND 핀을 모두 연결했습니다. 이들은 모두 동일한 전원 공급 장치를 공유하기 때문입니다. 이를 통해 전원에 대해 단일 2핀 커넥터를 사용할 수 있었고, 각 스위치는 자체 신호 와이어를 가졌습니다. 이는 배선의 양을 줄이고 베이스 내부를 훨씬 더 깔끔하게 만들었습니다.

마지막 팁: 납땜하기 전에 모든 커넥터의 극성을 다시 확인하세요. 각 커넥터가 어떤 구성 요소에 연결되는지 라벨을 붙이거나 메모하는 것도 좋은 생각입니다. 처음에는 불필요해 보일 수 있지만, 최종 조립 중에 많은 혼란을 줄여줄 것입니다.




STEP 12. 마이크로컨트롤러 프로그래밍


마이크로컨트롤러 프로그래밍


마이크로컨트롤러 프로그래밍


마이크로컨트롤러 프로그래밍


하드웨어 작업이 끝났으니 이제 펌웨어를 업로드할 차례입니다.

USB-to-UART 프로그래머를 프로그래밍 헤더에 올바른 방향으로 연결한 다음 컴퓨터에 연결하세요.

앞서 언급했듯이 ATtiny1614의 장점 중 하나는 UPDI 인터페이스를 사용해 프로그래밍할 때 데이터 핀 하나만 필요하다는 것입니다. 간단한 USB-to-UART 어댑터나 UPDI 프로그래머로 작동하는 다른 Arduino를 사용해 프로그래밍할 수도 있습니다. 이 빌드에서는 USB-to-UART 모듈을 사용합니다.

USB-to-UART 모듈의 TX 핀과 RX 핀은 저항을 통해 서로 연결되어 있으며, 이 연결부는 ATtiny1614의 UPDI 핀인 물리적 핀 10으로 연결됩니다.

소프트웨어로는 Arduino IDE를 사용합니다. 아직 설치하지 않았다면 먼저 megaTinyCore 보드 패키지를 설치하세요. 그런 다음 대상 마이크로컨트롤러로 ATtiny1614를 선택하고 프로그래머로 "SerialUPDI (Slow - 57600 baud)"를 선택하세요.

마지막으로 제가 제공한 코드를 복사해 붙여 넣고 Upload를 클릭한 다음 프로그래밍 과정이 완료될 때까지 몇 초 기다리세요. RTC에 CR2032 배터리를 넣으세요. 모든 것이 올바르게 연결되었다면 이제 램프를 최종 조립할 준비가 되었을 것입니다.


/*
* Sun Lamp Controller
* Hardware: ATtiny1614, DS3231 RTC, TM1637 Display, 3x TTP223 Touch Buttons
*/

#include <Wire.h>
#include <RTClib.h>
#include <TM1637Display.h>

// --- Pin Mapping ---
// Note: Pin numbers reflect megaTinyCore Arduino definitions, not physical leg numbers.

// Display & RTC
#define CLK_PIN 5 // Physical Pin 7 (PB2)
#define DIO_PIN 4 // Physical Pin 6 (PB3)

// Touch
#define BTN_MENU 3 // Physical Pin 5 (PA7)
#define BTN_UP 2 // Physical Pin 4 (PA6)
#define BTN_DN 8 // Physical Pin 11 (PA1)

// LED Channels (Must be hardware PWM pins)
#define LED_CH1 0 // Physical Pin 2 (PA4) - Warm White
#define LED_CH2 1 // Physical Pin 3 (PA5) - Cool White
#define LED_CH3 10 // Physical Pin 13 (PA3) - Amber


RTC_DS3231 rtc;
TM1637Display display(CLK_PIN, DIO_PIN);


enum Mode { NORMAL, SET_L1, SET_L2, SET_L3, SET_HOUR, SET_MINUTE };
Mode currentMode = NORMAL;


int currentHour = 0;
int currentMinute = 0;

// Brightness percentages (0-99 scale for 2-digit display)
int masterDim = 99;
int mixL1 = 99;
int mixL2 = 99;
int mixL3 = 99;


bool lastMenuState = LOW;
bool lastUpState = LOW;
bool lastDnState = LOW;
unsigned long upHoldTime = 0;
unsigned long dnHoldTime = 0;
unsigned long lastStepTime = 0;
unsigned long lastDisplayUpdate = 0;

const int HOLD_DELAY = 400;
const int STEP_SPEED = 20;

const uint8_t CHAR_C = 0b00111001;

void setup() {
// Initialize UI Pins
pinMode(BTN_MENU, INPUT);
pinMode(BTN_UP, INPUT);
pinMode(BTN_DN, INPUT);

// Initialize LED Pins
pinMode(LED_CH1, OUTPUT);
pinMode(LED_CH2, OUTPUT);
pinMode(LED_CH3, OUTPUT);
// Start Display
display.setBrightness(0x02);
display.clear();

// Start RTC (Halt and flash error if missing/miswired)
if (!rtc.begin()) {
while (1) {
display.showNumberHexEx(0xEEEE);
delay(500);
display.clear();
delay(500);
}
}
}

// --- Menu Helper Functions ---
void incrementSetting() {
switch (currentMode) {
case NORMAL: masterDim = min(99, masterDim + 1); break;
case SET_L1: mixL1 = min(99, mixL1 + 1); break;
case SET_L2: mixL2 = min(99, mixL2 + 1); break;
case SET_L3: mixL3 = min(99, mixL3 + 1); break;
case SET_HOUR: currentHour = (currentHour + 1) % 24; break;
case SET_MINUTE: currentMinute = (currentMinute + 1) % 60; break;
}
}

void decrementSetting() {
switch (currentMode) {
case NORMAL: masterDim = max(0, masterDim - 1); break;
case SET_L1: mixL1 = max(0, mixL1 - 1); break;
case SET_L2: mixL2 = max(0, mixL2 - 1); break;
case SET_L3: mixL3 = max(0, mixL3 - 1); break;
case SET_HOUR: currentHour = (currentHour == 0) ? 23 : currentHour - 1; break;
case SET_MINUTE: currentMinute = (currentMinute == 0) ? 59 : currentMinute - 1; break;
}
}

// --- Display Rendering ---
void updateDisplay() {
uint8_t segs[] = { 0, 0, 0, 0 };
bool blinkDigits = (millis() / 300) % 2 == 0;

if (currentMode == NORMAL || currentMode == SET_HOUR || currentMode == SET_MINUTE) {
// Render Clock Time
int displayHour = (currentMode == NORMAL) ? rtc.now().hour() : currentHour;
int displayMinute = (currentMode == NORMAL) ? rtc.now().minute() : currentMinute;
bool showColon = (currentMode != NORMAL) || ((millis() / 1000) % 2 == 0);

segs[0] = display.encodeDigit(displayHour / 10);
segs[1] = display.encodeDigit(displayHour % 10) | (showColon ? 0b10000000 : 0x00);
segs[2] = display.encodeDigit(displayMinute / 10);
segs[3] = display.encodeDigit(displayMinute % 10);

// Blinking effect during time setup
if (currentMode == SET_HOUR && blinkDigits) {
segs[0] = 0;
segs[1] = (showColon ? 0b10000000 : 0x00);
}
if (currentMode == SET_MINUTE && blinkDigits) {
segs[2] = 0;
segs[3] = 0;
}
}
else {
// Render LED Settings (e.g., "C1:99")
int val = 0, ch = 0;
if (currentMode == SET_L1) { val = mixL1; ch = 1; }
else if (currentMode == SET_L2) { val = mixL2; ch = 2; }
else if (currentMode == SET_L3) { val = mixL3; ch = 3; }

segs[0] = CHAR_C;
segs[1] = display.encodeDigit(ch) | 0b10000000; // Display channel & solid colon
segs[2] = display.encodeDigit(val / 10);
segs[3] = display.encodeDigit(val % 10);
}

display.setSegments(segs);
}

// --- LED Gamma Correction ---
// Converts linear percentages into a logarithmic PWM signal for human eyes
int calculatePWM(int master, int mix, int minPWM) {
if (master == 0 || mix == 0) return 0;
unsigned long linearPercent = (master * mix) / 98;
unsigned long curvePercent = (linearPercent * linearPercent) / 100;
// Maps the exponential curve above the physical turn-on threshold of the LED
int pwm = map(curvePercent, 0, 100, minPWM, 255);
return constrain(pwm, 0, 255);
}

void loop() {
// 1. Read Inputs
bool menuState = digitalRead(BTN_MENU);
bool upState = digitalRead(BTN_UP);
bool dnState = digitalRead(BTN_DN);

// 2. Menu Navigation
if (menuState == HIGH && lastMenuState == LOW) {
if (currentMode == NORMAL) { currentMode = SET_L1; }
else if (currentMode == SET_L1) { currentMode = SET_L2; }
else if (currentMode == SET_L2) { currentMode = SET_L3; }
else if (currentMode == SET_L3) {
DateTime now = rtc.now();
currentHour = now.hour();
currentMinute = now.minute();
currentMode = SET_HOUR;
}
else if (currentMode == SET_HOUR) { currentMode = SET_MINUTE; }
else if (currentMode == SET_MINUTE) {
// Save new time to hardware RTC
DateTime now = rtc.now();
rtc.adjust(DateTime(now.year(), now.month(), now.day(), currentHour, currentMinute, 0));
currentMode = NORMAL;
}
}
lastMenuState = menuState;

// 3. Up Button Logic (Tap & Hold)
if (upState == HIGH) {
if (lastUpState == LOW) {
upHoldTime = millis();
incrementSetting();
} else if (millis() - upHoldTime > HOLD_DELAY) {
if (millis() - lastStepTime > STEP_SPEED) {
incrementSetting();
lastStepTime = millis();
}
}
}
lastUpState = upState;

// 4. Down Button Logic (Tap & Hold)
if (dnState == HIGH) {
if (lastDnState == LOW) {
dnHoldTime = millis();
decrementSetting();
} else if (millis() - dnHoldTime > HOLD_DELAY) {
if (millis() - lastStepTime > STEP_SPEED) {
decrementSetting();
lastStepTime = millis();
}
}
}
lastDnState = dnState;

// 5. Update LED Outputs
// Custom minimum thresholds (25 for White, 5 for Amber) prevent sudden shut-offs
analogWrite(LED_CH1, calculatePWM(masterDim, mixL1, 25));
analogWrite(LED_CH2, calculatePWM(masterDim, mixL2, 25));
analogWrite(LED_CH3, calculatePWM(masterDim, mixL3, 5));

// 6. Throttled Display Refresh (20fps to prevent ghosting/flicker)
if (millis() - lastDisplayUpdate > 50) {
updateDisplay();
lastDisplayUpdate = millis();
}
delay(10);
}




STEP 13. LED 스트립을 장착하세요.


LED 스트립을 장착하세요.


LED 스트립을 장착하세요.


LED 스트립을 장착하세요.


다음으로, 중앙 실린더에 조명을 장착할 시간이었다. 나는 LED 스트립의 접착제를 드러내기 위해 보호 뒷면을 간단히 벗겨내고, 조심스럽게 3D 프린트된 홀더 주위에 감았다.

이 프로젝트에 세 가지 다른 색상의 LED를 사용하고 있기 때문에, 나는 작업을 진행하면서 차가운 흰색, 따뜻한 흰색, 그리고 호박색 스트립을 고르게 번갈아 배치하고 간격을 두도록 했다. 이들을 잘 정리하는 데 조금 더 시간을 들이면, 흰색 램프쉐이드가 위에 놓였을 때 서로 다른 색상이 완벽하게 섞일 수 있다.




STEP 14. 디스플레이 창 만들기


디스플레이 창 만들기


디스플레이 창 만들기


디스플레이 창 만들기


디스플레이 창 만들기


디스플레이 창 만들기


시계 디스플레이를 가리기 위해 2 mm 두께의 투명 아크릴 조각으로 작은 창을 만들었습니다.

아크릴을 유틸리티 나이프를 사용하여 여러 번 긁어서 55 mm × 25 mm로 잘랐습니다. 긁거나 부서진 날이 가장 잘 작동합니다. 긁힌 선이 충분히 깊어지면, 그 선을 따라 아크릴을 간단히 부러뜨려 깨끗한 모서리를 얻었습니다.

디스플레이를 조금 더 멋지게 보이게 하기 위해 아크릴에 냉각 창 필름을 붙였습니다. 이렇게 하면 디스플레이가 꺼져 있을 때 더 어두운 색조의 외관을 주면서도 켜져 있을 때 숫자가 선명하게 보이도록 합니다.

마지막으로 아크릴을 디스플레이 개구부 뒤쪽의 베이스 안에 놓고 몇 개의 작은 슈퍼 글루 방울로 고정했습니다. 가장자리에 아주 적은 양의 접착제만 사용하세요. 너무 많은 슈퍼 글루는 아크릴에 제거하기 어려운 흰색의 흐릿한 잔여물을 남기는 연기를 방출할 수 있습니다.




STEP 15. 최종 조립


최종 조립


최종 조립


최종 조립


최종 조립


최종 조립


최종 조립


최종 조립


최종 조립


이제 모든 것을 조립할 시간입니다. 먼저 세 개의 터치 스위치를 베이스의 슬롯에 슬라이드하여 넣었습니다. 각 스위치가 올바른 위치에 들어갔는지 확인하세요. 만약 실수로 스위치를 바꿨다면 걱정하지 마세요. 나중에 코드에서 쉽게 기능을 변경할 수 있습니다.

다음으로, M3 나사를 사용하여 4자리 디스플레이를 장착한 후 DC 전원 잭을 설치했습니다. 그 후, M2 나사를 사용하여 퍼프보드를 베이스 안에 고정했습니다.

전자 부품이 제자리에 놓인 후, 두 개의 M3 나사를 사용하여 LED 홀더를 베이스에 장착하고 모든 케이블을 해당 커넥터에 연결했습니다. 모든 것을 닫기 전에 램프를 켜고 모든 LED, 터치 스위치 및 시계가 제대로 작동하는지 확인하는 것이 좋습니다.

모든 테스트가 완료되면, 뒷 커버를 설치하고 M3 나사로 고정했습니다.

이 시점에서 조립은 거의 완료되었습니다. 남은 것은 램프 쉐이드를 위에 놓고 완성된 조립을 즐기는 것이었습니다.




STEP 16. 최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


최종 모습


조립이 완료되었으니, 드디어 완성된 램프를 볼 시간입니다.

12 V LED 스트립을 사용하고 있기 때문에, 램프는 12 V, 3 A 전원 어댑터로 전원을 공급받습니다. 전원 공급 장치를 연결하고, 램프 쉐이드를 위에 올려놓고, 처음으로 전원을 켰습니다.

흥미롭게도, 여기서 사용하고 있는 쉐이드는 사실 이전에 실패한 Vase Mode 인쇄물입니다. 상단 부분이 없지만, 단일 벽 인쇄물이 빛을 훨씬 더 고르게 확산시키기 때문에 완전히 인쇄된 버전보다 더 나아 보인다고 생각합니다.

램프에는 세 개의 터치 버튼이 있습니다: 플러스 (+), 마이너스 (-), 그리고 메뉴. 이들은 베이스의 상단에 양각으로 새겨져 있습니다.

플러스와 마이너스 버튼은 램프의 밝기를 조절합니다. 메뉴 버튼을 누르면 사용 가능한 설정을 순환합니다:

C1 → C2 → C3 → 시 → 분

첫 세 가지 옵션은 각 LED 스트립의 밝기를 개별적으로 조절합니다. 예를 들어, 램프가 오렌지색으로만 빛나게 하고 싶다면, 쿨 화이트와 웜 화이트 LED를 0%로 설정하고 오렌지색 LED만 켜두면 됩니다. 세 가지 색상을 혼합하여 다양한 조명 효과를 만들 수도 있습니다.

시와 분 옵션은 시계를 설정하는 데 사용되며, 플러스와 마이너스 버튼이 값을 조정합니다.

현재 누락된 한 가지는 LED 설정에 대한 메모리입니다. 램프의 전원이 켜질 때마다 색상 레벨이 기본값으로 돌아옵니다. 이 기능은 향후 업데이트에서 추가할 수 있습니다.

전반적으로, 이 프로젝트가 어떻게 진행되었는지 정말 만족합니다. 수중 침지된 대리석 베이스는 빛나는 램프 쉐이드와 잘 어울리며, 내장된 시계는 장식적이면서도 실용적입니다.

이 간단한 태양에서 영감을 받은 램프에 대해 어떻게 생각하시나요? 아래 댓글에서 여러분의 생각, 제안 또는 개선 아이디어를 듣고 싶습니다.

읽어주셔서 감사합니다, 그리고 즐거운 제작 되세요!


원문: https://www.instructables.com/DIY-Sun-Lamp/

좋아요 0
게시판

회사명 공방유니언 주소 각 공방 주소 참조
사업자 등록번호 0000 대표 공방유니언 전화 019-60105846 팩스 0000 이메일 gongbangunion@gmail.com
통신판매업신고번호 0000 개인정보관리책임자 공방유니언
Copyright © 2017 공방유니언. All Rights Reserved.