目录
第3篇: 辉芒微教程第三篇《IO口输入设置与按键切换继电器状态》
第4篇: 辉芒微教程第四篇《EEPROM-断电记忆开关状态》
第6篇: 辉芒微教程第六篇《定时器1和定时器2多个定时器混用》
第7篇: 辉芒微教程第七篇《PWM是什么与PWM3调节LED灯的亮度》
第8篇: 辉芒微教程第八篇《PWM4/PWM5调节舵机的角度》
第10篇:辉芒微教程第十篇《串口打印实战-EEPROM记忆日志数据打印》
第11篇:辉芒微教程第十一篇《ADC读取电压并且打印出来-简易万用表》
第12篇:辉芒微教程第十二篇《项目综合开发结构布置ADC的程序》
第14篇:辉芒微教程第十四篇《辉芒微外部中断实验》
第15篇:辉芒微教程第十五篇《辉芒微IIC实验》
第16篇:辉芒微教程第十六篇《辉芒微SPI实验》
第17篇:辉芒微教程第十七篇《辉芒微量产工作需要用哪些软件与做哪些工作》
第18篇:辉芒微教程第十八篇《辉芒微开发其他芯片说明》
前言
EEPROM作为一个断电不会丢失的数据的单片机功能,在有些产品中起到很重要的功能,假设客户要求你的产品能够进行断电保存记忆,比如你做一个电机产品,它现在是运行的,但是设备断电了,客户要求来电的时候,如果设备断电前是开着的,那么来电的时候就要打开电机运行。那这时候EEPROM就起到很重要的功能了!!!

(此段新手能理解就理解,不能理解就算了)做过STM32的老表一般会把这种数据保存到Flash中,但是每次写入都不是一个个字节写入,而是先擦除几百字节或者上千字节,再一个个写入,这样写入很不方便,因为需要建立一个很大的数组(不然会擦除其他数据),这样就很占运行内存,特别是8位单片机这种,并且我也不需要保存那么多数据,不过辉芒微相对于其他国外或者国产单片机就非常有优势,芯片内置EEPROM,无需额外购买EEPROM,并且它可以实现一个个写入,这样就很省运行空间了!

一、本节课目标
掌握辉芒微EEPROM的使用,并且实现断电记忆灯的开关状态。
二、电路原理
我们的KEY键接在PC2上,直接接地,需要做软件消抖,我们的LED接着PC4上,需要使用高电平点亮,低电平熄灭。
三、编程
(1)任务1:实现按键开关灯
#include "SYSCFG.h" //这个芯片的必要头文件
/*-------------------------------------------------
* 函数名称:DelayUs
* 功能: 短延时函数 --16M-2T--大概快1%左右.
* 输入参数:Time延时时间长度 延时时长Time us
* 返回参数:无
-------------------------------------------------*/
void DelayUs(unsigned char Time)
{
unsigned char a;
for(a=0;a<Time;a++)
{
NOP();
}
}
/*-------------------------------------------------
* 函数名称:DelayMs
* 功能: 短延时函数
* 输入参数:Time延时时间长度 延时时长Time ms
* 返回参数:无
-------------------------------------------------*/
void DelayMs(unsigned char Time)
{
unsigned char a,b;
for(a=0;a<Time;a++)
{
for(b=0;b<5;b++)
{
DelayUs(197); //快1%
}
}
}
void interrupt ISR(void) //中断函数,本节无需要
{
}
void SingleChipConfig(void) //单片机配置函数
{
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000;
TRISA = 0B00000000; //PA输入输出 0-输出 1-输入
PORTC = 0B00000000;
TRISC = 0B00000100; //PC输入输出 0-输出 1-输入
WPUA = 0B00000000; //PA端口上拉控制 1-开上拉 0-关上拉
WPUC = 0B00000100; //PC端口上拉控制 1-开上拉 0-关上拉
OPTION = 0B00001000; //Bit3=1,WDT MODE,PS=000=WDT RATE 1:1
MSCKCON = 0B00000000;
//Bit6->0,禁止PA4,PC5稳压输出
//Bit5->0,TIMER2时钟为Fosc
//Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
ANSEL = 0B00000000;
}
void main(void) //主函数
{
SingleChipConfig();
while(1)
{
if(!PC2)
{
DelayMs(50);
if(!PC2)
{
PC4 = !PC4;
while(PC2 == 0)
{
};
}
}
}
}
这个程序跟上节课差不多,不理解的朋友可以看上一篇章,接下来我们可以看一下效果;
DJI
(2)任务2:实现EEPROM的读写
void Eeprom_Write(unsigned char address,unsigned char value)//EEPROM写函数
{
CLRWDT();
EEADR = address;
asm("nop");
EEDAT = value;
EECON1 = 0x34;
WR = 1;
asm("nop");
asm("nop");
asm("nop");
while(WR==1)CLRWDT();
WREN1 = 0;
WREN2 = 0;
WREN3 = 0;
}
unsigned char Eeprom_Read(unsigned char address)//EEPROM读函数
{
unsigned char EepromData;
CLRWDT();
EEADR = address;
RD = 1;
EepromData = EEDAT;
RD = 0;
return(EepromData);
}
这个是EEPROM的写函数和读函数,其在辉芒微系列的8位单片机中,基本通用,其中的address是需要操作的地址,因为我们的芯片的EEPROM大小是256字节,因此其地址为0-255(对应16进制地址是0x00-0xff);
在编程软件里面,我们可以看到其EEPROM的初始化地址

由此看出,该芯片的EEPROM有256字节,默认每个字节的初始化大小为0xff,我们可以对单独的某个字节进行写入。
现在我们实验一下,在之前的程序上,加入我们的读写程序,并且程序运行一开始,在地址0xfe写入value值为0x8的数值。
#include "SYSCFG.h" //这个芯片的必要头文件
void Eeprom_Write(unsigned char address,unsigned char value)//EEPROM写函数
{
CLRWDT();
EEADR = address;
asm("nop");
EEDAT = value;
EECON1 = 0x34;
WR = 1;
asm("nop");
asm("nop");
asm("nop");
while(WR==1)CLRWDT();
WREN1 = 0;
WREN2 = 0;
WREN3 = 0;
}
unsigned char Eeprom_Read(unsigned char address)//EEPROM读函数
{
unsigned char EepromData;
CLRWDT();
EEADR = address;
RD = 1;
EepromData = EEDAT;
RD = 0;
return(EepromData);
}
/*-------------------------------------------------
* 函数名称:DelayUs
* 功能: 短延时函数 --16M-2T--大概快1%左右.
* 输入参数:Time延时时间长度 延时时长Time us
* 返回参数:无
-------------------------------------------------*/
void DelayUs(unsigned char Time)
{
unsigned char a;
for(a=0;a<Time;a++)
{
NOP();
}
}
/*-------------------------------------------------
* 函数名称:DelayMs
* 功能: 短延时函数
* 输入参数:Time延时时间长度 延时时长Time ms
* 返回参数:无
-------------------------------------------------*/
void DelayMs(unsigned char Time)
{
unsigned char a,b;
for(a=0;a<Time;a++)
{
for(b=0;b<5;b++)
{
DelayUs(197); //快1%
}
}
}
void interrupt ISR(void) //中断函数,本节无需要
{
}
void SingleChipConfig(void) //单片机配置函数
{
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000;
TRISA = 0B00000000; //PA输入输出 0-输出 1-输入
PORTC = 0B00000000;
TRISC = 0B00000100; //PC输入输出 0-输出 1-输入
WPUA = 0B00000000; //PA端口上拉控制 1-开上拉 0-关上拉
WPUC = 0B00000100; //PC端口上拉控制 1-开上拉 0-关上拉
OPTION = 0B00001000; //Bit3=1,WDT MODE,PS=000=WDT RATE 1:1
MSCKCON = 0B00000000;
//Bit6->0,禁止PA4,PC5稳压输出
//Bit5->0,TIMER2时钟为Fosc
//Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
ANSEL = 0B00000000;
}
void main(void) //主函数
{
SingleChipConfig();
Eeprom_Write(0xfe,0x08);
while(1)
{
if(!PC2)
{
DelayMs(50);
if(!PC2)
{
PC4 = !PC4;
while(PC2 == 0)
{
};
}
}
}
}
当我们编译并且下载到板子的时候,旁边的EEPROM框会变成这样

其中的0xfe的value值变成了0x08,当然,因为我这行代码是放在While外面的,所以它算是程序的初始化,如果你试图在while里面进行动态改变,如果想要查看EEPROM的数值变化,那这样的方式是查看不了的。
那么如果我们调试的程序一定想要看到现在的EEPROM值是多少怎么办呢,方法有很多种,这里我们只介绍一种,我常用的,这里我们就用到我们前面安装的FMDProgrammer软件。我们先在程序里面写一个变量增加,每隔一秒写入一次。然后我们运行了一段时间,再用这个软件进行查看。
我们把上面的while程序变动下:
unsigned char count;
void main(void) //主函数
{
SingleChipConfig();
while(1)
{
if(!PC2)
{
DelayMs(50);
if(!PC2)
{
PC4 = !PC4;
count++;
Eeprom_Write(0xfe,count);
while(PC2 == 0)
{
};
}
}
}
}
每当我们按一下的时候,地址0xfe的value值增加1,记住我们按下去的次数,然后再去这个软件里面读取。



最终我们看到按下11(0x0b)次,具体是多少,要看你们自己按了多少次。
(3)任务3:断电保存灯的开关状态
接下来我们来写本节课的主题程序,即记录按键按下灯的状态到EEPROM中,当设备断电或者开机的时候,可以读取对应的地址值,从而初始化的时候对灯进行开或者关的状态。
#include "SYSCFG.h" //这个芯片的必要头文件
void Eeprom_Write(unsigned char address,unsigned char value)//EEPROM写函数
{
CLRWDT();
EEADR = address;
asm("nop");
EEDAT = value;
EECON1 = 0x34;
WR = 1;
asm("nop");
asm("nop");
asm("nop");
while(WR==1)CLRWDT();
WREN1 = 0;
WREN2 = 0;
WREN3 = 0;
}
unsigned char Eeprom_Read(unsigned char address)//EEPROM读函数
{
unsigned char EepromData;
CLRWDT();
EEADR = address;
RD = 1;
EepromData = EEDAT;
RD = 0;
return(EepromData);
}
/*-------------------------------------------------
* 函数名称:DelayUs
* 功能: 短延时函数 --16M-2T--大概快1%左右.
* 输入参数:Time延时时间长度 延时时长Time us
* 返回参数:无
-------------------------------------------------*/
void DelayUs(unsigned char Time)
{
unsigned char a;
for(a=0;a<Time;a++)
{
NOP();
}
}
/*-------------------------------------------------
* 函数名称:DelayMs
* 功能: 短延时函数
* 输入参数:Time延时时间长度 延时时长Time ms
* 返回参数:无
-------------------------------------------------*/
void DelayMs(unsigned char Time)
{
unsigned char a,b;
for(a=0;a<Time;a++)
{
for(b=0;b<5;b++)
{
DelayUs(197); //快1%
}
}
}
void interrupt ISR(void) //中断函数,本节无需要
{
}
void SingleChipConfig(void) //单片机配置函数
{
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000;
TRISA = 0B00000000; //PA输入输出 0-输出 1-输入
PORTC = 0B00000000;
TRISC = 0B00000100; //PC输入输出 0-输出 1-输入
WPUA = 0B00000000; //PA端口上拉控制 1-开上拉 0-关上拉
WPUC = 0B00000100; //PC端口上拉控制 1-开上拉 0-关上拉
OPTION = 0B00001000; //Bit3=1,WDT MODE,PS=000=WDT RATE 1:1
MSCKCON = 0B00000000;
//Bit6->0,禁止PA4,PC5稳压输出
//Bit5->0,TIMER2时钟为Fosc
//Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
ANSEL = 0B00000000;
}
void main(void) //主函数
{
SingleChipConfig();
if( Eeprom_Read(0xfe)== 1 )
{
PC4 = 1;
}
else
{
PC4 = 0;
}
while(1)
{
if(!PC2)
{
DelayMs(50);
if(!PC2)
{
PC4 = !PC4;
Eeprom_Write(0xfe,PC4);
while(PC2 == 0)
{
};
}
}
}
}
初始化的if是读取EERPOM地址0xfe的数值,然后对其进行判断,如果返回结果是1则开灯,如果返回结果是0则关灯。
每次按键按下去的时候都会将PC4灯的状态保存到EEPROM中,这样下次设备开机的时候,就可以根据其数据对灯进行反应,我们可以看产品效果:
DJI
四、最后注意事项
不注意有可能做项目的时候自己坑自己哦!
无论是哪个品牌的单片机的EEPROM或者专门的EEPROM芯片,其写入都是有寿命的,不能跟无限制写入,比如我们的单片机,它可写入100K次(100 000次),因此在做项目的时候我们要考虑设备可能使用的次数,说人话就是不能频繁写入,假设我一天写100次,那你这个设备可以支持1000天,如果一天写入1000次,那么最多可写入100天(产品半年不到就可能废了,别逼你客户骂你)。


449

被折叠的 条评论
为什么被折叠?



