最近我在学习c8051F340的内部ADC0采样,就利用它的P0.3口作为输入口,采样一个直流电压,并将采样值送到P1、P2口。可是发现总是不正常,具体如下。
第一中方法,用中断。问题是不能连续采样,复位启动后第一次采样正确,再往后就保持住第一次采样值不变了。郁闷!程序如下:$NOMOD51
$include (c8051f340.inc)
;public Init_Device
cseg AT 0
ljmp Main
ORG 0053H
LJMP A00
Blink segment CODE
rseg Blink ; Switch to this code segment.
using 0 ; Specify register bank for the
; following program code.
; Initialization function for device,
; Call Init_Device from your main program
MAIN:
mov VDM0CN, #080h
clr A ; Wait 100us for initialization
djnz ACC, $
mov OSCICN, #0c3h;使用单片机内部时钟作为系统时钟,且系统时钟频率就是12MHz
mov REF0CN, #03h;使用单片机内部参考源作为AD的参考
;关闭内部温度传感器
mov REG0CN, #0A0h;Voltage Regulator Disabled.
anl PCA0MD, #NOT(40h) ;Watchdog Timer disabled
anl RSTSRC, #NOT(06H);时钟丢失时复位,电源不正常时复位
;adc初始化设置
MOV AMX0N,#1FH;AD工作在单端模式
MOV ADC0CF,#18H;ADC时钟为3MHz,AD采样数据在寄存器中右对齐
mov ADC0CN,#80h;ADC0 Enabled
;连续转换,每次写‘1’ to AD0BUSY开始一次ADC0 conversion
mov VDM0CN,#0;VDD Monitor Disabled
mov SMB0CF,#0;SMBus interface disabled
mov TCON,#0;Timer 0/1均为 disabled
mov IE,#80H;根据各个位决定各个中断是否允许
MOV IP,#10H;UART0设置为高中断优先级
MOV EIE1,#0cH;ADC0中断允许
mov EIP1,#08h;ADC0中断高优先级
mov EIE2,#00h;关闭其他扩展中
mov P0MDIN, #0f7h;P0.3为AD的输入口
mov P1MDIN,#0ffh
mov P2MDIN, #0ffh
mov P3MDIN,#0ffh
mov P4MDIN, #0ffh
mov P0MDOUT, #0FFh
mov P1MDOUT, #0FFh
mov P2MDOUT, #0FFh
mov P3MDOUT, #0FFh
mov P4MDOUT, #0FFh
MOV P0SKIP,#08H;P0.3 is skipped
mov XBR0,#00H
mov XBR1,#040h
mov XBR2,#00H
MOV P0,#00H
MOV P2,#00H;p0和p1用于指示ad转化结果
MOV AMX0P,#11H;AD输入口为P0.3
CLR AD0INT ;清除ADC转换完成标志
SETB AD0BUSY
; acall DELAY
; JNB AD0INT,$;AD0INT变高前原地等待
THER:
JNB AD0INT,THER
HERE:ljmp THER
;经实测共计10ms延迟
DELAY:
MOV R4,#85 ;此指令占有2个时钟周期
LOOP2:
MOV R5,#255 ;此指令占有2个时钟周期
LOOP1:
NOP ;此指令占有一个时钟周期
NOP
DJNZ R5,LOOP1 ;此指令占有2/3个时钟周期
DJNZ R4,LOOP2
RET
A00:
MOV P1,ADC0H;
MOV P2,ADC0L;采样数据送出显示
CLR AD0INT ;清除ADC转换完成标志,清除中断标志位
RETI
end
第二种方法,用循环。问题更严重,没有采样对过。每次开机P1、P2口输出的采样值就是全高不变,不管输入电压多少。
$include (c8051f340.inc)
;public Init_Device
cseg AT 0
ljmp Main
ORG 0053H
LJMP A00
Blink segment CODE
rseg Blink ; Switch to this code segment.
using 0 ; Specify register bank for the
; following program code.
; Initialization function for device,
; Call Init_Device from your main program
MAIN:
mov VDM0CN, #080h
clr A ; Wait 100us for initialization
djnz ACC, $
mov OSCICN, #0c3h;使用单片机内部时钟作为系统时钟,且系统时钟频率就是12MHz
mov REF0CN, #03h;使用单片机内部参考源作为AD的参考
;关闭内部温度传感器
mov REG0CN, #0A0h;Voltage Regulator Disabled.
anl PCA0MD, #NOT(40h) ;Watchdog Timer disabled
anl RSTSRC, #NOT(06H);时钟丢失时复位,电源不正常时复位
;adc初始化设置
MOV AMX0N,#1FH;AD工作在单端模式
MOV ADC0CF,#18H;ADC时钟为3MHz,AD采样数据在寄存器中右对齐
mov ADC0CN,#80h;ADC0 Enabled
;连续转换,每次写‘1’ to AD0BUSY开始一次ADC0 conversion
mov VDM0CN,#0;VDD Monitor Disabled
mov SMB0CF,#0;SMBus interface disabled
mov TCON,#0;Timer 0/1均为 disabled
mov IE,#80H;根据各个位决定各个中断是否允许
MOV IP,#10H;UART0设置为高中断优先级
MOV EIE1,#0cH;ADC0中断允许
mov EIP1,#08h;ADC0中断高优先级
mov EIE2,#00h;关闭其他扩展中
mov P0MDIN, #0f7h;P0.3为AD的输入口
mov P1MDIN,#0ffh
mov P2MDIN, #0ffh
mov P3MDIN,#0ffh
mov P4MDIN, #0ffh
mov P0MDOUT, #0FFh
mov P1MDOUT, #0FFh
mov P2MDOUT, #0FFh
mov P3MDOUT, #0FFh
mov P4MDOUT, #0FFh
MOV P0SKIP,#08H;P0.3 is skipped
mov XBR0,#00H
mov XBR1,#040h
mov XBR2,#00H
MOV P0,#00H
MOV P2,#00H;p0和p1用于指示ad转化结果
MOV AMX0P,#11H;AD输入口为P0.3
CLR AD0INT ;清除ADC转换完成标志
SETB AD0BUSY
; acall DELAY
; JNB AD0INT,$;AD0INT变高前原地等待
THER:
JNB AD0INT,THER
HERE:ljmp THER
;经实测共计10ms延迟
DELAY:
MOV R4,#85 ;此指令占有2个时钟周期
LOOP2:
MOV R5,#255 ;此指令占有2个时钟周期
LOOP1:
NOP ;此指令占有一个时钟周期
NOP
DJNZ R5,LOOP1 ;此指令占有2/3个时钟周期
DJNZ R4,LOOP2
RET
A00:
MOV P1,ADC0H;
MOV P2,ADC0L;采样数据送出显示
CLR AD0INT ;清除ADC转换完成标志,清除中断标志位
RETI
end
实在兄弟解决不了了。昨天折腾到半夜3点了也不行,救救我吧。 |