|
發布時間: 2019-1-15 00:32
正文摘要:請幫忙把STC89C52RC52程式改成STC8F2K08S2程式,還有就是我下面的程式EEPROM斷電記憶部分沒辦法記憶,有地方寫的不對,請大神幫忙修改下……。 程式如下: //頭函數 #include <reg52.h> #include<intrins.h ... |
|
給你一段我的代碼,調光完成,松手后存儲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的做斷電記憶它記憶不了,我都調試很久都沒調試出來,想不到好辦法了,因為剛接觸單片機不久,好多地方沒弄懂……。 |