Introduction: Single-chip open source project of button adjustable electronic clock (matrix button + infrared remote control button for time adjustment)
This program is written based on the 51hei single-chip development board. If you need to transplant it to your own circuit, just modify the corresponding port.
/**
************************************************************************
* @file : main.c
* @author : xr
* @date : 2014-04-21 22:23:12 - 2014-04-26 21:22:29
* @version : V1.2.3
* @brief : Electronic clock with adjustable time by buttons (matrix buttons + infrared remote control buttons for time adjustment) MCU STC89C52RC MCU Crystal oscillator 11.0592MHZ
************************************************************************
*/
#include #include "main.h" /*Define a structure to encapsulate the time and date read from DS1302 and the time and date set to DS1302*/ struct Time { unsigned char year; //DS1302 only stores the lower two bytes of the year unsigned char month; unsigned char day; unsigned char hour; unsigned char min; unsigned char sec; unsigned char week; }; /*Define a structure time variable to save time and date*/ struct Time timeBuf; //Struct variables must be used here, and structure pointers cannot be used, otherwise the write will fail! unsigned char setTimeIndex = 0; //Set the time status and set the cursor position and set the index value of the time position (0 is normal operation, 1-12 is the setting time status, 1-12 is the setting position) bit flag200ms = 0; unsigned char thr0, tlr0; //Infrared communication decoding key code and standard PC code mapping table unsigned char code IrdCodeMap[] = {0x45, 0x46, 0x47, //Switch, Mode, Mute 0x44, 0x40, 0x43, //Play/Pause, Fast Rewind, Fast Forward 0x07, 0x15, 0x09, //EQ, subtraction, addition 0x16, 0x19, 0x0D, //0, return, U/SD 0x0C, 0x18, 0x5E, //1, 2, 3 0x08, 0x1C, 0x5A, //4, 5, 6 0x42, 0x52, 0x4A};//7, 8, 9 // External variable declaration extern bit flagIrd; //Infrared data code value reception completed flag extern unsigned char irdCode[4]; //Save the four-byte data code decoded by the NEC protocol (user code + user inverse code, key code + key code inverse code) extern void InitLCD1602(); extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str); extern void LcdSetCoursor(unsigned char x, unsigned char y); extern void LcdOpenCoursor(); extern void InitDS1302(); extern void GetTimeFromDS1302(struct Time * time); extern void SetTimeToDS1302(struct Time * time); extern void KeyDriver(); extern void KeyScan(); extern void LcdCoursorRight(); extern void LcdCoursorLeft(); void ConfgiTimer0(unsigned int xms); void RefreshLcdShowTime(); extern void ConfigIrdByTimer1(); void IrdDrive(); void IrdKeyAction(); extern void SetTimeBcdByte(unsigned char keyNum); /*Main program main()*/ void main() { unsigned char psec = 0xFF; //Used to detect whether sec seconds have changed, if changed, refresh the time display ConfgiTimer0(1); //timing 1ms ConfigIrdByTimer1(); //Configure infrared communication InitLCD1602(); InitDS1302(); /*LCD initialization display*/ LcdShowStr(1, 0, "*"); LcdShowStr(2, 0, "20 - - "); LcdShowStr(12, 0, "*"); LcdShowStr(14, 0, "--"); LcdShowStr(0, 1, "time: --:--:--"); while (1) { KeyDriver(); //Detect key action if (flagIrd) { flagIrd = 0; IrdKeyAction(); //Detect infrared key action } if (flag200ms == 1 && (setTimeIndex == 0)) //Refresh the time display every 200ms and when setTimeIndex==0 is not in the set time state { flag200ms = 0; GetTimeFromDS1302(&timeBuf); //Get the time from DS1302 to the member of the timeBuf structure pointer variable if (timeBuf.sec != psec) //The current second value is not equal to the previous second value { RefreshLcdShowTime(); //Refresh time display psec = timeBuf.sec; //Backup the current second value (second register value) } } } } /*Timer T0 configuration*/ void ConfgiTimer0(unsigned int xms) { unsigned long tmp; tmp = 11059200/12; // cycle frequency tmp = (tmp * xms) / 1000; //The count value required for timing xms tmp = 65536-tmp; //Initial value loaded at regular intervals thr0 = (unsigned char)(tmp >> 8); tlr0 = (unsigned char)tmp; TMOD &= 0xF0; // Clear T0 control bit TMOD |= 0x01; //T0 mode 1, 16-bit configurable time mode TH0 = thr0; TL0 = tlr0; TR0 = 1; ET0 = 1; EA = 1; } /*Decompose a BCD code byte data and display it on the (x, y) coordinates of LCD1602*/ void LcdShowBCDByte(unsigned char x, unsigned char y, unsigned char bcdbyte) { unsigned char str[4]; str[0] = (bcdbyte >> 4) + '0'; //Get the high 4 bytes of the BCD code str[1] = (bcdbyte & 0x0F) + '0'; //Get the fourth byte of the BCD code str[2] = ''; LcdShowStr(x, y, str); } /*Refresh time to display on LCD1602*/ void RefreshLcdShowTime() { LcdShowBCDByte(4, 0, timeBuf.year); //Display year LcdShowBCDByte(7, 0, timeBuf.month); LcdShowBCDByte(10, 0, timeBuf.day); LcdShowBCDByte(6, 1, timeBuf.hour); LcdShowBCDByte(9, 1, timeBuf.min); LcdShowBCDByte(12, 1, timeBuf.sec); LcdShowBCDByte(14, 0, timeBuf.week); //Display the week } /************The following function is the high and low digits of the BCD code byte +1 and -1**********************/ /*Increment the high digit of the BCD code*/ unsigned char IncrementBCDByteHigh(unsigned char bcdbyte) { if ((bcdbyte & 0xF0) < 0x90) //Check if the high 4 bytes of bcdbyte are less than 9 { bcdbyte += 0x10; //high four bytes + 1 } else { //The high four-bit value returns to zero when it reaches 9 bcdbyte &= 0x0F;//0000 1111 } return (bcdbyte); //Return the modified BCD code value } /*Increment the low byte of the BCD code*/ unsigned char IncrementBCDByteLow(unsigned char bcdbyte) { if ((bcdbyte & 0x0F) < 0x09) //Get the lower four digits of bcdbyte { bcdbyte += 0x01; //low byte + 1 } else { //Reset to zero at 9 bcdbyte &= 0xF0; //lower four bits cleared } return (bcdbyte); } /*Decrement the high byte of the BCD data byte*/ unsigned char DescBCDByteHigh(unsigned char bcdbyte) { if ((bcdbyte & 0xF0) > 0) //Get the high 4 bytes of the BCD code byte { bcdbyte -= 0x10; //high four-bit byte number -1 } else { // Return to 9 from 0 bcdbyte |= 0x90; //或bcdbyte &= 0x9F } return (bcdbyte); } /*Decrement the low byte of the BCD data byte*/ unsigned char DescBCDByteLow(unsigned char bcdbyte) { if ((bcdbyte & 0x0F) > 0) { bcdbyte -= 0x01; //low digit -1 } else { // Return to 9 from 0 bcdbyte |= 0x09; } return (bcdbyte); } /*Set the cursor flashing position according to the value of setTimeIndex*/ void LcdRefreshSetCoursor() { switch (setTimeIndex) { case 1: LcdSetCoursor(4, 0); break; //Set the ten digits of the year case 2: LcdSetCoursor(5, 0); break; case 3: LcdSetCoursor(7, 0); break; case 4: LcdSetCoursor(8, 0); break; case 5: LcdSetCoursor(10, 0); break; case 6: LcdSetCoursor(11, 0); break; case 7: LcdSetCoursor(6, 1); break; case 8: LcdSetCoursor(7, 1); break; case 9: LcdSetCoursor(9, 1); break; case 10: LcdSetCoursor(10, 1); break; case 11: LcdSetCoursor(12, 1); break; case 12: LcdSetCoursor(13, 1); break; default: break; } LcdOpenCoursor(); } /*Increment the time value of the cursor blinking position*/ void IncTimeBysetTimeIndex() { switch (setTimeIndex) { case 1: timeBuf.year = IncrementBCDByteHigh(timeBuf.year); break; //year10++ten digits of the year++ case 2: timeBuf.year = IncrementBCDByteLow(timeBuf.year); break;//year digit++ case 3: timeBuf.month = IncrementBCDByteHigh(timeBuf.month); break;//月十位++ case 4: timeBuf.month = IncrementBCDByteLow(timeBuf.month); break;//月个位++ case 5: timeBuf.day = IncrementBCDByteHigh(timeBuf.day); break; case 6: timeBuf.day = IncrementBCDByteLow(timeBuf.day); break; case 7: timeBuf.hour = IncrementBCDByteHigh(timeBuf.hour); break; case 8: timeBuf.hour = IncrementBCDByteLow(timeBuf.hour); break; case 9: timeBuf.min = IncrementBCDByteHigh(timeBuf.min); break; case 10: timeBuf.min = IncrementBCDByteLow(timeBuf.min); break; case 11: timeBuf.sec = IncrementBCDByteHigh(timeBuf.sec); break; case 12: timeBuf.sec = IncrementBCDByteLow(timeBuf.sec); break; default: break; } RefreshLcdShowTime(); //Refresh time display LcdRefreshSetCoursor(); //Refresh cursor flashing display } /*Decrement the time value of the cursor position*/ void DecTimeBySetTimeIndex() { switch (setTimeIndex) { case 1: timeBuf.year = DescBCDByteHigh(timeBuf.year); break; //Decrease the ten digits of the year case 2: timeBuf.year = DescBCDByteLow(timeBuf.year); break; //Decrease the year digit case 3: timeBuf.month = DescBCDByteHigh(timeBuf.month); break; case 4: timeBuf.month = DescBCDByteLow(timeBuf.month); break; case 5: timeBuf.day = DescBCDByteHigh(timeBuf.day); break; case 6: timeBuf.day = DescBCDByteLow(timeBuf.day); break; case 7: timeBuf.hour = DescBCDByteHigh(timeBuf.hour); break; case 8: timeBuf.hour = DescBCDByteLow(timeBuf.hour); break; case 9: timeBuf.min = DescBCDByteHigh(timeBuf.min); break; case 10: timeBuf.min = DescBCDByteLow(timeBuf.min); break; case 11: timeBuf.sec = DescBCDByteHigh(timeBuf.sec); break case 12: timeBuf.sec = DescBCDByteLow(timeBuf.sec); break; default: break; } /*Refresh the time display first, then refresh the cursor flashing display*/ RefreshLcdShowTime(); LcdRefreshSetCoursor(); } /*Infrared button action function*/ void IrdKeyAction() { if (irdCode[2] == 0x44) // >>|| { if (setTimeIndex == 0) //Normal operation status { setTimeIndex = 1; LcdRefreshSetCoursor(); //Refresh cursor setting display } else { SetTimeToDS1302(&timeBuf); //Write time into DS1302 setTimeIndex = 0; RefreshLcdShowTime(); } } else if (irdCode[2] == 0x40) //|<< { if (setTimeIndex != 0) { LcdCoursorLeft(); } } else if (irdCode[2] == 0x43) // >>| { if (setTimeIndex != 0) { LcdCoursorRight(); } } else if (irdCode[2] == 0x15) //- { DecTimeBySetTimeIndex(); } else if (irdCode[2] == 0x09) //+ { IncTimeBysetTimeIndex(); } else if (irdCode[2] == 0x19) //EQ { setTimeIndex = 0; RefreshLcdShowTime(); } else if (irdCode[2] == 0x16) //Number key 0 { SetTimeBcdByte(0); } else if (irdCode[2] == 0x0C) //Number key 1 { SetTimeBcdByte(1); } else if (irdCode[2] == 0x18) //Number key 2 { SetTimeBcdByte(2); } else if (irdCode[2] == 0x5E) { SetTimeBcdByte(3); } else if (irdCode[2] == 0x08) { SetTimeBcdByte(4); } else if (irdCode[2] == 0x1C) { SetTimeBcdByte(5); } else if (irdCode[2] == 0x5A)
Previous article:Design of emergency power inverter circuit using single chip microcomputer SPWM
Next article:Circuit structure of P0 port of 51 single chip microcomputer
Recommended ReadingLatest update time:2024-11-16 17:50
- Popular Resources
- Popular amplifiers
- Principles and Applications of Single Chip Microcomputers 3rd Edition (Zhang Yigang)
- Signal Integrity and Power Integrity Analysis (Eric Bogatin)
- Traffic Light Control System Based on Fuzzy Control (Single-Chip Microcomputer Implementation)
- Principles and Applications of Single Chip Microcomputers (Second Edition) (Wanlong)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications