1. 51單片機做科學計算器的c語言程序
給些子程序吧
好的就加分,其實我也是收藏別人的
嵌入式系統>51單片機浮點運運算元程序庫
1: FSDT 功能:浮點數格式化
2: FADD 功能:浮點數加法
3: FSUB 功能:浮點數減法
4: FMUL 功能:浮點數乘法
5: FDIV 功能:浮點數除法
6: FCLR 功能:浮點數清零
7: FZER 功能:浮點數判零
8: FMOV 功能:浮點數傳送
9: FPUS 功能:浮點數壓棧
10: FPOP 功能:浮點數出棧
11: FCMP 功能:浮點數代數值比較不影響待比較操作數
12: FABS 功能:浮點絕對值函數
13: FSGN 功能:浮點符號函數
14: FINT 功能:浮點取整函數
15: FRCP 功能:浮點倒數函數
16: FSQU 功能:浮點數平方
17: FSQR 功能:浮點數開平方快速逼近演算法
18: FPLN 功能:浮點數多項式計算
19: FLOG 功能:以10為底的浮點對數函數
20: FLN 功能:以e為底的浮點對數函數
21: FE10 功能:以10為底的浮點指數函數
22: FEXP 功能:以e為底的浮點指數函數
23: FE2 功能:以2為底的浮點指數函數
24: DTOF 功能:雙位元組十六進制定點數轉換成格式化浮點數
25: FTOD 功能:格式化浮點數轉換成雙位元組定點數
26: BTOF 功能:浮點BCD碼轉換成格式化浮點數
27: FTOB 功能:格式化浮點數轉換成浮點BCD碼
28: FCOS 功能:浮點餘弦函數
29: FSIN 功能:浮點正弦函數
30: FATN 功能:浮點反正切函數
31: RTOD 功能:浮點弧度數轉換成浮點度數
32: DTOR 功能:浮點度數轉換成浮點弧度數
為便於讀者使用本程序庫,先將有關約定說明如下:
1.雙位元組定點操作數:用[R0]或[R1]來表示存放在由R0或R1指示的連續單元中的數據,地址小的單元存放高位元組?如果[R0]=1234H,若(R0)=30H,則(30H)=12H,(31H)=34H?
2.二進制浮點操作數:用三個位元組表示,第一個位元組的最高位為數符,其餘七位為階碼(補碼形式),第二位元組為尾數的高位元組,第三位元組為尾數的低位元組,尾數用雙位元組純小數(原碼)來表示?當尾數的最高位為1時,便稱為規格化浮點數,簡稱操作數?在程序說明中,也用[R0]或[R1]來表示R0或R1指示的浮點操作數,例如:當[R0]=-6.000時,則二進制浮點數表示為83C000H?若(R0)=30H,則(30H)=83H,(31H)=0C0H,(32H)=00H?
3.十進制浮點操作數:用三個位元組表示,第一個位元組的最高位為數符,其餘七位為階碼(二進制補碼形式),第二位元組為尾數的高位元組,第三位元組為尾數的低位元組,尾數用雙位元組BCD碼純小數(原碼)來表示?當十進制數的絕對值大於1時,階碼就等於整數部分的位數,如 876.5 的階碼是03H,-876.5 的階碼是 83H;當十進制數的絕對值小於1時,階碼就等於 80H 減去小數點後面零的個數,例如 0.00382 的階碼是 7EH,-0.00382的階碼是 0FEH?在程序說明中,用[R0]或[R1]來表示R0或R1指示的十進制浮點操作數?例如有一個十進制浮點操作數存放在30H?31H?32H中,數值是 -0.07315,即-0.7315乘以10的-1次方,則(30H)=0FFH,31H=73H,(32H)=15H?若用[R0]來指向它,則應使(R0)=30H?
4.運算精度:單次定點運算精度為結果最低位的當量值;單次二進制浮點算術運算的精度優於十萬分之三;單次二進制浮點超越函數運算的精度優於萬分之一;BCD碼浮點數本身的精度比較低(萬分之一到千分之一),不宜作為運算的操作數,僅用於輸入或輸出時的數制轉換?不管那種數據格式,隨著連續運算的次數增加,精度都會下降?
5.工作區:數據工作區固定在A?B?R2~R7,數符或標志工作區固定在PSW和23H單元(位1CH~1FH)?在浮點系統中,R2?R3?R4和位1FH為第一工作區,R5?R6?R7和位1EH為第二工作區?用戶只要不在工作區中存放無關的或非消耗性的信息,程序就具有較好的透明性?
6.子程序調用範例:由於本程序庫特別注意了各子程序介面的相容性,很容易採用積木方式(或流水線方式)完成一個公式的計算?以浮點運算為例:
計算 y = Ln √ | Sin (ab/c+d) |
已知:a=-123.4;b=0.7577;c=56.34;d=1.276; 它們分別存放在30H?33H?36H?39H開始的連續三個單元中?用BCD碼浮點數表示時,分別為a=831234H;b=007577H;c=025634H;d=011276H?
求解過程:通過調用BTOF子程序,將各變數轉換成二進制浮點操作數,再進行各
種運算,最後調用FTOB子程序,還原成十進制形式,供輸出使用?程序如下:
TEST: MOV R0,#39H ;指向BCD碼浮點操作數d
LCALL BTOF ;將其轉換成二進制浮點操作數
MOV R0,#36H ;指向BCD碼浮點操作數c
LCALL BTOF ;將其轉換成二進制浮點操作數
MOV R0,#33H ;指向BCD碼浮點操作數b
LCALL BTOF ;將其轉換成二進制浮點操作數
MOV R0,#30H ;指向BCD碼浮點操作數a
LCALL BTOF ;將其轉換成二進制浮點操作數
MOV R1,#33H ;指向二進制浮點操作數b
LCALL FMUL ;進行浮點乘法運算
MOV R1,#36H ;指向二進制浮點操作數c
LCALL FDIV ;進行浮點除法運算
MOV R1,#39H ;指向二進制浮點操作數d
LCALL FADD ;進行浮點加法運算
LCALL FSIN ;進行浮點正弦運算
LCALL FABS ;進行浮點絕對值運算
LCALL FSQR ;進行浮點開平方運算
LCALL FLN ;進行浮點對數運算
LCALL FTOB ;將結果轉換成BCD碼浮點數
STOP: LJMP STOP
END
運行結果,[R0]=804915H,即y=-0.4915,比較精確的結果應該是-0.491437?
(1) 標號: FSDT 功能:浮點數格式化
入口條件:待格式化浮點操作數在[R0]中?
出口信息:已格式化浮點操作數仍在[R0]中?
影響資源:PSW?A?R2?R3?R4?位1FH 堆棧需求: 6位元組
FSDT: LCALL MVR0 ;將待格式化操作數傳送到第一工作區中
LCALL RLN ;通過左規完成格式化
LJMP MOV0 ;將已格式化浮點操作數傳回到[R0]中
(2) 標號: FADD 功能:浮點數加法
入口條件:被加數在[R0]中,加數在[R1]中?
出口信息:OV=0時,和仍在[R0]中,OV=1時,溢出?
影響資源:PSW?A?B?R2~R7?位1EH?1FH 堆棧需求: 6位元組
FADD: CLR F0 ;設立加法標志
SJMP AS ;計算代數和
(3) 標號: FSUB 功能:浮點數減法
入口條件:被減數在[R0]中,減數在[R1]中?
出口信息:OV=0時,差仍在[R0]中,OV=1時,溢出?
影響資源:PSW?A?B?R2~R7?位1EH?1FH 堆棧需求:6位元組
FSUB: SETB F0 ;設立減法標志
AS: LCALL MVR1 ;計算代數和?先將[R1]傳送到第二工作區
MOV C,F0 ;用加減標志來校正第二操作數的有效符號
RRC A
XRL A,@R1
MOV C,ACC.7
ASN: MOV 1EH,C ;將第二操作數的有效符號存入位1EH中
XRL A,@R0 ;與第一操作數的符號比較
RLC A
MOV F0,C ;保存比較結果
LCALL MVR0 ;將[R0]傳送到第一工作區中
LCALL AS1 ;在工作寄存器中完成代數運算
MOV0: INC R0 ;將結果傳回到[R0]中的子程序入口
INC R0
MOV A,R4 ;傳回尾數的低位元組
MOV @R0,A
DEC R0
MOV A,R3 ;傳回尾數的高位元組
MOV @R0,A
DEC R0
MOV A,R2 ;取結果的階碼
MOV C,1FH ;取結果的數符
MOV ACC.7,C ;拼入階碼中
MOV @R0,A
CLR ACC.7 ;不考慮數符
CLR OV ;清除溢出標志
CJNE A,#3FH,MV01;階碼是否上溢?
SETB OV ;設立溢出標志
MV01: MOV A,@R0 ;取出帶數符的階碼
RET
MVR0: MOV A,@R0 ;將[R0]傳送到第一工作區中的子程序
MOV C,ACC.7 ;將數符保存在位1FH中
MOV 1FH,C
MOV C,ACC.6 ;將階碼擴充為8bit補碼
MOV ACC.7,C
MOV R2,A ;存放在R2中
INC R0
MOV A,@R0 ;將尾數高位元組存放在R3中
MOV R3,A
INC R0
MOV A,@R0 ;將尾數低位元組存放在R4中
MOV R4,A
DEC R0 ;恢復數據指針
DEC R0
RET
MVR1: MOV A,@R1 ;將[R1]傳送到第二工作區中的子程序
MOV C,ACC.7 ;將數符保存在位1EH中
MOV 1EH,C
MOV C,ACC.6 ;將階碼擴充為8bit補碼
MOV ACC.7,C
MOV R5,A ;存放在R5中
INC R1
MOV A,@R1 ;將尾數高位元組存放在R6中
MOV R6,A
INC R1
MOV A,@R1 ;將尾數低位元組存放在R7中
MOV R7,A
DEC R1 ;恢復數據指針
DEC R1
RET
AS1: MOV A,R6 ;讀取第二操作數尾數高位元組
ORL A,R7
JZ AS2 ;第二操作數為零,不必運算
MOV A,R3 ;讀取第一操作數尾數高位元組
ORL A,R4
JNZ EQ1
MOV A,R6 ;第一操作數為零,結果以第二操作數為准
MOV R3,A
MOV A,R7
MOV R4,A
MOV A,R5
MOV R2,A
MOV C,1EH
MOV 1FH,C
AS2: RET
EQ1: MOV A,R2 ;對階,比較兩個操作數的階碼
XRL A,R5
JZ AS4 ;階碼相同,對階結束
JB ACC.7,EQ3;階符互異
MOV A,R2 ;階符相同,比較大小
CLR C
SUBB A,R5
JC EQ4
EQ2: CLR C ;第二操作數右規一次
MOV A,R6 ;尾數縮小一半
RRC A
MOV R6,A
MOV A,R7
RRC A
MOV R7,A
INC R5 ;階碼加一
ORL A,R6 ;尾數為零否?
JNZ EQ1 ;尾數不為零,繼續對階
MOV A,R2 ;尾數為零,提前結束對階
MOV R5,A
SJMP AS4
EQ3: MOV A,R2 ;判斷第一操作數階符
JNB ACC.7,EQ2;如為正,右規第二操作數
EQ4: CLR C
LCALL RR1 ;第一操作數右規一次
ORL A,R3 ;尾數為零否?
JNZ EQ1 ;不為零,繼續對階
MOV A,R5 ;尾數為零,提前結束對階
MOV R2,A
AS4: JB F0,AS5 ;尾數加減判斷
MOV A,R4 ;尾數相加
ADD A,R7
MOV R4,A
MOV A,R3
ADDC A,R6
MOV R3,A
JNC AS2
LJMP RR1 ;有進位,右規一次
AS5: CLR C ;比較絕對值大小
MOV A,R4
SUBB A,R7
MOV B,A
MOV A,R3
SUBB A,R6
JC AS6
MOV R4,B ;第一尾數減第二尾數
MOV R3,A
LJMP RLN ;結果規格化
AS6: CPL 1FH ;結果的符號與第一操作數相反
CLR C ;結果的絕對值為第二尾數減第一尾數
MOV A,R7
SUBB A,R4
MOV R4,A
MOV A,R6
SUBB A,R3
MOV R3,A
RLN: MOV A,R3 ;浮點數規格化
ORL A,R4 ;尾數為零否?
JNZ RLN1
MOV R2,#0C1H;階碼取最小值
RET
RLN1: MOV A,R3
JB ACC.7,RLN2;尾數最高位為一否?
CLR C ;不為一,左規一次
LCALL RL1
SJMP RLN ;繼續判斷
RLN2: CLR OV ;規格化結束
RET
RL1: MOV A,R4 ;第一操作數左規一次
RLC A ;尾數擴大一倍
MOV R4,A
MOV A,R3
RLC A
MOV R3,A
DEC R2 ;階碼減一
CJNE R2,#0C0H,RL1E;階碼下溢否?
CLR A
MOV R3,A ;階碼下溢,操作數以零計
MOV R4,A
MOV R2,#0C1H
RL1E: CLR OV
RET
RR1: MOV A,R3 ;第一操作數右規一次
RRC A ;尾數縮小一半
MOV R3,A
MOV A,R4
RRC A
MOV R4,A
INC R2 ;階碼加一
CLR OV ;清溢出標志
CJNE R2,#40H,RR1E;階碼上溢否?
MOV R2,#3FH ;階碼溢出
SETB OV
RR1E: RET
(4) 標號:FMUL 功能:浮點數乘法
入口條件:被乘數在[R0]中,乘數在[R1]中?
出口信息:OV=0時,積仍在[R0]中,OV=1時,溢出?
影響資源:PSW?A?B?R2~R7?位1EH?1FH 堆棧需求:6位元組
FMUL: LCALL MVR0 ;將[R0]傳送到第一工作區中
MOV A,@R0
XRL A,@R1 ;比較兩個操作數的符號
RLC A
MOV 1FH,C ;保存積的符號
LCALL MUL0 ;計算積的絕對值
LJMP MOV0 ;將結果傳回到[R0]中
MUL0: LCALL MVR1 ;將[R1]傳送到第二工作區中
MUL1: MOV A,R3 ;第一尾數為零否?
ORL A,R4
JZ MUL6
MOV A,R6 ;第二尾數為零否?
ORL A,R7
JZ MUL5
MOV A,R7 ;計算R3R4×R6R7-→R3R4
MOV B,R4
MUL AB
MOV A,B
XCH A,R7
MOV B,R3
MUL AB
ADD A,R7
MOV R7,A
CLR A
ADDC A,B
XCH A,R4
MOV B,R6
MUL AB
ADD A,R7
MOV R7,A
MOV A,B
ADDC A,R4
MOV R4,A
CLR A
RLC A
XCH A,R3
MOV B,R6
MUL AB
ADD A,R4
MOV R4,A
MOV A,B
ADDC A,R3
MOV R3,A
JB ACC.7,MUL2;積為規格化數否?
MOV A,R7 ;左規一次
RLC A
MOV R7,A
LCALL RL1
MUL2: MOV A,R7
JNB ACC.7,MUL3
INC R4
MOV A,R4
JNZ MUL3
INC R3
MOV A,R3
JNZ MUL3
MOV R3,#80H
INC R2
MUL3: MOV A,R2 ;求積的階碼
ADD A,R5
MD: MOV R2,A ;階碼溢出判斷
JB ACC.7,MUL4
JNB ACC.6,MUL6
MOV R2,#3FH ;階碼上溢,設立標志
SETB OV
RET
MUL4: JB ACC.6,MUL6
MUL5: CLR A ;結果清零(因子為零或階碼下溢)
MOV R3,A
MOV R4,A
MOV R2,#41H
MUL6: CLR OV
RET
(5) 標號: FDIV 功能:浮點數除法
入口條件:被除數在[R0]中,除數在[R1]中?
出口信息:OV=0時,商仍在[R0]中,OV=1時,溢出?
影響資源:PSW?A?B?R2~R7?位1EH?1FH 堆棧需求: 5位元組
FDIV: INC R0
MOV A,@R0
INC R0
ORL A,@R0
DEC R0
DEC R0
JNZ DIV1
MOV @R0,#41H;被除數為零,不必運算
CLR OV
RET
DIV1: INC R1
MOV A,@R1
INC R1
ORL A,@R1
DEC R1
DEC R1
JNZ DIV2
SETB OV ;除數為零,溢出
RET
DIV2: LCALL MVR0 ;將[R0]傳送到第一工作區中
MOV A,@R0
XRL A,@R1 ;比較兩個操作數的符號
RLC A
MOV 1FH,C ;保存結果的符號
LCALL MVR1 ;將[R1]傳送到第二工作區中
LCALL DIV3 ;調用工作區浮點除法
LJMP MOV0 ;回傳結果
DIV3: CLR C ;比較尾數的大小
MOV A,R4
SUBB A,R7
MOV A,R3
SUBB A,R6
JC DIV4
LCALL RR1 ;被除數右規一次
SJMP DIV3
DIV4: CLR A ;借用R0R1R2作工作寄存器
XCH A,R0 ;清零並保護之
PUSH ACC
CLR A
XCH A,R1
PUSH ACC
MOV A,R2
PUSH ACC
MOV B,#10H ;除法運算,R3R4/R6R7-→R0R1
DIV5: CLR C
MOV A,R1
RLC A
MOV R1,A
MOV A,R0
RLC A
MOV R0,A
MOV A,R4
RLC A
MOV R4,A
XCH A,R3
RLC A
XCH A,R3
MOV F0,C
CLR C
SUBB A,R7
MOV R2,A
MOV A,R3
SUBB A,R6
ANL C,/F0
JC DIV6
MOV R3,A
MOV A,R2
MOV R4,A
INC R1
DIV6: DJNZ B,DIV5
MOV A,R6 ;四捨五入
CLR C
RRC A
SUBB A,R3
CLR A
ADDC A,R1 ;將結果存回R3R4
MOV R4,A
CLR A
ADDC A,R0
MOV R3,A
POP ACC ;恢復R0R1R2
MOV R2,A
POP ACC
MOV R1,A
POP ACC
MOV R0,A
MOV A,R2 ;計算商的階碼
CLR C
SUBB A,R5
LCALL MD ;階碼檢驗
LJMP RLN ;規格化
(6) 標號: FCLR 功能:浮點數清零
入口條件:操作數在[R0]中?
出口信息:操作數被清零?
影響資源:A 堆棧需求: 2位元組
FCLR: INC R0
INC R0
CLR A
MOV @R0,A
DEC R0
MOV @R0,A
DEC R0
MOV @R0,#41H
RET
(7) 標號: FZER 功能:浮點數判零
入口條件:操作數在[R0]中?
出口信息:若累加器A為零,則操作數[R0]為零,否則不為零?
影響資源:A 堆棧需求: 2位元組
FZER: INC R0
INC R0
MOV A,@R0
DEC R0
ORL A,@R0
DEC R0
JNZ ZERO
MOV @R0,#41H
ZERO: RET
(8) 標號: FMOV 功能:浮點數傳送
入口條件:源操作數在[R1]中,目標地址為[R0]?
出口信息:[R0]=[R1],[R1]不變?
影響資源:A 堆棧需求: 2位元組
FMOV: INC R0
INC R0
INC R1
INC R1
MOV A,@R1
MOV @R0,A
DEC R0
DEC R1
MOV A,@R1
MOV @R0,A
DEC R0
DEC R1
MOV A,@R1
MOV @R0,A
RET
(9) 標號: FPUS 功能:浮點數壓棧
入口條件:操作數在[R0]中?
出口信息:操作數壓入棧頂?
影響資源:A?R2?R3 堆棧需求: 5位元組
FPUS: POP ACC ;將返回地址保存在R2R3中
MOV R2,A
POP ACC
MOV R3,A
MOV A,@R0 ;將操作數壓入堆棧
PUSH ACC
INC R0
MOV A,@R0
PUSH ACC
INC R0
MOV A,@R0
PUSH ACC
DEC R0
DEC R0
MOV A,R3 ;將返回地址壓入堆棧
PUSH ACC
MOV A,R2
PUSH ACC
RET ;返回主程序
(10) 標號: FPOP 功能:浮點數出棧
入口條件:操作數處於棧頂?
出口信息:操作數彈至[R0]中?
影響資源:A?R2?R3 堆棧需求: 2位元組
FPOP: POP ACC ;將返回地址保存在R2R3中
MOV R2,A
POP ACC
MOV R3,A
INC R0
INC R0
POP ACC ;將操作數彈出堆棧,傳送到[R0]中
MOV @R0,A
DEC R0
POP ACC
MOV @R0,A
DEC R0
POP ACC
MOV @R0,A
MOV A,R3 ;將返回地址壓入堆棧
PUSH ACC
MOV A,R2
PUSH ACC
RET ;返回主程序
(11) 標號: FCMP 功能:浮點數代數值比較(不影響待比較操作數)
入口條件:待比較操作數分別在[R0]和[R1]中?
出口信息:若CY=1,則[R0] < [R1],若CY=0且A=0則 [R0] = [R1],否則[R0] > [R1]?
影響資源:A?B?PSW 堆棧需求: 2位元組
FCMP: MOV A,@R0 ;數符比較
XRL A,@R1
JNB ACC.7,CMP2
MOV A,@R0 ;兩數異號,以[R0]數符為准
RLC A
MOV A,#0FFH
RET
CMP2: MOV A,@R1 ;兩數同號,准備比較階碼
MOV C,ACC.6
MOV ACC.7,C
MOV B,A
MOV A,@R0
MOV C,ACC.7
MOV F0,C ;保存[R0]的數符
MOV C,ACC.6
MOV ACC.7,C
CLR C ;比較階碼
SUBB A,B
JZ CMP6
RLC A ;取階碼之差的符號
JNB F0,CMP5
CPL C ;[R0]為負時,結果取反
CMP5: MOV A,#0FFH ;兩數不相等
RET
CMP6: INC R0 ;階碼相同時,准備比較尾數
INC R0
INC R1
INC R1
CLR C
MOV A,@R0
SUBB A,@R1
MOV B,A ;保存部分差
DEC R0
DEC R1
MOV A,@R0
SUBB A,@R1
DEC R0
DEC R1
ORL A,B ;生成是否相等信息
JZ CMP7
JNB F0,CMP7
CPL C ;[R0]為負時,結果取反
CMP7: RET
(12) 標號: FABS 功能:浮點絕對值函數
入口條件:操作數在[R0]中?
出口信息:結果仍在[R0]中?
影響資源:A 堆棧需求: 2位元組
FABS: MOV A,@R0 ;讀取操作數的階碼
CLR ACC.7 ;清除數符
MOV @R0,A ;回傳階碼
RET
(13) 標號: FSGN 功能:浮點符號函數
入口條件:操作數在[R0]中?
出口信息:累加器 A=1 時為正數,A=0FFH時為負數,A=0 時為零?
影響資源:PSW?A 堆棧需求: 2位元組
FSGN: INC R0 ;讀尾數
MOV A,@R0
INC R0
ORL A,@R0
DEC R0
DEC R0
JNZ SGN
RET ;尾數為零,結束
SGN: MOV A,@R0 ;讀取操作數的階碼
RLC A ;取數符
MOV A,#1 ;按正數初始化
JNC SGN1 ;是正數,結束
MOV A,#0FFH ;是負數,改變標志
SGN1: RET
(14) 標號: FINT 功能:浮點取整函數
入口條件:操作數在[R0]中?
出口信息:結果仍在[R0]中?
影響資源:PSW?A?R2?R3?R4?位1FH 堆棧需求: 6位元組
FINT: LCALL MVR0 ;將[R0]傳送到第一工作區中
LCALL INT ;在工作寄存器中完成取整運算
LJMP MOV0 ;將結果傳回到[R0]中
INT: MOV A,R3
ORL A,R4
JNZ INTA
CLR 1FH ;尾數為零,階碼也清零,結束取整
MOV R2,#41H
RET
INTA: MOV A,R2
JZ INTB ;階碼為零否?
JB ACC.7,INTB;階符為負否?
CLR C
SUBB A,#10H ;階碼小於16否?
JC INTD
RET ;階碼大於16,已經是整數
INTB: CLR A ;絕對值小於一,取整後正數為零,負數為負一
MOV R4,A
MOV C,1FH
RRC A
MOV R3,A
RL A
MOV R2,A
JNZ INTC
MOV R2,#41H
INTC: RET
INTD: CLR F0 ;舍尾標志初始化
INTE: CLR C
LCALL RR1 ;右規一次
ORL C,F0 ;記憶舍尾情況
MOV F0,C
CJNE R2,#10H,INTE;階碼達到16(尾數完全為整數)否?
JNB F0,INTF ;捨去部分為零否?
JNB 1FH,INTF;操作數為正數否?
INC R4 ;對於帶小數的負數,向下取整
MOV A,R4
JNZ INTF
INC R3
INTF: LJMP RLN ;將結果規格化
(15) 標號: FRCP 功能:浮點倒數函數
入口條件:操作數在[R0]中?
出口信息:OV=0時,結果仍在[R0]中,OV=1時,溢出?
影響資源:PSW?A?B?R2~R7?位1EH?1FH 堆棧需求: 5位元組
FRCP: MOV A,@R0
MOV C,ACC.7
MOV 1FH,C ;保存數符
MOV C,ACC.6 ;絕對值傳送到第二工作區
MOV ACC.7,C
MOV R5,A
INC R0
MOV A,@R0
MOV R6,A
INC R0
MOV A,@R0
MOV R7,A
DEC R0
DEC R0
ORL A,R6
JNZ RCP
SETB OV ;零不能求倒數,設立溢出標志
RET
RCP: MOV A,R6
JB ACC.7,RCP2;操作數格式化否?
CLR C ;格式化之
MOV A,R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
DEC R5
SJMP RCP
RCP2: MOV R2,#1 ;將數值1.00傳送到第一工作區
MOV R3,#80H
MOV R4,#0
LCALL DIV3 ;調用工作區浮點除法,求得倒數
LJMP MOV0 ;回傳結果
(16) 標號: FSQU 功能:浮點數平方
入口條件:操作數在[R0]中?
出口信息:OV=0時,平方值仍然在[R0]中,OV=1時溢出?
影響資源:PSW?A?B?R2~R7?位1EH?1FH 堆棧需求: 9位元組
FSQU: MOV A,R0 ;將操作數
XCH A,R1 ;同時作為乘數
PUSH ACC ;保存R1指針
LCALL FMUL ;進行乘法運算
POP ACC
MOV R1,A ;恢復R1指針
RET
(17) 標號: FSQR 功能:浮點數開平方(快速逼近演算法)
入口條件:操作數在[R0]中?
出口信息:OV=0時,平方根仍在[R0]中,OV=1時,負數開平方出錯?
影響資源:PSW?A?B?R2~R7 堆棧需求: 2位元組
FSQR: MOV A,@R0
JNB ACC.7,SQR
SETB OV ;負數開平方,出錯
RET
SQR: INC R0
INC R0
MOV A,@R0
DEC R0
ORL A,@R0
DEC R0
JNZ SQ
MOV @R0,#41H;尾數為零,不必運算
CLR OV
RET
SQ: MOV A,@R0
MOV C,ACC.6 ;將階碼擴展成8bit補碼
MOV ACC.7,C
INC A ;加一
CLR C
RRC A ;除二
MOV @R0,A ;得到平方根的階碼,回存之
INC R0 ;指向被開方數尾數的高位元組
JC SQR0 ;原被開方數的階碼是奇數嗎?
MOV A,@R0 ;是奇數,尾數右規一次
RRC A
MOV @R0,A
INC R0
MOV A,@R0
RRC A
MOV @R0,A
DEC R0
SQR0: MOV A,@R0
JZ SQR9 ;尾數為零,不必運算
MOV R2,A ;將尾數傳送到R2R3中
INC R0
MOV A,@R0
MOV R3,A
MOV A,R2 ;快速開方,參閱定點子程序說明
ADD A,#57H
JC SQR2
ADD A,#45H
JC SQR1
ADD A,#24H
MOV B,#0E3H
MOV R4,#80H
SJMP SQR3
SQR1: MOV B,#0B2H
MOV R4,#0A0H
SJMP SQR3
SQR2: MOV B,#8DH
MOV R4,#0D0H
SQR3: MUL AB
MOV A,B
ADD A,R4
MOV R4,A
MOV B,A
MUL AB
XCH A,R3
CLR C
SUBB A,R3
MOV R3,A
MOV A,B
XCH A,R2
SUBB A,R2
MOV R2,A
SQR4: SETB C
MOV A,R4
RLC A
MOV R6,A
CLR A
RLC A
MOV R5,A
MOV A,R3
SUBB A,R6
MOV B,A
MOV A,R2
SUBB A,R5
JC SQR5
INC R4
MOV R2,A
MOV R3,B
SJMP SQR4
SQR5: MOV A,R4
XCH A,R2
RRC A
MOV F0,C
MOV A,R3
MOV R5,A
MOV R4,#8
SQR6: CLR C
MOV A,R3
RLC A
MOV R3,A
CLR C
MOV A,R5
SUBB A,R2
JB F0,SQR7
JC SQR8
SQR7: MOV R5,A
INC R3
SQR8: CLR C
MOV A,R5
RLC A
MOV R5,A
MOV F0,C
DJNZ R4,SQR6
MOV A,R3 ;將平方根的尾數回傳到[R0]中
MOV @R0,A
DEC R0
MOV A,R2
MOV @R0,A
SQR9: DEC R0 ;數據指針回歸原位
CLR OV ;開方結果有效
RET
(18) 標號: FPLN 功能:浮點數多項式計算
入口條件:自變數在[R0]中,多項式系數在調用指令之後,以40H結束?
出口信息:OV=0時,結果仍在[R0]中,OV=1時,溢出?
影響資源:DPTR?PSW?A?B?R2~R7?位1EH?1FH 堆棧需求: 4位元組
FPLN: POP DPH ;取出多項式系數存放地址
POP DPL
XCH A,R0 ;R0?R1交換角色,自變數在[R1]中
XCH A,R1
XCH A,R0
CLR A ;清第一工作區
MOV R2,A
MOV R3,A
MOV R4,A
CLR 1FH
PLN1: CLR A ;讀取一個系數,並裝入第二工作區
MOVC A,@A+DPTR
MOV C,ACC.7
MOV 1EH,C
MOV C,ACC.6
MOV ACC.7,C
MOV R5,A
INC DPTR
CLR A
MOVC A,@A+DPTR
MOV R6,A
INC DPTR
CLR A
MOVC A,@A+DPTR
MOV R7,A
INC DPTR ;指向下一個系數
MOV C,1EH ;比較兩個數符
RRC A
XRL A,23H
RLC A
MOV F0,C ;保存比較結果
LCALL AS1 ;進行代數加法運算
CLR A ;讀取下一個系數的第一個位元組
MOVC A,@A+DPTR
CJNE A,#40H,PLN2;是結束標志嗎?
XCH A,R0 ;運算結束,恢復R0?R1原來的角色
XCH A,R1
XCH A,R0
LCALL MOV0 ;將結果回傳到[R0]中
CLR A
INC DPTR
JMP @A+DPTR ;返回主程序
PLN2: MOV A,@R1 ;比較自變數和中間結果的符號
XRL A,23H
RLC A
MOV 1FH,C ;保存比較結果
LCALL MUL0 ;進行乘法運算
SJMP PLN1 ;繼續下一項運算
(19) 標號: FLOG 功能:以10為底的浮點對數函數
入口條件:操作數在[R0]中?
出口信息:OV=0時,結果仍在[R0]中,OV=1時,負數或零求對數出錯?
影響資源:DPTR?PSW?A?B?R2~R7?位1EH?1FH 堆棧需求:9位元組
FLOG: LCALL FLN ;先以e為底求對數
JNB OV,LOG
RET ;如溢出則停止計算
LOG: MOV R5,#0FFH;系數0.43430(1/Ln10)
MOV R6,#0DEH
MOV R7,#5CH
LCALL MUL1 ;通過相乘來換底
LJMP MOV0 ;傳回結果
2. 51單片機按鍵計數器C語言編程
#include<reg51.h>
#defineucharunsignedchar;
uchardistab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};//0到f
ucharnumber,dat,dis[4];
voidt0isr()interrupt1
{
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
number++;
number%=3;
switch(number)
P1=0x20<<number;
P0=distab[dis[number]];
}
voidint0isr()interrupt0
{
dat++;
dat%=1000;
dis[0]=dat%10;
dis[1]=dat%100/10;
dis[2]=dat/100;
}
main()
{
TMOD=0x01;
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
TR1=1;
ET1=1;
EX0=1;
IT0=1;
EA=1;
while(1);
}
3. 51單片機數碼管計算器的C程序
你再把分加到100分,我給你一個C語言的,帶電路圖。
;不知和您的硬體電路是否相同,
;不知和2你的單片機型號是否相同
sec_l equ 30h ;30單元存儲秒個位值
sec_h equ 31h ;31單元存儲秒十位值
bar_2 equ 32h ;32單元存儲"-"段碼的偏移量
min_l equ 33h ;33單元存儲分個位值
min_h equ 34h ;34單元存儲分十位值
bar_5 equ 35h ;35單元存儲"-"段碼的偏移量
hou_l equ 36h ;36單元存儲時個位值
hou_h equ 37h ;37單元存儲時十位值
sec equ 38h ;38單元為秒計數器(00s-59s)
min equ 39h ;39單元為分計數器(00m-59m)
hou equ 40h ;40單元為時計數器(00h-23h)
cou equ 41h ;41單元為軟計數器,對10ms時基信號累加到1s
dis_b equ 42h ;dis_b(42單元)作為位碼選通數碼管
dis_r equ 43h ;dis_r(43單元)為取段碼時的偏移量
key_v equ 44h ;存儲鍵值
key_t equ 45h ;按鍵掃描中臨時存儲鍵值
org 0000h
ajmp start
org 000bh ;定時器0的中斷入口地址
ajmp time0 ;跳到定時器0的中斷服務程序處
org 001bh ;定時器1的中斷入口地址
ajmp time1 ;跳到定時器1的中斷服務程序處
org 0030h
start:
mov p2,#0xff ;關所有數碼管
mov p1,#0xff ;p1為准雙向口,作輸入時先寫1
mov key_v,#0xff ;初始鍵值為ff
mov bar_2,#10 ;'-'段碼偏移量為10
mov bar_5,#10 ;'-'段碼偏移量為10
mov dis_b,#0x7f ;初始選通P2.7口數碼管
mov dis_r,#0 ;初始化偏移量為0
mov sec,#0 ;秒計數清零
mov min,#0 ;分計數清零
mov hou,#0 ;時計數清零
mov cou,#0 ;軟計數器清零
mov tmod,#00010001b ;定時/計數器0、1工作於方式1
mov th0,#0xd8 ;預置定時常數55536(d8f0),產生10ms時基信號
mov tl0,#0xf0
mov th1,#0xfc ;預置定時常數64536(fc18),產生1ms間隔用於動態顯示
mov tl1,#0x18
setb ea ;開總中斷
setb et0 ;定時/計數器0允許中斷
setb et1 ;定時/計數器1允許中斷
setb tr0 ;開定時/計數器0
setb tr1 ;開定時/計數器1
key:
mov a,p1 ;讀入鍵值
mov key_t,a ;存儲到臨時變數中
xrl a,key_v ;檢測鍵值是否改變
jz key ;未改變則重新掃描
lcall d_10ms ;有鍵按下則延時10ms消抖
mov a,p1 ;再次讀入鍵值
mov key_t,a ;存入臨時變數
xrl a,key_v ;檢測鍵值是否改變
jz key ;未改變則為抖動繼續掃描
mov key_v,key_t ;確定為鍵按下則保存鍵值
lcall key_to ;調用鍵處理部分
ajmp key ;循環掃描按鍵
key_to: ;鍵處理子程序
mov a,key_v ;讀入鍵值
cjne a,#0xef,next ;不是P1.4口鍵值則查下一個
ajmp k1 ;是則轉去執行該鍵的處理
next: cjne a,#0xdf,back ;也不是P1.5口鍵值則結束
ajmp k2 ;是則轉去執行該鍵的處理
k1: mov a,min ;讀入分計數器的值
cjne a,#59,k1_add ;分計數值未到59
mov min,#0 ;分鍾加到59時則清零
ajmp back ;結束
k1_add: inc min ;分加1
ajmp back ;結束
k2: mov a,hou ;讀入時計數器的值
cjne a,#23,k2_add ;時計數值未到23
mov hou,#0 ;時加到23時則清零
ajmp back ;結束
k2_add: inc hou ;時加1
back: ret ;結束
;--------------------------------------------------------------------------------
time0: ;定時器0中斷服務程序
push psw ;保護現場
push acc
inc cou ;軟計數器加1
mov a,cou ;計數器值送入a
cjne a,#100,over ;未計到100則返回繼續計數
mov cou,#0 ;計到100後軟計數器清零(到1s)
inc sec ;秒計數器加1(進位10ms*100=1s)
mov a,sec ;秒計數值送入a
cjne a,#60,over ;未計到60則返回繼續計數
mov sec,#0 ;計到60後秒計數器清零
inc min ;分計數器加1(進位60s=1m)
mov a,min ;分計數值送入a
cjne a,#60,over ;未計到60則返回繼續計數
mov min,#0 ;計到60後分計數器清零
inc hou ;時計數器加1(進位60m=1h)
mov a,hou ;時計數值送入a
cjne a,#24,over ;未計到24則返回繼續計數
mov hou,#0 ;計到24後時計數器清零,重新計時
over: mov th0,#0xd8 ;重置定時常數
mov tl0,#0xf0
pop acc ;恢復現場
pop psw
reti ;中斷返回
;--------------------------------------------------------------------------------
time1: ;定時器1中斷服務程序
push psw ;保護現場
push acc
push b
;以下是秒計數器值個位十位分開
mov a,sec ;秒計數器值送入a(被除數)
mov b,#10 ;除數10送入b
div ab
mov sec_l,b ;余數b(秒個位值)送入秒個位存儲單元
mov sec_h,a ;商a(秒十位值)送入秒十位存儲單元
;以下是分計數器值個位十位分開
mov a,min ;分計數器值送入a(被除數)
mov b,#10 ;除數10送入b
div ab
mov min_l,b ;余數b(分個位值)送入分個位存儲單元
mov min_h,a ;商a(分十位值)送入分十位存儲單元
;以下是時計數器值個位十位分開
mov a,hou ;時計數器值送入a(被除數)
mov b,#10 ;除數10送入b
div ab
mov hou_l,b ;余數b(時個位值)送入時個位存儲單元
mov hou_h,a ;商a(時十位值)送入時十位存儲單元
mov dptr,#table ;數碼管段碼表首址送入dptr
mov a,#sec_l ;取秒個位值的地址
add a,dis_r ;基址+偏移量
mov r0,a ;R0為欲顯示值的地址
mov a,@r0 ;取欲顯示值送入a
; dis_r : 0 1 2 3 4 5 6 7
;對應單元: sec_l sec_h bar_2 min_l min_h bar_5 hou_l hou_h
movc a,@a+dptr ;取對應值的段碼
mov p0,a ;段碼送入P0口
mov p2,dis_b ;位碼送入P2口
inc dis_r ;偏移量加1,下次中斷時顯示下個數
anl dis_r,#0x07 ;dis_r增到8時自動清0(使之在0到7間循環)
mov a,dis_b ;位碼循環右移,下次中斷時選通下個數碼管
rr a
mov dis_b,a
mov th1,#0xfc ;重置定時常數
mov tl1,#0x18
pop b
pop acc ;恢復現場
pop psw
reti
d_10ms: mov r5,#20 ;1+(1+2*255)*20+2*20=10.261ms@12M
temp1: mov r6,#255 ;1+2*255
djnz r6,$
djnz r5,temp1
ret
table: db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段碼表
; 0 1 2 3 4 5 6 7 8 9 - 對應內容
羚羊
end
4. 如何用51單片機做計算器(要求用C語言編程) 由於是新手所以沒積分 對不住各位了
給你參考一下的,我最近做的:
我的實驗板上的鍵不夠,所以只能做加法運算,而且兩數之和不能大於十。
嘿嘿,沒錯這個給某種人用的。
//**********myh.h***********有兩個文件,一個是頭文件myh.h一個是js.c
#include<reg52.h>
typedefunsignedcharuchar;
typedefunsignedintuint;
typedefbitBOOL;
//**
sbitrs=P2^6;
sbitrw=P2^5;
sbite=P2^7;
//**
ucharKey_Down(void);//返回0到12的鍵盤的編碼
voiddelay(uchar);//延時
voidInit(void);
voidWrite_Cmd(uchar);
voidWrite_Data(uchar);
BOOLIf_Busy();
//**
ucharcodeLcd_tab[]="0123456789+=";
ucharcodeKey_tab[]={0xb7,0xbb,0xbd,0xbe,0xd7,0xdb,0xdd,0xde,0xe7,0xeb,0xed,0xee};
//**********
uintQ0;
uintQ1;
uintQ2;
//*************js.c********
#include"myh.h"
//**************
voidmain()
{ucharm_key;
ucharm_inc=0;
Init();
Write_Cmd(0x80);
while(1)
{Q1=0;
Q0=0;
Q2=0;
m_key=Key_Down();
Write_Cmd(0x01);
Write_Data(Lcd_tab[m_key]);
Q0=m_key;
m_key=Key_Down();
Write_Data(Lcd_tab[m_key]);
m_key=Key_Down();
Write_Data(Lcd_tab[m_key]);
Q1=m_key;
m_key=Key_Down();
Write_Data(Lcd_tab[m_key]);
Q2=Q0+Q1;
Write_Data(Lcd_tab[Q2]);
}
}
//************************
ucharKey_Down(void)
{ucharKey_number=0;
ucharm_cx;
ucharm_cy;
ucharm_cxy;
P3=0x0f;
m_cx=P3;
while(1)
{if(m_cx!=0x0f)
{delay(500);
m_cx=P3;
if(m_cx!=0x0f)
break;}
else{P3=0x0f;m_cx=P3;}
}
P3=0x0f;
m_cx=P3&0x0f;
P3=0xf0;
m_cy=P3&0xf0;
m_cxy=m_cx|m_cy;
for(Key_number=0;Key_number<12;Key_number++)
{if(m_cxy==Key_tab[Key_number])
break;
}
returnKey_number;}
//**********
voiddelay(uchartime)
{ucharj;
for(;time>0;time--)
for(j=0;j<200;j++);
}
//**************
voidinit()
{delay(10);
Write_Cmd(0x38);
delay(10);
Write_Cmd(0x38);
delay(10);
Write_Cmd(0x38);
delay(10);
Write_Cmd(0x0c);
delay(10);
Write_Cmd(0x06);
delay(10);
Write_Cmd(0x01);
}
//***********
voidWrite_Cmd(ucharcmd)
{//while(If_Busy());
e=0;
rw=0;
rs=0;
delay(4);
P0=cmd;
delay(4);
e=1;
delay(10);
e=0;
}
//***
voidWrite_Data(uchardat)
{//while(If_Busy());
e=0;
rw=0;
rs=1;
delay(4);
P0=dat;
delay(4);
e=1;
delay(10);
e=0;
}
//**
BOOLIf_Busy()
{
BOOLresult;
rw=1;
rs=0;
e=1;
delay(4);
result=(BOOL)(P2&0x80);
e=0;
returnresult;
}
5. 單片機計算器C語言程序
//*************************************************************************************************
//*************************************************************************************************
//**<程序名>:多功能計算器 **
//**<功能>:可以進行6位數以內正整數的加減乘除運算,以及計時器和自定義倒計時功
*
//* ******************************頭文件及宏定義************************** *
//* *
//*************************************************************************************************
#include "includes.h"
#define TIME0H 0xFC
#define TIME0L 0x18 //定時器0溢出時間:5ms
#define TIME1H 0x44
#define TIME1L 0x80 //定時器1溢出時間:48ms
//*************************************************************************************************
//* *
//* ********************************全局變數****************************** *
//* *
//*************************************************************************************************
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定時器0定時刷新LED計數>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
unsigned long ul_Number=0; //LCD實時顯示數字。
unsigned char uca_ShowCustom[6]={0x88,0x83,0xC6,0xA1,0x86,0x84};
//存放自定義顯示字元。
unsigned char uc_DisCount=1; //LCD時事刷新計數。
bit b_ShowMode=0; //顯示模式標志位。
//0--數字模式,將要顯示的數字賦給ul_Number便可時事顯示數值,
// 默認為數字模式;
//1--自定義模式,該模式下自定義字元顯示。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定時器1計數刷新定時(計時模式)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
unsigned char uc_TimeCount=1; //定時器1定時計數。
bit b_ClockStart=0; //定時器1顯示計數標志位。
extern bit b_ClockOppose; //TimeOppose.c
extern unsigned long ul_ClockOppose;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<防抖動標志>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bit b_KeyShock=0; //鍵盤防抖動標志位。
//當按鍵中斷產生時,首先判斷此位。
//0--執行鍵盤掃描及鍵碼處理程序;1--不執行。
bit b_KillShock=0; //防抖標志清除位:0--不清除;1--清除。
unsigned char uc_KillCount=1; //抖動標志清除計數,使用定時器1。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<LCD閃爍顯示報告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
bit b_LCDClean=0; //通過設置b_LCDClean為1便可啟動延時清空LCD顯示。
unsigned char uc_CleanCount=1; //延遲時間可在T1中斷中設定。
unsigned char uc_ReportSymbol;
bit b_ReportFlash=0;
unsigned char uca_FlashBlank[]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
//*************************************************************************************************
//* *
//* ********************************主函數****************************** *
//* *
//*************************************************************************************************
void main()
{
P2=0x0F; //初始化鍵盤介面。
TMOD=0x11; //定時器0:模式一;定時器0:模式一.
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定時器0,用於LCD刷新>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
TH0=TIME0H;
TL0=TIME0L;
TR0=1; //開啟定時器0
ET0=1; //開定時器0中斷
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<定時器1,用於1s計時 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
TH1=TIME1H;
TL1=TIME1L;
TR1=1; //開啟定時器1
ET1=1; //開定時器1中斷
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<外部中斷0,用於執行鍵盤掃描和鍵處理程序>>>>>>>>>>>>>>>>>>>>>>>>>>>
IT0=1; //外部中斷0,中斷方式:下降沿
EX0=1; //開啟外部中斷0
PT0=1; //把定時器0溢出中斷設為高優先順序。
EA=1; //開啟總中斷
while(1);
}
//*************************************************************************************************
//* *
//* ***************************外部中斷0,調用鍵盤掃描程序************************* *
//* *
//*************************************************************************************************
void vINT0(void) interrupt 0
{
EX0=0; //在鍵掃描處理時,關閉外部中斷0,防抖動。
if(b_KeyShock==0)
{
vKeyProcess(ucKeyScan()); //當判斷有按鍵按下時,掃描鍵盤,並把掃描結果進行處理。
b_KeyShock=1; //設置防抖動標志。
}
else b_KeyShock=0; //如果有抖動則不執行鍵掃描,恢復防抖動標志。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<設置防抖動清除標志位 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(b_KeyShock==1)
b_KillShock=1; //如果防抖動標志位開啟則開啟防抖動標志清除位,
//300ms後清除防抖動標志。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<恢復鍵掃描處理前初始狀態 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
P2=0x0F; //恢復P2口。
EX0=1; //恢復按鍵中斷。
}
//*************************************************************************************************
//* *
//* ****************定時器1中斷,用於計時功能和防抖動標志清除以及顯示報告**************** *
//* *
//*************************************************************************************************
void vTimer1(void) interrupt 3
{
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<計時模式計數刷新>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(b_ClockStart==1) //當計時模式開啟式,如計時處於運行狀態則執行定時計數增加。
{
if(b_ClockOppose==0) //正常計時。
{
if(uc_TimeCount%21==0)
{
uc_TimeCount=1;
ul_Number++;
}
else uc_TimeCount++;
}
else
{ //倒計時模式。
if(uc_TimeCount%21==0)
{
uc_TimeCount=1;
if(ul_ClockOppose>0)
{
ul_ClockOppose--;
ul_Number=ul_ClockOppose;
}
else
{
b_ClockStart=0;
uc_ReportSymbol=7;
b_LCDClean=1;
}
}
else uc_TimeCount++;
}
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<防抖動標志清除>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(b_KillShock==1)
{
if(uc_KillCount%5==0) //當防抖動標志位為1時,計時300ms後清除抖動標志位。
{
b_KeyShock=0;
b_KillShock=0;
uc_KillCount=1;
}
else uc_KillCount++;
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<LCD顯示報告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(b_LCDClean==1)
{
if(uc_CleanCount==1)
{
EX0=0; //關閉鍵盤中斷,此時按鍵無效。
vShowReport(uc_ReportSymbol);
b_ShowMode=1;
}
if(uc_CleanCount%40==0) //通過設置b_LCDClean為1便可啟動延時清空LCD顯示。
{
b_LCDClean=0; //關閉清零標志位,清零結束。
uc_CleanCount=1; //恢復清零計數為初始值1.
b_ShowMode=0; //恢復顯示模式為默認的數字模式。
b_ReportFlash=0;
EX0=1; //重新開啟鍵盤中斷。
}
else
{
//<<<<<<<<<<<<<<<<<<<<<<<<<實現閃爍報告功能>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(uc_CleanCount%7==0)
{
if(b_ReportFlash==0)
{
vCharCopy(uca_FlashBlank);
b_ReportFlash=1;
}
else
{
vShowReport(uc_ReportSymbol);
b_ReportFlash=0;
}
}
uc_CleanCount++;
}
}
TH1=TIME1H;
TL1=TIME1L;
}
//*************************************************************************************************
//* *
//* ***************************定時器0,定時刷新LED************************* *
//* *
//*************************************************************************************************
void vTimer0(void) interrupt 1
{
if(b_ShowMode==0)
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<數字模式>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
{
vShowOneNum(*(pucLedNum(ul_Number)+uc_DisCount),6-uc_DisCount); //在LCD上顯示1位數字。
if(uc_DisCount==5)
uc_DisCount=0; //定時器0在每次被觸發時,改變LCD顯示。
else uc_DisCount++; //從第一位到第六位循環顯示。
}
else
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<自定義模式>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
{
vShowCustom(uca_ShowCustom[uc_DisCount],uc_DisCount);
if(uc_DisCount==5)
uc_DisCount=0; //定時器0在每次被觸發時,改變LCD顯示。
else uc_DisCount++; //從第一位到第六位循環顯示。
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<恢復定時器0初始狀態 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
TH0=TIME0H;
TL0=TIME0L;
},
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//*************************************************************************************************
//*************************************************************************************************
//**<程序名>:鍵盤掃描子程序 **
//**<功能>:當有外部中斷0時調用此函數,使用列掃描的方式獲取鍵碼,鍵碼由2位數字組成。高位為行號 **
//** 低位為列號。 **
//*************************************************************************************************
//*************************************************************************************************
//*************************************************************************************************
//* *
//* ******************************頭文件及宏定義************************** *
//* *
//*************************************************************************************************
#include <at89x51.h>
#define SCANPORT P2 //4×4鍵盤掃描埠,低4位是行線,高4位是列線。
//採用逐列掃描的方法,無按鍵時,低4位輸出1,高4位輸出0。
//當有按鍵時,高4位輸出掃描電位,低4位輸入掃描結果。
//*************************************************************************************************
//* *
//* ********************************全局變數****************************** *
//* *
//*************************************************************************************************
unsigned char uca_LineScan[4]={0xEF,0xDF,0xBF,0x7F}; //列線掃描電壓,分為第1,2,3,4根列線
//為低電平,其他為高電平。
//*************************************************************************************************
//* *
//* ********************************函數實現****************************** *
//* *
//*************************************************************************************************
unsigned char ucKeyScan()
{
unsigned char ucTemp=0; //掃描狀態暫存。
unsigned char ucRow=0,ucLine=0; //行號,列號。
for(ucLine=0;ucLine<4;ucLine++) //列掃描
{
SCANPORT=uca_LineScan[ucLine]; //輸出掃描電位。
ucTemp=SCANPORT&0x0F; //輸入掃描電位,並屏蔽高4位。
if(ucTemp!=0x0F)
{ //判斷該列是否有按鍵按下。
switch(ucTemp)
{
case 0x0E: ucRow=10;break; //如果有,則判斷行號。
case 0x0D: ucRow=20;break;
case 0x0B: ucRow=30;break;
case 0x07: ucRow=40;break;
default: ucRow=50;break;
}
break;
}
}
return ucRow+ucLine+1; //返回按鍵編碼。格式為2位數,高位為行號,低位為列號。
}
/////////////////////////////////////////////////////////////////////
//*************************************************************************************************
//*************************************************************************************************
//**<程序名>:計算器處理主程序,根據計算器的輸入狀態分派不同的函數對按鍵進行處理。 **
//**<功能>:當b_WorkMode=0是,若有鍵按下則調用此函數對鍵碼進行處理。 **
//*************************************************************************************************
//*************************************************************************************************
//*************************************************************************************************
//* *
//* ******************************頭文件及宏定義************************** *
//* *
//*************************************************************************************************
#include "CalReady.h"
//*************************************************************************************************
//* *
//* ********************************全局變數****************************** *
//* *
//*************************************************************************************************
extern unsigned long ul_Number; //LCE顯示數據,LCD實時顯示該數字。
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<工作模式(默認為計算器模式)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
extern bit b_WorkMode; //0--計算器模式;
//1--計時模式。
//定義在KeyProcess.c中。
unsigned char uc_ModeChange=0;
extern bit b_LCDClean;
extern unsigned char uc_ReportSymbol;
unsigned long ul_NumberOne=0; //第一個數
unsigned long ul_NumberTwo=0; //第二個數
unsigned char uc_Operator=0; //運算符
unsigned long ul_Result=0; //運算結果
unsigned char uc_NumPointer=1; //計算狀態
//*************************************************************************************************
//* *
//* *******************************計算器處理主函數****************************** *
//* *
//*************************************************************************************************
void vCalculator(unsigned char ucKeyCode)
{
if(ucKeyCode==41) //判斷按鍵是不是'NO/C'。
{
if(uc_NumPointer==1) //如果是『NO/C』鍵則判斷手機否是狀態一。
{
if(uc_ModeChange==2) //如果是狀態一則看uc_ModeChange是不是2。
{
uc_ModeChange=0; //如果是2則計時器模式。
b_WorkMode=1;
uc_ReportSymbol=3; //閃爍顯示:-CHAG-1。表明正在切換狀態。
b_LCDClean=1;
}
else
{
uc_ModeChange++; //如果uc_ModeChange不是2則加一。
ul_NumberOne=0; //清除所有數據,將所有數據恢復到狀態一。
ul_NumberTwo=0;
ul_Number=0;
uc_NumPointer=1;
}
}
else
{
ul_NumberOne=0; //清除所有數據,將所有數據恢復到狀態一。
ul_NumberTwo=0;
ul_Number=0;
uc_NumPointer=1;
}
}
else
{ //如果不是「NO/C」鍵,首先將uc_ModeChange清零。
uc_ModeChange=0;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<根據不同狀態分派不同的鍵處理函數>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
switch(uc_NumPointer)
{
case 1:
vCalReadyOne(ucKeyCode); //進入狀態一。
break;
case 2:
vCalReadyTwo(ucKeyCode); //進入狀態二。
break;
case 3:
vCalReadyThree(ucKeyCode); //進入狀態三。
break;
default:break;
}
}
}
6. 大神,求51單片機做簡易計算器的那個c語言程序
以下是我編的簡易計算器程序,基本成功
//4*4鍵盤檢測程序,按下鍵後相應的代碼顯示在液晶屏上
//顯示5位後,第6次顯示操作符號
//再顯示下一個數
// 鍵值與功能對應表
//鍵值 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//功能 0 1 2 3 4 5 6 7 8 9 + - × ÷ = 清零
#include<reg52.h>
sbit beep=P2^3;
sbit lcden=P3^4;
sbit rs=P3^5;
sbit rw=P3^6;
#define uint unsigned int
#define ulint unsigned long int
#define uchar unsigned char
#define lcddata P0
ulint bb,dd,ee,ff;
uchar d,flag1;
uchar fd1,fd2;
uchar b1=16,b2=16,b3=16,b4=16,b5=16;
uchar d1=16,d2=16,d3=16,d4=16,d5=16;
uchar f1=16,f2=16,f3=16,f4=16,f5=16,f6=16,f7=16,f8=16,f9=16,f10=16;
uchar key,keyval,c,temp;
void Delay1ms(uint i) //1ms延時程序
{
uint j;
for(;i>0;i--)
{
for(j=0;j<125;j++)
{;}
}
}
void write_com(uchar com)
{
lcddata=com;
rs=0;
rw = 0;
lcden=0;
Delay1ms(10);
lcden=1;
Delay1ms(10);
lcden=0;
}
void write_date(uchar date)
{
lcddata=date;
rs=1;
rw=0;
lcden=0;
Delay1ms(10);
lcden=1;
Delay1ms(10);
lcden=0;
}
void init2()
{
rw=0;
write_com(0x38);
Delay1ms(10);
write_com(0x0f);
Delay1ms(10);
write_com(0x06);
Delay1ms(10);
write_com(0x01);
Delay1ms(10);
}
void display1(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5) //第1個數顯示程序
{
init2();
write_com(0x80);//第1行,第1字
Delay1ms(10);
write_date(0x30+A1);
Delay1ms(10);
write_date(0x30+A2);
Delay1ms(10);
write_date(0x30+A3);
Delay1ms(10);
write_date(0x30+A4);
Delay1ms(10);
write_date(0x30+A5);
Delay1ms(10);
}
void display2(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5) //第2個數顯示程序
{
write_com(0x88);//第1行,第1字
Delay1ms(10);
write_date(0x30+A1);
Delay1ms(10);
write_date(0x30+A2);
Delay1ms(10);
write_date(0x30+A3);
Delay1ms(10);
write_date(0x30+A4);
Delay1ms(10);
write_date(0x30+A5);
Delay1ms(10);
}
void display3(uchar a) //操作符號顯示程序
{
write_com(0x86);//第1行,第1字
Delay1ms(10);
switch(a)
{
case 10:
write_date('+');
Delay1ms(10);
case 11:
write_date('-');
Delay1ms(10);
case 12:
write_date('x');
Delay1ms(10);
case 13:
write_date('/');
Delay1ms(10);
}
}
void display4(uchar A1,uchar A2,uchar A3,uchar A4,uchar A5,uchar A6,uchar A7,uchar A8,uchar A9,uchar A10,uchar A11,uchar A12) //結果顯示程序
{
write_com(0x80+0x40);//第2行,第1字
Delay1ms(10);
if (flag1==0)
{
write_date('-');
}
else write_date('+');
Delay1ms(10);
write_date(0x30+A1);
Delay1ms(10);
write_date(0x30+A2);
Delay1ms(10);
write_date(0x30+A3);
Delay1ms(10);
write_date(0x30+A4);
Delay1ms(10);
write_date(0x30+A5);
Delay1ms(10);
write_date(0x30+A6);
Delay1ms(10);
write_date(0x30+A7);
Delay1ms(10);
write_date(0x30+A8);
Delay1ms(10);
write_date(0x30+A9);
Delay1ms(10);
write_date(0x30+A10);
Delay1ms(10);
write_date('.');
Delay1ms(10);
write_date(0x30+A11);
Delay1ms(10);
write_date(0x30+A12);
Delay1ms(10);
}
uchar keyscan()
{
key=16;
P3=0xef;//P3.7輸出1個低電平
temp=P3; //讀取
temp=temp&0x0f;//屏蔽高4位
if(temp!=0x0f)
{
Delay1ms(10);
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xee:
key=0;
break;
case 0xed:
key=4;
break;
case 0xeb:
key=8;
break;
case 0xe7:
key=12;
break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
beep=0;
}
beep=1;
}
}
P3=0xdf;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delay1ms(10);
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xde:
key=1;
break;
case 0xdd:
key=5;
break;
case 0xdb:
key=9;
break;
case 0xd7:
key=13;
break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
beep=0;
}
beep=1;
}
}
P3=0xbf;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delay1ms(10);
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0xbe:
key=2;
break;
case 0xbd:
key=6;
break;
case 0xbb:
key=10;
break;
case 0xb7:
key=14;
break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
beep=0;
}
beep=1;
}
}
P3=0x7f;
temp=P3;
temp=temp&0x0f;
if(temp!=0x0f)
{
Delay1ms(10);
if(temp!=0x0f)
{
temp=P3;
switch(temp)
{
case 0x7e:
key=3;
break;
case 0x7d:
key=7;
break;
case 0x7b:
key=11;
break;
case 0x77:
key=15;
break;
}
while(temp!=0x0f)
{
temp=P3;
temp=temp&0x0f;
beep=0;
}
beep=1;
}
}
return(key);
}
void main()
{ while(1)
{
c=1;
while(c<6)//輸入第1個5 位數
{
keyval=keyscan();
if(keyval<10)
{
switch(c)
{
case 1:b1=keyval; break;
case 2:b2=keyval; break;
case 3:b3=keyval; break;
case 4:b4=keyval; break;
case 5:b5=keyval; break;
}
c++;
}
display1(b1,b2,b3,b4,b5);
}
while(c==6) //輸入計算符號
{
keyval=keyscan();
if((keyval>=10)&&(keyval<14)) //可去一層括弧,因邏輯運算優先順序較低
{
d=keyval;
}
c=1;
display3(d);
}
while(c<6) //輸入第2個5 位數
{
keyval=keyscan();
if(keyval<10)
{
switch(c)
{
case 1:d1=keyval; break;
case 2:d2=keyval; break;
case 3:d3=keyval; break;
case 4:d4=keyval; break;// 除
case 5:d5=keyval; break;
}
c++;
}
display2(d1,d2,d3,d4,d5);
}
bb= b1*10000+b2*1000+b3*100+b4*10+b5;
dd=d1*10000+d1*1000+d3*100+d4*10+d5;
while(keyval!=14) //等待按下"="
{
keyval=keyscan();
}
Delay1ms(10);
switch(d)
{
case 10:ee=bb+dd; break;//+
case 11:
flag1=1;
if(bb>=dd)
{
ee=bb-dd; //-
flag1=0;
}
else ee=dd-bb;
break;
case 12:ee=bb*dd; break;//*可能會溢出
case 13:ee=bb/dd; //除法小數部分會丟失,保留2位
ff=bb%dd;
fd1=ff*10/dd;
fd2=ff*100/dd%10;
break;
}
f10=ee/1000000000%10;
f9=ee/100000000%10;
f8=ee/10000000%10;
f7=ee/1000000%10;
f6=ee/100000%10;
f5=ee/10000%10;
f4=ee/1000%10;
f3=ee/100%10;
f2=ee/10%10;
f1=ee%10;
display4(f10,f9,f8,f7,f6,f4,f4,f3,f2,f1,fd1,fd2);
while(keyval!=15)
{
keyval=keyscan();
}
b1=0;b2=0;b3=0;b4=0;b5=0;
d1=0;d2=0;d3=0;d4=0;d5=0;
bb=0;dd=0;ee=0;
init2();
}
}
7. 單片機做的計算器(C語言代碼)
前段時間我自己寫的一個,你看看,先是電路圖,後面是代碼圖是用protues畫的,有什麼不懂加我QQ478769652 //程序測試通過
//能使用的功能:輸入K1(+,-,*,/)K2,按=得到結果,然後按on/c或0重新開始
//不能輸入K1+K2+K3或者類似的輸入,這種輸入導致程序出錯
//計算除法的時候不能顯示小數,如5/3得到的結果是1
#include<reg52.h>
unsigned char code tab[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
sbit P2_0=P2^0;
sbit P2_1=P2^1;
sbit P2_2=P2^2;
sbit P2_3=P2^3;
sbit P2_4=P2^4;
sbit P2_5=P2^5;
sbit P3_4=P3^4;
sbit P3_5=P3^5;
sbit P3_6=P3^6;
sbit P3_7=P3^7;long int n=0;
unsigned int flag;
void display();
void delay();
void keyboard();
main()
{
//m1,m2分別保存第一次和第二次輸入的兩個數據
//當m1,m2的輸入值超過999999時,此時將其情0
long int m1,m2;
P2=0xff;
while(1)
{
//檢測輸入的第一個數據
while(1)
{
display();
keyboard();
if(n>999999) n=0;
P3=0xf7;
if(P3_7==0) {flag=1; while(!P3_7); m1=n; n=0; break; }
P3=0xfb;
if(P3_7==0) {flag=2; while(!P3_7); m1=n; n=0; break; }
P3=0xfd;
if(P3_7==0) {flag=3; while(!P3_7); m1=n; n=0; break; }
P3=0xfe;
if(P3_7==0) {flag=4; while(!P3_7); m1=n; n=0; break; }
}
//檢測輸入的第二個數據
while(1)
{
display();
keyboard();
if(n>999999) n=0;
P3=0xf7;
if(P3_6==0) {m2=n; break;}
}
//計算結果,將其保存在n中然後進行顯示,注意當n的值太大超過4位元組時,此時顯示亂碼
while(1)
{
if(flag==1) n=m1+m2;
if(flag==2) n=m1-m2;
if(flag==3) n=m1*m2;
//由於類型原因,計算結果沒有小數
if(flag==4) n=m1/m2;
if(n>999999) n=0;
display();
P3=0xf7;
//計算完成之後,可以用on/c或者是0進行清0,然後進行下一輪計算
if(P3_4==0||P3_5==0) {n=0;break;}
}
}
}void keyboard()
{
//檢測第一行的按鍵
P3=0xfe;
if(P3_4==0)
{
n=n*10+7;
while(!P3_4);
}
if(P3_5==0)
{
n=n*10+8;
while(!P3_5);
}
if(P3_6==0)
{
n=n*10+9;
while(!P3_6);
}
//檢測第二行的按鍵
P3=0xfd;
if(P3_4==0)
{
n=n*10+4;
while(!P3_4);
}
if(P3_5==0)
{
n=n*10+5;
while(!P3_5);
}
if(P3_6==0)
{
n=n*10+6;
while(!P3_6);
}
//檢測第三行的按鍵
P3=0xfb;
if(P3_4==0)
{
n=n*10+1;
while(!P3_4);
}
if(P3_5==0)
{
n=n*10+2;
while(!P3_5);
}
if(P3_6==0)
{
n=n*10+3;
while(!P3_6);
} P3=0xf7;
if(P3_5==0)
{
n=n*10+0;
while(!P3_5);
}
}//顯示子程序
void display()
{
P0=tab[n%10];
P2_5=0;
delay();
P2_5=1; P0=tab[n/10%10];
P2_4=0;
delay();
P2_4=1; P0=tab[n/100%10];
P2_3=0;
delay();
P2_3=1; P0=tab[n/1000%10];
P2_2=0;
delay();
P2_2=1; P0=tab[n/10000%10];
P2_1=0;
delay();
P2_1=1; P0=tab[n/100000];
P2_0=0;
delay();
P2_0=1;
}
void delay()
{
int i;
for(i=0;i<500;i++);
}
8. 用51單片機來做,用c語言編程,做一個計算器,要求實現兩位加、減、乘、除
要實現兩位的運算蠻簡單的.你可以邊做,出什麼問題問我.
29165264
[email protected]
9. 求助單片機用c語言編程計算器!!!大神求解答
你這個程序究竟要C還是要匯編啊?都沒說清楚.提示你一下:輸入輸出函數,浮點數,檢測按鍵(鬆手檢測)數碼顯示....
先要搞清楚你究竟想用哪種語言編,還要弄清楚你的硬體電路才能編得出來.
10. 用C語言編寫單片機上計算器程序遇到問題
可以定義一個緩沖區 將收過來的數據(上位機的串口與單片機必須進行ascii轉換,比如0x31就是數據1.)傳入緩沖區,然後進行數據計算。