/* --- STC15F4K60S4 系列 AD转换查询方式举例----------------------------*/ //本示例在Keil开发环境下请选择Intel的8058芯片型号进行编译 //若无特别说明,工作频率一般为11.0592MHz #include "STC15F2K60S2.h" ADC_LOW2 EQU 0BEH ;ADC低2位结果 ADC_POWER EQU 80H ;ADC电源控制位 ADC_FLAG EQU 10H ;ADC完成标志 ADC_START EQU 08H ;ADC起始控制位 ADC_SPEEDLL EQU 00H ;540个时钟 ADC_SPEEDL EQU 20H ;360个时钟 ADC_SPEEDH EQU 40H ;180个时钟 ADC_SPEEDHH EQU 60H ;90个时钟 TIMER EQU 22H TRADER1 EQU 23H TRADER2 EQU 24H TRADER3 EQU 25H TRADER4 EQU 26H VOL_MAX EQU 27H VOL_MIN EQU 28H AMPLTUD EQU 29H ;----------------------------------------- ORG 0000H LJMP MAIN ORG 000BH LJMP TIM0 ;----------------------------------------- ORG 0100H MAIN: CLR A MOV P0M1, A ;设置为准双向口 MOV P0M0, A MOV P1M1, A ;设置为准双向口 MOV P1M0, A MOV P2M1, A ;设置为准双向口 MOV P2M0, A MOV P3M1, A ;设置为准双向口 MOV P3M0, A MOV P4M1, A ;设置为准双向口 MOV P4M0, A MOV P5M1, A ;设置为准双向口 MOV P5M0, A MOV P6M1, A ;设置为准双向口 MOV P6M0, A MOV P7M1, A ;设置为准双向口 MOV P7M0, A LCALL INIT_UART ;初始化串口 LCALL INIT_ADC ;初始化ADC ; 初始化定时器0 MOV TMOD, #02H MOV TL0, #0D8H ; 25US E7 50US CE 40US D8 MOV TH0, #0D8H SETB ET0 SETB EA CLR TR0 MOV TIMER, #0 MOV VOL_MAX, #0 MOV VOL_MIN, #0 LCALL DELAY500MS ; 系统在启动正式采样之前做0.5s延时 LCALL DELAY500MS LCALL DELAY500MS LCALL DELAY500MS LCALL DELAY500MS ;------------------------------- LOOP: MOV A,#2 ; 选择通道2 LCALL GET_ADC_RESULT ;读取高8位结果 // LCALL SEND_DATA ;显示结果 CJNE A, #0C2H, $+3 // 如果检测到高电平则等待 JNC LOOP LOOP2: MOV A, #2 LCALL GET_ADC_RESULT CJNE A, #27H, $+3 // 如果检测到低电平则等待 JC LOOP2 SETB TR0 // 下一个高电平到来,开始计时 LOOP3: MOV A, #2 LCALL GET_ADC_RESULT CJNE A, VOL_MAX, $+3 // 取高电平采样值中最大值 JC L3 MOV VOL_MAX, A // 保存最大值 L3: CJNE A, #0C2H, $+3 // 如果检测到高电平,则等待 JNC LOOP3 LOOP7: MOV A, #2 LCALL GET_ADC_RESULT CJNE A, VOL_MIN, $+3 // 取低电平采样值中最小值 JNC L7 MOV VOL_MIN, A // 保存最小值 L7: CJNE A, #27H, $+3 // 如果检测到低电平,则等待 JC LOOP7 CLR TR0 // 一个周期完,停止计时 MOV A, TIMER LCALL SEND_DATA MOV R4, #0H // 被除数赋值1000000 MOV R5, #0FH MOV R6, #42H MOV R7, #40H MOV R0, #0H // 除数赋值 MOV R1, #0H MOV R2, #0H MOV R3, A LCALL MULDIV // 调用除法程序 MOV R0, #0H // 除数赋值 MOV R1, #0H MOV R2, #0H MOV R3, #2AH LCALL MULDIV // 发送求得的频率值 MOV A, TRADER1 LCALL SEND_DATA MOV A, TRADER2 LCALL SEND_DATA MOV A, TRADER3 LCALL SEND_DATA MOV A, TRADER4 LCALL SEND_DATA MOV A, VOL_MAX CLR C ; 进位标志Cy清0 SUBB A, VOL_MIN ; 从累加器A中内容减去VOL_MIN与Cy的值,结果存放在累加器A中 ;LCALL SEND_DATA MOV B, #155 ; 除数:256*2/3.3v 幅度为电压最大值与最小值之差的1/2. DIV AB SWAP A MOV AMPLTUD, A MOV A, B MOV B, #15 DIV AB MOV R0, #AMPLTUD XCHD A, @R0 MOV A, AMPLTUD LCALL SEND_DATA // 下面进行波形判别 MOV TIMER, #0 // 清0计时器 MOV TL0, #0D8H // 重新给定时器赋初值 MOV TH0, #0D8H LOOP4: MOV A, #2 LCALL GET_ADC_RESULT CJNE A, #27H, $+3 // 如果为低电平,等待 JC LOOP4 LOOP5: MOV A, #2 LCALL GET_ADC_RESULT CJNE A, #0C2H, $+3 // 如果为高电平,等待 JNC LOOP5 SETB TR0 // 新的低电平到来,开始计时 LOOP6: MOV A, #2 LCALL GET_ADC_RESULT CJNE A, #5, $+3 // 如果为低电平,且电平值几乎为0并且几次采样值几乎相等,则等待 JC LOOP6 // 这里如果是正弦波或者三角波,都不会满足这个条件 CLR TR0 // 电平变高,停止计时 MOV A, TIMER ;LCALL SEND_DATA CJNE A, #6, $+3 // 如果低电平时间超过240us,说明为矩形波,否则直接退出 JC EXIT // 解释:一个周期中电平低于高电平的5/256的时间达到240us // 这就说明此信号在相当一部分时间内电平都为0,从而可知为矩形波 // 当然,这里的比较时间可以根据信号频率做更改。 // 说明:如果一个正弦波或三角波频率极低,也有可能满足这个条件 // 而这即为无法分辨的频率的下限。 MOV A, #01H LCALL SEND_DATA // 如果满足矩形波条件,则发送01表明为矩形波 EXIT: SJMP $ ;---------------------------------------------- ; TIM0中断服务程序 TIM0: INC TIMER RETI ;/*---------------------------- ;读取ADC结果 ;----------------------------*/ GET_ADC_RESULT: ORL A,#ADC_POWER | ADC_SPEEDHH | ADC_START MOV ADC_CONTR,A ;开始AD转换 NOP ;等待4个NOP NOP NOP NOP WAIT: MOV A,ADC_CONTR ;等待ADC转换完成 JNB ACC.4,WAIT ;ADC_FLAG(ADC_CONTR.4) ANL ADC_CONTR,#NOT ADC_FLAG ;清ADC标志 MOV A,ADC_RES ;返回ADC结果 RET ;/*---------------------------- ;初始化ADC ;----------------------------*/ INIT_ADC: MOV P1ASF,#0FFH ;设置P1口为AD口 MOV ADC_RES,#0 ;清除结果寄存器 MOV ADC_CONTR,#ADC_POWER | ADC_SPEEDHH MOV A,#2 ;ADC上电并延时 LCALL DELAY RET ;/*---------------------------- ;初始化串口 ;----------------------------*/ INIT_UART: MOV SCON,#5AH ;设置串口为8位可变波特率 MOV T2L,#0E8H ;设置波特率重装值(65536-11520000/4/115200) // 特别注意:这里的晶振频率是11520000,而不是之前认为的12000000, // 之前数据发送有错误就是因为这里搞错了。这个东西应该早先就检查 // ,而不是想当然,认为是多少就是多少。 MOV T2H,#0FFH MOV AUXR,#14H ;T2为1T模式, 并启动定时器2 ORL AUXR,#01H ;选择定时器2为串口1的波特率发生器 RET ;/*---------------------------- ;发送串口数据 ;----------------------------*/ SEND_DATA: JNB TI,$ ;等待前一个数据发送完成 CLR TI ;清除发送标志 MOV SBUF,A ;发送当前数据 RET /****************************************************************/ ;/*---------------------------- ;软件延时 ;----------------------------*/ DELAY: MOV R2,A CLR A MOV R0,A MOV R1,A DELAY1: DJNZ R0,DELAY1 DJNZ R1,DELAY1 DJNZ R2,DELAY1 RET ;------------------------------ DELAY500MS: ;@12.000MHz NOP NOP NOP PUSH 30H PUSH 31H PUSH 32H MOV 30H,#19 MOV 31H,#62 MOV 32H,#40 NEXT: DJNZ 32H,NEXT DJNZ 31H,NEXT DJNZ 30H,NEXT POP 32H POP 31H POP 30H RET ;------------------------------------ DELAY10US: ;@12.000MHz NOP NOP NOP NOP PUSH 30H MOV 30H,#20 NEXT2: DJNZ 30H,NEXT2 POP 30H RET /* 程序说明: 本程序中(R4R5R6R7——左边为高位)存放被除数, (R0R1R2R3——左边为高位)存放除数, (R3R4R5R6R7——左边为高位)存放结果。 当除数的长度为4字节时,(R3R4R5R6)是余数,(R7)是商; 当除数的长度为3字节时,(R3R4R5)是余数,(R6R7)是商; 当除数的长度为2字节时,(R3R4)是余数,(R5R6R7)是商; 当除数的长度为1字节时,(R3)是余数,(R4R5R6R7)是商; PS:程序并没有把余数和商放到特定的RAM 程序来源:“基于单片机汇编语言的通用多字节无符号数除法的改进” 严克剑,张淼,王丽琼 */ MULDIV: MOV B, #08H CJNE R0, #00H, DVDL MOV B, #10H CLR A XCH A, R3 ; R0R1R2R3存放除数 XCH A, R2 XCH A, R1 XCH A, R0 CJNE R0, #00H, DVDL CLR A XCH A, R2 XCH A, R1 XCH A, R0 MOV B, #18H CJNE R0, #00H, DVDL CLR A XCH A, R1 XCH A, R0 MOV B, #20H CJNE R0, #00H, DVDL SETB OV LJMP END_DIV DVDL: MOV DPL, #00H DVDL2: CLR C MOV A, R7 ; R4R5R6R7存放被除数 RLC A ; 结果存放在R3R4R5R6R7 MOV R7, A MOV A, R6 RLC A MOV R6, A XCH A, R5 RLC A XCH A, R5 XCH A, R4 RLC A XCH A, R4 XCH A, DPL RLC A XCH A, DPL JC DVDL1 DVDL4: SUBB A, R3 MOV A, R5 SUBB A, R2 MOV A, R4 SUBB A, R1 MOV A, DPL SUBB A, R0 JC DVDL3 DVDL1: CLR C MOV A, R6 SUBB A, R3 MOV R6, A MOV A, R5 SUBB A, R2 MOV R5, A MOV A, R4 SUBB A, R1 MOV R4, A MOV A, DPL SUBB A, R0 MOV DPL, A INC R7 ; 商的低位置1 DVDL3: DJNZ B, DVDL2 END_DIV: MOV R3, DPL MOV TRADER1, R4 MOV TRADER2, R5 MOV TRADER3, R6 MOV TRADER4, R7 RET END