|
|
【程序】通过串口控制DS1302时钟、RAM数据以及实现时钟更新的程序 |
一派掌門 二十級 |
【上位机截图】 获取DS1302中的31字节RAM数据(主电源切断后仍能保存,只要备用电池有电):
|
一派掌門 二十級 |
获取DS1302上的当前时间:
| |
一派掌門 二十級 |
电脑上的时间与DS1302同步:
| |
一派掌門 二十級 |
12/24小时制切换:
| |
一派掌門 二十級 |
更新RAM数据:
| |
一派掌門 二十級 |
【下位机】
| |
一派掌門 二十級 |
【单片机程序】 #include <reg52.h> #include <intrins.h>
#define BCD(n) (((n) / 10 << 4) + (n) % 10) #define DEBCD(n) ((((n) & 0xf0) >> 4) * 10 + ((n) & 0x0f))
sbit SCLK = P1^0; sbit DATA = P1^1; sbit RST = P1^2;
sbit RS = P2^0; sbit RW = P2^1; sbit E = P2^2; sbit BF = P0^7;
sbit K5 = P1^4; // 写入数据的按键 sbit K6 = P1^5; // 清除数据的按键 sbit K7 = P1^6; // AM/PM切换键 sbit K8 = P1^7; // 小时调整键
bit load_flag = 0; char comm_buf[32]; int comm_i = -1; unsigned char comm_cmd = 0;
void delay(unsigned int n) { unsigned char i; while (n--) for (i = 0; i < 115; i++); }
void Write1302(unsigned char dat) { unsigned char i; for (i = 0; i < 8; i++) { DATA = dat & 1; dat >>= 1; SCLK = 1; _nop_(); _nop_(); SCLK = 0; } }
void WriteSet1302(unsigned char addr, unsigned char dat) { RST = 0; SCLK = 0; RST = 1; Write1302(addr & 0xfe); Write1302(dat); RST = 0; }
unsigned char Read1302(void) { unsigned char dat = 0; unsigned char i; DATA = 1; for (i = 0; i < 8; i++) { _nop_(); _nop_(); dat >>= 1; if (DATA) dat |= 0x80; SCLK = 1; _nop_(); _nop_(); SCLK = 0; } return dat; }
unsigned char ReadSet1302(unsigned char addr) { unsigned char dat; RST = 0; // 开机时RST默认为1,所以必须先置0防止第一次读的时候出错 SCLK = 0; RST = 1; Write1302(addr | 1); dat = Read1302(); RST = 0; return dat; }
void LCDBusyTest(void) { RS = 0; RW = 1; E = 1; _nop_(); _nop_(); BF = 1; while (BF); E = 0; _nop_(); }
void LCDWriteCmd(unsigned char cmd) { LCDBusyTest(); RS = 0; RW = 0; E = 1; P0 = cmd; _nop_(); E = 0; _nop_(); }
void LCDWriteData(unsigned char dat) { LCDBusyTest(); RS = 1; RW = 0; P0 = dat; E = 1; _nop_(); _nop_(); E = 0; _nop_(); }
void LCDWriteString(char *s) { while (*s) LCDWriteData(*s++); }
/*void LCDWriteNumber(unsigned char num) { char str[4]; str[0] = num / 100 + '0'; str[1] = num % 100 / 10 + '0'; str[2] = num % 10 + '0'; str[3] = '\0'; if (str[0] == '0') { if (str[1] == '0') LCDWriteString(str + 2); else LCDWriteString(str + 1); } else LCDWriteString(str); }*/
void LCDInit(void) { delay(40); LCDWriteCmd(0x30); delay(10); LCDWriteCmd(0x30); delay(10); LCDWriteCmd(0x0c); delay(1); LCDWriteCmd(0x01); }
void SaveData(void) { char str[] = "Keyword:abcd45efThat's a string"; char i; WriteSet1302(0x8e, 0); for (i = 0; str[i] != '\0'; i++) WriteSet1302(0xc0 + i * 2, str[i]); WriteSet1302(0x8e, 0x80); }
void ClearData(void) { char i; WriteSet1302(0x8e, 0); for (i = 0; i < 31; i++) WriteSet1302(0xc0 + i * 2, '*'); WriteSet1302(0x8e, 0x80); }
void LoadData(void) { unsigned char i, dat; bit end = 0; LCDWriteCmd(0x80); for (i = 0; i < 31; i++) { if (i == 16) LCDWriteCmd(0x90); if (!end) { dat = ReadSet1302(0xc1 + i * 2); if (dat == '\0') { end = 1; dat = ' '; } } LCDWriteData(dat); } LCDWriteData(' '); }
void DisplayNum(unsigned char num) { num = DEBCD(num); LCDWriteData('0' + num % 100 / 10); LCDWriteData('0' + num % 10); }
void DisplayTime(void) { char list[] = {0xc8, 0xd5, 0xd2, 0xbb, 0xb6, 0xfe, 0xc8, 0xfd, 0xcb, 0xc4, 0xce, 0xe5, 0xc1, 0xf9, 0x00}; unsigned char tmp = ReadSet1302(0x81); char pm = 2; unsigned char hour = ReadSet1302(0x85); static unsigned char last_sec = -1; static unsigned char last_hour = -1; if (tmp == last_sec && hour == last_hour) return; last_sec = tmp; last_hour = hour; LCDWriteCmd(0x88); LCDWriteString("20"); DisplayNum(ReadSet1302(0x8d)); LCDWriteString("年"); DisplayNum(ReadSet1302(0x89)); LCDWriteString("月"); DisplayNum(ReadSet1302(0x87)); LCDWriteString("日"); LCDWriteCmd(0x98); if (hour & 0x80) { if (hour & 0x20) pm = 1; else pm = 0; hour &= 0x1f; } DisplayNum(hour); LCDWriteData(':'); DisplayNum(ReadSet1302(0x83)); LCDWriteData(':'); DisplayNum(tmp); if (pm == 0) LCDWriteString("AM"); else if (pm == 1) LCDWriteString("PM"); else LCDWriteString(" "); LCDWriteString("星期"); tmp = (ReadSet1302(0x8b) & 0x07); if (tmp == 7) tmp = 0; LCDWriteData(list[2 * tmp]); LCDWriteData(list[2 * tmp + 1]); }
void ChangeHour(void) { unsigned char dat = ReadSet1302(0x85); unsigned char hour; if (dat & 0x80) { // 12 -> 24 hour = dat & 0x1f; hour = DEBCD(hour); if (dat & 0x20) { if (hour != 12) hour += 12; } else { if (hour == 12) hour = 0; // 12 AM } dat = BCD(hour); } else { // 24 -> 12 hour = DEBCD(dat); dat = 0x80; if (hour > 12) { hour -= 12; dat |= 0x20 | BCD(hour); } else if (hour == 0) dat |= BCD(12); // 12 AM else { dat |= BCD(hour); if (hour == 12) dat |= 0x20; // 12 PM } } WriteSet1302(0x8e, 0); WriteSet1302(0x84, dat); WriteSet1302(0x8e, 0x80); }
void IncrementHour(void) { unsigned char dat = ReadSet1302(0x85); unsigned char hour; if (dat & 0x80) { hour = dat & 0x1f; hour = DEBCD(hour); dat &= 0xe0; if (hour == 12) // 12 AM/PM -> 1 AM/PM hour = 1; else { hour++; if (hour == 12) dat ^= 0x20; // 11 AM/PM -> 12 PM/AM } dat |= BCD(hour); } else { hour = DEBCD(dat); if (hour == 23) hour = 0; else hour++; dat = BCD(hour); } WriteSet1302(0x8e, 0); WriteSet1302(0x84, dat); WriteSet1302(0x8e, 0x80); }
int main(void) { LCDInit(); LoadData(); if (ReadSet1302(0x81) & 0x80) { WriteSet1302(0x8e, 0); WriteSet1302(0x8c, BCD(16)); WriteSet1302(0x8a, BCD(1)); WriteSet1302(0x88, BCD(7)); WriteSet1302(0x86, BCD(11)); WriteSet1302(0x84, BCD(23)); WriteSet1302(0x82, BCD(8)); WriteSet1302(0x80, BCD(40)); WriteSet1302(0x8e, 0x80); } SCON = 0x50; TMOD = 0x20; TH1 = TL1 = 0xfd; TR1 = 1; ES = 1; EA = 1; while (1) { DisplayTime(); if (load_flag) { load_flag = 0; LoadData(); } if (!K5) { delay(10); if (!K5) { SaveData(); LoadData(); while (!K5); } } if (!K6) { delay(10); if (!K6) { ClearData(); LoadData(); while (!K6); } } if (!K7) { delay(10); if (!K7) { ChangeHour(); while (!K7); } } if (!K8) { delay(10); if (!K8) { IncrementHour(); while (!K8); } } } }
void send(unsigned char dat) { SBUF = dat; while (!TI); TI = 0; }
void send1302data(void) { char i; for (i = 0; i < 31; i++) send(ReadSet1302(0xc1 + i * 2)); }
void sendtime(void) { unsigned char i; for (i = 0x81; i <= 0x8f; i += 2) send(ReadSet1302(i)); }
void es(void) interrupt 4 { unsigned char i, dat; if (RI) { dat = SBUF; if (comm_i >= 0 && comm_i < sizeof(comm_buf)) { comm_buf[comm_i] = dat; if (comm_cmd == 0x02 && dat == '\0') { comm_i = -1; WriteSet1302(0x8e, 0); for (i = 0; i < 31; i++) { WriteSet1302(0xc0 + i * 2, comm_buf[i]); if (comm_buf[i] == '\0') break; } WriteSet1302(0x8e, 0x80); load_flag = 1; send(0x80 | i); // 应答信号: 最高位始终为1,其他位表示收到的字符串长度 } else if (comm_cmd == 0x04 && comm_i >= 7) { comm_i = -1; WriteSet1302(0x8e, 0); WriteSet1302(0x80, 0x80); // 停止走时 WriteSet1302(0x80, comm_buf[0]); WriteSet1302(0x82, comm_buf[1]); if (ReadSet1302(0x85) & 0x80) WriteSet1302(0x84, comm_buf[3]); else WriteSet1302(0x84, comm_buf[2]); WriteSet1302(0x86, comm_buf[4]); WriteSet1302(0x88, comm_buf[5]); WriteSet1302(0x8a, comm_buf[6]); WriteSet1302(0x8c, comm_buf[7]); WriteSet1302(0x8e, 0x80); send(0x80); } else comm_i++; } else { comm_cmd = dat; switch (dat) { case 0x01: ChangeHour(); i = ReadSet1302(0x85); if (i & 0x80) send(0x81); else send(0x80); break; case 0x02: case 0x04: comm_i = 0; break; case 0x03: send(0x20); send1302data(); break; case 0x05: send(0x20); sendtime(); break; default: send(0xff); } } RI = 0; } }
| |
一派掌門 二十級 |
【电脑端程序(使用C语言编写)】 #include <tchar.h> #include <time.h> #include <Windows.h> #include <CommCtrl.h> #include <strsafe.h> #include "resource.h"
#define BCD(n) (((n) / 10 << 4) + (n) % 10) #define DEBCD(n) ((((n) & 0xf0) >> 4) * 10 + ((n) & 0x0f))
#pragma comment(lib, "comctl32.lib") #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' language='*' publicKeyToken='6595b64144ccf1df'\"")
HANDLE hCommPort; HWND hwndMain; HWND hwndEdit1, hwndEdit2;
void OpenPort(void) { COMMTIMEOUTS tout; DCB dcb; hCommPort = CreateFile(TEXT("\\\\.\\COM10"), GENERIC_READ | GENERIC_WRITE, (DWORD)NULL, NULL, OPEN_EXISTING, (DWORD)NULL, NULL); if (hCommPort == INVALID_HANDLE_VALUE) { MessageBox(hwndMain, TEXT("打开串口失败"), TEXT("错误"), MB_ICONERROR); EndDialog(hwndMain, 0); }
// 指定波特率 ZeroMemory(&dcb, sizeof(dcb)); dcb.DCBlength = sizeof(DCB); GetCommState(hCommPort, &dcb); dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; SetCommState(hCommPort, &dcb);
// 指定超时时间 ZeroMemory(&tout, sizeof(tout)); tout.ReadTotalTimeoutConstant = 1000; SetCommTimeouts(hCommPort, &tout); }
void DisplayTime(LPSTR buf) { int hour, wday; TCHAR h[4]; LPTSTR list = TEXT("日一二三四五六"); TCHAR str[100]; if (buf[3] & 0x80) { if (buf[3] & 0x20) h[0] = 'P'; else h[0] = 'A'; h[1] = 'M'; h[2] = ' '; h[3] = '\0';
hour = buf[3] & 0x1f; hour = DEBCD(hour); } else { h[0] = '\0'; hour = DEBCD(buf[3]); }
wday = buf[6] & 0x07; if (wday == 7) wday = 0;
StringCbPrintf(str, sizeof(str), TEXT("20%02d年%02d月%02d日\r\n%02d:%02d:%02d %s星期%c"), DEBCD(buf[7]), DEBCD(buf[5]), DEBCD(buf[4]), hour, DEBCD(buf[2]), DEBCD(buf[1]), h, list[wday]); SetWindowText(hwndEdit1, str); }
void SendTime(void) { BYTE buf[9]; DWORD dwSize; time_t t = time(NULL); struct tm info; localtime_s(&info, &t); buf[0] = 0x04; buf[1] = BCD(info.tm_sec); buf[2] = BCD(info.tm_min); buf[3] = BCD(info.tm_hour); buf[5] = BCD(info.tm_mday); buf[6] = BCD(info.tm_mon + 1); if (info.tm_wday == 0) buf[7] = 7; else buf[7] = info.tm_wday; buf[8] = BCD(info.tm_year - 100);
buf[4] = 0x80; if (info.tm_hour > 12) buf[4] |= 0x20 | BCD(info.tm_hour - 12); else if (info.tm_hour == 0) buf[4] |= BCD(12); else { buf[4] |= buf[3]; if (info.tm_hour == 12) buf[4] |= 0x20; }
WriteFile(hCommPort, buf, sizeof(buf), &dwSize, NULL); ReadFile(hCommPort, buf, 1, &dwSize, NULL); if (buf[0] & 0x80) SetWindowText(hwndEdit1, TEXT("更新时间成功")); else SetWindowText(hwndEdit1, TEXT("更新时间失败")); }
INT_PTR CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { char buf[101]; DWORD dwSize; int i; int wmId; WCHAR str[100];
switch (uMsg) { case WM_INITDIALOG: hwndMain = hWnd; hwndEdit1 = GetDlgItem(hWnd, IDC_EDIT1); hwndEdit2 = GetDlgItem(hWnd, IDC_EDIT2); SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(NULL, IDI_APPLICATION)); OpenPort(); break; case WM_COMMAND: wmId = LOWORD(wParam); switch (wmId) { case IDOK: GetWindowTextW(hwndEdit2, str, _countof(str)); // 获取用户输入的内容(UTF-16) ZeroMemory(buf, sizeof(buf)); WideCharToMultiByte(20936, (DWORD)NULL, str, wcslen(str), buf + 1, sizeof(buf) - 1, NULL, NULL); // 将UTF-16编码转换为液晶使用的GB2312编码(第一个参数指定) buf[0] = 0x02; // 要发送的第一个字节为控制指令
// 计算要发送的数据量 dwSize = strlen(buf); if (dwSize < 32) dwSize++; // 发送小于32字节的内容时, 必须以\0结束 else if (dwSize > 32) { MessageBox(hwndMain, TEXT("您输入的内容太长, 无法保存"), TEXT("提示"), MB_ICONWARNING); break; }
// 检查输入的字符串能否在液晶上成功显示,例如"a中"就不能正常显示 for (i = 1; i < (int)dwSize; i += 2) { if (!(buf[i] & 0x80) && (buf[i + 1] & 0x80)) { MessageBox(hwndMain, TEXT("您输入的内容无法在液晶上正确显示\n请重新输入!"), TEXT("提示"), MB_ICONWARNING); return FALSE; } }
WriteFile(hCommPort, buf, strlen(buf) + 1, &dwSize, NULL); ReadFile(hCommPort, buf, 1, &dwSize, NULL); if (buf[0] & 0x80) { StringCbPrintf(str, sizeof(str), TEXT("成功写入%d个字符"), buf[0] & 0x7f); MessageBox(hwndMain, str, TEXT("提示"), MB_ICONINFORMATION); } else MessageBox(hwndMain, TEXT("写入数据失败"), TEXT("提示"), MB_ICONWARNING); // 若收到的数据最高位不是1, 则表明写入失败 break; case IDCANCEL: CloseHandle(hCommPort); EndDialog(hWnd, wmId); break; case IDC_BUTTON1: buf[0] = 0x03; WriteFile(hCommPort, buf, 1, &dwSize, NULL); ReadFile(hCommPort, buf, _countof(buf), &dwSize, NULL); if (buf[0] != 0x20) { MessageBox(hwndMain, TEXT("读取数据失败"), TEXT("提示"), MB_ICONWARNING); break; } buf[dwSize] = '\0'; for (i = 1; i < (int)dwSize; i++) { if (buf[i] == '\0') buf[i] = ' '; } ZeroMemory(str, sizeof(str)); MultiByteToWideChar(20936, (DWORD)NULL, buf + 1, strlen(buf + 1), str, _countof(str)); SetWindowTextW(hwndEdit1, str); break; case IDC_BUTTON2: buf[0] = 0x05; WriteFile(hCommPort, buf, 1, &dwSize, NULL); ReadFile(hCommPort, buf, _countof(buf), &dwSize, NULL); if (buf[0] != 0x20) { SetWindowText(hwndEdit1, TEXT("读取时间失败")); break; } DisplayTime(buf); break; case IDC_BUTTON3: SendTime(); break; case IDC_BUTTON4: buf[0] = 0x01; WriteFile(hCommPort, buf, 1, &dwSize, NULL); ReadFile(hCommPort, buf, _countof(buf), &dwSize, NULL); if (buf[0] & 0x80) { if (buf[0] & 1) SetWindowText(hwndEdit1, TEXT("成功切换为12小时制")); else SetWindowText(hwndEdit1, TEXT("成功切换为24小时制")); } else SetWindowText(hwndEdit1, TEXT("切换失败")); break; } break; } return FALSE; }
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { InitCommonControls(); DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc); return 0; }
| |
一派掌門 二十級 |
【对话框】
| |
一派掌門 二十級 |
【resource.h 资源头文件】 //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by DS1302.rc // #define IDD_DIALOG1 101 #define IDC_BUTTON1 1001 #define IDC_EDIT1 1002 #define IDC_EDIT2 1003 #define IDC_BUTTON2 1005 #define IDC_BUTTON3 1006 #define IDC_BUTTON4 1007
// Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1008 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
| |
一派掌門 二十級 |
【rc资源文件】 // Microsoft Visual C++ generated resource script. // #include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h"
///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS
///////////////////////////////////////////////////////////////////////////// // English (Australia) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
#ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE //
1 TEXTINCLUDE BEGIN "resource.h\0" END
2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END
3 TEXTINCLUDE BEGIN "\r\n" "\0" END
#endif // APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// // // Dialog //
IDD_DIALOG1 DIALOGEX 0, 0, 309, 158 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "DS1302" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN GROUPBOX "命令",IDC_STATIC,7,7,295,40 PUSHBUTTON "获取自定义数据",IDC_BUTTON1,27,23,74,14 EDITTEXT IDC_EDIT1,7,51,295,46,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL GROUPBOX "设置自定义数据",IDC_STATIC,7,102,295,49 EDITTEXT IDC_EDIT2,15,116,275,14,ES_AUTOHSCROLL DEFPUSHBUTTON "确定",IDOK,241,133,50,14 PUSHBUTTON "获取时间",IDC_BUTTON2,108,23,50,14 PUSHBUTTON "更新时间",IDC_BUTTON3,164,23,50,14 PUSHBUTTON "12/24小时切换",IDC_BUTTON4,219,23,63,14 END
///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO //
#ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_DIALOG1, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 302 TOPMARGIN, 7 BOTTOMMARGIN, 151 END END #endif // APSTUDIO_INVOKED
#endif // English (Australia) resources /////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. //
///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
| |
一派掌門 二十級 |
单片机上用的是12864液晶,不是1602液晶。不过这两款液晶的读写时序几乎是一样的。
| |
|
|
|