Final version, with changing analogue clock colours, Friday 11:20am
Dependencies: MMA8451Q SPI_TFT_ILI9341 TFT_fonts mbed
Smart clock by Duncan and Kieran
Photo
Equipment
- PCB: FRDM-KL25Z
- TFT Color Display: MI0283QT-9A
- Buzzer
- 3 x buttons
- 3 x 2kΩ resistors and 1 x 100Ω resistor
- Stripboard
- Wires (stranded is preferable due to their flexibility)
- USB to Mini-USB cable, and computer
Setup
PCB to TFT (Output)
FRDM-KL25Z | MI0283QT-9A |
---|---|
P3V3 | 3.3V, IM1, IM2, IM3 |
GND | RD, IM0, LEDK |
PTD5 | CS |
PTD1 | RS |
PTD0 | RST |
PTD2 | SDI |
PTD3 | SDO |
PTA13 | WR |
P5V_USB through 100Ω resistor (approx. 20mA) | LEDA |
The buzzer should be connected between PTA12 and ground.
Note: The resistance between P5V_USB and LEDA can be reduced to increase the brightness of the screen. However, resistors lower than 30Ω have not been tested, and may result in the current causing damage to the PCB.
PCB to Buttons (Inputs)
FRDM-KL25Z | Input |
---|---|
PTA5 | Minute button |
PTC8 | Hour button |
PTC9 | Time change button - toggles between changing the alarm time and the clock time |
Each button should be connected in series with a 2kΩ resistor between 3.3V and 0V, so that pressing the button switches between these two voltages.
Features
- A digital clock, displayed in 24-hour format
- An analogue clock, displaying the time in standard 12-hour format
- Alarm can be changed using the minute and hour buttons
- Time can be changed by holding the third button
- Alarm will sound for one minute at the displayed time
- Putting the alarm on its side will snooze the alarm if the alarm is going off (or just disable it if the alarm is not sounding)
main.cpp@9:d34cdff0205c, 2017-05-26 (annotated)
- Committer:
- scat6490
- Date:
- Fri May 26 10:20:25 2017 +0000
- Revision:
- 9:d34cdff0205c
- Parent:
- 8:6bd70a8697f4
Final version, with changing analogue clock colours, Friday 11:20am
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
scat6490 | 6:d80627e78bfd | 1 | #include "stdio.h" // Import libraries to use |
scat6490 | 0:4fd6c8718206 | 2 | #include "mbed.h" |
scat6490 | 0:4fd6c8718206 | 3 | #include "SPI_TFT_ILI9341.h" |
scat6490 | 0:4fd6c8718206 | 4 | #include "string" |
scat6490 | 0:4fd6c8718206 | 5 | #include "Arial12x12.h" |
scat6490 | 0:4fd6c8718206 | 6 | #include "Arial24x23.h" |
scat6490 | 0:4fd6c8718206 | 7 | #include "Arial28x28.h" |
scat6490 | 0:4fd6c8718206 | 8 | #include "font_big.h" |
scat6490 | 7:007d23438920 | 9 | #include "MMA8451Q.h" |
scat6490 | 7:007d23438920 | 10 | |
scat6490 | 7:007d23438920 | 11 | #define MMA8451_I2C_ADDRESS (0x1d<<1) |
scat6490 | 0:4fd6c8718206 | 12 | |
scat6490 | 6:d80627e78bfd | 13 | Ticker timer; // Set up a timer |
scat6490 | 6:d80627e78bfd | 14 | DigitalOut buzzer(PTE30); // Set up inputs and outputs |
scat6490 | 6:d80627e78bfd | 15 | DigitalIn input1(PTA5); // Input for the minute button |
scat6490 | 5:f5fa116b57a1 | 16 | DigitalIn input60(PTC8); // Input for the hour button |
scat6490 | 5:f5fa116b57a1 | 17 | DigitalIn input_time_change(PTC9); // Input for the button which switches from changing the alarm and changing the time |
scat6490 | 5:f5fa116b57a1 | 18 | Serial pc(USBTX,USBRX); // Connection to the desktop, currently only used for debugging |
scat6490 | 0:4fd6c8718206 | 19 | SPI_TFT_ILI9341 TFT(PTD2, PTD3, PTD1, PTD5, PTD0, PTA13,"TFT"); // mosi, miso, sclk, cs, reset, dc for frdmkl25z |
scat6490 | 0:4fd6c8718206 | 20 | |
scat6490 | 5:f5fa116b57a1 | 21 | int clock_minutes, clock_hours, clock_seconds = 0; // Initialise clock at 00:00.00 |
scat6490 | 6:d80627e78bfd | 22 | int alarm_hours = 7; // Initialise alarm hours as 07 |
scat6490 | 6:d80627e78bfd | 23 | int alarm_minutes = 0; // Initialise alarm minutes as 00 so alarm is 07:00 |
scat6490 | 9:d34cdff0205c | 24 | int previous_state, enable; // Initialise the previous state and enable variables to detect changing rotation |
scat6490 | 1:a33f6ca5a5b3 | 25 | |
scat6490 | 5:f5fa116b57a1 | 26 | void timeup(){ // Function to increment the clock every second |
scat6490 | 5:f5fa116b57a1 | 27 | clock_seconds++; // Increment the time |
scat6490 | 5:f5fa116b57a1 | 28 | clock_seconds %= 60; // Reset seconds to 0 if it gets to 60 |
scat6490 | 4:2013f3158cc6 | 29 | |
scat6490 | 4:2013f3158cc6 | 30 | if (clock_seconds==0) |
scat6490 | 4:2013f3158cc6 | 31 | { |
scat6490 | 5:f5fa116b57a1 | 32 | clock_minutes++; // Add a minute if the seconds got reset |
scat6490 | 5:f5fa116b57a1 | 33 | clock_minutes %= 60; // Reset the minutes to 0 if it gets to 60 |
scat6490 | 4:2013f3158cc6 | 34 | } |
scat6490 | 4:2013f3158cc6 | 35 | if (clock_minutes==0 && clock_seconds==0) |
scat6490 | 4:2013f3158cc6 | 36 | { |
scat6490 | 5:f5fa116b57a1 | 37 | clock_hours++; // Add an hour if the minutes got reset |
scat6490 | 6:d80627e78bfd | 38 | clock_hours %= 24; // Reset the hour to 0 if it gets to 24` |
scat6490 | 4:2013f3158cc6 | 39 | } |
scat6490 | 4:2013f3158cc6 | 40 | } |
scat6490 | 4:2013f3158cc6 | 41 | |
scat6490 | 4:2013f3158cc6 | 42 | void drawclock() // Draws an analogue clock using the clock_minutes and clock_hours variables |
scat6490 | 4:2013f3158cc6 | 43 | { |
scat6490 | 5:f5fa116b57a1 | 44 | int hourX, hourY, minuteX, minuteY, secondX, secondY; // Initialise variables to be used |
scat6490 | 5:f5fa116b57a1 | 45 | int circleX = 250; // Circle centre X |
scat6490 | 4:2013f3158cc6 | 46 | int circleY = 200; // Circle centre Y |
scat6490 | 4:2013f3158cc6 | 47 | int circleRadius = 30; // Circle radius |
scat6490 | 4:2013f3158cc6 | 48 | |
scat6490 | 4:2013f3158cc6 | 49 | double factorH = (2 * 3.141) / 12; // Convert hour to radians |
scat6490 | 4:2013f3158cc6 | 50 | double factorM = (2 * 3.141) / 60; // Convert minute to radians |
scat6490 | 5:f5fa116b57a1 | 51 | double factorS = (2 * 3.141) / 60; // Convert second to radians |
scat6490 | 4:2013f3158cc6 | 52 | |
scat6490 | 5:f5fa116b57a1 | 53 | hourX = floor(0.6 * circleRadius * sin((double) (clock_hours * factorH))); // Calculate difference in X values of the two ends of the hour hand. |
scat6490 | 5:f5fa116b57a1 | 54 | hourY = floor(0.6 * circleRadius * cos((double) (clock_hours * factorH))); // Same for Y of hour hand. The 0.9 means the hands are smaller than the circle |
scat6490 | 5:f5fa116b57a1 | 55 | minuteX = floor(0.95 * circleRadius * sin((double) (clock_minutes * factorM))); // Same for X of minute hand |
scat6490 | 5:f5fa116b57a1 | 56 | minuteY = floor(0.95 * circleRadius * cos((double) (clock_minutes * factorM))); // Same for Y of minute hand |
scat6490 | 5:f5fa116b57a1 | 57 | secondX = floor(0.85 * circleRadius * sin((double) (clock_seconds * factorS))); // Same for X of second hand |
scat6490 | 5:f5fa116b57a1 | 58 | secondY = floor(0.85 * circleRadius * cos((double) (clock_seconds * factorS))); // Same for Y of second hand |
scat6490 | 4:2013f3158cc6 | 59 | |
scat6490 | 9:d34cdff0205c | 60 | if (enable) // Checks if the alarm is enabled |
scat6490 | 5:f5fa116b57a1 | 61 | { |
scat6490 | 9:d34cdff0205c | 62 | TFT.fillcircle(circleX, circleY, circleRadius, Green); // Draws a green circle |
scat6490 | 9:d34cdff0205c | 63 | TFT.circle(circleX, circleY, circleRadius, Black); // Draws a white circle around the red circle |
scat6490 | 9:d34cdff0205c | 64 | TFT.line(circleX, circleY, circleX + hourX, circleY - hourY, Black); // Draws the hour hand |
scat6490 | 9:d34cdff0205c | 65 | TFT.line(circleX, circleY, circleX + minuteX, circleY - minuteY, Black); // Draws the minute hand |
scat6490 | 9:d34cdff0205c | 66 | TFT.line(circleX, circleY, circleX + secondX, circleY - secondY, White); // Draws the second hand |
scat6490 | 9:d34cdff0205c | 67 | |
scat6490 | 9:d34cdff0205c | 68 | for (int i = 0; i < 12; i++) |
scat6490 | 9:d34cdff0205c | 69 | { |
scat6490 | 9:d34cdff0205c | 70 | int timeX = floor(circleRadius * sin((double) (i * factorH))); // Calculate the X for the hour indicators around the edge |
scat6490 | 9:d34cdff0205c | 71 | int timeY = floor(circleRadius * cos((double) (i * factorH))); // Same for Y of the hour indicators |
scat6490 | 5:f5fa116b57a1 | 72 | |
scat6490 | 9:d34cdff0205c | 73 | TFT.line(circleX + 0.8 * timeX, circleY - 0.8 * timeY, circleX + timeX, circleY - timeY, Black); // Draws the hour indicators |
scat6490 | 9:d34cdff0205c | 74 | } |
scat6490 | 9:d34cdff0205c | 75 | } else |
scat6490 | 9:d34cdff0205c | 76 | { |
scat6490 | 9:d34cdff0205c | 77 | TFT.fillcircle(circleX, circleY, circleRadius, Red); // Draws a red circle |
scat6490 | 9:d34cdff0205c | 78 | TFT.circle(circleX, circleY, circleRadius, White); // Draws a white circle around the red circle |
scat6490 | 9:d34cdff0205c | 79 | TFT.line(circleX, circleY, circleX + hourX, circleY - hourY, White); // Draws the hour hand |
scat6490 | 9:d34cdff0205c | 80 | TFT.line(circleX, circleY, circleX + minuteX, circleY - minuteY, White); // Draws the minute hand |
scat6490 | 9:d34cdff0205c | 81 | TFT.line(circleX, circleY, circleX + secondX, circleY - secondY, Black); // Draws the second hand |
scat6490 | 9:d34cdff0205c | 82 | |
scat6490 | 9:d34cdff0205c | 83 | for (int i = 0; i < 12; i++) |
scat6490 | 9:d34cdff0205c | 84 | { |
scat6490 | 9:d34cdff0205c | 85 | int timeX = floor(circleRadius * sin((double) (i * factorH))); // Calculate the X for the hour indicators around the edge |
scat6490 | 9:d34cdff0205c | 86 | int timeY = floor(circleRadius * cos((double) (i * factorH))); // Same for Y of the hour indicators |
scat6490 | 9:d34cdff0205c | 87 | |
scat6490 | 9:d34cdff0205c | 88 | TFT.line(circleX + 0.8 * timeX, circleY - 0.8 * timeY, circleX + timeX, circleY - timeY, White); // Draws the hour indicators |
scat6490 | 9:d34cdff0205c | 89 | } |
scat6490 | 5:f5fa116b57a1 | 90 | } |
scat6490 | 1:a33f6ca5a5b3 | 91 | } |
scat6490 | 1:a33f6ca5a5b3 | 92 | |
scat6490 | 0:4fd6c8718206 | 93 | int main() |
scat6490 | 0:4fd6c8718206 | 94 | { |
scat6490 | 7:007d23438920 | 95 | MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS); // Set up the accelerometer connection |
scat6490 | 7:007d23438920 | 96 | wait(0.5); // Just wait for set up |
scat6490 | 7:007d23438920 | 97 | previous_state = acc.getAccX() >= 0.5; // Initialise the previous state variable |
scat6490 | 3:6a328c7e9b1c | 98 | |
scat6490 | 6:d80627e78bfd | 99 | TFT.set_orientation(3); // Make the display horizontal |
scat6490 | 5:f5fa116b57a1 | 100 | TFT.background(Black); // Set background to black |
scat6490 | 5:f5fa116b57a1 | 101 | TFT.foreground(White); // Set text to white |
scat6490 | 5:f5fa116b57a1 | 102 | TFT.cls(); // Clear screen |
scat6490 | 0:4fd6c8718206 | 103 | |
scat6490 | 5:f5fa116b57a1 | 104 | TFT.set_font((unsigned char*) Arial12x12); // Set the font to Arial 12x12 |
scat6490 | 5:f5fa116b57a1 | 105 | TFT.fillrect(0, 0, 320, 32, Red); // Draw a red rectangle at the top |
scat6490 | 5:f5fa116b57a1 | 106 | TFT.locate(10, 10); // Move the text location |
scat6490 | 5:f5fa116b57a1 | 107 | TFT.printf("Clock by Duncan and Kieran"); // Write some text in the box at the top |
scat6490 | 0:4fd6c8718206 | 108 | |
scat6490 | 5:f5fa116b57a1 | 109 | TFT.background(Black); // Set background to black |
scat6490 | 5:f5fa116b57a1 | 110 | TFT.set_font((unsigned char*) Arial28x28); // Set the font to Arial 28x28 |
scat6490 | 8:6bd70a8697f4 | 111 | TFT.locate(30, 70); // Move the text location |
scat6490 | 8:6bd70a8697f4 | 112 | TFT.printf("Time:"); // Display some text |
scat6490 | 0:4fd6c8718206 | 113 | |
scat6490 | 5:f5fa116b57a1 | 114 | timer.attach(&timeup, 1); // Set up the timer so it increments every second |
scat6490 | 1:a33f6ca5a5b3 | 115 | |
scat6490 | 3:6a328c7e9b1c | 116 | while(1) { |
scat6490 | 6:d80627e78bfd | 117 | if (!input_time_change) // Check if the toggle switch is pressed to change which time the other buttons adjust (pressed changes the time, unpressed changes the alarm) |
scat6490 | 3:6a328c7e9b1c | 118 | { |
scat6490 | 5:f5fa116b57a1 | 119 | switch(input1){ // Check if the minute button is pressed |
scat6490 | 3:6a328c7e9b1c | 120 | case 1: |
scat6490 | 5:f5fa116b57a1 | 121 | clock_minutes++; // Increment the time minutes |
scat6490 | 5:f5fa116b57a1 | 122 | clock_minutes %= 60; // Set the minutes back to 0 if it's 60 |
scat6490 | 5:f5fa116b57a1 | 123 | wait(0.2); // Wait so the time doesn't increase too fast |
scat6490 | 5:f5fa116b57a1 | 124 | break; |
scat6490 | 3:6a328c7e9b1c | 125 | case 0: |
scat6490 | 5:f5fa116b57a1 | 126 | break; |
scat6490 | 3:6a328c7e9b1c | 127 | } |
scat6490 | 5:f5fa116b57a1 | 128 | switch(input60){ // Check if the hour button is pressed |
scat6490 | 3:6a328c7e9b1c | 129 | case 1: |
scat6490 | 5:f5fa116b57a1 | 130 | clock_hours++; // Increment the time hours |
scat6490 | 5:f5fa116b57a1 | 131 | clock_hours %= 24; // Set the hours back to 0 if it's 24 |
scat6490 | 5:f5fa116b57a1 | 132 | wait(0.2); // Wait so the time doesn't increase too fast |
scat6490 | 3:6a328c7e9b1c | 133 | break; |
scat6490 | 3:6a328c7e9b1c | 134 | case 0: |
scat6490 | 3:6a328c7e9b1c | 135 | break; |
scat6490 | 3:6a328c7e9b1c | 136 | } |
scat6490 | 3:6a328c7e9b1c | 137 | } else |
scat6490 | 3:6a328c7e9b1c | 138 | { |
scat6490 | 5:f5fa116b57a1 | 139 | switch(input1){ // Check if the minute button is pressed |
scat6490 | 3:6a328c7e9b1c | 140 | case 1: |
scat6490 | 5:f5fa116b57a1 | 141 | alarm_minutes++; // Increment the alarm minutes |
scat6490 | 5:f5fa116b57a1 | 142 | alarm_minutes %= 60; // Set the minutes back to 0 if it's 60 |
scat6490 | 5:f5fa116b57a1 | 143 | wait(0.2); // Wait so the alarm time doesn't increase too fast |
scat6490 | 3:6a328c7e9b1c | 144 | break; |
scat6490 | 3:6a328c7e9b1c | 145 | case 0: |
scat6490 | 3:6a328c7e9b1c | 146 | break; |
scat6490 | 3:6a328c7e9b1c | 147 | } |
scat6490 | 5:f5fa116b57a1 | 148 | switch(input60){ // Check if the hour button is pressed |
scat6490 | 3:6a328c7e9b1c | 149 | case 1: |
scat6490 | 5:f5fa116b57a1 | 150 | alarm_hours++; // Increment the alarm hours |
scat6490 | 5:f5fa116b57a1 | 151 | alarm_hours %= 24; // Set the hours back to 0 if it's 24 |
scat6490 | 5:f5fa116b57a1 | 152 | wait(0.2); // Wait so the alarm time doesn't increase too fast |
scat6490 | 3:6a328c7e9b1c | 153 | break; |
scat6490 | 3:6a328c7e9b1c | 154 | case 0: |
scat6490 | 3:6a328c7e9b1c | 155 | break; |
scat6490 | 3:6a328c7e9b1c | 156 | } |
scat6490 | 1:a33f6ca5a5b3 | 157 | } |
scat6490 | 7:007d23438920 | 158 | |
scat6490 | 7:007d23438920 | 159 | float x = acc.getAccX(); // Check the x-orientation |
scat6490 | 9:d34cdff0205c | 160 | enable = 1; // Initialise the enable variable |
scat6490 | 7:007d23438920 | 161 | |
scat6490 | 7:007d23438920 | 162 | if (x < 0.5){ // Check if the clock is tilted |
scat6490 | 7:007d23438920 | 163 | enable = 0; // Disable the alarm |
scat6490 | 7:007d23438920 | 164 | } |
scat6490 | 7:007d23438920 | 165 | if (enable != previous_state && !enable && clock_hours == alarm_hours && clock_minutes == alarm_minutes) // If the clock is tilted while the alarm is going off |
scat6490 | 7:007d23438920 | 166 | { |
scat6490 | 7:007d23438920 | 167 | alarm_minutes += 5; // Add 5 minutes (snooze) |
scat6490 | 7:007d23438920 | 168 | } |
scat6490 | 8:6bd70a8697f4 | 169 | if (clock_hours == alarm_hours && clock_minutes == alarm_minutes && enable) // Check if the time is equal to the alarm time, and the seconds is even |
scat6490 | 2:21c4f254786f | 170 | { |
scat6490 | 5:f5fa116b57a1 | 171 | buzzer = 1; // Buzz |
scat6490 | 8:6bd70a8697f4 | 172 | wait(0.2); // Wait |
scat6490 | 8:6bd70a8697f4 | 173 | buzzer = 0; // Don't buzz |
scat6490 | 8:6bd70a8697f4 | 174 | wait(0.2); // Wait |
scat6490 | 2:21c4f254786f | 175 | } else |
scat6490 | 2:21c4f254786f | 176 | { |
scat6490 | 5:f5fa116b57a1 | 177 | buzzer = 0; // Don't buzz |
scat6490 | 2:21c4f254786f | 178 | } |
scat6490 | 1:a33f6ca5a5b3 | 179 | |
scat6490 | 6:d80627e78bfd | 180 | TFT.foreground(White); // Set text to white |
scat6490 | 8:6bd70a8697f4 | 181 | TFT.locate(120, 70); // Move the text location |
scat6490 | 8:6bd70a8697f4 | 182 | TFT.printf("%02d:%02d.%02d", clock_hours, clock_minutes, clock_seconds); // Write the time to the TFT |
scat6490 | 7:007d23438920 | 183 | |
scat6490 | 7:007d23438920 | 184 | if (enable){ // Check if the alarm is enabled |
scat6490 | 7:007d23438920 | 185 | TFT.foreground(Green); // Write the alarm text in green |
scat6490 | 7:007d23438920 | 186 | } else { |
scat6490 | 7:007d23438920 | 187 | TFT.foreground(Red); // Write the alarm text in red |
scat6490 | 7:007d23438920 | 188 | } |
scat6490 | 5:f5fa116b57a1 | 189 | TFT.locate(30, 120); // Move the text location |
scat6490 | 5:f5fa116b57a1 | 190 | TFT.printf("Alarm: %02d:%02d", alarm_hours, alarm_minutes); // Write the alarm time to the TFT |
scat6490 | 3:6a328c7e9b1c | 191 | |
scat6490 | 5:f5fa116b57a1 | 192 | drawclock(); // Call a function to draw the analogue clock |
scat6490 | 7:007d23438920 | 193 | previous_state = enable; // Update the state to changes can be detected |
scat6490 | 0:4fd6c8718206 | 194 | } |
scat6490 | 0:4fd6c8718206 | 195 | |
scat6490 | 0:4fd6c8718206 | 196 | } |