本帖最后由 sbcceeq 于 2011-6-22 13:22 编辑
众位高手好,我根据资料改编了一个程序,功能是控制充电和电机的正反转,使用PIC16F886,程序能通过编译,但是接在电路
板上之后运行,发现什么动作也没有,很是苦恼,程序里肯定有错误,但到底是什么导致无相应动作呢?比如我按键盘让电机正转,但什么动作也没有,盼望大家能帮我指出错误,我把程序和电路主图放在下面。
万分感谢!!!
#include <pic.h>
/*__CONFIG(0x3F71);*/
__CONFIG(HS&WDTDIS&LVPDIS);
/***************/
unsigned int t_count;
unsigned char seco; // global seconds
unsigned char min; // global minutes
unsigned char hour; // global hour
#define uchar unsigned char
#define uint unsigned int
#define T1_1MS 1000 //延时常数1000,此数用于TMR1每隔 1毫秒中断扫描键盘
void TRICKLE_charge();
void FAST_charge();
void DELAY(unsigned int n);
void init(void)
{
/***** TMR0设置 *****/
//option=0b00000111;
T0CS=0; // 选择CLKOUT信号为时钟源
PSA=0; // 预分频器给TIMER0用
PS2=1;
PS1=1;
PS0=1; // 分频比为1:256
TMR0=0; // Timer0计数值寄存器初值为零,单片机主频为4M,产生1S定时需要中断1000000/65536=15.28次近似取15次
T0IF=0; // Timer0中断标志位清空
T0IE=1; // Timer0中断使能位置位,允许Timer0中断
GIE=1; // 总中断打开
//CCP1口PWM设置*****/
TRISC2=0; //RC2/CCP1为输出
PR2=39; //周期为(1/25)ms
CCPR1L=0; //当初始占空比为0,此值为0x20时,占空比0.8
CCP1CON=0b00001100; //PWM模式
T2CON=0b00000100; //TMR2预分频1:1,开始工作
// PORTB中断初始 *****/
//void PORTBINT( )可以起这个名, PORTB电平变化引起中断
RBPU=0;;//B口弱上拉有效*/
PORTB=0X00; //RB1,RB2 先送低电平*/
RBIE=1;; //B口电平变化中断允许 */
PORTB=PORTB; //读B口的值,以锁存旧值,为变位中断创造条件*/
// TMR1中断初始 *****/
TMR1H=T1_1MS>>8; //取延时常数的高字节,延时常数为1000,此数用于TMR1每隔 1毫秒中断扫描键盘
TMR1L=T1_1MS; //取延时常数的低字节
TMR1IE=1; //TMR1中断使能
INTCON=0b1000000; //GIE、PEIE置1才能进入TMR1中断
T1CON=0b00000001; //TMR1预分频系数1:1,内部延时,开始工作
/***** I/O Ports *****/
PORTA = 0x00; // Port A清零
ANSEL=0;
PORTB = 0x00; // Port B清零
PORTC = 0x00; // Port C清零
TRISA = 0x0F; // Port A 低4位口为输入
TRISB=0XE0; // 输入:RB5,RB6,RB7 输出:RB1,RB2,RB3,RB4
TRISC = 0xEB; // 输入:RC7、RC6、RC5 输出:RC2
/***** A/D *****/
ADCON1 = 0x80;//Port A 模拟量输入,右对齐,每位AD转换时间TAD=32Tosc=8us
}
// 在AD转换中用到的关闭PWM的函数//
void NO_PWM() //在下降沿时关闭PWM .
{
if (CCPR1L != 0)
{
while(!RC2); // 等待PWM == 1
while(RC2); // 等待PWM == 0
TRISC2 = 1; // 关闭PWM
}
}
#define VOLTAGE 1
#define TEMPERATURE 2
#define CURRENT 0
unsigned int measure(unsigned char value)//用来采集电压电流等模拟量,经过处理得到平均值
{
unsigned int av=0; // 存放多次A/D转换10位结果的平均值
uchar i=0;
uchar a=0;
switch (value)
{//通道号赋值
case VOLTAGE:
NO_PWM();
a=1;//选AN1模拟通道准备测电池电压
break;
case TEMPERATURE:
NO_PWM();
a=2;//选AN2模拟通道准备测温度
break;
case CURRENT:
a=0;//选AN0模拟通道准备测电池电流
break;
}
//进行AD转换,计算10位AD采样结果的平均值
av=0;
for(i=10;i;--i)
{uchar q;
unsigned int x;
ADCON0=(0x81|(a<<3));//使能AD模块,设置并打开AD转换通道,AD时钟为32Tosc
for (q=1;q<5;i++) NOP(); //打开AD通道后延时20us左右
GODONE=1; //开始AD转换
while (GODONE==1); //等待AD转换结束
ADIF=0; //清AD结束标志
x=ADRESH<<8;
x|=ADRESL;//AD转换结果转为10位
av = av+x;
}
if(RC2==1)
{TRISC2 = 0;
} //若关闭了CCP2口则现在打开
av = av/10;
return(av); // 返回处理后的平均值
}
void TMINT(void)//计时器,充电时间控制用
{
if(T0IE && T0IF)
{
T0IF=0;
TMR0=0;//TMR0重新赋初值
t_count++;
if( t_count==15) //单片机主频为4M,产生1S定时需要中断1000000/65536=15.28次近似取15次
{
t_count=0;
if ( 60 == ++seco )
{
if ( 60 == ++min )
{
if ( 24 == ++hour )
{
hour = 0x00;
}
min = 0x00;
}
seco = 0x00;
}
}
}
}
void DELAY(unsigned int n)//延时n毫秒
{
unsigned int j;
char k;
for (j=0;j<n;j++)
for (k=246;k>0;k--)
NOP();
}
#define k1 RC6//正转按键
#define k2 RC7//反转按键
#define k3 RC5//停止按键
#define in1 RB5//上行程开关输入
#define in2 RB6//下行程开关输入
#define in3 RB7//红外输入
#define out1 RB3//正转输出
#define out2 RB4//反转输出
unsigned char keyval; //储存按键值*/
void motor() //电机控制函数
{
keyval=0; //按键值初始化为0,什么也不做
while(1)
{
switch(keyval)
{
case 1: out1=0;out2=1;//K1按下,电机正转
break;
case: out1=1;out2=0;//K2按下,电机反转
break;
case 3: out1=0;out2=0;//K3按下,电机停止
break;
}
}
}
/*************************************************
函数功能:定时器TMR1的中断服务子程序,用于扫描键盘
**************************************************/
uint T1_100MS=1000;
void keyint();
static void interrupt
isr(void)
{
uchar A,num;
if (TMR1IF==1)
{ TMR1IF=0; //清TMR1溢出中断标志位
TMR1H=T1_100MS>>8; //延时常数重新赋值,常数为1000,此数用于TMR1每隔 1毫秒中断扫描键盘,TMR1H=(65536-
1000)/256
TMR1L=T1_100MS; //整形数赋给字符型变量,只赋整型的低字节,TMR1L=(65536-1000)%256
if((PORTC&0xf0)!=0xf0) //第一次检测到有键按下
{
DELAY(20); //延时20ms再去检测,防止键盘抖动
if(k1==0)keyval=1; //按键k1被按下
if(k2==0)keyval=2; //按键k2被按下
if(k3==0)keyval=3; //按键k3被按下
}
if(A==1){num++; //电机反转(关门)启动计时标志
//关门启动时间计数器
A=0 ; //电机反转(关门)启动计时标志清零
}
}
else if(RBIF==1)keyint();
else if(T0IF){TMINT();}
}
//PORTB端口电平变化中断服务程序,信号来自红外和行程开关,保护电机与人身安全
void keyint()
{
if(RBIF)
{
DELAY(10); ///软件延时10ms
if ((RB7==0)||(RB6==0)||(RB5==0)) //确认开关信号是否为干扰
if(RB5==0) //上行程信号输入后电机停止
{ out1=0; out2=0;}
if(RB6==0)
{ out1=0; out2=0;}//下行程信号输入后电机停止
PORTB=PORTB; ///读B口的值,改变中断发生的条件,避免键
//一直按下时,连续进行键识别
RBIF=0; ///键扫描时可能会产生"电平变化"而使RBIF
} ///置1,再清除一次RBIF以避免额外中断
}
//快充,包括恒流充电和恒压充电**************************************************************************//
#define MAX_I_FAST 614 //最大充电电流1A,经电流采样电路后的数值为(3*1023)/5=614
#define I_BUFFER 8 //电流允许误差
#define I_tricle 62 //涓充转换电流,充电电流小于此值时就认为已转到涓充阶段,(3*0.1)/1023=62
#define MAX_TEMP_ABS 1023 // 充电允许的最大温度,超过此温度,电池不应充电
#define MIN_TEMP_ABS 1
#define MAX_TEMP_FAST 800
#define MiX_VOLTAGE 584 //电池允许充电的最低电压,低于此值,电池属故障,292对应电池20V
#define MaX_VOLTAGE 865
#define VOLT_const 848// 恒压充电时的电压,对应于恒压充电电压29V
#define VOLT_TOLERANCE 8//恒压充电时电压允许误差
#define VOLT_TRICKLE 818//涓充时电压 ,对应于涓充充电电压28V
#define tricle_TIME_need 30//涓充时间30分钟
#define MAX_TIME_FAST 90 //根据电池容量和最大电流得到快充最大时间是90分钟左右
void FAST_charge()
{
unsigned int temp = 0;
unsigned char fast_finish_hour = 0,fast_finish_min,fast_charge_I;
unsigned char last_min;
unsigned char A=1;//快充标志位
temp = measure(TEMPERATURE);
// if TEMPERATURE within absolute limits
if ((temp > MIN_TEMP_ABS) && (temp < MAX_TEMP_ABS)&& (temp <MAX_TEMP_FAST))
{
// calculate FAST charge finish time
fast_finish_min = (min + MAX_TIME_FAST);
fast_finish_hour = hour;
while (fast_finish_min > 60)
{
fast_finish_min = fast_finish_min - 60;
fast_finish_hour++;
}
CCPR1L = 0x00;
temp = measure(VOLTAGE);
if ((temp > MiX_VOLTAGE) &&(temp < MaX_VOLTAGE)) //MiX_VOLTAGE 是我定义的最小电池电压,应该是10V
{
/*恒流充电*/
do
{
fast_charge_I = measure(CURRENT);
if (fast_charge_I < (MAX_I_FAST-I_BUFFER))
CCPR1L++;
else if (fast_charge_I > (MAX_I_FAST-I_BUFFER))//fast_charge_I是恒流电流
CCPR1L--;
} while (fast_charge_I != (MAX_I_FAST-I_BUFFER));//取成614-8=606
}
//恒压充电 VOLT_const就是恒压充电电压28V对应848,没有加公差8
while ((temp >= (VOLT_const - VOLT_TOLERANCE)) && (temp <= (VOLT_const + VOLT_TOLERANCE)))
{
do
{
temp = measure(VOLTAGE);
if (temp < VOLT_const)
CCPR1L++;
else if (temp > VOLT_const)
CCPR1L--;
} while (temp != VOLT_const);
//快充时间溢出
if ((hour == fast_finish_hour)&&(min == fast_finish_min))
{
NO_PWM();
RB2=1;
}
temp = measure(TEMPERATURE);
if ( temp >MAX_TEMP_ABS)
{
NO_PWM();
RB2=1;
}
temp = measure(CURRENT);
if ( temp > MAX_I_FAST)
{
//电流超过最大快充电流时禁止PWM输出,故障指示亮
NO_PWM();
RB2=1;
}
//每隔一分钟检测电流是否到涓充转换电流,若到就转涓充
if (min != last_min)
{
last_min = min;
temp = measure(CURRENT);
if ( temp < I_tricle)//I_tricle是涓充电流
{
TRICKLE_charge(); //转涓充
}
}
}
}
else
{ NO_PWM();
RB2=1;//电池电压过低,无法充电,报警响,提示要更换电池
}
}
// 涓充
//************************************************************************************/
unsigned char trickle_finish_min = 0,tricle_min=0;
uchar last_min=0,tricle_hour=0;
void TRICKLE_charge()
{
unsigned int temp = 0;
unsigned char trickle_finish_hour = 0;
// if TEMPERATURE within absolute limits
temp = measure(TEMPERATURE);
if ((temp > MIN_TEMP_ABS) &&(temp < MAX_TEMP_ABS))
{
// if charge voltage lower than absolute max charge voltage
if (measure(VOLTAGE) <= (VOLT_TRICKLE + VOLT_TOLERANCE))//818对应是涓充电压,8对应变化量,则相加为826
{
if (min != last_min)
{
last_min = min;
if ( (measure(CURRENT)) <I_tricle)//I_tricle)是我自己定义的在涓充时的电流
{
// calculate tricle finish time
tricle_min = (min + tricle_TIME_need);//tricle_TIME_need是我自己定义的涓充时间
tricle_hour = hour;
while (tricle_min > 60)
{
tricle_min = tricle_min - 60;
tricle_hour++;
}
}
}
do // set VOLT_TRICKLE
{
temp = measure(VOLTAGE);
if ((temp < VOLT_TRICKLE)&&(CCPR1L < 0xFF))
{
CCPR1L++;
}
if ((temp > VOLT_TRICKLE)&&(CCPR1L > 0x00))
{
CCPR1L--;
}
}while (temp!= VOLT_TRICKLE); // VOLT_TRICKLE is set now
if ((hour == tricle_hour) && (min == tricle_min))
{
NO_PWM();
RB1=1;//充满灯亮
}
}
else if(RB2=0)
{
RB2=1;// 故障灯亮
}
}
else if(RB2=0)
{
RB2=1;//故障灯亮
}
}
void main()
{init();
while(1)
{
FAST_charge();
motor();
}
} |