program.c
/********************************************
program8.c
说明:带CAN通讯功能的两路充电器程序代码
主控芯片:PIC16F887
引脚关系:
芯片时钟:16Mhz
CAN通讯速率:125Kb/s
Author:Alex
Date:2016/01/28 12:09
File:
********************************************/
#include <program8.h>
__CONFIG (CP_OFF &WDTE_OFF& BOREN_OFF&PWRTE_OFF &FOSC_HS&WRT_OFF&LVP_OFF&CPD_OFF);
void main()
{
/****定义临时无符号整形变量****/
/****定义临时整形变量****/
int i;
/****定义临时浮点型整形变量****/
count=0;
CAN_FLAG=0; /*开机复位,清接收到标志*/
canreflag=0;
Init_PWM(); /*初始化配置PWM*/
Init_Int(); /*初始化中断*/
Init_Spi(); /*初始化SPI*/
Init_Can(); /*初始化CAN通讯*/
Usart_init(); /*初始化串口通讯*/
Bat_init(); /*初始化左右侧电池的状态标志位*/
TRISE=0X00;
PORTE=0x00;
ENA=1; /*关掉2路通讯*/
delay(500); /*延时1秒*/
while(1)
{
if(RD2==0) /*左电池盒闭合状态*/
{
delay(30); /*延时去抖*/
if(RD2==0) /*此时开关处于闭合状态,有电池插入电池盒*/
{
Bat_1.in=1; /*将左电池进入充电站标志位置1*/
}
}
else /*左电池盒打开状态*/
{
Bat_1.in=0; /*将左电池进入充电站标志位清零*/
}
if(RD3==0) /*右电池盒闭合状态*/
{
delay(30); /*延时去抖*/
if(RD3==0) /*此时开关处于闭合状态,有电池插入电池盒*/
{
Bat_2.in=1; /*将左电池进入充电站标志位置1*/
}
}
else /*左电池盒打开状态*/
{
Bat_2.in=0; /*将左电池进入充电站标志位清零*/
}
if(Bat_1.in==1) /*左侧电池盒闭合的时候*/
{
if(Bat_1.init==0) /*左侧电池盒初始化未完成*/
{
delay(500); /*延时1秒*/
LeftBattery_Init(); /*左侧电池盒初始化*/
if(Bat_1.init==1) /*左侧电池盒初始化完成*/
{
LeftBattery_Deal(); /*左侧电池盒控制电流充电*/
}
}
else /*左侧电池盒初始化已完成*/
{
LeftBattery_Deal(); /*左侧电池盒控制电流充电*/
}
}
else /*左侧电池盒打开的时候*/
{
Bat_1_Reset(); /*左侧电池状态复位*/
}
if(Bat_2.in==1) /*右侧电池盒闭合的时候*/
{
if(Bat_2.init==0) /*右侧电池盒初始化未完成*/
{
if(Bat_1.init==0) /*左侧电池盒初始化未完成*/
{
//delay(200); /*延时1秒*/
LeftBattery_Init(); /*左侧电池盒初始化*/
if(Bat_1.init==1) /*左侧电池盒初始化完成*/
{
LeftBattery_Deal(); /*左侧电池盒控制电流充电*/
}
}
ENA=0; /*打开2路通讯*/
delay(500); /*延时1秒*/
RightBattery_Init(); /*右侧电池盒初始化*/
if(Bat_2.init==1) /*左侧电池盒初始化完成*/
{
RightBattery_Deal(); /*右侧电池盒控制电流充电*/
}
}
else /*右侧电池盒初始化已完成*/
{
RightBattery_Deal(); /*右侧电池盒控制电流充电*/
}
}
else /*右侧电池盒不在里面的时候*/
{
Bat_2_Reset(); /*右侧电池状态复位*/
}
if(count%20==0) /*采集两路的温度值,根据温度控制风扇。*/
{
show_temp();
}
count++;
}
}
/*****************************************************************/
#ifndef __program8_H__
#define __program8__
#include "pic.h"
#include <PWM.h>
#include <INT.h>
#include <SPI_887.h>
#include <CAN_887.h>
#include <usart.h>
#include <DELAY.h>
#include <ADC.h>
#include <VAR.h>
#include <mcp2515.h>
#include <bat.h>
#define uchar unsigned char
#define uint unsigned int
#define nop() asm("nop")
#define CS RD1 /*标签为CANCSRH4*/
#define RESET RD0 /*标签为RESETCAN*/
#define FAN RC0 /*定义风扇*/
void Init_Int(void); /*初始化中断*/
void interrupt ISR(void); /*中断处理函数*/
#endif
can887.c
/********************************************************
MCP2515 CAN通讯程序,测试CAN协议
**********************************************************/
#include <CAN_887.h>
/***************************
函数:void Init_Can(void)
函数描述:初始化CAN通讯
变量:无
*****************************/
void Init_Can(void)
{
RESET=1; /*关闭复位*/
CS=1; /*关闭片选*/
CS=0; /*打开片选,选中MCP2515*/
/**************************************
复位MCP2515 进入配置模式,以便配置寄存器。
****************************************/
SPIReset(); /*SPI复位*/
CS=1; /*关闭片选*/
delay(20); /*延时20ms*/
/**设置为配置模式**/
/*配置验收屏蔽滤波器0*/
CAN_Write(RXM0SIDH, 0x00); //为0时,对应的滤波位不起作用
CAN_Write(RXM0SIDL,0x00);
/*配置验证滤波器0*/
CAN_Write(RXF0SIDH,0x00); //标准标识符高字节
CAN_Write(RXF0SIDL,0x00); //标准标识符低字节
/**设置通讯速率 晶振16M 波特率125Kbps**/
CAN_Write(CNF1,CAN_125Kbps); //CNF1=0x07
//set CNF1,SJW=00,长度为1TQ,BRP=49,TQ=[2*(BRP+1)]/Fsoc=2*50/8M=12.5us,16M
//配置寄存器1,默认CAN波特率为125Kbit/s
CAN_Write(CNF2,0x80|PHSEG1_3TQ|PRSEG_1TQ); //3,1;6,2
//set CNF2,SAM=0,在采样点对总线进行一次采样,PHSEG1=(2+1)TQ=3TQ,PRSEG=(0+1)TQ=1TQ
//配置寄存器2,位时间为3TQ,同步段1TQ
//传播段1TQ,PHSEG1=3TQ,PRSEG=1TQ
CAN_Write(CNF3,PHSEG2_3TQ); //3;7 配置寄存器3,唤醒滤波器使能
//set CNF3,PHSEG2=(2+1)TQ=3TQ,同时当CANCTRL.CLKEN=1时设定CLKOUT引脚为时间输出使能位
//set TXB0,设置发送缓冲器0的标识符和发送的数据,以及发送的数据长度
/*配置发送缓冲区0,发送标准数据帧到ID:0X00的CAN节点*/
CAN_Write(TXB0SIDH,0x06); //标准标识符高字节
CAN_Write(TXB0SIDL,0x00); //标准标识符低字节
CAN_Write(TXB0DLC,DLC_8); //设置发送数据的长度为8个字节,DLC_8
//设置接收缓冲器0的标识符和初始化数据
CAN_Write(RXB0SIDH,0x00); //设置接收缓冲器0的标准标识符,待修改***
CAN_Write(RXB0SIDL,0x60); //用到标准标识符
CAN_Write(RXB0CTRL,0x60); //仅仅接收标准标识符的有效信息,FIILHIT0=0表示RXB0 ,采用FILHIT0
CAN_Write(RXB0DLC,DLC_8); //设置接收数据的长度为8个字节,DLC_8
/*配置验收滤波器*/
CAN_Write(RXF0SIDH,0xFF); //标准标识符高字节
CAN_Write(RXF0SIDL,0xE0); //标准标识符低字节
/*配置验收屏蔽滤波器0*/
CAN_Write(RXM0SIDH,0xFF); //标准标识符高字节
CAN_Write(RXM0SIDL,0xE0); //标准标识符低字节
//设置接收缓冲器0中断
CAN_Write(CANINTF,0x00); //清空中断标志位
CAN_Write(CANINTE,0x01); //接收缓冲器0满中断使能位
CAN_Write(CANCTRL,REQOP_NORMAL|CLKOUT_ENABLED); //设置正常模式
delay(10);
dummy=CAN_Read(CANSTAT); //读取CAN状态寄存器的值
if (OPMODE_NORMAL != (dummy && 0xE0)) //判断进入正常工作模式
CAN_Write(CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED); //设置正常模式
}
/***************************
函数:void CAN_Send(unsigned char *CAN_TX_Buf)
函数描述:CAN发送数据程序
变量:无
*****************************/
void CAN_Send(unsigned char *CAN_TX_Buf)
{
unsigned char tempdata;
tempdata=CAN_Read(CAN_RD_STATUS);
CAN_Write(TXB0D0,CAN_TX_Buf[0]);
CAN_Write(TXB0D1,CAN_TX_Buf[1]);
CAN_Write(TXB0D2,CAN_TX_Buf[2]);
CAN_Write(TXB0D3,CAN_TX_Buf[3]);
CAN_Write(TXB0D4,CAN_TX_Buf[4]);
CAN_Write(TXB0D5,CAN_TX_Buf[5]);
CAN_Write(TXB0D6,CAN_TX_Buf[6]);
CAN_Write(TXB0D7,CAN_TX_Buf[7]);
if(tempdata&0x04)//判断TXREQ标志位
{
delay(5);
CAN_Write(TXB0CTRL,0);//清除TXREQ标志位
while(CAN_Read(CAN_RD_STATUS)&0x04);//等待TXREQ清零
}
CS=0;
SPISendByte(CAN_RTS_TXB0);//发送缓冲器0请求发送
CS=1;
}
/***************************
函数:void CAN_Send_onebyte(unsigned char k)
函数描述:CAN发送一个字节数据程序
变量:无
*****************************/
void CAN_Send_onebyte(unsigned char k)
{
unsigned char tempdata;
tempdata=CAN_Read(CAN_RD_STATUS);
CAN_Write(TXB0D0,k);
if(tempdata&0x04)//判断TXREQ标志位
{
delay(5);
CAN_Write(TXB0CTRL,0);//清除TXREQ标志位
while(CAN_Read(CAN_RD_STATUS)&0x04);//等待TXREQ清零
}
CS=0;
SPISendByte(CAN_RTS_TXB0);//发送缓冲器0请求发送
CS=1;
}
/***************************
函数:void CAN_Receive(unsigned char *CAN_RX_Buf)
函数描述:CAN接收程序
变量:无
*****************************/
void CAN_Receive(unsigned char *CAN_RX_Buf)
{
// unsigned char tempdata;
// tempdata=CAN_Read_SS(CAN_RX_STATUS);
// if(tempdata&0x40)//说明接收的是RXB0中的标准数据帧
// {
// delay(1);
// CS=0;
// SPISendByte(CAN_RX_Buf);//将接收的首地址定为RXB0D0
CAN_RX_Buf[0]=CAN_Read(RXB0D0);
CAN_RX_Buf[1]=CAN_Read(RXB0D1);
CAN_RX_Buf[2]=CAN_Read(RXB0D2);
CAN_RX_Buf[3]=CAN_Read(RXB0D3);
CAN_RX_Buf[4]=CAN_Read(RXB0D4);
CAN_RX_Buf[5]=CAN_Read(RXB0D5);
CAN_RX_Buf[6]=CAN_Read(RXB0D6);
CAN_RX_Buf[7]=CAN_Read(RXB0D7);
CAN_Write(CANINTF,0);
// CS=1;
// }
}
/***************************
函数:unsigned char CAN_Receive_onebyte()
函数描述:CAN接收一个字节函数
变量:tempdata
*****************************/
unsigned char CAN_Receive_onebyte()
{
unsigned char tempdata;
//tempdata=SPIByteRead(CAN_RX_STATUS);
//if(tempdata&0x40)//说明接收的是RXB0中的标准数据帧
//{
// delay_ms(1);
//CS=LOW;
//WriteSPI(CAN_RX_BUFF);//将接收的首地址定为RXB0D0
tempdata=CAN_Read(RXB0D0);
CAN_Write(CANINTF,0);
return tempdata;
//CS=HIGH;
//}
}
/***************************
函数:void CAN_writetxb0id(unsigned int txb0id)
函数描述:位修改指令函数
变量:无
*****************************/
void CAN_writetxb0id(unsigned int txb0id)
{
CAN_Write(TXB0SIDH,(txb0id>>3));//设置发送缓冲器0的标准标识符,待修改***
CAN_Write(TXB0SIDL,(0x00FF&(txb0id<<5)));//用到标准标识符
}
/***************************
函数:void CAN_deal(void)
函数描述:CAN通讯接收处理函数
变量:无
*****************************/
void CAN_deal(void)
{
CAN_FLAG=0; /*清接收到标志*/
canrecebuf[0]=CAN_Read(RXB0D0);
canrecebuf[1]=CAN_Read(RXB0D1);
canrecebuf[2]=CAN_Read(RXB0D2);
canrecebuf[3]=CAN_Read(RXB0D3);
canrecebuf[4]=CAN_Read(RXB0D4);
canrecebuf[5]=CAN_Read(RXB0D5);
canrecebuf[6]=CAN_Read(RXB0D6);
canrecebuf[7]=CAN_Read(RXB0D7);
CAN_Write(CANINTF,0);
}
/***************************
函数:void CAN_0x21(int num)
函数描述:按地址0X21发送并接收数据,初始化第二步
变量:无
*****************************/
void CAN_0x21(int num)
{
/**访问地址0X0021**/
CAN_writetxb0id(0x0021);
if(num==1)
{
cansentbuf[0]=0x01; /*1为左侧电池盒 */
}
else
{
cansentbuf[0]=0x02; /*2为右侧电池盒*/
}
cansentbuf[1]=canrecebuf[0];
cansentbuf[2]=canrecebuf[1];
cansentbuf[3]=canrecebuf[2];
cansentbuf[4]=canrecebuf[3];
cansentbuf[5]=0x00;
cansentbuf[6]=0x00;
cansentbuf[7]=0x00;
CAN_Send(cansentbuf); /*发送数组,发送CAN通讯*/
delay(100); /*延时等待中断接收*/
CAN_deal(); /*接收数组*/
canjudgbuf[5]=canrecebuf[0];
canjudgbuf[6]=canrecebuf[1];
canjudgbuf[7]=canrecebuf[2];
// canjudgbuf[8]=canrecebuf[3];
canjudgbuf[9]=canrecebuf[7];
if(canreflag==1)
{
canreflag=0; /*清接收到标志*/
if(num==1)
{
for(int i=0;i<=4;i++) /*判断初始化过程中,两次接收到的条码是否一致。间接检验通讯是否正确进行*/
{
if(canjudgbuf[i]!=canjudgbuf[i+5])
{
Bat_1.init=0; /*初始化执行失败*/
break; /*若发现两次的的条码不对应,跳出循环,继续初始化 */
}
else
{
Bat_1.init=1; /*初始化执行成功*/
}
}
}
else
{
for(int i=0;i<=4;i++) /*判断初始化过程中,两次接收到的条码是否一致。间接检验通讯是否正确进行*/
{
if(canjudgbuf[i]!=canjudgbuf[i+5])
{
Bat_2.init=0; /*初始化执行失败*/
break; /*若发现两次的的条码不对应,跳出循环,继续初始化 */
}
else
{
Bat_2.init=1; /*初始化执行成功*/
}
}
}
}
else
{
Bat_2.init=0; /*初始化执行失败*/
}
for(int i=0;i<=9;i++) /*将判断的数组进行清零*/
{
canjudgbuf[i]=0;
}
}
/***************************
函数:void CAN_0x25(int num)
函数描述:按地址0X25发送并接收数据,读取电池故障信息。
变量:无
*****************************/
void CAN_0x25(int num)
{
/**访问地址0X0025**/
CAN_writetxb0id(0x0025);
if(num==1)
{
cansentbuf[0]=0x01; /*1为左侧电池盒 */
}
else
{
cansentbuf[0]=0x02; /*2为右侧电池盒*/
}
cansentbuf[1]=0x00;
cansentbuf[2]=0x29;
cansentbuf[3]=0x00;
cansentbuf[4]=0x00;
cansentbuf[5]=0x00;
cansentbuf[6]=0x00;
cansentbuf[7]=0x00;
CAN_Send(cansentbuf); /*发送数组,发送CAN通讯*/
delay(100); /*延时等待中断接收*/
CAN_deal(); /*接收数组*/
// canrecebuf[5]=1; /*模拟发送报文中有错误*/
if(canreflag==1)
{
canreflag=0; /*清接收到标志*/
if(num==1)
{
Bat_1.init=1; /*左电池盒初始化标志位为1*/
}
else
{
Bat_2.init=1; /*右电池盒初始化标志位为1*/
}
if(num==1)
{
for(i=0;i<7;i++) /*将故障数据的值按位或*/
{
Bat_1.error=Bat_1.error||canrecebuf[i];
}
Bat_1.error1=canrecebuf[0]||canrecebuf[2]||canrecebuf[3]; /*左电池过压、温度故障标志位*/
Bat_1.error2=canrecebuf[4]; /*左电池过流故障标志位*/
}
else
{
for(i=0;i<7;i++) /*将故障数据的值按位或*/
{
Bat_2.error=Bat_2.error||canrecebuf[i];
}
Bat_2.error1=canrecebuf[0]||canrecebuf[2]||canrecebuf[3]; /*左电池过压、温度故障标志位*/
Bat_2.error2=canrecebuf[4]; /*左电池过流故障标志位*/
}
for(i=0;i<7;i++) /*清接收数组*/
{
canrecebuf[i]=0;
}
}
else
{
if(num==1)
{
Bat_1.init=0; /*左电池盒初始化未成功,需要重新初始化*/
Bat_1_Reset(); /*左侧电池状态复位*/
}
else
{
Bat_2.init=0; /*右电池盒初始化未成功,需要重新初始化*/