给你一段我的代码,调光完成,松手后存储pwm值 /*---------------------------- 感应扫描 ----------------------------*/ void keyscan() { if(PHO==0) //没有感应 要及时清零一些标志 { ucKeyLock1=0; //感应自锁标志清零 uiKeyTimeCnt1=0;//感应去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。 if(flag2) //长按松手后,存储pwm值 { IapEraseSector(0x0001); // 清除EEPROM IapProgramByte(0x0001, pwm_val); // 将pwm值据写入EEPROM flag2 = 0; //pwm值写入EEPROM后,存储标志清零 } } else if(ucKeyLock1==0)//有感应,且是第一次感应 { IR = 1; //关闭红外发射 ++uiKeyTimeCnt1; //延时计数器 if(uiKeyTimeCnt1>const_key_time1)//短按 { uiKeyTimeCnt1=0; ucKeyLock1=1; //自锁按键置位,避免一直触发 flag1 = !flag1; } } else if(uiKeyTimeCnt1<const_key_time2)//长按 { ++uiKeyTimeCnt1; //延时计数器 if(uiKeyTimeCnt1==const_key_time2) { uiKeyTimeCnt1=198;//此处调节调光速度,值越大,调光越快 flag2=1; //存储标志置1 if(flag == 1) { if(pwm_val < 255) { pwm_val++; //亮度变暗 if(pwm_val==255)//此处赋值255可以调灭 { delay(100); flag = 0; } } } if( flag ==0 ) { if(pwm_val > 0) { pwm_val--; //亮度变亮 if(pwm_val==0)// { delay(100); flag = 1; } } } } } } |
wulin 发表于 2019-1-23 16:53 大师,现在我要把这个程式改为两路iO口输出,具体工作为:上电一路IO口输出高电平另一个不输出,,断电再上电输出另一路高电平,怎么实现? |
nanyexin 发表于 2019-1-31 22:19 STC8F2K08S2是没有硬件PWM(PCA)寄存器,在这个程序中PWM调光是在主循环中由软件处理。 |
nanyexin 发表于 2019-1-15 15:48 ;;;这是STC15W系列的 汇编语言编写的 停电保存数据,上电恢复数据 部分的程序 ;;;在 STC12C系列 上有使用过, ;;; STC8F2K08S2 可以对比一下几个相关寄存器地址是否一致,一致可以直接使用 ;;;用C语言的没有 ; / *** *** *** *** *** *** / CPU STC15W404AS ; / *** *** *** *** *** *** / 12.000MHz WDT_CONTR EQU 0C1H ; 看门狗 ISP_DATA EQU 0C2H ; EEPROM 数据寄存器 ISP_ADDRH EQU 0C3H ; 地址寄存器H ISP_ADDRL EQU 0C4H ; 地址寄存器L ISP_CMD EQU 0C5H ; 命令寄存器 ISP_TRIG EQU 0C6H ; 触发寄存器 ISP_CONTR EQU 0C7H ; ( 等待时间 < 6M 4 ) ISPRH EQU 78H ; ( 等待时间 < 12M 3 ) ISPRL EQU 79H ; ( 等待时间 < 20M 2 ) ISPWH EQU 7AH ; ( 等待时间 < 12M 3 ) ISPWL EQU 7BH ; ( 等待时间 < 20M 2 ) ; / *** *** *** *** *** *** / 通用数据存储器 RAM 256 字节 ; / *** *** *** *** *** *** / 定义内部RAM L EEPROM 5K RIV_R0 EQU 1CH RIV_R1 EQU 1DH PTJSA0 EQU 50H ; 停电保存数据 PTJSA1 EQU 51H ; 可以根据需要字节 ; ------------------------------- ; / *** *** *** *** *** *** / ; ISP - 78H 79H 7AH 7BH PJSQS0 EQU 7EH PJSQS1 EQU 7FH ; / *** *** *** *** *** *** / 通用 标志位 ; / *** *** *** *** *** *** / 20H --- 2FH PLVD_BZ BIT 26H ; 停电处理标志 PLVD_B2 BIT 27H ; / *** *** *** *** *** *** / 程序入口 ; / *** *** *** *** *** *** / ORG 0000H L0000: LJMP MIN000 ; 初始化 主程序 START ORG 0033H L0033: LJMP LVD000 ; LVD 低电压 ( LVDF ) ; RETI ; / *** *** *** *** *** *** / ELVDI (低电压) 中断 ; / *** *** *** *** *** *** / ; 5V-3.7V 5.50V - 3.30V 4.06V - 1.32V LVD000: PUSH PSW ; 电流检测 PUSH ACC SETB RS0 ; 1 区 R1 R3 CLR RS1 ANL PCON, #11011111B ; 清 LVDF 位 MOV A, PCON JNB ACC.5, LVD008 ; LVDF CLR EA CLR TR1 SETB PLVD_BZ JNB PLVD_B2, LVD008 CLR PLVD_B2 LVD003: MOV A, PJSQS0 ; 数据 MOV B, #08H MUL AB MOV ISPWL, A ; 0000H - 01FFH MOV ISPWH, B MOV R1, #PTJSA0 ; 断电保存数据写入 MOV R3, #08H LVD006: MOV A, @R1 LCALL ISP010 ; 字节写 INC ISPWL INC R1 DJNZ R3, LVD006 INC PJSQS0 LVD007: ANL PCON, #11011111B ; 清 LVDF 位 MOV A, PCON JB ACC.5, LVD007 LVD008: CLR PLVD_BZ SETB EA POP ACC POP PSW RETI ; / *** *** *** *** *** *** / 初始化 主程序A ; / *** *** *** *** *** *** / MIN000: MOV SP, #0B0H ; 初始化 主程序 SP = B0H - FFH MOV IE, #11000000B ; IE.6 ( EPCA_LVD 中断 ) MIN002: LCALL MIM000 ; 初始化 MIN010: NOP ; 主程序 NOP MOV WDT_CONTR, #3EH ; 看门狗 初始化 12M ( 1.0485 S ) NOP ; 喂狗 同 NOP ; 主控程序在这里加入 MIN050: JMP MIN010 RET ; / *** *** *** *** *** *** / 读写 STC15W404AS EEPROM ; / *** *** *** *** *** *** / 1 字节读 ISP000: MOV ISP_CONTR, #83H ; 打开 IAP 功能 设置等待时间 MOV ISP_CMD, #01H ; 送字节读命令 MOV ISP_ADDRH, ISPRH ; 送地址高字节 MOV ISP_ADDRL, ISPRL ; 送地址低字节 CLR EA ; 关中断 MOV ISP_TRIG, #5AH ; 起动 ISP/IAP 触发寄存器 MOV ISP_TRIG, #0A5H NOP MOV A, ISP_DATA ; 将读出的数据送往Acc JB PLVD_BZ, $+5 SETB EA LCALL ISP030 ; 关闭 IAP 功能 RET ; / *** *** *** *** *** *** / 1 字节编程 ISP010: MOV ISP_CONTR, #83H ; 打开 IAP 功能 设置等待时间 MOV ISP_CMD, #02H ; 送字节编程命令 MOV ISP_ADDRH, ISPWH ; 送地址高字节 MOV ISP_ADDRL, ISPWL ; 送地址低字节 MOV ISP_DATA, A ; 数据进ISP_DATA CLR EA ; 关中断 MOV ISP_TRIG, #5AH ; 起动 ISP/IAP 触发寄存器 MOV ISP_TRIG, #0A5H NOP JB PLVD_BZ, $+5 SETB EA LCALL ISP030 ; 关闭 IAP 功能 RET ; / *** *** *** *** *** *** / 擦除扇区 ISP020: MOV ISP_CONTR, #83H ; 打开 IAP 功能 设置等待时间 MOV ISP_CMD, #03H ; 送擦除扇区命令 MOV ISP_ADDRH, ISPWH ; 送地址高字节 MOV ISP_ADDRL, ISPWL ; 送地址低字节 CLR EA ; 关中断 MOV ISP_TRIG, #5AH ; 起动 ISP/IAP 触发寄存器 MOV ISP_TRIG, #0A5H NOP JB PLVD_BZ, $+5 SETB EA LCALL ISP030 ; 关闭 IAP 功能 RET ; / *** *** *** *** *** *** / 关闭 IAP 功能 ISP030: MOV ISP_CONTR, #00H MOV ISP_CMD, #00H MOV ISP_TRIG, #00H MOV ISP_ADDRH, #0FFH ; 指向非EEPROM区 MOV ISP_ADDRL, #0FFH RET RET ; / *** *** *** *** *** *** / 初始化 STC15W404AS ; / *** *** *** *** *** *** / 读回DAT *** MIM000: MOV R4, #20 ; 50000 uS * 20 MIM001: NOP NOP MOV WDT_CONTR, #3CH ; 看门狗 初始化 12M ( 1.0485 S ) NOP NOP ; 喂狗 同 DJNZ R4, MIM001 CLR PLVD_BZ ; CLR PLVD_B2 MOV RIV_R1, #50 ; 30 S LCALL MIM050 ; 机器编号 NOP MIM010: MOV PJSQS0, #40H ; 读回 编码 MIM013: DEC PJSQS0 ; 0000H - 01FFH MOV A, PJSQS0 CJNE A, #0FFH, MIM015 RET MIM015: MOV B, #08H ; 计算地址 MUL AB MOV ISPRL, A ; 0000H - 01FFH MOV ISPRH, B LCALL ISP000 ; 字节读 CJNE A, #0FFH, MIM016 JMP MIM013 MIM016: MOV R0, #PTJSA0 MOV R3, #08H MIM018: LCALL ISP000 ; 字节读 MOV @R0, A ; 写 RAM INC ISPRL INC R0 DJNZ R3, MIM018 INC PJSQS0 MIM050: RET ; / *** *** *** *** *** *** / 结束 END |
nanyexin 发表于 2019-1-26 23:19 //不完全看明白你的意图,把你的程序改成单键控制掉电记忆PWM调光灯 //去掉定时器PWM调光,用主循环完成PWM调光,去掉delay延时用计数法 //完成消抖、短按、长按、长按连+连-。程序按1T单片机编写,经实际电路验证无误。 //操作平台IAP15W4K58S4,因不涉及其它内部新增功能,程序与STC8F2K08S2通用。 //#include <STC8F2K08S2.h> #include <STC8.H> #include<intrins.h> //#include<math.h> //计算小数点的头文件 #define uint unsigned int #define uchar unsigned char #define WT_12M 0x83 //CPU的等待时间 #define key_S 500 //宏定义短按(约20ms) #define key_L 25000 //宏定义长按(约1s) #define key_M 24500 //宏定义长按步进速度 //管脚声明 sbit LED = P1^0; //开关指示 sbit K1= P3^3; //触摸输入 sbit PWM = P1^1; //灯光控制输出 //子程序声明 void init(); void keyscan(); void IapIdle(); uchar IapRead(uint addr); void IapProgram(uint addr, uchar dat); void IapErase(uint addr); //变量声明 uchar scale; //占空变量 uchar num; //计数变量 uchar save; //保存的数据变量 bit flag=0; //长按标志 bit flag_add_dec=0; //长按时加减标志 /****************主函数**********************/ void main() { P0M0 = 0x00;//初始化端口弱上拉 P0M1 = 0x00; P1M0 = 0x00; P1M1 = 0x00; P2M0 = 0x00; P2M1 = 0x00; P3M0 = 0x00; P3M1 = 0x00; P4M0 = 0x00; P4M1 = 0x00; P5M0 = 0x00; P5M1 = 0x00; P6M0 = 0x00; P6M1 = 0x00; P7M0 = 0x00; P7M1 = 0x00; init(); //调用初始化函数 save=IapRead(0x0400);//读取EEPROM保存的数据 if(save==0xff) //如果初次加电EEPROM没有写数据,默认寄存器0xff。 save = 0x01; //初始化占空变量与开关变量 scale = save>>1; //分解--占空变量 LED = save & 0x01;//分解--开关变量 while(1) //循环 { keyscan();//按键扫描 if(LED==0)//PWM控制 { if(++num==100) num=0; if(num<scale) PWM=0; else PWM=1; } save =(scale<<1)|LED;//占空变量与开关变量合并为1个字节 } } void keyscan() //按键扫描 { static uint count=0; //计数变量 static uchar count1=0; //1T单片机12倍计数变量 if(!K1) { if(++count1>=12) {//如果使用12T单片机要屏蔽此段语句 count1=0; count++; } if(count>=key_L) //长按 { if(flag_add_dec==0) //是加状态 { if(scale<100) //达到最亮 scale++; //灯光比例++ } else { if(scale>0) //达到最暗 scale--; //灯光比例-- } count=key_M; // flag=1; //长按标志置1 } } else //按键松手 { if(flag==1) //判断长按松手 { flag=0; flag_add_dec=~flag_add_dec;//长按加减标志取反 count=0; //count清0 } else if(count>key_S && count<key_L)//判断短按松手 { LED=~LED; if(LED==1) PWM=1; count=0; //count清0 } } } /*********外部中断0初始化函数**********/ void init() { IT0=1;//跳变沿出发方式(下降沿) EX0=1;//打开INT0的中断允许。 EA=1; //中断总开关 } /**********外部中断0************/ void Int0() interrupt 0 //外部中断0的中断函数 { IapErase(0x0400); //擦除扇区 IapProgram(0x0400, save); //保存占空变量与开关变量合并为1个字节的数据 } void IapIdle() { IAP_CONTR = 0; //关闭IAP功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRH = 0x80; //将地址设置到非IAP区域 IAP_ADDRL = 0; } uchar IapRead(uint addr) { uchar dat; IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 1; //设置IAP读命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); dat = IAP_DATA; //读IAP数据 IapIdle(); //关闭IAP功能 return dat; } void IapProgram(uint addr, uchar dat) { IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 2; //设置IAP写命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_DATA = dat; //写IAP数据 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); IapIdle(); //关闭IAP功能 } void IapErase(uint addr) { IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 3; //设置IAP擦除命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); // IapIdle(); //关闭IAP功能 } |
5100103 发表于 2019-1-15 11:57 请问STC8F EEPROM中怎么记忆多个字节,要怎地修改? |
wulin 发表于 2019-1-26 10:32 大师。我调试了很久,终于可以记忆它了,不过就是只能记忆0和1,就是灯亮或不亮。但是我的功能是无级调光,不能只记忆0和1,我要在哪里修改才可以调光亮度在那个级都可以记忆呀? |
nanyexin 发表于 2019-1-26 17:30 在没有充分经验的情况下不要试图一下子就能把比较复杂的程序调试通。因该分块调试,都调通后再合在一起统调比较容易发现问题。就你的程序而言,定时器明显设置不合理,微秒级定时要用模式2,节省中断重装时间。而且你设置的是12T模式,T0中断任务耗时30um,T1中断任务耗时8um,CPU响应中断、保存现场也需要时间,可是你设置25us要发生两次中断,也就是说前面中断任务还没有完成,下一次的中断请求又到来,这叫CPU情何以堪? |
nanyexin 发表于 2019-1-26 17:30 现在已经能记忆了,但是只能记忆最亮,不能随意记忆,是不是哪里设置的不对,因为我的是无极调光,不能只记录最亮的。 还有,怎么写入和读取多个数呢? |
wulin 发表于 2019-1-26 10:32 已经调试了三个多小时了,没有一点进展,请大师帮我看看哪里有问题? #include <STC8F2K08S2.h> #include<intrins.h> #include<math.h> //计算小数点的头文件 #define uint unsigned int #define uchar unsigned char #define WT_30M 0x80 #define WT_24M 0x81 #define WT_20M 0x82 #define WT_12M 0x83 #define WT_6M 0x84 #define WT_3M 0x85 #define WT_2M 0x86 #define WT_1M 0x87 /******************************************************************** 延时函数 *********************************************************************/ void delay(uchar dat)//延时程序 { uchar m,n,s; for(m=dat;m>0;m--) for(n=20;n>0;n--) for(s=248;s>0;s--); } void IapIdle() { IAP_CONTR = 0; //关闭IAP功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRH = 0x80; //将地址设置到非IAP区域 IAP_ADDRL = 0; } char IapRead(int addr) { char dat; IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 1; //设置IAP读命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); dat = IAP_DATA; //读IAP数据 IapIdle(); //关闭IAP功能 return dat; } void IapProgram(int addr, char dat) { IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 2; //设置IAP写命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_DATA = dat; //写IAP数据 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); IapIdle(); //关闭IAP功能 } void IapErase(int addr) { IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 3; //设置IAP擦除命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); // IapIdle(); //关闭IAP功能 } uchar scale1=10; //定义占空比比例,初始是50% uchar scale=40; //定义占空比比例,初始是50% uchar num2; uchar Key_num,Key_num1; uchar n; bit bdata flag_add_dec=0; //长按时是加还是减取决于此变量 bit flag=0; //长按时是加还是减取决于此变量 bit write=0; //管脚声明 sbit LED = P1^0; //灯光控制输出 1 sbit K1= P3^3; //触摸输入 sbit LED1 = P1^1; //灯光控制输出2 /*********定时器初始化函数**********/ void init() { IT0=1;//跳变沿出发方式(下降沿) EX0=1;//打开INT0的中断允许。 TMOD=0x11; //工作方式 1 定时器0,1 TH0=0xff; TL0=0xe7; //T0赋初值25us TH1=0xff; TL1=0xe7; EA=1; //中断总开关 ET0=1; //打开中断允许开关 ET1=1; TR0=1;//打开定时器开关 TR1=1; } /****************主函数**********************/ void main() { init(); //调用初始化函数 num2 = IapRead(0x0400); if(num2>81) { num2=scale; } while(1) //循环 { if(K1==0) //有触摸信号 { delay(20);//延时,去抖,除掉干扰信号 if(K1==0) //再次判断有触摸信号 { while(!K1)//触摸信号不消失就会在此循环中 { Key_num++; //长按计时变量加 if(Key_num>=100) //检测到是长按(如果没加到100就退出则执行后面的if(Key_num!=0)) { Key_num=0; //清零,执行长按功能 //在灯开着时才可以调节亮度 while(!K1) //触摸信号一直在,进入循环,进行加减亮度 { if(flag_add_dec==0) //是加状态 { scale++; //灯光比例++ if(scale>=81) //达到最亮 scale=81; //保持最亮 } else { scale--; //灯光比例-- if(scale<=2) //达到最暗 { scale=2; //保持最暗 } } delay(30); } flag_add_dec=!flag_add_dec; //执行一次长按后,此变量取反(1变0,0变1) } delay(2); //此延时是调节长按时间的 } if(Key_num!=0) //如果不是长按按键 { Key_num=0; //清零 TR0=~TR0; //定时器取反,就是开关定时器,从而开关灯 if(TR0==0) //如果是关灯时,将LED输出置高,关闭输出 LED=1; LED1=1; } } } num2=scale; } } /******************定时器T0服务函数:脉冲发生函数*******************/ void time0() interrupt 1 { TH0=0xff; TL0=0xe7; //T0赋初值10us n++; //每25us n++ if(n<scale) //n<设置比例时,打开灯 { LED=0; LED1=~LED; } else if(n>=scale)//n大于等于设置比例时 关闭灯 { LED=1; LED1=~LED; } if(n==80) //n==40 :25us*40=1ms 1kHZ { n=0; //n=0 } } void time() interrupt 3 { TH1=0xff; TL1=0xe7; //T0赋初值12.5us //每25us n++ } /*外部中断0----*/ void Int0() interrupt 0 //外部中断0的中断函数 { IapErase(0x0400); //擦除扇区 IapProgram(0x0400,num2);//写入新的地址 } |
nanyexin 发表于 2019-1-26 01:23 硬件连接示意图 ![]() //基于STC8F2K64S4,测试工作频率为11.0592MHz //此程序使用外部中断1(INT1),也可以选择: //比较器中断(CMP),低压检测中断(LVD) //注:此程序未经实物验证,只是提供编程思路 #include <STC8.H> //#include "reg51.h" #include "intrins.h" #define uint unsigned int #define uchar unsigned char sbit key1=P3^4; sbit key2=P3^5; sbit LED=P1^7; uchar num=0x00; // 关闭IAP功能 void IapIdle() { IAP_CONTR = 0; //关闭IAP功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRH = 0x80; //将地址设置到非IAP区域 IAP_ADDRL = 0; } //从ISP/IAP/EEPROM区域读取一字节 uchar IapRead(uint addr) { uchar dat; IAP_CONTR = 0x83; //使能IAP IAP_CMD = 1; //设置IAP读命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); dat = IAP_DATA; //读IAP数据 IapIdle(); //关闭IAP功能 return dat; } //写一字节数据到ISP/IAP/EEPROM区域 void IapProgram(uint addr, uchar dat) { IAP_CONTR = 0x83; //使能IAP IAP_CMD = 2; //设置IAP写命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_DATA = dat; //写IAP数据 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); IapIdle(); //关闭IAP功能 } // ISP/IAP/EEPROM扇区擦除 void IapErase(uint addr) { IAP_CONTR = 0x83; //使能IAP IAP_CMD = 3; //设置IAP擦除命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); IapIdle(); //关闭IAP功能 } //初始化PWM void PWM_Init() { CCON = 0; //初始化PCA控制寄存器 CL = 0; //复位PCA寄存器 CH = 0; CMOD = 0x02; //设置PCA时钟源,PWM频率=11.0592MHZ/2/256=21.600KHZ PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM CCAP0H = CCAP0L = 0x80; //PWM0的占空比为50% CCAPM0 = 0x42; //PCA模块0为8位PWM模式 CR = 1; //PCA定时器开始工作 } void keyscan() { static uint count1=0,count2=0; if(!key1)//亮度增加 { if(++count1>=2000) { count1=0; if(num>0x00) num--; } } if(!key2)//亮度减弱 { if(++count2>=2000) { count2=0; if(num<0xcc)//亮度下限 num++; } } } void main() { P1M0 = 0x80; //P1.7推挽输出 P1M1 = 0x00; //P1.7推挽输出 P3M0 = 0x00; //P3.2高阻 P3M1 = 0x04; //P3.2高阻 PWM_Init(); //初始化PWM IT0 = 1; //设置INT0下降沿中断 EX0 = 1; //使能INT0中断 EA = 1; num = IapRead(0x0400); if(num>0xcc)//占空比不大于80% num=0xcc; while (1) { keyscan(); //按键扫描 CCAP0H=num;//P1.7 PWM输出 } } //中断服务程序 void exint0() interrupt 0 //INT0中断入口 { IapErase(0x0400);//扇区擦除 IapProgram(0x0400,num);//保存num值 } |
wulin 发表于 2019-1-23 16:53 如果用大电容那个外部中断该怎的设置呢?我有写了个普通的0和1LED灯它是可以记忆的,但是我换到单键做无极调光里面就记忆不了,想用大电容控制写入,但是调试了挺久都不行……。 |
楼主,注意下载时,硬件选项中的“设置用户EEPROM大小”要选择你需要的EEPROM大小值,否则会访问不成功的。 解决了是下载配置的问题,把地址改成0x0000就可以了! |
wulin 发表于 2019-1-23 16:53 不是可以用計時器萊做計數,每幾秒寫入一次嗎?我現在用的就是這個方法,沒幾秒寫進去一次,但是我按照你說的數據手冊中一樣的EEPROM例程來帶進去裏面一點反應都沒有,是不是不能按照數據手冊的測試例程來做,,,, |
nanyexin 发表于 2019-1-23 11:52 掉电记忆是需要外部硬件支持的,否则单片机没有电源怎么工作?如下图,C2值远大于C1。把写EEPROM的程序放在外部中断里。一旦掉电进入外部中断,由C2维持短暂工作。 ![]() |
5100103 发表于 2019-1-15 11:57 你好。我已经把这个EEPROM例程放进我的程式中,断电重启还是没有办法记忆,我现在用的是STC8F2K08S2这款IC。 |
Angle145 发表于 2019-1-16 09:47 我也知道是读写不成功呀,所以我是想不出来哪里的问题呀,所以才请教大神们呀? |
GUELL 发表于 2019-1-15 14:05 嗯,那有STC8F2K08S2的例程吗,最好有EEPROM这方面的……。 |
#include "reg51.h" #include "intrins.h" //测试工作频率为11.0592MHz sfr IAP_DATA = 0xC2; sfr IAP_ADDRH = 0xC3; sfr IAP_ADDRL = 0xC4; sfr IAP_CMD = 0xC5; sfr IAP_TRIG = 0xC6; sfr IAP_CONTR = 0xC7; #define WT_30M 0x80 #define WT_24M 0x81 #define WT_20M 0x82 #define WT_12M 0x83 #define WT_6M 0x84 #define WT_3M 0x85 #define WT_2M 0x86 #define WT_1M 0x87 void IapIdle() { IAP_CONTR = 0; //关闭IAP功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRH = 0x80; //将地址设置到非IAP区域 IAP_ADDRL = 0; } char IapRead(int addr) { char dat; IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 1; //设置IAP读命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); dat = IAP_DATA; //读IAP数据 IapIdle(); //关闭IAP功能 return dat; } void IapProgram(int addr, char dat) { IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 2; //设置IAP写命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_DATA = dat; //写IAP数据 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); IapIdle(); //关闭IAP功能 } void IapErase(int addr) { IAP_CONTR = WT_12M; //使能IAP IAP_CMD = 3; //设置IAP擦除命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); // IapIdle(); //关闭IAP功能 } void main() { IapErase(0x0400); P0 = IapRead(0x0400); //P0=0xff IapProgram(0x0400, 0x12); P1 = IapRead(0x0400); //P1=0x12 while (1); } 这是8F系列断电记忆的例程 你可以学习下。 |
yzwzfyz 发表于 2019-1-15 07:53 问题是,我现在用52RC的做断电记忆它记忆不了,我都调试很久都没调试出来,想不到好办法了,因为刚接触单片机不久,好多地方没弄懂……。 |