#include <pic.h> //16F877A,4MHz晶振
#include <math.h>
__CONFIG(XT&WDTEN&LVPDIS);
#define uchar unsigned char
#define uint unsigned int
uchar dis_table[]={0xeb,0x88,0xb3,0xba,0xd8,0x7a,0x7b,0xa8,0xfb,0xfa,0x00};//数码管不带点显示
static uchar bank2 dis_table1[]={0xef,0x8c,0xb7,0xbe,0xdc,0x7e,0x7f,0xac,0xff,0xfe,0x00};//带点显示
uchar tmr0num,ledflashnum,whichdisp;//led闪烁计数值
uint lednum[3],dischargenum; //AD值lednum[0]为放电电流值[1]充电电流值[2]为电池电压值
void init(void)
{
TRISA=0xff;
TRISB=0xf9; //RB0RB1RB2为输出,其他未用设置为输入
TRISC=0x03; //RC2-RC7置为输出0,RC0RC1设置为输入1
TRISD=0x00; //TRISE不能随便给值否则会影响到RD脚功能见书P191《实战上》
}
void AD_init(void)
{
ADCS0=0;
ADCS1=1; //AD转换时钟选择位=FOSC/32
PCFG0=1;
PCFG1=0;
PCFG2=0;
PCFG3=1;//设定ADCON1,1001RA0RARA5为AD转换口
ADIE=1;
ADFM=1;//设定ADCON1AD值右对齐
}
void intinit(void)//INT中断初始化
{
RB0=1;
INTEDG=1;
INTF=0;
INTE=1;
GIE=1;
}
void tmr0init(void)//TIMR0初始化
{
OPTION=0x06; //0001 0110 预分频128,允许内部上拉,预分频分配给TMR0,用于内部指令计数
T0IF=0;
GIE=1;
T0IE=1;
PEIE=1;
TMR0=217;//217初值,每5ms中断一次
}
uint adc_read(uchar channel)//电流采样、放电次数、电池电压
{
uint k,buf,adbuf;
double i_val;
ADCON0 = (channel << 3) + 0x81; // 启动 AD模块工作, FOSC/32 osc.
asm("CLRWDT");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
ADGO = 1;//启动转换
while(ADGO)
continue; //wait for conversion complete*/
adbuf=ADRESH*256+ADRESL;
i_val=(double)adbuf;
if(channel==0)//AN0放电电流采样通道
{
i_val=(i_val*38.34)/1023;//放电电流
if(i_val>2500) i_val=2500;
}
if(channel==2)//AN2充电电流采样通道
{
;
}
if(channel==4)//AN4电压采样通道
{
i_val=(i_val*15.76)/1023;//电压采样转换
if(i_val>1000) i_val=1000;
}
k=(int)i_val;
return k;
}
void interrupt int0tmr0(void)
{
if(INTF&&INTE)
{
INTF=0;
whichdisp++;
dischargenum++;
if(dischargenum>9999) dischargenum=0;
if(whichdisp>=3) whichdisp=0;
}
if(T0IF&&T0IE)
{
T0IF=0;
//if((ledflashnum==20)&&(lednum>=600)) RB1=!RB1;//如果电压一直大于6V则红灯闪烁
//if(lednum<600) RB1=1; //如果电压低于6V则红灯常亮,表示放电完毕,正在休息1个小时。
switch (whichdisp)//选择显示放电电流?放电次数?还是电池电压要根据INTRB0按键顺序
{
case 0://电池电压显示
{
if(tmr0num==0)
{
RC5=1;
RC6=1;
RC7=1;
if((lednum[2]/1000)>0)
{
PORTD=dis_table[lednum[2]/1000];//第1位显示
RC4=0;
}
else RC4=1;
}
if(tmr0num==1)
{
RC4=1;
RC6=1;
RC7=1;
PORTD=dis_table1[lednum[2]%1000/100];//第2位带点显示
RC5=0;
}
if(tmr0num==2)
{
RC4=1;
RC5=1;
RC7=1;
PORTD=dis_table[lednum[2]%100/10];//第3位显示
RC6=0;
}
if(tmr0num==3)
{
RC4=1;
RC5=1;
RC6=1;
PORTD=dis_table[lednum[2]%10];//第4位显示
RC7=0;
}
break;
} //电池电压在此行选择结束
case 1://放电次数显示
{
if(tmr0num==0)
{
RC5=1;
RC6=1;
RC7=1;
PORTD=dis_table[dischargenum/1000];//第1位显示
RC4=0;
}
if(tmr0num==1)
{
RC4=1;
RC6=1;
RC7=1;
PORTD=dis_table[dischargenum%1000/100];//第2位显示
RC5=0;
}
if(tmr0num==2)
{
RC4=1;
RC5=1;
RC7=1;
PORTD=dis_table[dischargenum%100/10];//第3位显示
RC6=0;
}
if(tmr0num==3)
{
RC4=1;
RC5=1;
RC6=1;
PORTD=dis_table[dischargenum%10];//第4位显示
RC7=0;
}
break;
}
case 2: //放电电流显示
{
if(tmr0num==0)
{
RC5=1;
RC6=1;
RC7=1;
if((lednum[0]/1000)>0)
{
PORTD=dis_table[lednum[0]/1000];//第1位显示
RC4=0;
}
else RC4=1;
}
if(tmr0num==1)
{
RC4=1;
RC6=1;
RC7=1;
PORTD=dis_table[lednum[0]%1000/100];//第2位显示
RC5=0;
}
if(tmr0num==2)
{
RC4=1;
RC5=1;
RC7=1;
PORTD=dis_table[lednum[0]%100/10];//第3位显示
RC6=0;
}
if(tmr0num==3)
{
RC4=1;
RC5=1;
RC6=1;
PORTD=dis_table[lednum[0]%10];//第4位显示
RC7=0;
}
break;//放电电流显示在此行选择结束
}
default:
break;
} //SWITCH选择到此结束
TMR0=217;//217初值,每5ms中断一次
tmr0num++;
if(tmr0num>=4)tmr0num=0;
} //T0中断到此行结束
}
void main()
{
uchar i;
init();
intinit();
tmr0init();
AD_init();
while(1)
{
asm("CLRWDT");
for(i=0;i>=3;i++)
lednum=adc_read(i*2);//轮循采样
}
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
有了adc通过的前提,再看读数数值是否与预想一致,也就是那个lednum数组是否放进了数据。
按键读出部分不知道为什么没有防抖。显示部分是否能跑通没有细看。这部分需要用假数据单独测试。
还是换用16f887比较好。其ANSEL/ANSELH都能够显性设置AD端口。
采样采到没有?在程序中插入探测标志(闪烁的led),先看看。
有了adc通过的前提,再看读数数值是否与预想一致,也就是那个lednum数组是否放进了数据。
按键读出部分不知道为什么没有防抖。显示部分是否能跑通没有细看。这部分需要用假数据单独测试。
还是换用16f887比较好。其ansel/anselh都能够显性设置ad端口。
-----------------------------------------------------------------------
单独试了,各个AD通道及动态数码管显示,都正常的。
一周热门 更多>