最近做了个CAN总线取件纠错的系统,开机LED灯闪烁一次。但是程序运行的时候LED一直闪,就是在init()函数初始化LED闪烁一次后程序不断复位,实在找不出原因了,烦请各位大神帮忙分析下原因。
#include <pic18f25k80.h>
#define uchar unsigned char
#define uint unsigned int
#define LED PORTBbits.RB4
void init();//初始化函数
void caninit();//CAN初始化
void cansend();//发送函数
void interrupt canrec();//can总线接收中断函数
void delay(uint time);//延时函数
void run();//上位机操作码判断函数
uchar addr;//地址
uchar sidh;//发送标识符高位
uchar sidl;//发送标识符低位
uchar sidh1;//接收标识符高位
uchar sidl1;//接收标识符低位
uchar opcode;//操作码
uchar fucode;//功能码
uchar takenum;//取件数量
uchar opnum;//操作数量
uchar stcation;//指示状态
#pragma config INTOSCSEL=LOW//休眠期间LF-INTOSC处于低功耗模式
#pragma config SOSCSEL=DIG //数字模式使能RC0,RC1端口功能
#pragma config XINST=OFF //不使用扩展指令集
#pragma config RETEN=OFF //禁止超低功耗稳压器
#pragma config IESO=OFF // 禁止双速启动
#pragma config FOSC=HS1 //振荡器4-16MHZ
#pragma config FCMEN=OFF //禁止故障保护时钟
#pragma config PLLCFG=OFF //直接试用晶振
#pragma config BOREN=OFF //关闭欠压复位
#pragma config BORPWR=LOW //低功耗级别
#pragma config BORV=3 //欠压复位电压1.8V
#pragma config PWRTEN=OFF //禁止上电延时复位
#pragma config WDTPS=256 //WDT后分频比为1:256约为1.024S
#pragma config WDTEN=OFF //关闭看门狗
#pragma config CANMX=PORTB //CAN TX RX为RB2 RB3
#pragma config MSSPMSK=MSK7 //7位地址掩码
#pragma config MCLRE=ON // 使能MCLR复位引脚,禁止RE3IO功能
#pragma config STVREN=OFF //堆栈下溢、满不会导致复位
#pragma config BBSIZ=BB2K //引导区为2K
#pragma config CP0=OFF //代码保护关闭
#pragma config CP1=OFF
#pragma config CP2=OFF
#pragma config CP3=OFF
#pragma config CPD=OFF
#pragma config CPB=OFF
#pragma config WRT0=OFF //不写保护
#pragma config WRT1=OFF
#pragma config WRT2=OFF
#pragma config WRT3=OFF
#pragma config WRTB=OFF
#pragma config WRTC=OFF
#pragma config WRTD=OFF
#pragma config EBTR0=OFF
#pragma config EBTR1=OFF
#pragma config EBTR2=OFF
#pragma config EBTR3=OFF //允许表读
#pragma config EBTRB=OFF
void main()
{
INTCON=0x00;//关中断
init();//初始化
caninit();//CAN初始化
INTCON=0XC0;//开中断
while(1)
{
if(PORTBbits.RB0==0)//发送数据判断
{
delay(10);
if(PORTBbits.RB0==0)//消抖
{
while(PORTBbits.RB0==1);//检测开关是否释放
LED=1;//如果释放LED灯闪烁2次
delay(50);
LED=0;
delay(50);
LED=1;
delay(50);
LED=0;
delay(50);
stcation=0;//更新指示状态
opnum=opnum++;//操作数量加1
if(opnum>takenum)
{
fucode=0x06;//如果取件错误,设置错误码
}
cansend();//CAN总线发送数据
}
}
run();//上位机命令判断
}
}
void init()
{
TRISC=0xff;//设置RC口为输入
TRISB=0x09;//设置RB0为输入,CANTX为输出,CANRX为输入,RB4为输出
//INTCON2bits.nRBPU=1;//开RB上拉
LED=1;//开机LED闪烁1次
delay(50);
LED=0;
delay(50);
addr=PORTC;//读取取件器设置地址值
sidh=(addr>>3)&0x20;//CAN发送高位标识符
sidl=(addr<<5)&0x00;//CAN发送低位标识符
sidh1=(addr>>3)&0x00;//can接收高位标识符
sidl1=(addr<<5)&0x00;//can接收低位标识符
opcode=1;//初始化操作码
fucode=1;//初始化功能码
takenum=0;//初始化取件数量
opnum=0;//初始化操作数量
stcation=0;//初始化指示状态
}
void caninit()
{
CANCON=0x80;//请求进入CAN配置模式
while(CANSTAT&0x80==0);//等待进入CAN配置模式
BRGCON1=0X01;//设置SJW和BRP,SJW=1TQ,BRP=01H
BRGCON2=0X90;//设置Phase_Seg1=3TQ和Prog _Seg=1TQ
BRGCON3=0X42;//设置Phase_Seg2=3TQ
TXB0CON=0X03;//设置发送优先级为最高
TXB0SIDH=sidh;//高位标识符
TXB0SIDL=sidl;//低位标识符
TXB0DLC=0x05;//设置数据长度为5字节
RXB0SIDH=sidh1;//接收缓冲区0高位标识符
RXB0SIDL=sidl1;//接收缓冲区0低位标识符
RXB0CON=0X20;//接收标准标识符
RXB0DLC=0X05;//设置接收缓冲区0数据长度为5字节
RXF0SIDH=sidh1;//过滤器
RXF0SIDL=sidl1;//过滤器
RXM0SIDH=0XFF;//屏蔽与过滤器标识符不同的数据
RXM0SIDL=0XFF;//屏蔽与过滤器标识符不同的数据
RXB1SIDH=0X00;//接收广播
RXB1SIDL=0X00;//接收广播
RXB1CON=0X22;//接收标准标识符和过滤器为RXF2
RXB0DLC=0X05;//设置接收缓冲区1数据长度为5字节
RXF2SIDH=0X00;//过滤器
RXF2SIDL=0X00;//过滤器
RXM1SIDH=0XFF;//接收与过滤器2相同标识符的数据
RXM1SIDL=0XFF;//接收与过滤器2相同标识符的数据
CIOCON=0x31;//CAN IO初始化 使用振荡器作为时钟
CANCON=0X00;//正常工作模式
while(CANSTAT&0XE0!=0);//检测CAN总线是否正常工作
PIR5=0X00;//清所有CAN中断
PIE5=0X0c;//开CAN接收中断
IPR5=0X0c;//CAN接收中断最高优先级
}
void interrupt canrec()//CAN总线接收中断函数
{
if((PIR5bits.RXB0IF==1)&&(opcode!=0x06))//缓冲区0接收中断
{
PIR5bits.RXB0IF=0;//清中断标志位
RXB0CONbits.RXFUL=0;//打开接收缓冲器0接收数据
while(RXB0CONbits.RXFUL==0);
opcode=RXB0D0;//接收操作码
fucode=RXB0D1;//接收功能码
takenum=RXB0D2;//取件数量
}
if((PIR5bits.RXB1IF==1)&&(opcode!=0x06))//CAN总线缓冲区1接收中断
{
PIR5bits.RXB1IF=0;//清中断标志位
RXB1CONbits.RXFUL=0;//打开接收缓冲区1接收数据
while(RXB1CONbits.RXFUL==1);//等待接收完成
opcode=RXB1D0;//接收操作码
fucode=RXB1D1;//接收功能码
takenum=RXB1D2;//接收取件数量
}
if((PIR5bits.RXB1IF==1)&&(opcode==6)) //误码率测试
{
PIR5bits.RXB1IF=0;//清中断标志位
RXB1CONbits.RXFUL=0;//打开接收缓冲区1接收数据
while(RXB1CONbits.RXFUL==1);//等待接收完成
TXB0D0=RXB1D0;
TXB0D1=RXB1D1;
TXB0D2=RXB1D2;
TXB0D3=RXB1D3;
TXB0D4=RXB1D4;
cansend();
}
if((PIR5bits.RXB0IF==1)&&(opcode==6)) //误码率测试
{
PIR5bits.RXB0IF=0;//清中断标志位
RXB0CONbits.RXFUL=0;//打开接收缓冲区0接收数据
while(RXB0CONbits.RXFUL==1);//等待接收完成
TXB0D0=RXB0D0;
TXB0D1=RXB0D1;
TXB0D2=RXB0D2;
TXB0D3=RXB0D3;
TXB0D4=RXB0D4;
cansend();
}
}
void cansend()//CAN发送数据函数
{
if(opcode!=0x06)
{
TXB0D0=opcode;//写发送缓冲区
TXB0D1=fucode;//写发送缓冲区
TXB0D2=takenum;//写发送缓冲区
TXB0D3=opnum;//写发送缓冲区
TXB0D4=stcation;//写发送缓冲区
TXB0CONbits.TXREQ=1;//开始发送
while(PIR5bits.TXB0IF);//检测是否发送完毕
TXB0CONbits.TXREQ=0;//禁止发送
}
if(opcode==0x06)
{
TXB0CONbits.TXREQ=1;//开始发送
while(PIR5bits.TXB0IF);//检测是否发送完毕
TXB0CONbits.TXREQ=0;//禁止发送
}
}
void run()//上位机命令判断函数
{
switch(opcode)//操作码判断
{
case 0:
{
cansend();//状态查询
opcode=1;
break;
}
case 1:
{
if(fucode==0)//复位
{
LED=0;
opcode=1;
fucode=1;
takenum=0;
opnum=0;
stcation=0;
}
if(fucode==1)//取件
{
if(takenum!=0)
{
LED=1;
fucode=1;
stcation=1;
}
if(takenum==0)
{
LED=0;
}
}
break;
}
case 2://进入测试流程
{
stcation=0x02;
LED=1;
delay(50);
LED=0;
delay(50);
LED=1;
delay(50);
LED=0;
delay(50);
LED=1;
delay(50);
LED=0;
delay(50);
LED=1;
delay(50);
LED=0;
delay(50);
LED=1;
delay(50);
LED=0;
opcode=0;
stcation=0;
break;
}
case 3://设置取件指示灯
{
if(fucode==0x03)
{
LED=0;
stcation=0;
}
if(fucode==0x04)
{
LED=1;
stcation=1;
}
if(fucode==0x05)
{
do
{
LED=1;
delay(50);
LED=0;
delay(50);
stcation=0x03;
}
while((fucode!=0x05)||(opcode!=0x03));
stcation=0;
}
break;
}
case 5://重启
{
WDTCON=1;//开狗
while(1);//等待看门狗重启程序
}
}
}
void delay(uint time)//延时函数
{
uint a,b;
for(a=time;a>0;a--)
for(b=110;b>0;b--);
}
此帖出自
小平头技术问答
用 C 对PIC18Fxx时,要注意对变量的定义一定要用#pragma udata(idata) 为变量分配地址,否则容易出错。
第二、子函数的形参和局部变量越少越好。这两点是我用教训换来的。我没仔细看你的程序,你说的“复位“现象可以通过仿真看看RCON的值,确定复位源。一般的,如果不开WATCHDOG的话,软件写成什么样都不会引起复位的
一周热门 更多>