当前位置: 首页 > news >正文

网站描述代码怎么写互联网营销师课程

网站描述代码怎么写,互联网营销师课程,短视频万能素材库,北京专业制作网站目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、延时2、定时器03、串口通信4、DS13025、LCD16026、独立按键 四、主函数总结 系列文章目录 前言 之前做了一个WiFi定时器时钟#xff0c;用八位数码管进行显示#xff0c;但是定时器时钟的精度较低#xff0… 目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、延时2、定时器03、串口通信4、DS13025、LCD16026、独立按键 四、主函数总结 系列文章目录 前言 之前做了一个WiFi定时器时钟用八位数码管进行显示但是定时器时钟的精度较低需要频繁校时。 这次做一个LCD1602版本的WiFi时钟同样通过ESP826601S从网络获取时间获取时间后将时间写入DS1302时钟芯片每一次成功获取网络时间后会每隔24小时自动校时长时间之后ESP8266模块可能会与网络断开连接但是这不影响如果校时超时20s会发送指令重启ESP8266模块重新连接WiFi和网络并校时。不校时的时候通过DS1302时钟芯片读取时间。 有三个版本都是用普中A2开发板 ①八位数据接口汉字显示星期 ②八位数据接口滚动显示时分秒 ③I2C通信四位数据接口汉字显示星期 本文代码对应的是版本②。 三个版本用到的单片机都是STC89C52RC。 用到的外设有ESP826601S、LCD1602、DS1302、独立按键。 效果查看/操作演示B站搜索“甘腾胜”或“gantengsheng”查看。 源代码下载B站对应视频的简介有工程文件下载链接。 一、效果展示 二、原理分析 1、如何获取网络时间 ESP826601S模块的使用和串口通信可以看一下我的另一篇博客八位数码管WiFi定时器时钟 2、如何显示汉字 LCD1602显示汉字的原理可以看一下我的另一篇博客LCD1602多汉字动态扫描显示 这次只需要显示一个汉字不需要扫描显示简单很多只需要用到6个自定义字符就行了。 3、滚动显示时间 隔一段时间向上移动一个像素就行了变化一个数字需要移动8个像素因为LCD1602每个区域是5*8的点阵代码中是隔70ms移动一个像素隔8*70ms560ms完成一个数字的滚动停顿一下再等待进行下一次的滚动显示。 4、版本③的LCD1602的I2C通信 I2C的通信协议可以看一下其他博主的介绍这里说明一下指令的问题。需要先发一个0x02的指令设置为四线模式。因为用了6T双倍速模式相当于晶振翻倍了相当于变成了22.1184MHzI2C通信需要加延时才行了不然会超过PCF8574T允许的最大通信速率导致显示不正常。 三、各模块代码 1、延时 h文件 #ifndef __DELAY_H__ #define __DELAY_H__void Delay(unsigned int xms);#endifc文件 /*** brief 延时函数延时xms毫秒* param xms 延时的时间范围0~65535* retval 无*/void Delay(unsigned int xms) //11.0592MHz6T双倍速模式 {unsigned char i,j;while(xms){i4;j146;do{while(--j);} while(--i);xms--;} }2、定时器0 h文件 #ifndef __TIMER0_H__ #define __TIMER0_H__void Timer0_Init(void);#endifc文件 #include REGX52.H/*** brief 定时器0初始化* param 无* retval 无*/ void Timer0_Init(void) {TMOD0xF0; //设置定时器模式高四位不变低四位清零TMOD|0x01; //设置定时器模式通过低四位设为“定时器0工作方式1”的模式TL00x66; //设置定时初值定时1ms晶振11.0592MHzTH00xFC; //设置定时初值定时1ms晶振11.0592MHzTF00; //清除TF0标志TR01; //定时器0开始计时ET01; //打开定时器0中断允许EA1; //打开总中断PT00; //当PT00时定时器0为低优先级当PT01时定时器0为高优先级 }/*定时器中断函数模板 void Timer0_Routine() interrupt 1 //定时器0中断函数 {static unsigned int T0Count; //定义静态变量TL00x66; //设置定时初值定时1ms晶振11.0592MHzTH00xFC; //设置定时初值定时1ms晶振11.0592MHzT0Count;if(T0Count1000){T0Count0;} } */3、串口通信 h文件 #ifndef __UART_H__ #define __UART_H__void UART_Init(); void UART_SendByte(unsigned char Byte); void UART_SendString(char *String);#endifc文件 #include REGX52.H/*** brief 串口初始化115200bps11.0592MHz6T模式误差0.00%* param 无* retval 无*/ void Uart_Init(void) {PCON|0x80; //使能波特率倍速位SMOD倍速后为115200bpsSCON 0x50; //8位数据,可变波特率 // AUXR0xBF; //定时器时钟12T模式89C52芯片无需设置这个 // AUXR0xFE; //串口1选择定时器1为波特率发生器89C52芯片无需设置这个TMOD0x0F; //设置定时器模式TMOD|0x20; //设置定时器模式TL10xFF; //设置定时初始值TH10xFF; //设置定时重载值ET10; //禁止定时器1中断TR11; //定时器1开始计时EA1; //开启所有中断ES1; //开启串口中断PS1; //要设置串口中断的优先级比定时器的高//否则发送或接收数据的时候会被打断影响数据发送和接收 }/*** brief 串口发送一个字节数据* param Byte 要发送的一个字节数据* retval 无*/ void UART_SendByte(unsigned char Byte) {SBUFByte;while(TI0);TI0; }/*** brief 串口发送字符串* param String 要发送的字符串* retval 无*/ void UART_SendString(char *String) {while(*String){UART_SendByte(*String);String;} }/*串口中断函数模板 void UART_Routine() interrupt 4 {if(RI1){RI0;} } */4、DS1302 h文件 #ifndef __DS1302_H__ #define __DS1302_H__//外部可调用的时间数组索引0~6分别对应年、月、日、时、分、秒、星期 extern char DS1302_Time[];void DS1302_Init(void); void DS1302_WriteByte(unsigned char Command,Data); unsigned char DS1302_ReadByte(unsigned char Command); void DS1302_SetTime(void); void DS1302_ReadTime(void);#endifc文件 #include REGX52.H//引脚定义 sbit DS1302_SCLKP3^6; sbit DS1302_IOP3^4; sbit DS1302_CEP3^5;#define DS1302_WP 0x8E //写保护的地址//DS1302写入时间的地址年月日时分秒星期 unsigned char code DS1302_WriteAddress[7]{0x8c,0x88,0x86,0x84,0x82,0x80,0x8a,}; //DS1302读取时间的地址年月日时分秒星期 unsigned char code DS1302_ReadAddress[7]{0x8d,0x89,0x87,0x85,0x83,0x81,0x8b,}; //时间数组年月日时分秒星期 char DS1302_Time[]{25,1,10,18,12,53,5}; //时间的初始值/*** brief DS1302初始化* param 无* retval 无*/ void DS1302_Init(void) {DS1302_CE0;DS1302_SCLK0; }/*** brief DS1302写一个字节* param Command 命令字/地址* param Data 要写入的数据* retval 无*/ void DS1302_WriteByte(unsigned char Command,Data) {unsigned char i;DS1302_CE1;for(i0;i8;i) //循环8次每次写1位先写低位再写高位{DS1302_IOCommand(0x01i);DS1302_SCLK1; //SCLK置1后立即置0该时序操作需考虑时钟芯片是否可承受这个时钟的最快频率DS1302_SCLK0; //由于单片机没有这么快的频率故可不加延时}for(i0;i8;i){DS1302_IOData(0x01i);DS1302_SCLK1; //CLK由低到高产生一个上升沿从而写入数据DS1302_SCLK0;}DS1302_CE0; }/*** brief DS1302读一个字节* param Command 命令字/地址* retval Data 读出的数据*/ unsigned char DS1302_ReadByte(unsigned char Command) {unsigned char i,Data0x00;DS1302_CE1;for(i0;i8;i){DS1302_IOCommand(0x01i);DS1302_SCLK0;DS1302_SCLK1;}for(i0;i8;i){DS1302_SCLK1;DS1302_SCLK0; //要先1后0否则全都是65if(DS1302_IO){Data|(0x01i);}}DS1302_CE0;DS1302_IO0; //读取后将IO设置为0否则读出的数据会出错return Data; }/*** brief DS1302设置时间调用之后DS1302_Time数组的数字会被设置到DS1302中* param 无* retval 无*/ void DS1302_SetTime(void) {unsigned char i;DS1302_WriteByte(DS1302_WP,0x00); //设置前关闭写保护for(i0;i7;i) //依次写入年月日时分秒星期{DS1302_WriteByte(DS1302_WriteAddress[i],DS1302_Time[i]/10*16DS1302_Time[i]%10); //十进制转换为BCD码}DS1302_WriteByte(DS1302_WP,0x80); //设置后开启写保护 }/*** brief DS1302读取时间调用之后DS1302中的数据会被读取到DS1302_Time数组中* param 无* retval 无*/ void DS1302_ReadTime(void) {unsigned char Temp,i;for(i0;i7;i) //依次读取年月日时分秒星期{TempDS1302_ReadByte(DS1302_ReadAddress[i]);DS1302_Time[i]Temp/16*10Temp%16;//BCD码转换为十进制} }5、LCD1602 h文件 #ifndef __LCD1602_H__ #define __LCD1602_H__void LCD_WriteCommand(unsigned char Command); void LCD_WriteData(unsigned char Data); void LCD_SetCursor(unsigned char Line,unsigned char Column); void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_Clear(void); void LCD_MoveLeft(void); void LCD_MoveRight(void); void LCD_ScrollNum(unsigned char Line,unsigned char Column,unsigned char Order,unsigned char Number,unsigned char Quantity,char Offset);#endifc文件 #include REGX52.H//引脚配置 sbit LCD_RSP2^6; sbit LCD_RWP2^5; sbit LCD_ENP2^7; #define LCD_DataPort P0//阴码亮点为1横向取模高位在左 unsigned char code NumberTable[]{ //5*7数字字模低5位 0x0E,0x11,0x13,0x15,0x19,0x11,0x0E,0x00, //0 0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00, //1 0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,0x00, //2 0x1F,0x02,0x04,0x02,0x01,0x11,0x0E,0x00, //3 0x02,0x06,0x0A,0x12,0x1F,0x02,0x02,0x00, //4 0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E,0x00, //5 0x06,0x08,0x10,0x1E,0x11,0x11,0x0E,0x00, //6 0x1F,0x01,0x02,0x04,0x08,0x08,0x08,0x00, //7 0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00, //8 0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C,0x00, //9 };//函数定义 /*** brief LCD1602私有延时函数11.0592MHz6T调用可延时40us* param 无* retval 无*/ void LCD_Delay40us(void) {unsigned char i;i34;while(--i); }/*** brief LCD1602延时函数11.0592MHz6T调用可延时2ms* param 无* retval 无*/ void LCD_Delay2ms(void) {unsigned char i, j;i8;j40;do{while(--j);}while(--i); }/*** brief LCD1602写指令* param Command 要写入的指令* retval 无*/ void LCD_WriteCommand(unsigned char Command) {LCD_RS0;LCD_RW0;LCD_DataPortCommand;LCD_EN1;LCD_Delay40us();LCD_EN0;LCD_Delay40us(); }/*** brief LCD1602写数据* param Data 要写入的数据* retval 无*/ void LCD_WriteData(unsigned char Data) {LCD_RS1;LCD_RW0;LCD_DataPortData;LCD_EN1;LCD_Delay40us();LCD_EN0;LCD_Delay40us(); }/*** brief LCD1602设置光标位置* param Line 行位置范围1~2* param Column 列位置范围1~16* retval 无*/ void LCD_SetCursor(unsigned char Line,unsigned char Column) {if(Line1){LCD_WriteCommand(0x80|(Column-1));}else if(Line2){LCD_WriteCommand(0x80|(Column-10x40));} }/*** brief LCD1602初始化函数* param 无* retval 无*/ void LCD_Init() {LCD_WriteCommand(0x38); //八位数据接口两行显示5*7点阵LCD_WriteCommand(0x0C); //显示开光标关闪烁关LCD_WriteCommand(0x06); //数据读写操作后光标自动加一画面不动LCD_WriteCommand(0x01); //光标复位清屏LCD_Delay2ms(); //清屏指令执行需要较长时间需要较长的延时 }/*** brief 在LCD1602指定位置上显示一个字符* param Line 行位置范围1~2* param Column 列位置范围1~16* param Char 要显示的字符* retval 无*/ void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) {LCD_SetCursor(Line,Column);LCD_WriteData(Char); }/*** brief 在LCD1602指定位置开始显示所给字符串* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param String 要显示的字符串* retval 无*/ void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) {unsigned char i;LCD_SetCursor(Line,Column);for(i0;String[i]!\0;i){LCD_WriteData(String[i]);} }/*** brief 返回值X的Y次方*/ int LCD_Pow(int X,int Y) {unsigned char i;int Result1;for(i0;iY;i){Result*X;}return Result; }/*** brief 在LCD1602指定位置开始显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围0~65535* param Length 要显示数字的长度范围1~5* retval 无*/ void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(iLength;i0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%100);} }/*** brief 在LCD1602指定位置开始以有符号十进制显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围-32768~32767* param Length 要显示数字的长度范围1~5* retval 无*/ void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) {unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number0){LCD_WriteData();Number1Number;}else{LCD_WriteData(-);Number1-Number;}for(iLength;i0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%100);} }/*** brief 在LCD1602指定位置开始以十六进制显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围0~0xFFFF* param Length 要显示数字的长度范围1~4* retval 无*/ void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(iLength;i0;i--){SingleNumberNumber/LCD_Pow(16,i-1)%16;if(SingleNumber10){LCD_WriteData(SingleNumber0);}else{LCD_WriteData(SingleNumber-10A);}} }/*** brief 在LCD1602指定位置开始以二进制显示所给数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Number 要显示的数字范围0~1111 1111 1111 1111* param Length 要显示数字的长度范围1~16* retval 无*/ void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) {unsigned char i;LCD_SetCursor(Line,Column);for(iLength;i0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%20);} }/*** brief LCD1602的光标复位清屏* param 无* retval 无*/ void LCD_Clear(void) {LCD_WriteCommand(0x01);LCD_Delay2ms(); }/*** brief LCD1602的屏幕向左移动一个字符位光标不动* param 无* retval 无*/ void LCD_MoveLeft(void) {LCD_WriteCommand(0x18); }/*** brief LCD1602的屏幕向左移动一个字符位光标不动* param 无* retval 无*/ void LCD_MoveRight(void) {LCD_WriteCommand(0x1C); }/*** brief LCD1602向上滚动显示数字* param Line 起始行位置范围1~2* param Column 起始列位置范围1~16* param Order 所用到的CGRAM的自定义字符的序号范围0~7* param Number 要显示的数字范围0~9* param Quantity 这一位置所显示数字的总数量例如秒的个位可以显示0~9这十个数字显示的数字的总数量为10* param Offset 滚动显示的偏移量范围-7~0* retval 无*/ void LCD_ScrollNum(unsigned char Line,unsigned char Column,unsigned char Order,unsigned char Number,unsigned char Quantity,char Offset) {unsigned char i,j,k;LCD_SetCursor(Line,Column);LCD_WriteData(Order);k8*Quantity;j(8*NumberOffsetk)%k;LCD_WriteCommand(0x408*Order);for(i0;i8;i){LCD_WriteData(NumberTable[(ji)%k]);} }6、独立按键 h文件 #ifndef __KEYSCAN_H__ #define __KEYSCAN_H__unsigned char Key(void); void Key_Tick(void);#endifc文件 #include REGX52.Hsbit Key1P3^1; sbit Key2P3^0; sbit Key3P3^2; sbit Key4P3^3;unsigned char KeyNumber;/*** brief 获取独立按键键码* param 无* retval 按下按键的键码范围0,1~12,0表示无按键按下*/ unsigned char Key(void) {unsigned char KeyTemp0;KeyTempKeyNumber;KeyNumber0; //主程序中获取键码值之后键码值清零在下一次定时器扫描按键之前再次获取键码值一定会返回0return KeyTemp; }/*** brief 获取当前按键的状态无消抖及松手检测* param 无* retval 按下的按键范围0~4无按键按下时返回值为0*/ unsigned char Key_GetState() {unsigned char KeyValue0;if(Key10){KeyValue1;}if(Key20){KeyValue2;}if(Key30){KeyValue3;}if(Key40){KeyValue4;}return KeyValue; }/*** brief 按键驱动函数在中断中调用* param 无* retval 无*/ void Key_Tick(void) {static unsigned char NowState,LastState;static unsigned int KeyCount;LastStateNowState; //按键状态更新NowStateKey_GetState(); //获取当前按键状态//如果上个时间点按键未按下这个时间点按键按下则是按下瞬间if(LastState0){switch(NowState){case 1:KeyNumber1;break;case 2:KeyNumber2;break;case 3:KeyNumber3;break;case 4:KeyNumber4;break;default:break;}}//如果上个时间点按键按下这个时间点按键按下则是一直按住按键if(LastState NowState){KeyCount;if(KeyCount10) //按下超过200ms才被检测为长按定时器中断函数中每隔20ms检测一次按键{if(LastState1 NowState1){KeyNumber5;}if(LastState2 NowState2){KeyNumber6;}if(LastState3 NowState3){KeyNumber7;}if(LastState4 NowState4){KeyNumber8;}}}else{KeyCount0;}//如果上个时间点按键按下这个时间点按键未按下则是松手瞬间if(NowState0){switch(LastState){case 1:KeyNumber9;break;case 2:KeyNumber10;break;case 3:KeyNumber11;break;case 4:KeyNumber12;break;default:break;}}}四、主函数 main.c /*by甘腾胜20250125 效果展示:可以在B站搜索“甘腾胜”或“gantengsheng”查看 单片机STC89C52RC 晶振6T11.0592MHz 波特率115200bps 外设ESP8266(01S)模块、LCD1602、DS1302、独立按键 注意 1ESP8266供电电压为3.3V接5V会发热严重RX和TX要交叉连接 2此版本不用更改ESP8266模块的默认波特率115200bps但下载的时候需要勾选“使能6T双倍速模式” 3无需设置ESP8266模块默认的WiFi模式AP模式超时20s运行时程序会自动设置为STA模式 4每隔24h会自动联网校时如果校时超时20s会重启ESP8266模块重新连接WiFi和网络并校时 5串口中断的优先级要比定时器0的高否则会影响通信 6代码末尾有月份、星期的英文以及网站返回的时间数据的样例强调1ESP8266模块供电电压为3.3V不能用5V 强调2下载的时候需要勾选“使能6T双倍速模式”操作说明K1 K2 K3 K4 【K4】手动联网校时*/#include REGX52.H //包含头文件 #include Delay.h #include UART.h #include Timer0.h #include KeyScan.h #include DS1302.h #include LCD1602.h//预设三个WiFi账号如果连接不上超时20s会连接下一个连接WiFi成功账号和密码保存到了Flash后下次上电自动连接 /*例设置第一个预设账号 如果WiFi账号是abc 如果WiFi密码是12345678 则应改成char code WiFi1[]ATCWJAP\abc\,\12345678\\r\n; */ char code WiFi1[]ATCWJAP\ganpan\,\01234567\\r\n; //发送的字符串中如果有双引号需要用反斜杠转义 char code WiFi2[]ATCWJAP\wulou\,\199019911992\\r\n; char code WiFi3[]ATCWJAP\GTS\,\01234567\\r\n;unsigned char KeyNum; //存储获得的键码值 char Judge[5]; //用来判断是不是我们想要保存的字符串 char TimeBuffer[25]; //用来存储接收到的时间的字符型的信息 bit OKFlag0; //接收到了ESP8266返回的OK文本的标志1接收到了0未接收到 bit ReadyFlag0; //ESP8266准备好了的标志1准备好了0未准备好 bit WiFiGotIPFlag0; //ESP8266连接WiFi且获取了IP的标志1已获取IP0未获取IP bit WiFiDisconnectFlag0; //未能连接WiFi的标志1未能连接0无 bit GetTimeFlag0; //从网络获取时间的标志1获取0不获取 bit GotTimeFlag0; //从网络获取了时间的标志1已获取0未获取到 char Time[7]; //存储接收到的字符型的时间数据转化之后的十进制数据索引0~6分别对应年、月、日、时、分、秒、星期 bit ShowOKFlag; //成功获取网络时间后显示“OK”的标志1显示0不显示 unsigned int T0Count1,T0Count2,T0Count3,T0Count4,T0Count5,T0Count6; //定时器计数的变量 unsigned int ProofTimeCount; //定时器中隔一段时间自动校时的计数 bit TimeOutFlag; //连接WiFi超时的标志1超时2未超时 bit TimeOutCountFlag1; //启动超时计数的标志1启动2不启动 bit ReadTimeFlag1; //从DS1302时钟芯片读取时间的标志1读取2不读取 char Offset1,Offset2,Offset3,Offset4,Offset5,Offset6; //数字向上滚动的偏移量 //时十位时个位分十位分个位秒十位秒个位 unsigned char LastHour_10,LastHour_1,LastMinute_10,LastMinute_1,LastSecond_10,LastSecond_1; bit ShowTimeFlag; //显示时间的标志1显示2不显示用来控制上电获取到网络时间后再显示时间/*** brief ESP8266初始化* param 无* retval 无*/ void ESP8266_Init(void) { LCD_Clear(); //LCD清屏LCD_ShowString(1,1,ESP8266); //第一行显示“ESP8266”表示等待ESP8266准备好Delay(100); //适当延时延时0.1s//退出透传模式如果ESP8266不断电只让单片机复位的话ESP8266就还处于透传模式发送AT指令会无效UART_SendString();Delay(1000); //退出透传模式要1s之后才能发AT指令if(ReadyFlag) //如果上电直接返回“ready”{ReadyFlag0;LCD_ShowString(2,1,ready); //LCD第二行显示“ready”表示ESP8266已准备好Delay(500);}else //如果不返回“ready”则重启一下ESP8266模块{UART_SendString(ATRST\r\n); //复位while(!ReadyFlag); //等待ESP8266返回readyReadyFlag0;LCD_ShowString(2,1,ready);Delay(500);}LCD_Clear();LCD_ShowString(1,1,WIFI); //LCD第一行显示“WIFI”表示等待ESP8266连接WiFi//WiFi账号密码保存在ESP8266的Flash中掉电不丢失//如果上次已经成功连接则上电自动按上次的网络名称和密码连接T0Count30; //超时的计数清零TimeOutFlag0; //超时的标志清零while(!WiFiGotIPFlag !WiFiDisconnectFlag !TimeOutFlag);if(TimeOutFlag) //如果是因为超时退出上面的while循环说明ESP8266处于AP模式{UART_SendString(ATCWMODE1\r\n); //发送AT指令设置为STAStation模式while(!OKFlag); //等待ESP8266返回“OK”OKFlag0;}if(WiFiGotIPFlag) //如果成功获取了IP{WiFiGotIPFlag0;LCD_ShowString(2,1,GOT IP); //表示ESP8266已连接WiFi并获取了IPDelay(500);}else //如果WiFi不能连接{ //WiFi账号密码是保存到ESP8266的flash里的如果在else中连接成功//下次上电就可以直接连接WiFi并获得IP就不会进入此else中WiFiDisconnectFlag0;LCD_ShowString(2,1,DISCONNECT); //表示ESP8266不能连接WiFiDelay(500);LCD_ShowString(2,1,CONNECTING1); //表示ESP8266正在连接第一个预设的WiFi账号T0Count30; //超时的计数清零TimeOutFlag0; //超时的标志清零//如果WiFi连接不成功就按下面的账号密码进行连接UART_SendString(WiFi1);while(!OKFlag !WiFiGotIPFlag !TimeOutFlag);OKFlag0;WiFiGotIPFlag0;if(TimeOutFlag) //如果是因为超时退出上面的while循环说明第一个预设的WiFi账号没连上{LCD_ShowString(2,1,CONNECTING2); //表示ESP8266正在连接第二个预设的WiFi账号T0Count30; //超时的计数清零TimeOutFlag0; //超时的标志清零//如果上面的WiFi连接不成功超时20s了就会尝试下面的账号密码进行连接//超时的时间不能少于15s否则会导致连接不成功//如果上面的WiFi连接成功就不会连接下面的WiFi账号UART_SendString(WiFi2);while(!OKFlag !WiFiGotIPFlag !TimeOutFlag);OKFlag0;WiFiGotIPFlag0;if(TimeOutFlag) //如果是因为超时退出上面的while循环说明第二个预设的WiFi账号没连上{LCD_ShowString(2,1,CONNECTING3); //第二位数码管显示“3”表示ESP8266正在连接第三个预设的WiFi账号//如果上面的WiFi连接不成功超时20s了就会尝试下面的账号密码进行连接//如果上面的WiFi连接成功就不会连接下面的WiFi账号UART_SendString(WiFi3);while(!OKFlag !WiFiGotIPFlag); //如果第三个WiFi账号连接不上就会在此处陷入死循环OKFlag0;WiFiGotIPFlag0;}}LCD_ShowString(2,1, );LCD_ShowString(2,1,GOT IP);//下面的处理不能少如果是第一次连上WiFi还会多返回一个“OK”暂时未知原因有大佬知道原因的请私信告知我一下谢谢//如果不处理会导致第一次连上WiFi后程序卡在数码管显示“5”Delay(1500); //延时1.5sOKFlag0; //延时不能少于1s要等ESP8266返回OK令OKFlag置1之后再将OKFlag置零}LCD_Clear();LCD_ShowString(1,1,CIPSTART); //表示ESP8266开始建立TCP连接UART_SendString(ATCIPSTART\TCP\,\www.beijing-time.org\,80\r\n); //建立 TCP 连接while(!OKFlag);OKFlag0;LCD_ShowString(2,1,CONNECT OK); //表示ESP8266已建立TCP连接Delay(500);LCD_Clear();LCD_ShowString(1,1,CIPMODE1); //表示ESP8266开始设置传输模式UART_SendString(ATCIPMODE1\r\n); //设置传输模式0为普通模式1为透传模式while(!OKFlag);OKFlag0;LCD_ShowString(2,1,OK); //表示ESP8266已经设置传输模式为透传模式Delay(500);LCD_Clear();LCD_ShowString(1,1,CIPSEND); //表示ESP8266开始发送数据//开始发送数据在透传模式时当输入单独一包 时返回普通 AT 指令模式要至少间隔 1 秒再发下一条 AT 指令UART_SendString(ATCIPSEND\r\n);while(!OKFlag );OKFlag0;LCD_ShowString(2,1,OK); //表示ESP8266已经准备好了可以发送数据了Delay(500); }/*** brief 将接收到的时间数据字符型转换为十进制的数据保存到时间数组Time中* param 无* retval 无*/ void ConvertTime(void) {Time[0](TimeBuffer[14]-0)*10(TimeBuffer[15]-0); //年if(TimeBuffer[8]J TimeBuffer[9]a){Time[1]1;} //月else if(TimeBuffer[8]F){Time[1]2;}else if(TimeBuffer[8]M TimeBuffer[9]a TimeBuffer[10]r){Time[1]3;}else if(TimeBuffer[8]A TimeBuffer[9]p){Time[1]4;}else if(TimeBuffer[8]M TimeBuffer[9]a TimeBuffer[10]y){Time[1]5;}else if(TimeBuffer[8]J TimeBuffer[9]u TimeBuffer[10]n){Time[1]6;}else if(TimeBuffer[8]J TimeBuffer[9]u TimeBuffer[10]l){Time[1]7;}else if(TimeBuffer[8]A TimeBuffer[9]u){Time[1]8;}else if(TimeBuffer[8]S){Time[1]9;}else if(TimeBuffer[8]O){Time[1]10;}else if(TimeBuffer[8]N){Time[1]11;}else if(TimeBuffer[8]D){Time[1]12;}Time[2](TimeBuffer[5]-0)*10(TimeBuffer[6]-0); //日Time[3](TimeBuffer[17]-0)*10(TimeBuffer[18]-0); //时Time[4](TimeBuffer[20]-0)*10(TimeBuffer[21]-0); //分Time[5](TimeBuffer[23]-0)*10(TimeBuffer[24]-0); //秒if(TimeBuffer[0]M){Time[6]1;} //星期else if(TimeBuffer[0]T TimeBuffer[1]u){Time[6]2;}else if(TimeBuffer[0]W){Time[6]3;}else if(TimeBuffer[0]T TimeBuffer[1]h){Time[6]4;}else if(TimeBuffer[0]F){Time[6]5;}else if(TimeBuffer[0]S TimeBuffer[1]a){Time[6]6;}else if(TimeBuffer[0]S TimeBuffer[1]u){Time[6]7;}//返回的是GMT北京时间比格林威治时间(Greenwich Mean Time简称GMT)早8小时。Time[3]8; //UTC/GMT 8.00 东八区if(Time[3]/24) //如果加8小时后是第二天{Time[3]%24;Time[6]; //星期增加if(Time[6]7){Time[6]1;}Time[2];if(Time[2]32) //大月{Time[2]1;Time[1];if(Time[1]12){Time[1]1;Time[0];Time[0]%100;}}else if(Time[2]31) //小月{if(Time[1]4 || Time[1]6 || Time[1]9 || Time[1]11){Time[2]1;Time[1];}}else if(Time[2]30) //闰年二月{if(Time[1]2 Time[0]%40){Time[2]1;Time[1];}}else if(Time[2]29) //平年二月{if(Time[1]2 Time[0]%4){Time[2]1;Time[1];}}}/*由于网络延迟、数据的处理等导致处理后的时间慢一两秒这里进行补偿加多2秒*/if(Time[3]23 || Time[4]59 || Time[5]58) //如果加多2秒不会跳到第二天{Time[5]2;if(Time[5]60){Time[5]%60;Time[4];if(Time[4]60){Time[4]%60;Time[3];}}}}/*** brief 更新显示时间* param 无* retval 无*/ void ShowTime(void) {LCD_ShowChar(1,8,-);LCD_ShowChar(1,11,-);LCD_ShowChar(2,6,:);LCD_ShowChar(2,9,:);LCD_ShowString(1,1, );LCD_ShowString(2,1, );LCD_ShowChar(1,4,2);LCD_ShowChar(1,5,0);LCD_ShowNum(1,6,DS1302_Time[0],2); //年LCD_ShowNum(1,9,DS1302_Time[1],2); //月LCD_ShowNum(1,12,DS1302_Time[2],2); //日LCD_ShowNum(2,13,DS1302_Time[6],1); //星期LCD_ScrollNum(2,4,0,DS1302_Time[3]/10,3,Offset1); //时十位if(DS1302_Time[3]/100){LCD_ScrollNum(2,5,1,DS1302_Time[3]%10,4,Offset2); //时个位}else{LCD_ScrollNum(2,5,1,DS1302_Time[3]%10,10,Offset2); //时个位} LCD_ScrollNum(2,7,2,DS1302_Time[4]/10,6,Offset3); //分十位LCD_ScrollNum(2,8,3,DS1302_Time[4]%10,10,Offset4); //分个位LCD_ScrollNum(2,10,4,DS1302_Time[5]/10,6,Offset5); //秒十位LCD_ScrollNum(2,11,5,DS1302_Time[5]%10,10,Offset6); //秒个位if(ShowOKFlag){LCD_ShowChar(1,16,O);LCD_ShowChar(2,16,K);}else{LCD_ShowChar(1,16,20); //无显示LCD_ShowChar(2,16,20); //无显示} }void main() {unsigned char i;P2_50; //防止开发板的蜂鸣器发声LCD_Init(); //LCD1602初始化Timer0_Init(); //定时器0初始化DS1302_Init(); //DS1302初始化UART_Init(); //串口初始化ESP8266_Init(); //ESP8266初始化WiFiGotIPFlag0; //ESP8266初始化的时候回显信息会让WiFiGotIPFlag置1TimeOutCountFlag0; //TimeOutCountFlag置0不进行超时的计时TimeOutFlag0; //超时标志清零LCD_Clear();GetTimeFlag1; //上电获取一次网络时间while(1){KeyNumKey(); //获取键码值if(KeyNum) //如果有按键按下{if(KeyNum12) //如果按下K4松手瞬间{GetTimeFlag1; //手动校时}}if(WiFiGotIPFlag) //如果不小心触碰到ESP8266模块导致接触不良而重启模块的话获取IP后重新连接网络{TimeOutCountFlag1; //启动超时的计时防止出错卡在while循环LCD_Clear();LCD_ShowString(1,1,CIPSTART); //表示ESP8266开始建立TCP连接UART_SendString(ATCIPSTART\TCP\,\www.beijing-time.org\,80\r\n); //建立 TCP 连接while(!OKFlag !TimeOutFlag);OKFlag0;TimeOutFlag0;LCD_ShowString(2,1,CONNECT OK); //表示ESP8266已建立TCP连接Delay(500);LCD_Clear();LCD_ShowString(1,1,CIPMODE1); //表示ESP8266开始设置传输模式UART_SendString(ATCIPMODE1\r\n); //设置传输模式0为普通模式1为透传模式while(!OKFlag !TimeOutFlag);OKFlag0;TimeOutFlag0;LCD_ShowString(2,1,OK); //表示ESP8266已经设置传输模式为透传模式Delay(500);LCD_Clear();LCD_ShowString(1,1,CIPSEND); //表示ESP8266开始发送数据//开始发送数据在透传模式时当输入单独一包 时返回普通 AT 指令模式要至少间隔 1 秒再发下一条 AT 指令UART_SendString(ATCIPSEND\r\n);while(!OKFlag !TimeOutFlag);OKFlag0;TimeOutFlag0;LCD_ShowString(2,1,OK); //表示ESP8266已经准备好了可以发送数据了Delay(500);WiFiGotIPFlag0; //要放在最后否则回显信息又会让WiFiGotIPFlag置1TimeOutCountFlag0; //停止超时的计时GetTimeFlag1;}if(GetTimeFlag) //从网络获取时间{TimeOutFlag0; //超时的标志清零TimeOutCountFlag1; //启动超时的计时如果获取时间超时则重启ESP8266模块GetTimeFlag0;//透传模式下向“www.beijing-time.org”随便发送点什么就会返回时间信息UART_SendString(T\r\n);}if(TimeOutFlag) //如果获取时间超时了可能是ESP8266没接收到指令或者网络断开了{TimeOutFlag0; //超时的标志清零TimeOutCountFlag0; //停止超时的计时UART_SendString(); //退出透传模式Delay(1000); //退出透传模式要1s后才能发AT指令UART_SendString(ATRST\r\n); //重启一下模块}if(GotTimeFlag) //如果获取了时间{GotTimeFlag0;TimeOutFlag0; //超时的标志清零TimeOutCountFlag0; //停止超时的计时ConvertTime();for(i0;i7;i){DS1302_Time[i]Time[i];}DS1302_SetTime(); //将获取到的网络时间写入DS1302时钟芯片LastHour_10DS1302_Time[3]/10; //成功获取时间后更新变量的值LastHour_1DS1302_Time[3]%10;LastMinute_10DS1302_Time[4]/10;LastMinute_1DS1302_Time[4]%10;LastSecond_10DS1302_Time[5]/10;LastSecond_1DS1302_Time[5]%10;ShowOKFlag1; //校时后1行16列显示“O”2行16列显示“K”显示2sT0Count40; //显示“OK”2s的计数清零T0Count20; //每次成功校对时间后用于自动校时的计数清0ProofTimeCount0; //每次成功校对时间后用于自动校时的计数清0ShowTimeFlag1;}if(ReadTimeFlag ShowTimeFlag) //从DS1302芯片中读取时间{ReadTimeFlag0;DS1302_ReadTime(); //读取时间if(LastHour_10 ! DS1302_Time[3]/10){Offset1-8;T0Count60;}if(LastHour_1 ! DS1302_Time[3]%10){Offset2-8;T0Count60;}if(LastMinute_10 ! DS1302_Time[4]/10){Offset3-8;T0Count60;}if(LastMinute_1 ! DS1302_Time[4]%10){Offset4-8;T0Count60;}if(LastSecond_10 ! DS1302_Time[5]/10){Offset5-8;T0Count60;}if(LastSecond_1 ! DS1302_Time[5]%10){Offset6-8;T0Count60;} LastHour_10DS1302_Time[3]/10;LastHour_1DS1302_Time[3]%10;LastMinute_10DS1302_Time[4]/10;LastMinute_1DS1302_Time[4]%10;LastSecond_10DS1302_Time[5]/10;LastSecond_1DS1302_Time[5]%10;ShowTime(); //更新显示时间}} }void Timer0_Routine() interrupt 1 //定时器0中断函数 {//因使能了6T双倍速模式所以定时器计算器中12T模式定时20ms对应的是6T模式的10msTL00x00; //设置定时初值定时10ms晶振11.0592MHzTH00xB8; //设置定时初值定时10ms晶振11.0592MHzT0Count1;T0Count2;if(TimeOutCountFlag){T0Count3;} //TimeOutCountFlag为1才开始超时的计时else{T0Count30;}T0Count4;T0Count5;T0Count6;if(T0Count12) //每隔20ms检测一次按键{T0Count10;Key_Tick();}if(T0Count26000) //1min即60s{T0Count20;ProofTimeCount;ProofTimeCount%1440; //60*1440s24h每隔24小时自动联网校时if(!ProofTimeCount){GetTimeFlag1;}}if(T0Count32000) //ESP8266连接WiFi的超时时间20s{T0Count30;TimeOutFlag1;}if(T0Count4200) //如果从网络获取了时间显示“OK”2秒钟{T0Count40;ShowOKFlag0;}if(T0Count510) //每隔100ms从DS1302时钟芯片读取一次时间{T0Count50;ReadTimeFlag1;}if(T0Count67) //每隔70ms滚动一个像素{T0Count60;Offset1;Offset2;Offset3;Offset4;Offset5;Offset6;if(Offset10){Offset10;}if(Offset20){Offset20;}if(Offset30){Offset30;}if(Offset40){Offset40;}if(Offset50){Offset50;}if(Offset60){Offset60;}} }void UART_Routine() interrupt 4 //串口中断函数 {static unsigned char i,j;char TempChar; //缓存变量static bit ReceiveTimeFlag0; //开始保存时间数据的标志1开始保存0不保存if(RI1) //如果接收标志位为1接收到了数据{RI0; //接收标志位清0TempCharSBUF; //用缓存变量取出SBUF的数据//如果接收到的字符是下面四个之一则从数组Judge的索引0的位置开始保存接下来的字符if(TempCharO || TempCharD || TempCharr || TempCharI){i0;}//如果不小心触碰到ESP8266模块导致接触不良而重启模块的话获取IP后令WiFiGotIPFlag置1再在主函数中重新连接网络//返回的时间数据里有“PI”会误使WiFiGotIPFlag置1所以要有下面的处理if(TempCharI){Judge[1]\0;}Judge[i]TempChar;i;if(ReceiveTimeFlag) //开始接收包含时间信息的字符串{j;if(j4){TimeBuffer[j-4]TempChar;}if(j28){ReceiveTimeFlag0;GotTimeFlag1;}}//接收到“ready”注意下面的if中Judge[1]和Judge[2]的字符不能和Judge[0]的重复if(Judge[0]r Judge[1]e Judge[2]a){Judge[1]\0;ReadyFlag1;}//接收到“DISCONNECT”if(Judge[0]I Judge[1]S Judge[2]C){Judge[1]\0;WiFiDisconnectFlag1;}//接收到“GOT IP”if(Judge[0]I Judge[1]P){Judge[1]\0;WiFiGotIPFlag1;}//接收到“OK”if(Judge[0]O Judge[1]K){Judge[1]\0;OKFlag1;}//接收到“Date: ”,说明接下来的字符串包含时间信息if(Judge[0]D Judge[1]a Judge[2]t){Judge[1]\0;ReceiveTimeFlag1;j0;}i%5; //Judge数组只有5个数据} }/*月份和星期January一月 February二月 March三月 April四月 May五月 June六月 July七月 August八月 September九月 October十月 November十一月 December十二月Monday星期一 Tuesday星期二 Wednesday星期三 Thursday星期四 Friday星期五 Saturday星期六 Sunday星期日*//*网站返回的时间数据第四行HTTP/1.1 400 Bad Request Content-Type: text/html; charsetus-ascii Server: Microsoft-HTTPAPI/2.0 Date: Mon, 13 Jan 2025 08:27:07 GMT Connection: close Content-Length: 326!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.01//ENhttp://www.w3.org/TR/html4/strict.dtd HTMLHEADTITLEBad Request/TITLE META HTTP-EQUIVContent-Type Contenttext/html; charsetus-ascii/HEAD BODYh2Bad Request - Invalid Verb/h2 hrpHTTP Error 400. The request verb is invalid./p /BODY/HTML*/总结 LCD1602滚动显示时分秒的实现没用多少时间因为之前做过一个32X8点阵屏的时钟原理是差不多的不过LCD1602由于硬件原因会拖影现象。I2C版本的LCD1602的通信速率比较慢如果星期的显示耗时较长实时更新会导致走时的显示不流畅即看起来会有卡顿的现象所以星期的显示在检测到星期发生变化再进行更新显示。
http://www.hkea.cn/news/14573875/

相关文章:

  • html怎么做音乐网站游戏网站建设策划方案模板
  • 做网站怎么申请域名网站 迁移
  • 毕业设计做 什么网站好wordpress ftp重置
  • net网站阿里云主机配置软件开发培训要学多久
  • 做网站有什么框架网站上的图片一般多大合适
  • 做网站实训心得合肥建设工程网
  • 河南网站优化排名网站备案被注销的原因
  • 浙江省工程建设管理质量协会网站Wordpress 打开xml rpc
  • 怎样设计网站前端和后端哪个常熬夜
  • 切实加强门户网站建设国家反诈中心app下载怎么注册
  • 泰安网络推广 网站建设 网站优化微信公众号网站怎么做
  • 网站需要怎么优化比较好设计网站流程
  • php做网站开发怎么给网站做推广
  • 用thinksns做的网站工作室推广网站
  • 做网站宿迁做英文网站违法吗
  • 武威网站建设优化怎么样做电影网站
  • 服务佳的网站建设大连有做途家网站吗
  • 招生网站怎么做外国优秀网站设计
  • 网站素材 图标为企网站
  • 做网站的服务器有什么作用带分期功能的网站建设
  • 网站注册域名企业信息查询平台有哪些
  • 网站建设工作量评估报价表wordpress去版权信息
  • 做汽配外贸是在哪个网站做html编辑器有哪些
  • 网站域名被黑贵阳网站建设王道下拉惠
  • 阳谷网站建设费用网络培训资格证书如何获得
  • 深圳做网站的好公司淡水网站建设
  • 网站建设方案页面设计分析苏州专业做网站公司有哪些
  • 成都建工雅安建设有限责任公司网站太原seo外包公司
  • 学校网站建站漂亮的html页面源码
  • 网站建设目的是什么京东网站设计特点