📄 communication._c
字号:
Wait(); //等
if(TestAck()!=TWI_MTX_DATA_ACK ) //ACK
return 1; //出错
delay_nms(50);
}
Stop(); //I2C停止
return 0; //整个过程正常时返回0
}
//时钟读
uchar clock_rd(uchar command,uchar num)
{
uchar j=0;
Start() ; //I2C开始
Wait() ; //等待TWIINT标志为1
if(TestAck()!=TWI_START )
return 1; //出错
i2c_wt_8bit(command); //写I2C从器件地址及写方式
Wait(); //等
if(TestAck()!=TWI_MRX_ADR_ACK ) //ACK
return 1; //出错
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after reception
(0<<TWWC);
delay_nus(25); //最低值!
for(j=1;j<num;j++) //读取num-1个
{
if(TestAck()!= TWI_MRX_DATA_ACK ) //ACK
return 1; //出错
i2c_rd_buff[j-1]=TWDR; //读取数
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after reception
(0<<TWWC);
delay_nus(25); //最低值!
}
if(TestAck()!= TWI_MRX_DATA_ACK ) //ACK
return 1; //出错
i2c_rd_buff[num-1]=TWDR; //读取数
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send NACK after reception
(0<<TWWC);
delay_nus(25); //最低值!
if(TestAck()!= TWI_MRX_DATA_NACK ) //NACK
return 1; //出错
Stop(); //I2C停止
return 0; //整个过程正常时返回0
}
//片内E2PROM的读写 自编
//片内E2PROM写函数
void EEPROM_write(unsigned int address,unsigned char data)
{
while(EECR&(1<<EEWE))
;
EEAR=address;
EEDR=data;
EECR|=(1<<EEMWE);
EECR|=(1<<EEWE);
}
//片内E2PROM读函数
unsigned char EEPROM_read(unsigned int address)
{
uchar i;
while(EECR&(1<<EEWE))
;
EEAR=address;
EECR|=(1<<EERE);
//return EEDR;
i=EEDR;
return i;
}
/***********************************************************************************/
//自动搜索,存储下面接点的投用情况及投用类型
void atuo_search(void)
{
uint t=0;
uint addrxy=0;
uchar addrxyh=0,addrxyl=0;
uchar k=0,i=0;
uchar j=0;
uchar temp1=0,temp2=0;
uchar temp3=0,temp4=0,temp5=0,temp6=0; //节点投用判断用
//uchar autoc[5]={0xff,0xff,0xff,0xff,0xff};
uchar xuanbit2[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
for(k=0;k<4;k++) //读取转换器的投用情况
{
canuse[k]=EEPROM_read(0x0008+k) ;
delay_nms(3);
}
for(fl=1;fl<=32;fl++) //32个转换器 fu le
{
wdr();
temp1=(fl-1)%8; //余数
temp2=(fl-1)/8; //商
if((xuanbit2[temp1]&canuse[temp2])==0) //表示对应的转换器投用
{
write_MCP(TXB0SIDH,fl); //接收方的地址
write_MCP(TXB0SIDL,0x08); //扩展帧格式
write_MCP(TXB0EID8,0x00); //标识发送方地址
write_MCP(TXB0EID0,0x00); //485节点地址
write_MCP(TXB0DLC, 8); //发送8个字节
write_MCP(TXB0D0, 0xab); //命令字节1
write_MCP(TXB0D1, 0xba); //命令字节2
write_MCP(TXB0D2, 0x00);
write_MCP(TXB0D3, 0x00);
write_MCP(TXB0D4, 0x00);
write_MCP(TXB0D5, 0x00);
write_MCP(TXB0D6, 0x00);
write_MCP(TXB0D7, 0x00);
EIMSK&=~(1<<INT6) ;
UCSR1B&=~(1<<RXCIE1);
send_box_0(); //发送
//NOP();
mcu_ok(1); //灭
wdr();
delay_nms(1000);
wdr();
delay_nms(1000);
while(zhongbuff[0][2]!=0xac) //一直等待
{
t++;
if(t>65000)
{
t=0;
break;
}
}
if( zhongbuff[0][2]==0xac)
{
t=0;
zhongbuff[0][2]=0;
for(k=0;k<5;k++)
autoc[k]=zhongbuff[0][k+3]; //此转换器下接点的投用情况
//n可以作为对应转换器的地址
//保存节点的投用情况及投用类型
//要做的工作
for(k=0;k<6;k++) //清零
zhongbuff[0][k+2]=0;
for(k=0;k<4;k++) //存节点的投用情况
EEPROM_write(0x000c+k+fl*4,autoc[k+1]);
EEPROM_write(0x0090+fl,autoc[0]);
}
EIMSK|=(1<<INT6) ;
UCSR1B|=(1<<RXCIE1);
}
delay_nms(10);
mcu_ok(0); //亮
}
for(k=0;k<33;k++) //读取所有485节点的投用情况
{
wdr();
for(j=0;j<4;j++)
detuse[k][j]= EEPROM_read(0x000c+j+k*4);
}
for(k=0;k<33;k++) //读取每个转换器下1-8#探测器 联动选择情况字节段
det_link[k]=EEPROM_read(0x0090+k) ;
//以下是为了显示屏蔽灯而编写的程序段
gal3data|=0x22; //关闭两个屏蔽灯
GAL3ADDR=gal3data;
for(fl=1;fl<=32;fl++) //32个转换器 fu le
{
wdr();
if((gal3data|0xdd)==0xdd) //两个屏蔽灯都亮
break;
temp1=(fl-1)%8; //余数
temp2=(fl-1)/8; //商
if((xuanbit2[temp1]&canuse[temp2])==0) //表示对应的转换器投用
{
for(i=1;i<=8;i++) //前8号节点
{
temp3=(i-1)%8; //余数
temp4=(i-1)/8; //商
temp5=i%8; //余数
temp6=i/8; //商
if(((detuse[fl][temp4]& xuanbit2[temp3])!=0)&&((detuse[fl][temp6]&xuanbit2[temp5])==0)) //该节点不投用下个节点投用
{
//读取外部ram中的标志字节
addrxy=(uint)(fl*256)+(i-1)*8; //探测器和节点对应的RAM地址
addrxyh=(uchar)(((addrxy&0xff00)>>8)); //高址
addrxyl=(uchar)(addrxy&0x00ff); //低址
EIMSK&=~(1<<INT6);
fhz=I2cRead(SLA1_W,SLA1_R, addrxyh,addrxyl,1); //读出
k=i2c_rd_buff[0]; //转移命令
EIMSK|=(1<<INT6);
if(k==0x55) //探测器屏蔽
{
gal3data&=0xfd; //探测器屏蔽灯亮
GAL3ADDR=gal3data;
}
else if(k==0xa9) //联动
{
gal3data&=0xdf; //联动屏蔽灯亮
GAL3ADDR=gal3data; //
}
}
}
for(i=9;i<=31;i++) //9-32
{
temp3=(i-1)%8; //余数
temp4=(i-1)/8; //商
temp5=i%8; //余数
temp6=i/8; //商
if(((detuse[fl][temp4]& xuanbit2[temp3])!=0)&&((detuse[fl][temp6]&xuanbit2[temp5])==0)) //该节点不投用下个节点投用
{
gal3data&=0xfd; //探测器屏蔽灯亮
GAL3ADDR=gal3data;
break;
}
}
}
}
}
//转换器自动搜索
void conv_auto_search(void)
{
uchar i=0; uint t=0;
uchar tempbuf[10]={0,0,0,0,0,0,0,0,0,0};
uchar tem1=0,tem2=0;
EEPROM_write(0x0008,0xff);
EEPROM_write(0x0009,0xff);
EEPROM_write(0x000a,0xff);
EEPROM_write(0x000b,0xff);
for(i=0;i<32;i++)
can_cuo_flag[i]=0;
for(i=1;i<=32;i++)
{
write_MCP(TXB0SIDH,i); //接收方的地址
write_MCP(TXB0SIDL,0x08); //扩展帧格式
write_MCP(TXB0EID8,0x00); //标识发送方地址
write_MCP(TXB0EID0,0x00); //485节点地址
write_MCP(TXB0DLC, 8); //发送8个字节
write_MCP(TXB0D0, 0xaa); //命令字节1
write_MCP(TXB0D1, 0xbb); //命令字节2
write_MCP(TXB0D2, 0x00);
write_MCP(TXB0D3, 0x00);
write_MCP(TXB0D4, 0x00);
write_MCP(TXB0D5, 0x00);
write_MCP(TXB0D6, 0x00);
write_MCP(TXB0D7, 0x00);
mcu_ok(1);
wdr();
EIMSK&=~(1<<INT6) ;
UCSR1B&=~(1<<RXCIE1);
send_box_0(); //发送
delay_nms(5);
while(zhongbuff[0][2]!=0xbd) //一直等待
{
t++;
if(t>10000)
{
t=0;
break;
}
}
t=0;
mcu_ok(0);
if(zhongbuff[0][2]==0xbd) //正确返回时
{
save1(0x0008 ,i);
}
zhongbuff[0][2]=0;
EIMSK|=(1<<INT6) ;
UCSR1B|=(1<<RXCIE1);
delay_nms(3);
}
delay_nms(10);
}
//485
//自动搜索函数,发送命令返回值根据返回值来判断是否投用及投用的为联动或探测器
void detuse_auto_search(void)
{
uint addrxy=0;
uchar addrxyh=0,addrxyl=0;
uchar detaddr=0;
uchar j=0;uchar i=0,k=0;
uchar temp1=0,temp2=0,temp5=0,temp6=0;
uchar set0[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uchar set1[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
for(detaddr=0;detaddr<32;detaddr++)
{
wdr();
Usart_Transmit_Data(detaddr+1,1); //开始发送节点地址
Usart_Transmit_Data(0x69,0); //发送查询命令
Usart_Transmit_Data(((detaddr+1)^0x69),0);//发送校验字节
for(j=0;j<4;j++)
{
zhongbuff[detaddr][j]=Usart_Receive_Data();
if(errorflag==1)
{
errorflag=0;
zhongbuff[detaddr][0]=detaddr+1;
zhongbuff[detaddr][1]=0x69;
zhongbuff[detaddr][2]=0x0f; //通讯故障,既没有此节点
zhongbuff[detaddr][3]=(detaddr+1)^0x69^0x0f;
break; //跳出for循环
}
}
if(zhongbuff[detaddr][2]==0xab) //此节点投用为探测器
{
if((detaddr+1)<=8) //存detchoose[0]
{
det_link[0]|=set1[detaddr] ; //对应的位设定为1
}
temp1=detaddr%8; //取余数
temp2=detaddr/8; //取商
detuse[0][temp2]&=set0[temp1]; //存投用情况
}
else if(zhongbuff[detaddr][2]==0xba) //此节点投用为联动
{
det_link[0]&=set0[detaddr] ; //一定<8,对应的位设定为0
temp1=detaddr%8; //取余数
temp2=detaddr/8; //取商
detuse[0][temp2]&=set0[temp1]; //存投用情况
}
else if(zhongbuff[detaddr][2]==0x0f) //此节点没有投用
{
temp1=detaddr%8; //取余数
temp2=detaddr/8; //取商
detuse[0][temp2]|=set1[temp1]; //存投用情况
}
else
;
}
//wunai=1;
wdr();
EEPROM_write(0x0090,det_link[0]);//保存1-8是探测器还是联动模块信息 1默认探测器
EEPROM_write(0x000c,detuse[0][0]);//保存1-32节点的投用情况 1默认未投用
EEPROM_write(0x000d,detuse[0][1]);//保存1-32节点的投用情况
EEPROM_write(0x000e,detuse[0][2]);//保存1-32节点的投用情况
EEPROM_write(0x000f,detuse[0][3]);//保存1-32节点的投用情况
//以下是为了显示屏蔽灯而编写的程序段
gal3data|=0x22; //关闭两个屏蔽灯
GAL3ADDR=gal3data;
for(i=1;i<=8;i++) //前8号节点
{
wdr();
if((gal3data|0xdd)==0xdd) //两个屏蔽灯都亮
break;
temp1=(i-1)%8; //余数
temp2=(i-1)/8; //商
temp5=i%8; //余数
temp6=i/8; //商
if(((detuse[0][temp2]& set1[temp1])!=0)&&((detuse[0][temp6]&set1[temp5])==0)) //该节点不投用下个节点投用
{
//读取外部ram中的标志字节
addrxy=(uint)((i-1)*8); //探测器和节点对应的RAM地址
addrxyh=(uchar)(((addrxy&0xff00)>>8)); //高址
addrxyl=(uchar)(addrxy&0x00ff); //低址
EIMSK&=~(1<<INT6);
fhz=I2cRead(SLA1_W,SLA1_R, addrxyh,addrxyl,1); //读出
k=i2c_rd_buff[0]; //转移命令
EIMSK|=(1<<INT6);
if(k==0x55) //探测器屏蔽
{
gal3data&=0xfd; //探测器屏蔽灯亮
GAL3ADDR=gal3data;
}
else if(k==0xa9) //联动
{
gal3data&=0xdf; //联动屏蔽灯亮
GAL3ADDR=gal3data; //
}
}
}
for(i=9;i<=31;i++) //9-32
{
wdr();
temp1=(i-1)%8; //余数
temp2=(i-1)/8; //商
temp5=i%8; //余数
temp6=i/8; //商
if(((detuse[fl][temp2]& set1[temp1])!=0)&&((detuse[fl][temp6]&set1[temp5])==0)) //该节点不投用下个节点投用
{
gal3data&=0xfd; //探测器屏蔽灯亮
GAL3ADDR=gal3data;
break;
}
}
}
/**************************485总线时用*******************************/
void lunxun485(void)
{
uchar addr=0x01; //地址计数
uchar N=0x01; //1-8节点设置 判断用
uchar M=0x01; //用作 节点是否投用判断
uchar counter1=0,counter2=0; //8个节点轮寻完时,轮寻下8个控制字节
uchar i=0,j=0,k=0; //k 选择判断哪8个探测器投用 用
uchar m=0,check_sum=0;
wdr() ; //dog
while(addr<=8) //探测器或联动模块
{
if((M&detuse[0][0])==0x00) //如果投用
{
if((jiemian!=0)&&(denglu==0)) //时钟
clock_disp() ;
if((N&det_link[0])==0x00) //联动模块
{
Usart_Transmit_Data(addr,1); //开始发送节点地址
Usart_Transmit_Data(0xA9,0); //发送输入通道查询命令
Usart_Transmit_Data((addr^0xA9),0);//发送校验字节
for(j=0;j<5;j++)
zhongbuff[i][j]=Usart_Receive_Data();
//保存查询联动模块所返回的状态
for(j=5;j<10;j++)
zhongbuff[i][j]=0;//把剩余的空间填充0
}
else //对应节点为探测器时
{
Usart_Transmit_Data(addr,1); //开始发送节点地址
Usart_Transmit_Data(0x55,0); //发送状态查询命令
Usart_Transmit_Data((addr^0x55),0);//发送校验字节
for(j=0;j<10;j++)
zhongbuff[i][j]=Usart_Receive_Data();
//保存查询探测器所返回的状态]
}
for(m=0;m<10;m++)
check_sum=check_sum^zhongbuff[i][m];
//校验和
if(check_sum!=0)
//如果校验和不对
{
check_sum=0;
Usart_Transmit_Data(addr,1); //发送命
Usart_Transmit_Data(0xa6,0); //令要求
Usart_Transmit_Data((addr^0xa6),0);//重发!
if((N&det_link[0])==0x00) //联动模块
{
for(j=0;j<5;j++)
zhongbuff[i][j]=Usart_Receive_Data();
//保存查询联动模块所返回的状态
for(j=5;j<10;j++)
zhongbuff[i][j]=0;//把剩余的空间填充0
}
else
{
for(j=0;j<10;j++)
zhongbuff[i][j]=Usart_Receive_Data();
//保存查询探测器所返回的状态]
}
for(m=0;m<10;m++)
check_sum=check_sum^zhongbuff[i][m];
//校验和
}
if((check_sum!=0)||(errorflag==1))
{
can_cuo_flag[addr]++;
check_sum=0; //用于下一个的校验再
errorflag=0;
if(can_cuo_flag[addr]>=3)
{
zhongbuff[i][0]=addr;
if((N&det_link[0])==0x00) //联动模块
zhongbuff[i][1]=0xA9;
else
zhongbuff[i][1]=0x55;
zhongbuff[i][2]=0xf0;//状态,包括出错状态
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -