-
Update: bug fix, calling project complete
1 天前 • 0 commentsI've identified a bug that will set the number of seconds in the current minute to zero whenever the alarm is updated remotely and corrected it in the latest firmware update.
Other than that, I'm calling this project complete as the clock is now functioning exactly how I intended it to. I've let one run for a few days and have identified no further issues with it at this time.
-
Update: Code optimization and feature to display seconds
12/21/2024 at 20:37 • 0 commentsFor this update to the firmware, I added a mode that displays the number of seconds in the current minute. I thought this would be useful for my purposes as I'm always wondering how many seconds are in the current minute - the clock has the data, but not a good way to display it in addition to the current time. I thought the best way to implement this would be to make it a separate display mode. As always, I also added support for this mode to be activated through the remote interface.
I also collapsed the separate lampTest and dimmedLights flags into a single displayMode flag for changing the display mode. This display mode can either allow the showing of normal time, display the digits for a lamp test, dim the display, or show the number of seconds counted in the current minute.
-
Update: lamp test feature
12/13/2024 at 02:14 • 0 commentsUpdate: short update today. Added a lamp test feature to test all of the light-emitting elements on the PCB. How do I accomplish this? Feeding 8s to the 74LS47 during the normal 61 Hz refresh cycle, turning on all of the LEDs directly controlled by the MCU, and then performing a 35 Hz refresh of the day LEDs (required as they are controlled by the 74HC238 and therefore can only be turned on one a time normally).
My camera appears to have caught the day LEDs between refreshes so some of them appear to be off - but to the human eye, they appear to all on at the same time.
How do you trigger the lamp test? Press SW7 to dim the lights, then press SW8 to activate the lamp test. Press any button after that to exit the lamp test.
-
Update: cleaned up USART code
12/12/2024 at 01:10 • 0 commentsBytes:
0x41 - Query current time. Returns 4 bytes representing current seconds, minutes, hours, and days
0x42 - Set current time. Send 3 bytes afterward containing minutes, hours, and seconds. It will always zero out seconds. Each byte must be sent within 10 ms of the last one to avoid a timeout. ERROR will be sent if the time is invalid. DONE will be sent if the time is valid.
0x43 - Will return "TEST", followed by a newline and carriage return.
0x44 - Will enable the alarm. If the alarm is already enabled, ERROR will be sent.
0x45 - Will disable the alarm. If the alarm is already disabled, ERROR will be sent.0x46 - Set current alarm time. Send 2 bytes afterward containing minutes and hours. Each byte must be sent within 10 ms of the last one to avoid a timeout. ERROR will be sent if the received time is invalid. DONE will be sent if the time is valid.
0x47- Snooze the alarm if it is active. If the alarm is inactive, ERROR will be sent. If it is active, the alarm will be snoozed and DONE will be returned.
0x48- Stop the alarm if it is active. If the alarm is inactive, ERROR will be sent. If it is active, the alarm will be stopped and DONE will be returned.0x49- Dim all lights on the clock if the lights are not dimmed. If the lights are already dimmed, ERROR will be returned. Otherwise, DONE will be returned and all lights will be dimmed.
0x5- Turn on active lights on the clock if the lights are dimmed. If the lights are already on, ERROR will be returned. Otherwise, DONE will be returned and all active lights will be turned on.
-
Update: code cleanup, minor bug fixes
12/11/2024 at 02:03 • 0 commentsI finally got around to some housekeeping on the code:
- Fixed a bug from the method I'm using to blank the display. This bug would leave the display blanked if it an alarm was snoozed or disabled during the off period of the display flashing.
- It feels wrong to use the port direction register to accomplish this so I'm just using the same technique I use to blank the digits mid-refresh - send the null character (0xFF) to the 74LS47 at all times.
- Changed how the buzzer works. Instead of leaving the Timer1 overflow interrupt on the entire time and toggling the port direction register to activate the buzzer, the Timer1 overflow interrupt is enabled upon activation of an alarm.
- Got rid of modulo operations wherever I could. They weren't necessarily an issue as far as program execution speed went, but conditionals are easier for people to follow + have an inherent speed advantage on the ATmega328PB, which doesn't have any floating point hardware.
- Cleaned up the code. Moved all functions to a header file and removed their dependencies on global variables - now, global variables are passed and updated through pointers. I still have more to do, but this is a start.
- Fixed a bug from the method I'm using to blank the display. This bug would leave the display blanked if it an alarm was snoozed or disabled during the off period of the display flashing.
-
Update: Code optimization, dimmed light mode, quality of life improvements
12/10/2024 at 01:31 • 0 commentsI went and added some more features to the clock today, including:
- A feature that dims all light-emitting elements on the PCB, including the seven-segment displays and discrete LEDs. I figured this would make it a more practical alarm clock, as the brightness might make sleeping next to it an issue. This is activated by pushing SW7.
- Any button will bring the clock out of this dim mode. Alarms going off will automatically end the dim mode.
- All switches will now snooze the alarm if it goes off - except for SW8, which turns off the alarm.
- The display now flashes when the alarm goes off as an additional indicator that you have to wake up.
- Changed the way LEDs update: this is now updated periodically during a 4ms periodic refresh i.e. conditions are checked and LEDs are illuminated accordingly. This removes the need to update LEDs whenever modes are switched.
- Refresh rate of the screen was bumped from ~50 Hz to ~60 Hz. Originally, refresh rate was on a 5ms periodic timer in which the digit to be illuminated would switch every 5ms - this results in a 20ms period to refresh all LEDs, in turn resulting in a ~50 Hz refresh period. This has been updated to be a 4ms periodic timer to bring the refresh rate higher to ~ 60 Hz
The updated code is in the files section.
-
Update: Alarm code working, added basic serial functionality
12/09/2024 at 11:09 • 0 commentsI've been working on adding the alarm and snooze/stop functions to the alarm clock and have been successful so far. Things to note so far:
- A single alarm can be set with SW5 (using the same buttons to change the time) and armed with SW6
- The alarm tone is TBD, but right now it is a 250 Hz square wave with a 50% duty cycle. Need to work on this more, but it is simply a placeholder that seems to work well.
- Snooze causes the alarm to stop going off, but then triggers another alarm in 5 minutes unless the alarm is de-activated.
- Added some basic remote configuration functionality over serial. This uses the on-board FT230X to communicate with a host PC. This remote configuration capability should ideally allow configuration of all clock settings from a serial interface without the use of buttons. Right now, the current time (day/hour/minutes), alarm status, and alarm time (hours/minutes) can be set over serial. The ability to snooze and stop an alarm will be added next.
- Serial here is a simple 8N1, 38400 baud interface. Why 38400? The error for a 38400 baud rate seems to be much less than all others and this is important for a system running off an internal oscillator.
- I foolishly tied the FT230X's reset line to the main reset line without a jumper so now I can't use debugWIRE for serial functions. Bummer.
-
Update: PCBs arrived and prototype clock code
12/07/2024 at 12:42 • 0 commentsI received 2 assembled PCBs earlier from JLCPCB this week and have been toying around with the board's various peripherals. Everything seems to work as intended, thankfully - I'm always a bit worried about my PCBs not coming out how I intended. In fact, the PCBs look great:
The good news is that the FTDI FT230X USB-to-serial converter on the PCB works very well and responds , despite me accidentally using the wrong resistors specified (22 ohm vs 27 ohm), neglecting to use the capacitors they specified, and relying on the 8 MHz internal oscillator on the ATmega328PB. The USB power interface works - nothing to report more there.
The interface to the ULN2003 load drivers seems to work flawlessly - before anyone says "but the ULN2003 is old and outdated!", I used them solely because JLCPCB classifies them as a basic part without additional setup costs. The LEDs (and the 74HC238 glue logic for day selection) work well and are reasonably bright.
The seven-segment driver hardware I put together also works very well - the 74LS47 and a series of 4 PMOS transistors driven by a 74HC139 are responsive and respond well to the scan algorithm executed by the ATmega328PB. Right now, a 50 Hz refresh rate is being used and results in no visual discontinuities.
It took some tinkering, but the 4021 shift-register interface for the 8 user input buttons is implemented and uses some NOP commands to ensure that the datasheet delay times are being respected. What is unfortunate is that routing challenges resulted in SW1 not matching up to bit 0 on the shift register, but things like this are easily fixed in software.
The Timer2 overflow interrupt driven by the 32 kHz crystal results in a near-perfect 1 second interrupt interval as configured. I've previously experienced some minor annoyances trying to do the same on a PIC16LF1823 due to the 16-bit timer register there and slow PIC CPU operation throwing off the timing slightly.
I wrote a test program to activate the buzzer with a variable Timer1 output and it's just loud enough for this application. I still have to work on a proper frequency to get that working how I want it to.
I've been using avr-gcc + MPLAB X with a PICkit 5 (configured for the ISP interface) for development and have experienced no issues so far.
I wrote a test program to implement a basic clock with 24HR/AM/PM modes implemented as well as some buttons to change the minutes/hours/day of the week. Day of the week is implemented and will rollover when the hour counter hits 24. I set the clock, left it on the entire night, and returned to find it was keeping time throughout the night.
Next, I will have to implement the alarm clock function - which appears to be a challenging part due to the UX considerations.
I've uploaded the (so far) source code to the project page for anyone who wants to read it.