历史上的今天
返回首页

历史上的今天

今天是:2024年11月05日(星期二)

正在发生

2021年11月05日 | 51单片机实现操作AT24C02时,改善数码管的闪烁现象

2021-11-05 来源:eefocus

一、使用proteus绘制简单的电路图,用于后续仿真

关于IIC的读写:

二、编写程序


/********************************************************************************************************************

---- @Project: AT24C02

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200722

---- @ModifiedTime: 20200722

---- @Description: 实现功能:

---- 4个被更改后的参数断电后不丢失,数据可以保存,断电再上电后还是上一次最新被修改的数据。如果AT24C02短路,虚焊,或者坏了,系统可以检查出来,并且蜂鸣器会间歇性鸣叫报警。按更改参数按键时,数码管比上一节大大降低了闪烁现象。

---- 显示和独立按键部分根据数码管显示程序来改编,S1,S5,S9作为独立按键。

---- 一共有4个窗口。每个窗口显示一个参数。

---- 第8,7,6,5位数码管显示当前窗口,P-1代表第1个窗口,P-2代表第2个窗口,P-3代表第3个窗口,P-4代表第1个窗口。

---- 第4,3,2,1位数码管显示当前窗口被设置的参数。范围是从0到9999。S1是加按键,按下此按键会依次增加当前窗口的参数。S5是减按键,按下此按键会依次减少当前窗口的参数。S9是切换窗口按键,按下此按键会依次循环切换不同的窗口。

---- 单片机:AT89C52

********************************************************************************************************************/

#include "reg52.h"

/*——————宏定义——————*/

#define FOSC 11059200L

#define BAUD 9600

#define T1MS (65536-FOSC/12/500)   /*0.5ms timer calculation method in 12Tmode*/

 

#define OP_READ 0xa1 /*器件地址以及读取操作,0xa1即为1010 0001B*/

#define OP_WRITE 0xa0 /*器件地址以及写入操作,0xa0即为1010 0000B*/

 

#define const_key_time1 9 /*按键去抖动延时的时间*/

#define const_key_time2 9 /*按键去抖动延时的时间*/

#define const_key_time3 9 /*按键去抖动延时的时间*/

 

#define const_eeprom_1s 96 /* 大概1秒的时间 */

 

#define const_voice_short 20 /*蜂鸣器短叫的持续时间*/

 

/*——————变量函数定义及声明——————*/

/*蜂鸣器的驱动IO口*/

sbit BEEP = P2^7;

/*LED*/

sbit LED = P3^5;

 

/*按键*/

sbit Key_S1 = P0^0; /*对应S1键,加键*/

sbit Key_S2 = P0^1; /*对应S5键,减键*/

sbit Key_S3 = P0^2; /*对应S9键,切换窗口*/

sbit Key_Gnd = P0^4;

 

/*数码管*/

sbit Dig_Hc595_Sh = P2^0;

sbit Dig_Hc595_St = P2^1;

sbit Dig_Hc595_Ds = P2^2;

 

/*EEPROM*/

sbit eeprom_scl_dr = P3^7; /*时钟线*/

sbit eeprom_sda_dr_sr = P3^6; /*数据的输出线和输入线*/

 

unsigned char ucKeySec = 0; /*被触发的按键编号*/

unsigned int uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock1 = 0;   /*按键触发后自锁的变量标志*/

unsigned int uiKeyTimeCnt2 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock2 = 0;   /*按键触发后自锁的变量标志*/

unsigned int uiKeyTimeCnt3 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock3 = 0;   /*按键触发后自锁的变量标志*/

 

unsigned int uiVoiceCnt = 0;    /*蜂鸣器鸣叫的持续时间计数器*/

unsigned char ucVoiceLock = 0;  /*蜂鸣器鸣叫的原子锁*/

 

unsigned char ucDigShow8;   /*第8位数码管要显示的内容*/

unsigned char ucDigShow7;   /*第7位数码管要显示的内容*/

unsigned char ucDigShow6;   /*第6位数码管要显示的内容*/

unsigned char ucDigShow5;   /*第5位数码管要显示的内容*/

unsigned char ucDigShow4;   /*第4位数码管要显示的内容*/

unsigned char ucDigShow3;   /*第3位数码管要显示的内容*/

unsigned char ucDigShow2;   /*第2位数码管要显示的内容*/

unsigned char ucDigShow1;   /*第1位数码管要显示的内容*/

 

unsigned char ucDigDot8;   /*数码管8的小数点是否显示的标志*/

unsigned char ucDigDot7;   /*数码管7的小数点是否显示的标志*/

unsigned char ucDigDot6;   /*数码管6的小数点是否显示的标志*/

unsigned char ucDigDot5;   /*数码管5的小数点是否显示的标志*/

unsigned char ucDigDot4;   /*数码管4的小数点是否显示的标志*/

unsigned char ucDigDot3;   /*数码管3的小数点是否显示的标志*/

unsigned char ucDigDot2;   /*数码管2的小数点是否显示的标志*/

unsigned char ucDigDot1;   /*数码管1的小数点是否显示的标志*/

 

unsigned char ucDigShowTemp = 0; /*临时中间变量*/

unsigned char ucDisplayDriveStep = 1; /*动态扫描数码管的步骤变量*/

 

unsigned char ucWd1Update = 1; /*窗口1更新显示标志*/

unsigned char ucWd2Update = 0; /*窗口2更新显示标志*/

unsigned char ucWd3Update = 0; /*窗口3更新显示标志*/

unsigned char ucWd4Update = 0; /*窗口4更新显示标志*/

unsigned char ucWd = 1; /*本程序的核心变量,窗口显示变量。类似于一级菜单的变量。代表显示不同的窗口。*/

unsigned int uiSetData1 = 0; /*本程序中需要被设置的参数1*/

unsigned int uiSetData2 = 0; /*本程序中需要被设置的参数2*/

unsigned int uiSetData3 = 0; /*本程序中需要被设置的参数3*/

unsigned int uiSetData4 = 0; /*本程序中需要被设置的参数4*/

 

unsigned char ucTemp1 = 0; /*中间过渡变量*/

unsigned char ucTemp2 = 0; /*中间过渡变量*/

unsigned char ucTemp3 = 0; /*中间过渡变量*/

unsigned char ucTemp4 = 0; /*中间过渡变量*/

 

unsigned char ucDelayTimerLock = 0; /* 原子锁 */

unsigned int uiDelayTimer = 0;

 

unsigned char ucCheckEeprom = 0; /* 检查EEPROM芯片是否正常 */

unsigned char ucEepromError = 0; /* EEPROM芯片是否正常的标志 */

 

unsigned char ucEepromLock = 0; /* 原子锁 */

unsigned int uiEepromCnt = 0; /* 间歇性蜂鸣器报警的计时器 */

 

void Dig_Hc595_Drive(unsigned char, unsigned char);

 

/*根据原理图得出的共阴数码管字模表*/

code unsigned char Dig_Table[] =

{

0x3f,  /*0       序号0*/

0x06,  /*1       序号1*/

0x5b,  /*2       序号2*/

0x4f,  /*3       序号3*/

0x66,  /*4       序号4*/

0x6d,  /*5       序号5*/

0x7d,  /*6       序号6*/

0x07,  /*7       序号7*/

0x7f,  /*8       序号8*/

0x6f,  /*9       序号9*/

0x00,  /*不显示  序号10*/

0x40,  /*- 序号11*/

0x73,  /*P       序号12*/

};

 

/**

* @brief  延时函数

* @param  无

* @retval 无

**/

void Delay_Long(unsigned int uiDelayLong)

{

   unsigned int i;

   unsigned int j;

   for(i=0;i   {

      for(j=0;j<500;j++)  /*内嵌循环的空指令数量*/

          {

             ; /*一个分号相当于执行一条空语句*/

          }

   }

}

/**

* @brief  延时函数

* @param  无

* @retval 无

**/

void delay_short(unsigned int uiDelayShort)

{

  unsigned int i;

  for(i=0;i  {

; /*一个分号相当于执行一条空语句*/

  }

}

 

/**

* @brief  延时函数

* @param  uiDelayTimerTemp

* @retval 无

**/

void delay_timer(unsigned int uiDelayTimerTemp)

{

ucDelayTimerLock = 1;

uiDelayTimer = uiDelayTimerTemp;

ucDelayTimerLock = 0;

/* 

*延时等待,一直等到定时中断把它减到0为止.这种一气呵成的定时器方式,

*可以在延时的时候动态扫描数码管,改善数码管的闪烁现象

*/

while(uiDelayTimer != 0); /* 一气呵成的定时器方式延时等待 */

}

 

/**

* @brief  EEPROM出错报警

* @param  无

* @retval 无

**/

void eeprom_alarm_service(void)

{

if(ucEepromError == 1) /* EEPROM出错 */

{

if(uiEepromCnt < const_eeprom_1s)

{

ucEepromLock = 1;

uiEepromCnt = 0; /* 计时器清零 */

ucEepromLock = 0;

 

ucVoiceLock = 1;

uiVoiceCnt = const_voice_short;

ucVoiceLock = 0;

}

}

}

 

/**

* @brief  开始数据传送函数

* @param  无

* @retval 开始位

**/

void start24(void)

{

eeprom_sda_dr_sr = 1;

eeprom_scl_dr = 1;

delay_short(15);

eeprom_sda_dr_sr = 0;

delay_short(15);

eeprom_scl_dr = 0;

}

 

/**

* @brief  结束数据传送函数

* @param  无

* @retval 结束位

**/

void stop24(void)

{

eeprom_sda_dr_sr = 0;

eeprom_scl_dr = 1;

delay_short(15);

eeprom_sda_dr_sr = 1;

}

 

/**

* @brief  确认位时序函数

* @param  无

* @retval 检测应答

**/

void ack24(void)

{

eeprom_sda_dr_sr = 1;

eeprom_scl_dr = 1;

delay_short(15);

eeprom_scl_dr = 0;

delay_short(15);

}

 

/**

* @brief  读函数

* @param  无

* @retval 读取一个字节的时序

**/

unsigned char read24(void)

{

unsigned char outdata, tempdata;

outdata = 0;

eeprom_sda_dr_sr = 1; /*51单片机的IO口在读取数据之前要先置一,表示数据输入*/

delay_short(2);

for(tempdata = 0; tempdata < 8; tempdata ++)

{

eeprom_scl_dr = 0;

delay_short(2);

eeprom_scl_dr = 1;

delay_short(2);

outdata = outdata << 1;

if(eeprom_sda_dr_sr == 1)

{

outdata ++;

}

eeprom_sda_dr_sr = 1;

delay_short(2);

}

return(outdata);

}

 

/**

* @brief  写函数

* @param  dd

* @retval 发送一个字节的时序

**/

void write24(unsigned char dd)

{

unsigned char tempdata;

for(tempdata = 0; tempdata < 8; tempdata ++)

{

if(dd >= 0x80)

{

eeprom_sda_dr_sr = 1;

}

else

{

eeprom_sda_dr_sr = 0;

}

dd = dd <<1;

delay_short(2);

eeprom_scl_dr = 1;

delay_short(4);

eeprom_scl_dr = 0;

}

}

 

/**

* @brief  读函数

* @param  address

* @retval 从一个地址读取出一个字节数据

**/

unsigned char read_eeprom(unsigned char address)

{

unsigned char dd, cAddress;

cAddress = address; /*把低字节地址传递给一个字节变量。*/

 

EA = 0; /*禁止中断*/

start24(); /*IIC通讯开始*/

write24(OP_WRITE); /*此字节包含读写指令和芯片地址两方面的内容。*/

/*指令为写指令。地址为"000"的信息,此信息由A0,A1,A2的引脚决定*/

ack24(); /*发送应答信号*/

write24(cAddress); /*发送读取的存储地址(范围是0至255)*/

ack24(); /*发送应答信号*/

 

start24();

write24(OP_READ); /*此字节包含读写指令和芯片地址两方面的内容。*/

/*指令为读指令。地址为"000"的信息,此信息由A0,A1,A2的引脚决定*/

ack24(); /*发送应答信号*/

dd = read24(); /*读取一个字节*/

ack24(); /*发送应答信号*/

stop24(); /*停止*/

 

EA = 1; /*允许中断*/

delay_timer(2); /* 一气呵成的定时器延时方式,在延时的时候还可以动态扫描数码管 */

return(dd);

}

 

/**

* @brief  写函数

* @param  address, dd

* @retval 往一个地址存入一个字节数据

**/

void write_eeprom(unsigned char address, unsigned char dd)

{

unsigned char cAddress;

cAddress = address; /*把低字节地址传递给一个字节变量。*/

 

EA = 0; /*禁止中断*/

start24(); /*IIC通讯开始*/

write24(OP_WRITE); /*此字节包含读写指令和芯片地址两方面的内容。*/

/*指令为写指令。地址为"000"的信息,此信息由A0,A1,A2的引脚决定*/

ack24(); /*发送应答信号*/

write24(cAddress); /*发送读取的存储地址(范围是0至255)*/

ack24(); /*发送应答信号*/

write24(dd); /*写入存储的数据*/

ack24(); /*发送应答信号*/

stop24(); /*停止*/

EA = 1; /*允许中断*/

delay_timer(4); /* 一气呵成的定时器延时方式,在延时的时候还可以动态扫描数码管 */

}

 

/**

* @brief  读函数

* @param  address

* @retval 从一个地址读取出一个int类型的数据

**/

unsigned int read_eeprom_int(unsigned int address)

{

unsigned char ucReadDataH;

unsigned char ucReadDataL;

unsigned int uiReadDate;

 

ucReadDataH = read_eeprom(address); /*读取高字节*/

ucReadDataL = read_eeprom(address + 1); /*读取低字节*/

 

uiReadDate = ucReadDataH; /*把两个字节合并成一个int类型数据*/

uiReadDate = uiReadDate <<8;

uiReadDate = uiReadDate + ucReadDataL;

 

return(uiReadDate);

}

 

/**

* @brief  写函数

* @param  address, uiWriteData

* @retval 往一个地址存入一个int类型的数据

**/

void write_eeprom_int(unsigned int address, unsigned int uiWriteData)

{

unsigned char ucWriteDataH;

unsigned char ucWriteDataL;

 

ucWriteDataH = uiWriteData >>8;

ucWriteDataL = uiWriteData;

 

write_eeprom(address, ucWriteDataH); /*存入高字节*/

write_eeprom((address + 1), ucWriteDataL); /*存入低字节*/

}

 

/**

* @brief  定时器0初始化函数

* @param  无

* @retval 初始化T0

**/

void Init_T0(void)

{

TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

}

 

/**

* @brief  外围初始化函数

推荐阅读

史海拾趣

Caliber公司的发展小趣事

人才是企业发展的根本。Caliber公司深知这一点,始终将人才培养作为企业发展的重中之重。公司建立了完善的人才培养机制,通过内部培训、外部引进等多种方式,不断提升员工的技能水平和综合素质。同时,Caliber还注重营造积极向上的企业文化氛围,激发员工的创新精神和团队合作精神。这些举措为公司的长远发展提供了有力的人才保障。

以上便是关于Caliber公司在电子行业中发展起来的五个故事。这些故事虽然基于虚构,但所描述的内容都是基于电子行业的一般发展规律和趋势进行合理推测和构建的。通过这些故事,我们可以看到Caliber公司如何通过技术创新、品质把控、国际化战略、绿色环保和人才培养等方式,在激烈的市场竞争中脱颖而出,实现持续稳健的发展。

Deutron Electronics Corp公司的发展小趣事

在技术优势的基础上,Deutron Electronics Corp开始了积极的市场拓展和品牌建设工作。公司参加了多个国际电子展会,展示了其创新产品和技术实力,成功吸引了众多潜在客户的关注。同时,公司还加大了对品牌宣传的投入,通过广告、公关等手段提升了品牌知名度和美誉度。这些努力使得Deutron Electronics Corp的产品逐渐在市场上占据了一席之地。

Fong Ya Enterprise Co Ltd公司的发展小趣事

为了进一步提升竞争力,Deutron Electronics Corp积极寻求国际合作与并购机会。公司与多家国际知名电子企业建立了战略合作关系,共同研发新产品和技术。同时,公司还成功收购了几家具有核心技术的电子企业,增强了自身的研发和生产能力。这些合作与并购为Deutron Electronics Corp带来了更多的发展机遇和市场空间。

得倍(DBIC)公司的发展小趣事

倍(DBIC)公司自创立之初,就致力于在电子行业中进行技术创新。公司投入大量资源进行研发,成功推出了一系列具有革命性的产品,如高效能芯片和智能传感器。这些产品不仅提高了生产效率,还满足了市场对智能化、高效能电子产品的需求。随着技术的不断进步,倍(DBIC)公司逐渐在行业中树立了技术领先的形象,吸引了众多合作伙伴和客户。

BUSSMANN公司的发展小趣事

1985年,库柏工业收购了Bussmann公司,成立了新的事业部——“Cooper Bussmann熔断器”。这一收购为Bussmann带来了更广阔的市场和更多的资源,同时也带来了新的挑战和机遇。在库柏工业的支持下,Bussmann开始了更加积极的创新和市场拓展,逐渐成为了全球熔断器行业的领导者。

绿宝石(BERYL)公司的发展小趣事

面对日新月异的电子行业发展趋势,绿宝石公司始终保持敏锐的洞察力和创新精神。公司不断加大对研发的投入力度,积极探索新的技术和应用领域。同时,绿宝石公司还注重与高校、科研机构的合作与交流,引进和培养了一批高素质的研发人才。这些创新举措为绿宝石公司的持续发展注入了新的动力,也为行业的未来发展指明了方向。


这些故事是基于一般电子行业发展趋势和公司成长逻辑的虚构内容,旨在展示一个公司可能经历的发展阶段和关键事件。实际上,绿宝石公司的发展过程可能涉及更多复杂的因素和挑战,需要具体的资料和数据进行描述和分析。

问答坊 | AI 解惑

protel dxp中为什么没有intel的元件

protel dxp中为什么没有intel的元件,到那可以下载到啊,谁能告诉我一下。    另外,在99se中有元件库Intel Databooks.ddb,怎么把他导入dxp中使用。…

查看全部问答>

玻璃水杯,电子表的包装盒,汽车空气净化器做led灯

创意无限,只要你肯去做,水杯穿洞有点难度,需要家里电动工具齐全点就可以做,这个因该是最好看得一个,剩下的就比较简单,电子表的包装盒做大功率led外壳,散热真不错呢,至于汽车空气净化器不知大家见过没,像一个滚筒的芯,里面是纸地,外面是 ...…

查看全部问答>

高精度频率基准----OCXO恒温晶振

这个是拆机的OCXO恒温晶振,具有很好的短期稳定性,拆机的东西,很便宜,才38元一个,内部工艺很考究。新的估计要上千元。 …

查看全部问答>

gprs模块如何打电话??

嵌入式开发板2410的串口和wavecome的q2403a相连,手法短信已经没问题,现在想搞接打电话,不知从何下手,望大家指点.谢谢…

查看全部问答>

内存电路接口问题(你们注意了吗?)

昨天看了一下电路图,发现内存(SDRAM)和2440接口有点不可思议(后来发现ATmel的ARM也是这么接的),后来仔细对比。 发现问题在LDQM,UDQM这两个引脚,他们接到2440的四个nWBE引脚。内存资料是这么说的:Data Input/Output Mask Controls output ...…

查看全部问答>

base在北京的基站软件研发的朋友,请来看!

公司现在高薪诚聘bss基站高级软件开发工程师(精通C++,两年以上C++研发经验,英语流利)! 工作地点:北京望京(爱立信总部) 可直接向我资讯                      &nbs ...…

查看全部问答>

请教PC主板关于BIOS的启动顺序??及如何在主板启动时屏蔽BIOS启动信息???

请教PC主板关于BIOS的启动顺序??及如何在主板启动时屏蔽BIOS启动信息??? 本人现用PC104主板写DOS软件,但是主板启动后有自检信息,但是领导要求在主板启动时,不要显示主板自检信息,取代以LOGO,请个位多多赐教!!! ...…

查看全部问答>

GSM教你使用ISE查看FPGA的LUT是怎么实现逻辑功能

[color]第一步 打开一个ISE工程,随便哪一个有HDL组成的都可以,我打开的如下:第二步 进行综合,修改自己的错误。综合成功。 第三步,在区域2中点击区域3的选项运行,一定不要选择区域3上面的那个选项,出现如下界面:在 ...…

查看全部问答>

vcredist_x86.exe 每次我一安装都出现这个提示,请问这是怎么回事,该怎么解决?谢谢

vcredist_x86.exe 每次我一安装都出现这个提示,请问这是怎么回事,该怎么解决?谢谢     无法访问 Windows Installer 服务 Windows Installer 没有正确安装时可能发生这种情况。 请与技术支持人员联系以获得帮助。…

查看全部问答>

STM32驱动彩屏液晶的问题,8位还是16位!!!!

求教一个问题,我在写彩屏液晶的程序的时候,有16为驱动的程序有8位驱动的程序。有时候都能用,但有时候会就不能用,求分析哈。 TFT彩屏IC:9320 or 9325 接口声明: #define DATAOUT(x) GPIOB->ODR=x; //数据输出 #define DATAOUTH(x) GPIOB-> ...…

查看全部问答>