pic单片机多路ad转换

pic单片机多路ad转换,第1张

我恰好做过一个PIC 4通道A/D,您先看看我的程序 有问题留言

#include <pic.h> //调用头文件,可以去PICC软件下去查找PIC16F873A单片机的头文件

#include <stdio.h>//调用头文件

#include <math.h> //调用头文件

__CONFIG(XT&PROTECT&WDTEN&PWRTEN)//定义配置字,晶振类型:XT,打开开门狗,代码保护

unsigned char count,count1,tunnel,t1s //0.1s计时,1s计时,通道号,1s时间到标志

unsigned int result[4],s[4] //转换电压结果、转换时间结果

unsigned char f[4] //输入端口状态存储表

union{

struct{

unsigned b0:1 //通道1有输入标志

unsigned b1:1 //通道2有输入标志

unsigned b2:1 //通道3有输入标志

unsigned b3:1 //通道4有输入标志

unsigned b4:1 //通道1需要AD采样标志

unsigned b5:1 //通道2需要AD采样标志

unsigned b6:1 //通道3需要AD采样标志

unsigned b7:1 //通道4需要AD采样标志

}one

unsigned char allbits

}myflag //共占一个字节的数据寄存器存储空间的标志位

#define b0 myflag.one.b0 //定义标志b0

#define b1 myflag.one.b1 //定义标志b1

#define b2 myflag.one.b2 //定义标志b2

#define b3 myflag.one.b3 //定义标志b3

#define b4 myflag.one.b4 //定义标志b4

#define b5 myflag.one.b5 //定义标志b5

#define b6 myflag.one.b6 //定义标志b6

#define b7 myflag.one.b7 //定义标志b7

#define in1 RB4 //定义1通道输入口为RB4端口

#define in2 RB5 //定义2通道输入口为RB5端口

#define in3 RB6 //定义3通道输入口为RB6端口

#define in4 RB7 //定义4通道输入口为RB7端口

#define out1 RC0 //定义1通道输出口为RC0端口

#define out2 RC1 //定义2通道输出口为RC1端口

#define out3 RC2 //定义3通道输出口为RC2端口

#define out4 RC3 //定义4通道输出口为RC3端口

//---------------------------------------

//名称: 定时器T0中断初始化函数

//-----------------------------------------

void T0init(void)

{

T0CS=0 //T0工作在定时器方式

PSA=0 //分频器给TMR0

PS0=1 //1:16分频

PS1=1

PS2=0

T0IF=0 //清零T0中断标志

T0IE=1 //清除T0中断使能

}

//---------------------------------------

//名称:RB口引脚电平变化中断初始化函数

//-----------------------------------------

void RBinit(void)

{

RBPU=1//内部弱上拉禁止

RBIF=0//中断标志清零

RBIE=1//中断使能

PORTB=PORTB //锁存旧值,为下次变化做准备

}

//---------------------------------------

//名称:RA口引脚A/D初始化函数

//-----------------------------------------

void ADinit(void)

{

ADCON1=0x00 //设置RA口所有为模拟输入,采取左对齐方式存放结果

ADCON0=0b11000001 //AD采样时钟为内部RC,默认第一次通道为RA0,启用转换模块

ADIE=0//关闭中断使能禁止

}

//---------------------------------------

//名称: 主初始化函数

//-----------------------------------------

void init(void)

{

unsigned char i

TRISA=0b00101111 //初始化AN0-AN5为输入

TRISC=0x00 //初始化C口为输出

TRISB=0xFF //初始化RB0-RB7为输入

PORTC=0b00000000 //初始化输出

count=0//初始化T0计数器

count1=0 //初始化T0计数器

tunnel=1 //初始化通道号为1

myflag.allbits=0x00//初始化标志位

for(i=0i<4i++) //初始化延时量和输入端口状态

{s[i]=30

f[i]=0}

}

//---------------------------------------

//-----------------------------------------

//名称: 中断服务子函数

//-----------------------------------------

void interrupt ISR(void)

{

//全局中断屏蔽

if(RBIF&&RBIE) //RB边沿中断类型判别

{

PORTB=PORTB

RBIF=0

if(in1)//判断1通道状态

b0=1

else

b0=0

if(in2) //判断2通道状态

b1=1

else

b1=0

if(in3) //判断3通道状态

b2=1

else

b2=0

if(in4) //判断4通道状态

b3=1

else

b3=0

} //RB_int服务子程序1

if(T0IF&&T0IE)//定时器T0中断类型判别

{

TMR0=TMR0+8 //发生一次的时间为250*16=4ms

T0IF=0

count+=1

if(count==25) //计数基数25*16*250=0.1s

{

count=0

count1+=1

if(count1==5) //计数基数0.1s*5=0.5s

{

count1=0

t1s=1 //1s时间到标志

}

}

} //Tmr0_int服务子程序3

//全局中断使能

}

//-----------------------------------------

//名称:delay延时

//-----------------------------------------

void delay()

{

unsigned int i

for(i=0i<10i++)//采样延时160us

}

//-----------------------------------------

//-----------------------------------------

//名称:A/D转换选择子程序

//-----------------------------------------

void ADconvert(void)

{

switch(tunnel) //AD通道选择

{

case 1: //1通道AD采样转换

ADCON0=0b11000001//设置1通道

delay() //采样延时

#asm

clrf_STATUS

bsf _ADCON0,2

btfsc _ADCON0,2

goto$-1

#endasm //结束采样

result[0]=ADRESH //把结果保存

s[0]=result[0]*120>>8 //把结果转化为时间

if(s[0]<2) //限制最小值1s

s[0]=2

else if(s[0]>120)

s[0]=120 //限制最大值60s

break //跳出

case(2)://2通道AD采样转换

ADCON0=0b11001001 //设置2通道

delay() //采样延时

#asm

clrf_STATUS

bsf _ADCON0,2

btfsc _ADCON0,2

goto$-1

#endasm //结束采样

{result[1]=ADRESH} //把结果保存

s[1]=result[1]*120>>8 //把结果转化为时间

if(s[1]<2) //限制最小值1s

s[1]=2

else if(s[1]>120)

s[1]=120 //限制最大值60s

break//跳出

case(3)://3通道AD采样转换

ADCON0=0b11010001 //设置3通道

delay()

#asm

clrf_STATUS

bsf _ADCON0,2

btfsc _ADCON0,2

goto$-1

#endasm //结束采样

{result[2]=ADRESH} //把结果保存

s[2]=result[2]*120>>8 //把结果转化为时间

if(s[2]<2) //限制最小值1s

s[2]=2

else if(s[2]>120)

s[2]=120 //限制最大值60s

break//跳出

case(4)://4通道AD采样转换

ADCON0=0b11011001 //设置4通道

delay() //采样延时

#asm

clrf_STATUS

bsf _ADCON0,2

btfsc _ADCON0,2

goto$-1

#endasm //结束采样

{result[3]=ADRESH} //把结果保存

s[3]=result[3]*120>>8 //把结果转化为时间

if(s[3]<2) //限制最小值1s

s[3]=2

else if(s[3]>120)

s[3]=120 //限制最大值60s

break//跳出

default:break //出错跳出

}

}

//---------------------------------------

//名称:deal通道处理

//-----------------------------------------

void deal(void)

{

unsigned char i

if(t1s)//判断0.5秒时间是否到

{

asm("nop")

t1s=0 //0.5秒时间标志清零,等待下0.5秒

if(b0) //是第1通道吗

{

if(b4)//是第1通道有变化后的采样吗

{tunnel=1 //赋值AD通道号

ADconvert()//开始AD转换

b4=0} //没变化不再采样

if(!(s[0]--))//延时计时开始

out1=1} //继电器开始动作

else out1=0

if(b1) //是第2通道吗

{

if(b5) //是第2通道有变化后的采样吗

{tunnel=2 //赋值AD通道号

ADconvert()//开始AD转换

b5=0} //没变化不再采样

if(!(s[1]--))//延时计时开始

out2=1} //继电器开始动作

else out2=0

asm("clrwdt")

if(b2) //是第3通道吗

{

if(b6) //是第3通道有变化后的采样吗

{tunnel=3 //赋值AD通道号

ADconvert() //开始AD转换

b6=0} //没变化不再采样

if(!(s[2]--))//延时计时开始

out3=1} //继电器开始动作

else out3=0

if(b3) //是第4通道吗

{

if(b7) //是第4通道有变化后的采样吗

{tunnel=4 //赋值AD通道号

ADconvert()//开始AD转换

b7=0} //没变化不再采样

if(!(s[3]--))//延时计时开始

out4=1} //继电器开始动作

else out4=0

}

asm("nop") //1秒时间没到继续检测

}

//-----------------------------------------

//名称:主函数

//-----------------------------------------

void main()

{

init() //全局初始化

T0init() //T0初始化

ADinit() //A/D初始化

RBinit() //RB初始化

asm("nop") //稳定状态

asm("nop")

delay()

delay() //耗时0.7ms

//-----------------------------------------

{ //开机初始化采样AD

tunnel=1

ADconvert()

tunnel=2

ADconvert()

tunnel=3

ADconvert()

tunnel=4

ADconvert()

} //开机1次AD,到此耗时2.4ms,这个时间前不要有触发

if(in1)//开机一次状态判断

{b0=1

f[0]=in1} //存储开机时1通道状态

if(in2)

{b1=1

f[1]=in2} //存储开机时2通道状态

if(in3)

{b2=1

f[2]=in3} //存储开机时3通道状态

if(in4)

{ b3=1

f[3]=in4} //存储开机时4通道状态

//-----------------------------------------

ei() //打开全局中断

//-----------------------------------------

while(1) //主循环

{

asm("clrwdt") //清看门狗

if(b0)//判断1通道状态

{

if(f[0]!=in1)

{f[0]=in1 //存储1通道状态

b4=1} //1通道是否进行AD标志

} //设定1通道有效标志

else

{

b4=0

f[0]=in1} //设定1通道无效标志

if(b1) //判断2通道状态

{

if(f[1]!=in2)

{f[1]=in2//存储2通道状态

b5=1} //2通道是否进行AD标志

} //设定2通道有效标志

else

{

b5=0

f[1]=in2} //设定2通道无效标志

if(b2) //判断3通道状态

{

if(f[2]!=in3)

{f[2]=in3 //存储3通道状态

b6=1} //3通道是否进行AD标志

} //设定3通道有效标志

else

{

b6=0

f[2]=in3} //设定3通道无效标志

if(b3) //判断4通道状态

{

if(f[3]!=in4)

{f[3]=in4//存储4通道状态

b7=1} //4通道是否进行AD标志

} //设定4通道有效标志

else

{

b7=0

f[3]=in4} //设定4通道无效标志

deal()//最大循环时间不超过4ms,看门狗典型值18ms

asm("nop")//中断检测

}

}

//---------------------------------------

在C语言里没有指令,只有语句,用C语言执行A/D转换如下:

//A/D转换初始化子程序

void

adinitial()

{

ADCON0=0x41;

//选择A/D通道为RA0,且打开A/D转换器

//在工作状态,使A/D转换时钟为8Tosc

ADCON1=0X8E;

//转换结果右移,及ADRESH寄存器的高6位为"0"

//把RA0口设置为模拟量输入方式

ADIE=1;

//A/D转换中断允许

PEIE=1;

//外围中断允许

TRISA0=1;

//设置RA0为输入方式

}

//读ADRESH寄存器就能得到AD转换值了,

汇编的如下:

ADINT

MOVLW

0X51

MOVWF

ADCON0

;选择A/D转换通道为RA2,且打开A/D在工

;作状态,并使A/D转换时钟为8tosc

BANKSEL

ADCON1

;选BANK1体

MOVLW

0X80

MOVWF

ADCON1

;转换结果右移,即ADRESH寄存器的高6位;为“0”,且把RA2口设置成模拟量输入口

CLRF

PIE1

;禁止其它中断

BSF

PIE1,ADIE

;A/D转化中断允许

BSF

TRISA,2

;设置RA2口为输入方式

BSF

INTCON,PEIE

;外围中断允许

BSF

INTCON,GIE

;总中断允许

BCF

STATUS,RP0

;返回BANK0

RETURN

工欲善其事必先利其器。初始化子程序adinitial()是用于做准备的,设置一下AD模块,打开这个AD,设置输入的方式和采样转换时间什么的。所以这叫“初始化”。

而中断服务程序就是实际执行AD采集的任务的。

有AD中断发生,单片机自动标志AD标志位,然后触发中断服务程序。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11128963.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-13
下一篇 2023-05-13

发表评论

登录后才能评论

评论列表(0条)

保存