国际近期新闻/来宾网站seo

国际近期新闻,来宾网站seo,做网站的公司哪家有名,app制作软件平台一、数据存储 先把需要的模块导入做个测试 //main.c#include <REGX52.H> #include " LCD1602.h" #include " Key.h"void main() {LCD_Init();LCD_ShowString(1,1,"Hello");while(1){}} 代码思路 分成两块写&#xff0c;一块写I2C.c&am…

一、数据存储

先把需要的模块导入做个测试

//main.c#include <REGX52.H>
#include " LCD1602.h"
#include " Key.h"void main()
{LCD_Init();LCD_ShowString(1,1,"Hello");while(1){}}

代码思路

分成两块写,一块写I2C.c,一块写AT24C02.c。I2C写起始,终止,发送,接收,发送应答,接收应答;AT写两个数据帧,一个是写入数据帧,一个是读取数据帧。

1.I2C模块

记得在.h文件里声明好

第一步先位定义

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

下面的函数写作均可以看上一节推文的图来照着写

第二步写

起始函数

假如我们先发送再接收数据帧,就无法确定上一节结束后的SCL和SDA的状态,所以一开始要置1初始化,然后先拉下SDA(置0),再拉下SCL

void I2C_Start(void)
{I2C_SDA=1;I2C_SCL=1;I2C_SDA=0;I2C_SCL=0;
}

结束函数

跟起始函数一样的我们无法确定初始状态,所以要初始化,但因为SCL无论发送接收还是应答最后都是0,所以在这里不初始化也没问题

void I2C_Stop(void)
{I2C_SDA=0;I2C_SCL=1;	I2C_SDA=1;}

发送数据函数

在开始时SCL是0,SDA=传入数据的最高位,我们定义参数unsigned char Byte为传入数据。然后把SCL置1再置0(这里扩展一下,除了写周期是5ms,其他操作基本在1us以下,不用加延时函数)接下来SCL一直置1置0,而SDA要根据Byte的数据来决定,所以我们用for循环来读取Byte的位数据传给SDA

void I2C_SendByte(unsigned char Byte)
{unsigned char i;for(i=0;i<8;i++){I2C_SDA=Byte&(0x80>>i);I2C_SCL=1;I2C_SDA=0;}
}

接收数据函数

既然是接收,就要写有返回值的函数

在这里SDA初始化需要为1,然后我们对SDA的值做判断,如果SDA=1,我们就对该值置1,如果SDA=0,我们就不进行操作。我们只需要定义Byte=0x00,然后对0x80进行或等于,最后再套上for循环

unsigned char I2C_ReceiveByte(void)
{unsigned char i,Byte=0x00;I2C_SDA=1;for(i=0;i<8;i++){I2C_SCL=1;if(I2C_SDA){Byte|=(0x80>>i);}	I2C_SCL=0;}return Byte;
}

发送应答函数

下面介绍一种C51特有的数据类型,bit,只有一位且只能存0和1

我们就定义一个参数bit作为应答位

先让SDA=应答位,再把SCL拉高再拉低

void I2C_SendAck(bit AckBit)
{I2C_SDA=AckBit;I2C_SCL=1;I2C_SCL=0;
}

接收应答函数 

这里跟前面一样,但可能有一点难理解,这样解释一下

我们要明确,我们操作的始终是主机,主机接收应答时,从机时自动发送应答的,并不是我们操作从机做出什么应答,我们只需接收从机发送的应答即可

我们将SDA置1把SDA控制权给从机后,从机就会把SDA置1或0(从机发送应答,主机接收应答)所以我们只需接收SDA即可

unsigned char I2C_ReceiveAck(void)
{bit AckBit;I2C_SDA=1;I2C_SCL=1;Ackbit=I2C_SDA;I2C_SCL=0;return Ackbit;
}

最后加上注释我们的I2C模块就完成啦

#include <REGX52.H>sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;/*** @brief  I2C开始* @param  无* @retval 无*/
void I2C_Start(void)
{I2C_SDA=1;I2C_SCL=1;I2C_SDA=0;I2C_SCL=0;
}/*** @brief  I2C停止* @param  无* @retval 无*/
void I2C_Stop(void)
{I2C_SDA=0;I2C_SCL=1;	I2C_SDA=1;}/*** @brief  I2C发送一个字节* @param  Byte 要发送的字节* @retval 无*/
void I2C_SendByte(unsigned char Byte)
{unsigned char i;for(i=0;i<8;i++){I2C_SDA=Byte&(0x80>>i);I2C_SCL=1;I2C_SCL=0;}
}/*** @brief  I2C接收一个字节* @param  无* @retval 接收到的一个字节数据*/
unsigned char I2C_ReceiveByte(void)
{unsigned char i,Byte=0x00;I2C_SDA=1;for(i=0;i<8;i++){I2C_SCL=1;if(I2C_SDA){Byte|=(0x80>>i);}	I2C_SCL=0;}return Byte;
}/*** @brief  I2C发送应答位* @param  AckBit 应答位,0为应答,1为非应答* @retval 无*/
void I2C_SendAck(unsigned char AckBit)
{I2C_SDA=AckBit;I2C_SCL=1;I2C_SCL=0;
}/*** @brief  I2C接收应答位* @param  无* @retval 接收到的应答位,0为应答,1为非应答*/
unsigned char I2C_ReceiveAck(void)
{unsigned char Ackbit;I2C_SDA=1;I2C_SCL=1;Ackbit=I2C_SDA;I2C_SCL=0;return Ackbit;
}
//I2C.h#ifndef __I2C_H__
#define __I2C_H__void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(bit Ackbit);
unsigned char I2C_ReceiveAck(void);#endif

2.AT24C02模块

这里我们要写两个函数,一个是字节写,一个是数据读

先来写字节写

首先是调用I2C起始,然后是I2C发送字节,在这里SLAVE ADDRESS+W是固定值0xA0,我们直接定义它,等下的SLAVE ADDRESS+R是0xA1,但是我们只需要定义一个,然后改他的最后一位就可以。

这里可以简单测试一下我们之前的代码有没有错,没错的情况是LED灯全亮,把地址故意写错就只会亮268

//AT24C02.c
#define AT24C02_ADDRESS 0xA0void AT24C02_WriteByte(unsigned char WordAddress,Data)
{unsigned char Ack;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);Ack=I2C_ReceiveAck();if(Ack==0)P2=0x00;}

这是完整代码,不难,只需要照着图写,每一个步骤对应一个函数调用,跟拼图一样

void AT24C02_WriteByte(unsigned char WordAddress,Data)
{I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();
}

下面写数据读

unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C02_ADDRESS|0x01);I2C_ReceiveAck();Data=I2C_ReceiveByte();I2C_SendAck(1);I2C_Stop();return Data;
}

 在这里我们验证一下

正常情况下是在LCD第二行显示066,这里很容易出问题,因为前面写了很多函数,一错误千奇百怪,解决方法也各不相同,我第一次显示255,是因为AT函数里忘加终止函数了,第二次显示002是因为在I2C函数里SDA和SCL的顺序乱了,调整过来后也显示成功066了。

还有前面提到的,写入操作是5ms,在写入后我们要跟上一个延时函数,不然会出错

#include <REGX52.H>
#include " LCD1602.h"
#include " Key.h"
#include " AT24C02.h"
#include " Delay.h"unsigned char Data;void main()
{LCD_Init();LCD_ShowString(1,1,"Hello");AT24C02_WriteByte(1,66);Delay(5);Data=AT24C02_ReadByte(1);LCD_ShowNum(2,1,Data,3)while(1){	}}

最后加上注释我们的AT24C02模块也完成啦

//AT24C02.c#include <REGX52.H>
#include "I2C.H"#define AT24C02_ADDRESS 0xA0/*** @brief  AT24C02写入一个字节* @param  WordAddress 要写入字节的地址* @param  Data 要写入的数据* @retval 无*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();
}/*** @brief  AT24C02读取一个字节* @param  WordAddress 要读取字节的地址* @retval 读取的地址*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C02_ADDRESS|0x01);I2C_ReceiveAck();Data=I2C_ReceiveByte();I2C_SendAck(1);I2C_Stop();return Data;
}
//AT24C02.h#ifndef __AT24C02_H__
#define __AT24C02_H__void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);#endif

3.数据存储主函数

如果按下按键1,数据++,LCD显示;如果按下按键2,数据--,LCD显示;如果按下按键3,把数据写入AT24C02,即存储,因为数据是16位,就要拆开,把高八位存到位置1,把高八位存到位置0,在LCD上显示写入成功,延时一秒再清零;如果按下按键4,把数据读出来,先读出位置0,再读出位置1,存到数据,然后LCD显示读取成功,延时一秒再清零。

//main#include <REGX52.H>
#include " LCD1602.h"
#include " Key.h"
#include " AT24C02.h"
#include " Delay.h"unsigned char KeyNum;
unsigned int Num;void main()
{LCD_Init();LCD_ShowNum(1,1,Num,5);while(1){	KeyNum=Key();if(KeyNum==1){Num++;LCD_ShowNum(1,1,Num,5);}if(KeyNum==2){Num--;LCD_ShowNum(1,1,Num,5);}if(KeyNum==3){AT24C02_WriteByte(0,Num%256);Delay(5);AT24C02_WriteByte(1,Num/256);Delay(5);LCD_ShowString(2,1,"Write OK");Delay(1000);LCD_ShowString(2,1,"         ");}if(KeyNum==4){Num=AT24C02_ReadByte(0);Num|=AT24C02_ReadByte(1)<<8;LCD_ShowNum(1,1,Num,5);LCD_ShowString(2,1,"READ OK");Delay(1000);LCD_ShowString(2,1,"       ");}}}

到这里我们就完成啦。烧录后按按键1会加,按按键2会减,然后按按键3存储,断电后重启再按按键4会读取。

二、秒表(定时器扫描按键数码管)

总体思路:

Key和Nixie都需要中断,但是Timer0里只能有一个中断函数,不能定义多个

我们就需要一种新的写法,在main里写一个中断函数,然后在Key和Nixie里调用这个中断函数,假如Key需要每隔多少s一次中断,我们就令main里的定时器计数多少,这样每隔多久就会自动调用多少 

这样就避免模块里多个函数融合在一起,或者交叉使用,这样干净简洁

1.定时器扫描按键

下面解释一下定时器扫描按键是怎么工作

我们知道按键按下松开会有一下下的抖动,按键默认是高电平,原来我们是检测是否产生低电平,如果有就Delay把抖动滤掉,然后while死循环等检测到高电平,然后Delay把抖动滤掉,这样的while死循环死等是对CPU的资源浪费

现在我们每个20ms读取当前的按键值,而不是死等,这个20ms就可以直接把抖动滤掉,即使在抖动中也无所谓,因为不管读到高/低电平,最终出来的数都会是没有抖动的,高电平就和上一个20ms的接轨,低电平就和下一个20ms的接轨。

我们还需要用一个变量记住当前的状态和上一个状态,如果现在是0,上一个状态是1,现在就是按键按下的瞬间;如果现在是1,上一个状态是0,现在就是按键松开的瞬间。

我们在检测到按键松手的瞬间就定义一个变量标识符,只有当标识符为1才会一直读取按键值,这样就可以避免死等

//key.c#include <REGX52.H>
#include "DELAY.h"unsigned char Key_KeyNumber;unsigned char Key(void)
{unsigned char Temp=0;Temp=Key_KeyNumber;Key_KeyNumber=0;return Temp;
}unsigned int Key_GetState()
{unsigned char KeyNumber=0;if(P3_1==0){KeyNumber=1;}if(P3_0==0){KeyNumber=2;}if(P3_2==0){KeyNumber=3;}if(P3_3==0){KeyNumber=4;}return KeyNumber;	
}void Key_Loop(void)
{static unsigned char 	NowState,LastState;LastState=NowState;NowState=Key_GetState();if(LastState==1&&NowState==0){Key_KeyNumber=1;}if(LastState==2&&NowState==0){Key_KeyNumber=2;}if(LastState==3&&NowState==0){Key_KeyNumber=3;}if(LastState==4&&NowState==0){Key_KeyNumber=4;}}
//Key.h#ifndef __KEY_H_
#define __KEY_H_unsigned int Key();
void Key_Loop(void);#endif
//main.c#include <REGX52.H>
#include " Timer0.h"
#include " Key.h"
#include " Delay.h"
#include " Nixie.h"unsigned char KeyNum;
unsigned char Temp;void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum)Temp=KeyNum;Nixie(1,Temp);}}void Timer0_Routine() interrupt 1
{static unsigned int	T0Count;TL0 = 0x18;  //设置定时初值TH0 = 0xFC;  //设置定时初值T0Count++;if(T0Count>=20){T0Count=0;Key_Loop();}}

2.定时器扫描数码管

数码管也有Delay,如果Delay太久会影响显示效果,即主函数不能有过多的操作,而定时器又可以替代Delay的作用

定时器扫描数码管可以确保数码有很高的优先级,一直在扫描,不会被Delay

定义一个显示缓存区,存9个数据

unsigned char Nixie_Buf[9];unsigned char NixieTable[]={0x3F,0x06,0x5b,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

先清零位选,再段选,再位选,这样我们只需隔一段时间调用这个函数,也能起到延时的效果 

void Nixie(unsigned char Location,Number)
{P0=0x00;switch(Location){case 1:P2_4=0;P2_3=0;P2_2=0;break;case 2:P2_4=0;P2_3=0;P2_2=1;break;case 3:P2_4=0;P2_3=1;P2_2=0;break;case 4:P2_4=0;P2_3=1;P2_2=1;break;case 5:P2_4=1;P2_3=0;P2_2=0;break;case 6:P2_4=1;P2_3=0;P2_2=1;break;case 7:P2_4=1;P2_3=1;P2_2=0;break;case 8:P2_4=1;P2_3=1;P2_2=1;break;}P0=NixieTable[Number];
}

写一个循环函数,每调用一次显示一位,无条件每隔2ms显示一次

void Nixie_Loop(void)
{static unsigned char i;Nixie(i,Nixie_Buf[i]);i++;if(i>=9){i=1;}
}

这样我们只需要在主函数里调用Nixie_Loop这个函数,就可以做到同时扫描8位

下面再优化一下,把函数也改的规范一点

Nixie_Buf是数据缓存区,一共有9位,但是我们的数码管只有八位,所以Loop函数是从数组的第二位,也就是[1]开始的,所以作为第一位的[0]被跳过,也正是因为跳过了第一位,所以数组的长度是8+1=9

NixieTable是数码管显示数字对应的段码表,新增第十位对应是0,原因后面解释

而Nixie_Buf[]和NixieTable[]数组,是通过函数Nixie_Loop()函数中调用函数Nixie()来实现的

我们可以观察到Nixie_Loop()函数里,调用了Nixie_Scan(i,Nixie_Buf[i]);我们知道Nixie_Scan函数里前面的参数i是决定在哪个LED上显示,而后面的参数Nixie_Buf[i],被嵌套在P0=NixieTable[Number]里,他会通过i的选择,在Nixie_Buf里找到对应的数,再通过这个数,在NixieTable里找到与这个数相对应的数。

而我们前面把Nixie_Buf[]全给10(跳过第一位),也就是说无论

i=任何数

Nixie_Buf[i]=10

NixieTable[10]=0

即什么都不显示

此时我们再写一个新的函数Nixie_SetBuf,就可以通过传入参数,而改变Nixie_Buf里的值,这样就能选取到NixieTable[]其他的数,也就是数码管能显示其他的数字了

//Nixie.cinclude <REGX52.H>
#include "Delay.h"unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10};unsigned char NixieTable[]={0x3F,0x06,0x5b,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};void Nixie_SetBuf(unsigned char Location,Number)
{Nixie_Buf[Location]=Number;}void Nixie_Scan(unsigned char Location,Number)
{P0=0x00;switch(Location){case 1:P2_4=0;P2_3=0;P2_2=0;break;case 2:P2_4=0;P2_3=0;P2_2=1;break;case 3:P2_4=0;P2_3=1;P2_2=0;break;case 4:P2_4=0;P2_3=1;P2_2=1;break;case 5:P2_4=1;P2_3=0;P2_2=0;break;case 6:P2_4=1;P2_3=0;P2_2=1;break;case 7:P2_4=1;P2_3=1;P2_2=0;break;case 8:P2_4=1;P2_3=1;P2_2=1;break;}P0=NixieTable[Number];
}void Nixie_Loop(void)
{static unsigned char i;Nixie_Scan(i,Nixie_Buf[i]);i++;if(i>=9){i=1;}
}
//Nixie.h#ifndef __NIXIE_H
#define __NIXIE_Hvoid Nixie_Scan(unsigned char Location,Number);
void Nixie_Loop(void);
void Nixie_SetBuf(unsigned char Location,Number);#endif

 这样就能实现同时在数码管123上都显示我们按下的按键数值

注意这里我们还修改了定时器的计时值,分成两个,T0Count1是按键的,T0Count2是数码管的

//main#include <REGX52.H>
#include " Timer0.h"
#include " Key.h"
#include " Delay.h"
#include " Nixie.h"unsigned char KeyNum;
unsigned char Temp;void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum){Nixie_SetBuf(1,KeyNum);Nixie_SetBuf(2,KeyNum);Nixie_SetBuf(3,KeyNum);}}
}void Timer0_Routine() interrupt 1
{static unsigned int	T0Count1,T0Count2;TL0 = 0x18;  //设置定时初值TH0 = 0xFC;  //设置定时初值T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop();}T0Count2++;if(T0Count2>=2){T0Count2=0;Nixie_Loop();}}

下面我们实现在数码管上显示秒表

我们先让数码管显示00-00-00,显示的函数前面我们写了,0也有,那这个“-”呢,自然就是要在NixieTable里加上“0x40”了(这里一个小妙招,我们对3和8在数码管上是不是正好缺了一个“-”,那么“-”就等于0x70对应“8”减去0x30对应“3”刚好就等于0x40)

然后我们安在主函数里调用显示

我们定义了分,秒,和百分秒

void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum){}Nixie_SetBuf(1,Min/10);Nixie_SetBuf(2,Min%10);Nixie_SetBuf(3,11);Nixie_SetBuf(4,Sec/10);Nixie_SetBuf(5,Sec%10);Nixie_SetBuf(6,11);Nixie_SetBuf(7,MinSec/10);Nixie_SetBuf(8,MinSec%10);}
}

接着我们怎么让他跑起来呢(计时)

我们就要用到计时器,我们先像刚才一样定义一个循环函数,然后在定时器里定义一个新的计时,来循环调用这个循环函数

	T0Count3++;if(T0Count3>=10){T0Count3=0;Sec_Loop();}

然后我们再去写循环函数,Sec_Loop

void Sec_Loop(void)
{MinSec++;if(MinSe>=100){MinSec=0;Sec++;if(Sec>60){Sec=0;Min++;if(Min>=60){Min=0;}	}}
}

这样我们的函数就能跑起来了

那我们应该怎么控制启动和暂停呢

定义一个变量,如果这个变量非1就不执行刚才的循环函数,然后如果keynum=1,这个变量取反一下,如果keynum=2,让分秒百分秒都清零

这样我们就实现了默认显示“00-00-00”,按下按键1开始计时,再次按下暂停;按下按键2清零

#include <REGX52.H>
#include " Timer0.h"
#include " Key.h"
#include " Delay.h"
#include " Nixie.h"unsigned char KeyNum;
unsigned char Min,Sec,MinSec;
unsigned char RunFlag;void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum==1){RunFlag=!RunFlag;}if(KeyNum==2){Min=0;Sec=0;MinSec=0;}Nixie_SetBuf(1,Min/10);Nixie_SetBuf(2,Min%10);Nixie_SetBuf(3,11);Nixie_SetBuf(4,Sec/10);Nixie_SetBuf(5,Sec%10);Nixie_SetBuf(6,11);Nixie_SetBuf(7,MinSec/10);Nixie_SetBuf(8,MinSec%10);}
}void Sec_Loop(void)
{if(RunFlag){MinSec++;if(MinSec>=100){MinSec=0;Sec++;if(Sec>60){Sec=0;Min++;if(Min>=60){Min=0;}	}}}
}void Timer0_Routine() interrupt 1
{static unsigned int	T0Count1,T0Count2,T0Count3;TL0 = 0x18;  //设置定时初值TH0 = 0xFC;  //设置定时初值T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop();}T0Count2++;if(T0Count2>=2){T0Count2=0;Nixie_Loop();}T0Count3++;if(T0Count3>=10){T0Count3=0;Sec_Loop();}}

接下来我们再加入存储功能,即AT24C02

如果按键3按下,写入,调用,然后延时,分别存入分秒百分秒

如果按键4按下,读出,调用

		if(KeyNum==3){AT24C02_WriteByte(0,Min);Delay(5);AT24C02_WriteByte(1,Sec);Delay(5);AT24C02_WriteByte(2,MinSec);Delay(5);}if(KeyNum==4){Min=AT24C02_ReadByte(0);Sec=AT24C02_ReadByte(1);MinSec=AT24C02_ReadByte(2);}Nixie_SetBuf(1,Min/10);Nixie_SetBuf(2,Min%10);Nixie_SetBuf(3,11);Nixie_SetBuf(4,Sec/10);Nixie_SetBuf(5,Sec%10);Nixie_SetBuf(6,11);Nixie_SetBuf(7,MinSec/10);Nixie_SetBuf(8,MinSec%10);}

这样我们就实现全部功能啦

下面是完整代码

#include <REGX52.H>
#include " Timer0.h"
#include " Key.h"
#include " Delay.h"
#include " Nixie.h"
#include " AT24C02.h"
#include " I2C.h"unsigned char KeyNum;
unsigned char Min,Sec,MinSec;
unsigned char RunFlag;void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum==1){RunFlag=!RunFlag;}if(KeyNum==2){Min=0;Sec=0;MinSec=0;}if(KeyNum==3){AT24C02_WriteByte(0,Min);Delay(5);AT24C02_WriteByte(1,Sec);Delay(5);AT24C02_WriteByte(2,MinSec);Delay(5);}if(KeyNum==4){Min=AT24C02_ReadByte(0);Sec=AT24C02_ReadByte(1);MinSec=AT24C02_ReadByte(2);}Nixie_SetBuf(1,Min/10);Nixie_SetBuf(2,Min%10);Nixie_SetBuf(3,11);Nixie_SetBuf(4,Sec/10);Nixie_SetBuf(5,Sec%10);Nixie_SetBuf(6,11);Nixie_SetBuf(7,MinSec/10);Nixie_SetBuf(8,MinSec%10);}
}void Sec_Loop(void)
{if(RunFlag){MinSec++;if(MinSec>=100){MinSec=0;Sec++;if(Sec>60){Sec=0;Min++;if(Min>=60){Min=0;}	}}}
}void Timer0_Routine() interrupt 1
{static unsigned int	T0Count1,T0Count2,T0Count3;TL0 = 0x18;  //设置定时初值TH0 = 0xFC;  //设置定时初值T0Count1++;if(T0Count1>=20){T0Count1=0;Key_Loop();}T0Count2++;if(T0Count2>=2){T0Count2=0;Nixie_Loop();}T0Count3++;if(T0Count3>=10){T0Count3=0;Sec_Loop();}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/72868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于DeepSeek的智慧医药系统(源码+部署教程)

运行环境 智慧医药系统运行环境如下&#xff1a; 前端&#xff1a; HTMLCSS后端&#xff1a;Java AIGCDeepseekIDE工具&#xff1a;IDEA技术栈&#xff1a;Springboot HTMLCSS MySQL 主要角色 智慧医药系统主要分为两个角色。 游客 尚未进行注册和登录。具备登录注册、…

南开提出1Prompt1Story,无需训练,可通过单个连接提示实现一致的文本到图像生成。

&#xff08;1Prompt1Story&#xff09;是一种无训练的文本到图像生成方法&#xff0c;通过整合多个提示为一个长句子&#xff0c;并结合奇异值重加权&#xff08;SVR&#xff09;和身份保持交叉注意力&#xff08;IPCA&#xff09;技术&#xff0c;解决了生成图像中身份不一致…

BLUEM2引擎源码2025最新版

BLUE 引擎解析&#xff1a;传奇私服圈中的热门引擎 一、BLUE 引擎简介 BLUE 引擎是传奇私服圈子中较为知名的一款游戏引擎&#xff0c;它在传统的传奇引擎基础上进行了优化和扩展&#xff0c;使得私服开发者可以更加方便地搭建和管理服务器。相比于早期的 GEE、LEG、Hero 等引…

第53天:Web攻防-SQL注入数据库类型用户权限架构分层符号干扰利用过程发现思路

#知识点&#xff1a;(本节课了解即可&#xff09; 1、Web攻防-SQL注入-产生原理&应用因素 2、Web攻防-SQL注入-各类数据库类型利用 一、数据库知识&#xff1a; 1、数据库名&#xff0c;表名&#xff0c;列名&#xff0c;数据 2、自带数据库&#xff0c;数据库用户及权限 3…

如何有效判断与排查Java GC问题

目录 一、GC的重要性与对性能的影响 &#xff08;一&#xff09;GC对性能的影响简要分析 1.GC暂停与应用停顿 2.GC吞吐量与资源利用率 3.GC对内存管理的作用&#xff1a;资源回收 4.GC策略与优化的选择 &#xff08;二&#xff09;GC的双刃剑 二、GC性能评价标准 &…

olmOCR:高效精准的 PDF 文本提取工具

在日常的工作和学习中&#xff0c;是否经常被 PDF 文本提取问题困扰&#xff1f;例如&#xff1a; 想从学术论文 PDF 中提取关键信息&#xff0c;却发现传统 OCR 工具识别不准确或文本格式混乱&#xff1f;需要快速提取商务合同 PDF 中的条款内容&#xff0c;却因工具不给力而…

蓝桥杯备赛:炮弹

题目解析 这道题目是一道模拟加调和级数&#xff0c;难的就是调和级数&#xff0c;模拟过程比较简单。 做法 这道题目的难点在于我们在玩这个跳的过程&#xff0c;可能出现来回跳的情况&#xff0c;那么为了解决这种情况&#xff0c;我们采取的方法是设定其的上限步数。那么…

2025年渗透测试面试题总结-奇安信安全工程师(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 奇安信安全工程师 1. MVC框架详细说明 2. SQL注入详细介绍 3. XSS和CSRF的区别 4. XXE漏洞原理 5. …

【阿里云】控制台使用指南:从创建ECS到系统诊断测评

前言 随着云计算技术的快速发展&#xff0c;越来越多的企业和开发者开始使用云服务来部署和管理应用程序。在众多云服务提供商中&#xff0c;阿里云&#xff08;Alibaba Cloud&#xff09;凭借其强大的基础设施和丰富的服务&#xff0c;成为了众多用户的首选。本文旨在介绍如何…

关于OceanBase与CDH适配的经验分享

CDH是Cloudera早期推出的一个开源平台版本&#xff0c;它实质上成为了Apache Hadoop生态系统内公认的安装与管理平台&#xff0c;专为企业级需求量身打造。CDH为用户提供了即装即用的企业级解决方案。通过整合Hadoop与另外十多项关键开源项目&#xff0c;Cloudera构建了一个功能…

电机驱动电路:单桥(H桥)与双桥(双H桥)详解

一、电机驱动电路的作用 电机驱动电路通过控制电流方向和大小,实现电机的正反转、调速及制动。常见的结构包括单桥(H桥)和双桥(双H桥),分别适用于不同场景。 二、单桥(H桥)驱动电路 1. 结构示意图(文字描述) 开关元件:4个功率开关(如MOSFET或IGBT)组成桥臂,分…

[网络爬虫] 动态网页抓取 — Selenium 入门操作

&#x1f31f;想系统化学习爬虫技术&#xff1f;看看这个&#xff1a;[数据抓取] Python 网络爬虫 - 学习手册-CSDN博客 0x01&#xff1a;WebDriver 类基础属性 & 方法 为模仿用户真实操作浏览器的基本过程&#xff0c;Selenium 的 WebDriver 模块提供了一个 WebDriver 类…

在 IntelliJ IDEA(2024) 中创建 JAR 包步骤

下是在 IntelliJ IDEA 中创建 JAR 包的详细的步骤&#xff1a; ​1. 选择File -> Project Structure->Artifacts&#xff0c; (1)点击➕新建&#xff0c;如下图所示&#xff1a; (2)选择JAR->Empty (3)输入jar包名称&#xff0c;确定输出路径 &#xff08;4&#…

idea启动项目报端口被占用

端口确实被占用 winR&#xff0c;输入cmd&#xff0c;进入终端&#xff0c;查找到对应端口的进程id&#xff0c;杀掉项目 netstat -ano | findstr "8080"taskkill /F /PID 37020 idea设置中&#xff0c;选择让maven代替进行项目关闭&#xff0c;此时其实点击build可…

达梦数据库在Linux,信创云 安装,备份,还原

&#xff08;一&#xff09;系统环境检查 1操作系统&#xff1a;确认使用的是国产麒麟操作系统&#xff0c;检查系统版本是否兼容达梦数据库 V8。可以通过以下命令查看系统版本&#xff1a; cat /etc/os-release 2硬件资源&#xff1a;确保服务器具备足够的硬件资源&#xff0…

p5.js:模拟 n个彩色小球在一个3D大球体内部弹跳

向 豆包 提问&#xff1a;编写一个 p5.js 脚本&#xff0c;模拟 42 个彩色小球在一个3D大球体内部弹跳。每个小球都应留下一条逐渐消失的轨迹。大球体应缓慢旋转&#xff0c;并显示透明的轮廓线。请确保实现适当的碰撞检测&#xff0c;使小球保持在球体内部。 cd p5-demo copy…

linux环保监测4G边缘网关:环境数据的可靠传输者

环保监测工控机&#xff0c;常被称为“环境数据采集器”或“环保数据终端”&#xff0c;是一种专门用于环境监测领域的工业计算机。它具备强大的数据处理能力、稳定的运行性能和多种接口&#xff0c;能够实时采集、处理和传输环境监测数据。这些数据包括空气质量、水质、噪声、…

k8s概念及k8s集群部署(Centos7)

Centos7部署k8s集群 部署之前&#xff0c;先简单说下k8s是个啥&#xff1a; 一、k8s简介&#xff1a; k8s&#xff0c;全称&#xff1a;kubernetes&#xff0c;它可以看作是一个分布式系统支撑平台。k8s的作用&#xff1a; 1、故障自愈&#xff1a; k8s这个玩意可以监控容器…

Manus AI Agent 技术解读:架构、机制与竞品对比

目录 1. Manus 是什么&#xff1f; 1.1 研发背景 1.2 技术特点 1.3 工具调用能力 1.4 主要应用场景 2. Manus 一夜爆火的原因何在&#xff1f; 2.1 技术突破带来的震撼 2.2 完整交付的产品体验 2.3 生态与开源策略 3. Manus 与其他 AI Agent 的对比分析 3.1 技术架构…

PCIE接口

PCIE接口 PIC接口介绍PIC总线结构PCI总线特点PCI总线的主要性能PIC的历程 PCIE接口介绍PCIe接口总线位宽PCIE速率GT/s和Gbps区别PCIE带宽计算 PCIE架构PCIe体系结构端到端的差分数据传递PCIe总线的层次结构事务层数据链路层物理层PCIe层级结构及功能框图 PCIe链路初始化PCIe链路…