|
发表于 2007-9-26 19:28:05
|
显示全部楼层
今天调了大半天,搞定了EVIEW文本屏MD204L和M64通MODBUS,因为用的功能不多,就读位,写位,读字,写字,
msec(uchar a)
{
uchar b;
for(;a>0;a--)
for(b=0;b<100;b++);
}
/*=======================校验码生成========================================*/ //这个是从OURAVR下的呵呵
uint crc_make(uchar *ptr, uint len)
{
uint crc=0xffff;
uchar i;
while(len!=0)
{
crc^=*ptr;
for(i=0;i<8;i++)
{
if((crc&0x0001)==0)
crc=crc>>1;
else
{
crc=crc>>1;
crc^=0xa001;
}
}
len-=1;
ptr++;
}
return crc;
}
/*======================校验码比较======================= */
uchar crc_check(uchar a) //a为接收到的字符个数
{
uint crc0,crc1;
crc0=crc_make(rxd_data,(a-2));
crc1=(rxd_data[a-1]<<8)+rxd_data[a-2];
if(crc0==crc1) return 1;
else return 0;
}
/*====================开始发送================================*/
send_start(uchar a)
{
uchar b;
PORTE|=4;
for(b=0;b<a;b++)
{
UDR0=send_data;
while(!(UCSR0A&0x20));
msec(1);
}
PORTE&=~4;
}
//转发送
/*======================读位======================= */
read_bit()
{
uchar b,c;
uint a;
if(crc_check(8)==0) return; //CRC检查
a=(rxd_data[2]<<8)+rxd_data[3]; //合并地址
b=a/16; //取位所在的节地址
c=a%16; //取位在字地址的位地址
send_data[0]=1; //发送本地地址
send_data[1]=1; //发送功能码
send_data[2]=2; //发送字节数
if((m_sign&(1<<c))!=0) send_data[3]=1; //读该地址的位状态并发送
else send_data[3]=0;
send_data[4]=0; //位状态的低字节
a=crc_make(send_data,5); //生成CRC
send_data[6]=a>>8; //发送高字节
send_data[5]=a&255; //发送低字节
send_start(8); //开始发送
}
/*======================读字======================= */
read_word()
{
uint a;
if(crc_check(8)==0) return; //CRC检查
a=(rxd_data[2]<<8)+rxd_data[3]; //合并地址
send_data[0]=1; //发送本地地址
send_data[1]=3; //发送功能码
send_data[2]=2; //发送字节数
send_data[3]=(modbus_word[a]>>8); //读该地址高字节并发送
send_data[4]=(modbus_word[a]&255); //读该地址低字节并发送
a=crc_make(send_data,5); //生成CRC
send_data[6]=a>>8; //发送高字节
send_data[5]=a&255; //发送低字节
send_start(8); //开始发送
}
/*======================写位======================= */
write_bit()
{
uchar b,c;
uint a;
if(crc_check(8)==0) return; //CRC检查
a=(rxd_data[2]<<8)+rxd_data[3]; //合并地址
b=a/16; //取位所在的节地址
c=a%16; //取位在字地址的位地址
if(rxd_data[4]==0xff) m_sign|=(1<<c); //写1
else m_sign&=~(1<<c); //写0
send_data[0]=1; //发送本地地址
send_data[1]=5; //发送功能码
send_data[2]=rxd_data[2]; //发送高8位地址
send_data[3]=rxd_data[3]; //发送低8位地址
send_data[4]=rxd_data[4]; //读该位状态高字节
send_data[5]=00; //发送位状态的低字节
a=crc_make(send_data,6); //生成CRC
send_data[7]=a>>8; //发送高字节
send_data[6]=a&255; //发送低字节
send_start(9); //开始发送
}
/*======================读字======================= */
write_word()
{
uchar b,c;
uint a;
if(crc_check(11)==0) return; //CRC检查
a=(rxd_data[2]<<8)+rxd_data[3]; //合并地址
modbus_word[a]=(rxd_data[7]<<8)+rxd_data[8];
send_data[0]=1; //发送本地地址
send_data[1]=16; //发送功能码
send_data[2]=rxd_data[2]; //发送字节数
send_data[3]=rxd_data[3]; //读该地址高字节并发送
send_data[4]=0;
send_data[5]=1; //读该地址低字节并发送
a=crc_make(send_data,5); //生成CRC
send_data[7]=a>>8; //发送高字节
send_data[6]=a&255; //发送低字节
send_start(9); //开始发送
}
/*====================485服务函数1MS调用一次===========================*/
rs485_check()
{
if(send_overtime<4) {send_overtime++;} //如果接收超时标志小于5,加1
if((send_overtime==4)&&(rxd_end)) //如果超时且接收结束,就处理数据
{
rxd_pointer=0; //接收指针清0
rxd_end=0; //清零接收标志
switch(rxd_data[1]) //判断命令
{
case 1:read_bit();break; //读位
case 3:read_word();break; //读字
case 5:write_bit();break; //写位
case 16:write_word();break; //写字
default: break;
}
}
}
/*==============================================================*/
main()
{
DDRE=0XE;
DDRB=0X60;
TCCR0=0X0C;
TIMSK|=2;
OCR0=230;
UCSR0B=0X98;
UCSR0C=0X6;
UBRR0L=95;
UBRR0H=0;
SREG|=0X80;
while(1)
{
if(m_sign[5]&(1<<8)) PORTB&=~(1<<6);
else PORTB|=(1<<6);
if(m_sign[0]&(1<<9)) PORTB&=~(1<<5);
else PORTB|=(1<<5);
}
}
#pragma interrupt_handler rs458rx:19
rs458rx()
{
rxd_data[rxd_pointer]=UDR0; //数据进缓存
rxd_pointer++; //接收指针加1
rxd_end=1; //接收标志置1
send_overtime=0; //接收超时标志清0
}
#pragma interrupt_handler t0_ctc:16
t0_ctc()
{
rs485_check(); //485工作程序,保证1MS调用一次,
} |
|