搜索
bottom↓
回复: 162

分享喜悦:Modbus成功完成

[复制链接]

出0入0汤圆

发表于 2004-11-29 10:15:56 | 显示全部楼层 |阅读模式
这几天在网友、同事的帮忙下,我终于完成Modbus,昨天通讯成功,计算机、单片机(M16)收、发自如。心情高兴,独乐乐不如众乐乐。





unsigned int cal_crc(unsigned char *ptr, unsigned int len)

             {  

              unsigned int crc=0xffff;  

              unsigned char 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;

             }  

                         

void fenli(unsigned int data,unsigned int data1)

     {

          send_data[data1]=(unsigned char)(data);

          send_data[data1+1]=(unsigned char)(data>>8);

         }



unsigned int zhuhe(unsigned char data1,unsigned char data)

    {

         unsigned int t;

         t=data1;

         t=(t<<8)+data;

         return t;

        }

       

void send_run(void)

    {

         if(send_sp>num_send-1)

         {

          send_sp=0;

          flag_send=0;

         }

         else

         {

          UDR=send_data[send_sp];

          send_sp++;       

         }

         num_stop=0;

        }

       

void error(unsigned char data)

     {

          unsigned char add;

          num_send=5;

          send_data[1]=0x11;

          send_data[2]=data;

          add=cal_crc(send_data,3);

          fenli(add,3);

         }

         

void data_act(void)

     {

          unsigned int add,i,n;

          send_data[0]=address;

          add=zhuhe(recieve_data[2],recieve_data[3]);

          add=add*2-2; /*&micro;&Oslash;&Ouml;·*/

          if(add>49) error(2);

          else

          {

           if(recieve_data[1]==3)

           {

           n=zhuhe(recieve_data[4],recieve_data[5]); /*&sup3;¤&para;&Egrave;*/       

           num_send=6+n;

           send_data[1]=recieve_data[1];  /*&sup1;&brvbar;&Auml;&Uuml;*/

           send_data[2]=recieve_data[4];

           send_data[3]=recieve_data[5];  /*&sup3;¤&para;&Egrave;*/

           for(i=0;i<n;i++)

           send_data[i+4]=variable_data[i+add];

           n=4+n;

           i=cal_crc(send_data,n);

           fenli(i,n);

          }

          else if(recieve_data[1]==6)

          {          

           num_send=num_recieve;

           for(i=1;i<num_recieve;i++)

           send_data[1]=recieve_data[1];       

          }

          else error(1);

          }

         }

         

unsigned char crc_recieve(unsigned char data)

       {

            unsigned int crc0,crc1;

                crc0=cal_crc(recieve_data,num_recieve);

                crc1=zhuhe(recieve_data[data-1],recieve_data[data-2]);

                if(crc0=crc1) return 1;

                else return 0;

           }

   

   

void time1compatt(void)                  

         {       

          unsigned char flag;

          if(flag_send==2) send_run();

          num_stop+=1;

          if(num_stop>3)

          {             

           if(flag_send==1)

           {

            flag=crc_recieve(num_recieve);

                if(flag==1)

                {

            data_act();

            flag_send=2;

            num_recieve=0;

                }

           }

           num_stop=0;                           

          }

         }

         

#pragma interrupt_handler usrt_resieve:12   

void usrt_resieve(void)                  

         {       

          recieve_data[num_recieve]=UDR;

          num_recieve+=1;

          num_stop=0;

          flag_send=1;

         }

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2004-11-29 11:10:38 | 显示全部楼层
恭喜!

出0入0汤圆

发表于 2004-11-29 12:22:05 | 显示全部楼层
问个问题,Modbus是什么东西,能介绍一下吗

出0入0汤圆

 楼主| 发表于 2004-11-29 12:35:01 | 显示全部楼层
是一种总线,前面有个帖子已经介绍了

出0入0汤圆

发表于 2004-11-29 15:13:16 | 显示全部楼层
谢谢zhzzh18 小章,我也想做一个modbus看看,有了你的成果就方便多了。

出0入0汤圆

发表于 2004-11-29 15:54:33 | 显示全部楼层
是ASCII还是字节??

出0入0汤圆

发表于 2004-11-29 15:54:45 | 显示全部楼层
是ASCII还是字节??

出0入0汤圆

发表于 2004-11-29 15:56:49 | 显示全部楼层
是ASCII还是字节??

出0入0汤圆

 楼主| 发表于 2004-11-29 16:47:25 | 显示全部楼层
是RTU模式。

出0入0汤圆

发表于 2004-11-30 14:29:04 | 显示全部楼层
大哥 给个说明文档还有注释呀

出0入0汤圆

发表于 2004-11-30 15:05:48 | 显示全部楼层
zhzzh18 小章:

pc软件如何延时3字节时间?

我们pc软件部的人说:只能用100ms延时代替。我不懂pc,你有什么好办法吗?

出10入120汤圆

发表于 2004-11-30 15:24:23 | 显示全部楼层
在MODBUS文件中,RTU中没有规定3.5个字节的精确定时,他仅仅是要求在祯头和祯尾空闲的时间是最少3.5字节的时间,所以楼上PC软件部所说的延时100MS是符合MODBUS规范的。

出0入0汤圆

发表于 2004-11-30 16:09:59 | 显示全部楼层
是符合的。但延时时间太长了,你有没有办法小点。

搞电子的,对实时性能有点上瘾,省一点是一点。

出0入0汤圆

发表于 2005-1-5 21:56:36 | 显示全部楼层
pc提供的api函数timeouts里面有一个interval设置,把这个设置成4mS,这样4mS没有接受到数据Readfile函数就会返回

出0入0汤圆

 楼主| 发表于 2005-1-6 09:19:17 | 显示全部楼层
to: SUN0_LIANG 混沌的心

    不好意思

    根据波特率来定时,定时接收,这样就很好的延时3个字节了;

出0入0汤圆

发表于 2005-2-2 10:19:43 | 显示全部楼层
楼主,非常感谢你的无私帮助。我是个刚学AVR的新手,我把你的程序在串口调试助手上调试时什么都没有啊,编译都没有出错,不知问题出在哪里?您能不能把你的代码给我发一份啊?小弟实在是感激万分。我的E-mail:sym125@126.com

出0入0汤圆

 楼主| 发表于 2005-2-3 09:52:46 | 显示全部楼层
to:sym125     

    不好意思,完整的代码一个仪表程序,涉及公司资料,我不敢给你,不过可以告诉你,你初始化通讯的特殊寄存器,定时接收,程序就可以了。我不知道你怎么调试的,我调试时有同事做的Modbus调试界面,就是用协议做的PC通讯程序。

出0入0汤圆

发表于 2005-2-3 16:25:06 | 显示全部楼层
to:zhzzh18

   你好,我是用的485和232都可以用的串口调试界面,这个应该没有问题。我想可能还是出在下位机的软件上的问题,我今天调试了一下,串口能接收数据,但就不是按照MODBUS协议的来通信的。还望你能帮我指点一二,谢谢。

出0入0汤圆

 楼主| 发表于 2005-2-3 17:20:56 | 显示全部楼层
to:sym125

    能否讲明白点,

    串口能接收数据?  是单片机能接受数据还是PC机能接收数据?

    不是按照MODBUS协议的来通信的     是哪方面不是按照MODBUS协议的来通信?PC机、单片机还是两者都不是按照MODBUS协议的来通信的?

    后天我就回家了,可能要很长时间不上网。

出0入0汤圆

发表于 2005-2-4 08:40:32 | 显示全部楼层
to:zhzzh18

    你好,真是太麻烦你了,真没有想到有这么热心的好人啊!比起咱们老师来都好他上百倍啊。我的是PC机能接收数据,但接收的数据不是按MODBUS协议中RTU的通信方式来的,都是些很乱的数据,那就更不用说后面的检验码正确否了。小弟现在实在是一愁莫展啊,身边找个请教的人都没有啊,能得到你的指点,真像这寒冬里的一把火,无限的温暖

出0入0汤圆

 楼主| 发表于 2005-2-4 09:32:14 | 显示全部楼层
单片机与PC机通讯调试步骤:

     1:确定PC机通讯没问题,方法:把PC机串口的数据发送脚与数据接收脚连在一起,看接收的数据是不是发送的数据

     2:确认接线的正确性

     3:PC机与单片机双方协议一定,



     我建议你:一不一步来

     1:先发送一个字节数据,看对不对

     2:在发送一串数据,看对不对

     3:你发送,对方应答,你再接收,看对不对

     4:最后才做校验。

出0入0汤圆

发表于 2005-3-21 13:56:45 | 显示全部楼层
不错!

值得收藏!!!

出0入0汤圆

发表于 2005-5-7 16:54:34 | 显示全部楼层
"zhzzh18 小章"大侠,你的程序我认真读过了, 写的真是不错.



移植到我的程序中,基本调试通过.(在不发错的前提下,通讯正常)

我想还是把遇到的问题说一下, 大家讨论,共同进步.



我觉得前辈的程序, 某一个地方缺乏容错性,就是不够健壮.

如下:

<漏洞1>

flag=crc_recieve(num_recieve);

      if(flag==1)

      {

       data_act();

       flag_send=2;

       num_recieve=0;

      }

..................      



也就是说,只有CRC16通过,才能使flag=1, 才能执行内部的程序.

如果CRC16没有通过,那么num_recieve不会清零.

这样在随后的,crc0=cal_crc(recieve_data,num_recieve)语句中

那个发错而没有得到清楚的数据一直参与CRC检测运算, 并且cal_crc

永远不会返回1,不会通过.......

连锁反应:num_recieve得不到清零,recieve_data早晚要溢出.



结论:一个坏数据,会影响整个程序!!

ps:我知道大家会编写通信的上位机软件,通过软件做界面的通讯似乎不会

有数据错发, 但是我不敢确定没有异常状况造成数据错发,一旦有,全完了,等复位吧.



针对这个漏洞,我想应该加入判断机制,从接受到完整贞到处理回应一定是在有限时间

内完成的. 这样当num_recieve不为0时,判断它的变化情况, 一个例子,超过2秒还没有

变化, 应该就是数据错误造成的了. (我说的2秒当然不够精确,具体的时间需要大家验证)





<漏洞2>

这个.......不知道算不算漏洞, 因为大家的理解也许不一样.

如下:



crc0=cal_crc(recieve_data,num_recieve);

crc1=zhuhe(recieve_data[data-1],recieve_data[data-2]);

if(crc0=crc1) return 1;

else return 0;



大家看cal_crc的参数, 假如已经收到了一个完整的贞

假设num_recieve=8 这样 第7个和第8个数据分别是crc16_high,crc16_low

做为输入cal_crc计算却是8,整个贞全参与了cal_crc!!!

如果这样的话,crc0=crc1怎么可能相等呢??

应改成,crc0=cal_crc(recieve_data,num_recieve-2);

用前6个数据参与校验, 然后结果和第7,第8数据进行比较,如果相等,则通过.

程序应该是这样的吧......



其中对(num_recieve-2)要加入长度判断,防止在num_recieve<=2时执行语句.

实际上modbus协议的最小长度贞一般应该大于7个字节. 所以num_recieve>7再cal_crc( )吧





针对第2个漏洞,改正后,在硬件上调试通过.

如下: 串口助手输入: 05 03 00 01 00 01 4E D4  

      串口助手输出: 05 03 00 02 00 13 43 A4



就写这么多吧.






-----此内容被Asail于2005-05-07,20:42:47编辑过

出0入0汤圆

 楼主| 发表于 2005-5-13 16:07:57 | 显示全部楼层
to:Asail

    不好意思,我休息了一段时间,没上网,几天才看到,不好意思

    第一个问题非常好,一个人的思维总是有他的局限的,需要别人的指点,三人行必有我师焉。应该把num_recieve=0;  

放在if(num_stop>3) {  这后面。

   第二问题,也有道理

  谢谢   Asail

出0入0汤圆

发表于 2005-5-14 10:01:07 | 显示全部楼层
还有一个问题:

#pragma interrupt_handler usrt_resieve:12     

void usrt_resieve(void)                  

    {   

     recieve_data[num_recieve]=UDR;

     num_recieve+=1;

     num_stop=0;

     flag_send=1;

    }

中 是否应该加一句判断num_recieve超限的语句呢?要不然接收中断一直有效的话就要超出数组recieve_data[num_recieve]的能力了。如果数组定义了20个字节的大小,那么可以在接收中断的末尾加两句

if(recieve_data[num_recieve]>=20)

    num_recieve=0;

就可以了。

出0入0汤圆

发表于 2005-5-16 11:34:01 | 显示全部楼层
zhzzh18 小章前辈,不客气.

三人行必有我师焉.

你能把自己的modbus程序完全贴出来,首先你就是大家的老师.大家最应该感谢你.



楼上的igoal兄弟,我觉得你的修改方法好象欠妥.(只是个人看法)



num_recieve的清零应该建立在正确应答的基础上.

如果超出数组的容限,应该做出错误应答及时报告出来.



理由如下:

由于AVR的处理速度很快,我认为recieve_data只要做到存储下一贞完整的

通讯数据即可.收到完整贞后,即清零并回应.

而数据贞的大小是由modbus协议所决定的.20个应该够了.

超限似乎意味着--->异常.





我想经过大家的讨论,zhzzh18 小章前辈的程序会进一步完善,以后大家

可以直接拿来用多好.



期待更多的人参与讨论.



 

出0入0汤圆

 楼主| 发表于 2005-5-18 10:55:03 | 显示全部楼层
to: Asail

    叫我前辈,我不敢当,说不定我比你小都敢,我毕业也才两三年,愧对前辈二字呀,还是叫我小章,亲切点。

   igoal 说的有道理,但不是单单接受缓存清零,而该清零并关接受矢能,并发送报告。

   

   前面那段程序只是我初步调试成功时,后面随着产品销售,市场的信息回馈,改变了不少。但我想还是能做的更好的。一个产品不可能一次就可以做好的,而是慢慢完善的。

出0入0汤圆

发表于 2005-6-1 17:07:07 | 显示全部楼层
小章, 你一定比我大,嘿嘿



这句说到我心里去了: 一个产品不可能一次就可以做好的,而是慢慢完善的。

现在我最不敢说的话就是:我的产品没有BUG.(尤其是硬件方面的问题)



有时候觉得一个人单枪匹马的做项目,想考虑周全,有点难啊......

出0入0汤圆

发表于 2005-10-31 15:09:26 | 显示全部楼层
其实Modbus CRC16接收校验最好的方法是将整个接收到的串进行校验,其结果为零,表示CRC正确,非零则接收失败。不用进行分离计算比较!

出0入0汤圆

发表于 2005-11-12 15:45:03 | 显示全部楼层
再请问MODBUS-RTU格式,不带奇偶校验位,是否一定要加两个停止位?

出0入0汤圆

 楼主| 发表于 2005-11-14 09:41:39 | 显示全部楼层
不要吧,那只是一种格式而已

出0入0汤圆

发表于 2006-2-28 15:06:57 | 显示全部楼层
void data_act(void)

     {

     unsigned int add,i,n;

     send_data[0]=address;

     add=zhuhe(recieve_data[2],recieve_data[3]);

     add=add*2-2; /*&micro;&Oslash;&Ouml;·*/

     if(add>49) error(2);

     else

问一个RZ问题,这里add=add*2-2; 为什么要乘2减2呢???

出0入0汤圆

发表于 2006-2-28 23:12:44 | 显示全部楼层
能不能多加点注解呀!谢谢!

出0入0汤圆

发表于 2006-2-28 23:40:04 | 显示全部楼层
一点疑惑,我记得看过的MODBUS协议出错返回异常码和故障码,异常码=功能码+0x80,

void error(unsigned char data)

     {

     unsigned char add;

     num_send=5;

     send_data[1]=0x11; //异常码:是否应该返回receive_data[1]+0x80

     send_data[2]=data; //故障码

     add=cal_crc(send_data,3);

     fenli(add,3);

    }

出0入0汤圆

发表于 2006-3-21 00:41:48 | 显示全部楼层
to:zhzzh18 小章前辈

   你上边贴的modbus的程序很有用,但我好多地方看不懂,不知道从那先看,能不能给我加些注释。也不知道你能看到我的留言不。我正在做毕业设计,希望你能帮忙。也希望其他前辈们能够帮忙把那上面那个程序加些详细的注释,发给我。

我Email:hm79440@sina.com

出0入0汤圆

发表于 2006-4-3 16:42:15 | 显示全部楼层
to:zhzzh18



      你的程序只有接受部分,没有发送部分!我现在正在做MODBUS协议,遇到了问题:,没有办法向串口发送数据!希望前辈能提供发送数据的历程和相应的USRAT初始化程序!急急急急

出0入0汤圆

发表于 2006-5-19 10:48:45 | 显示全部楼层
请问,在MODBUS中从站的地址如何定义,请详解!迷惑中~~~~~~~~~

出0入0汤圆

 楼主| 发表于 2006-10-26 11:33:38 | 显示全部楼层
to;airboxboonly1

   void send_run(void) //这个不是发送吗?



to;bdlhj

   从机地址就是一个编号,是你定义的,你可以给个变量让它可设定,也可以在程序里固定死

出0入0汤圆

发表于 2006-11-27 09:28:19 | 显示全部楼层
楼主,小弟也正在做MODBUS 的工程,感谢你的无私奉献,能告诉我怎样判断一个帧是否结束在RTU中,是依靠3.5字节的判断吗。前后字节如果超过3.5个字节就认为是一个帧的结束吗

出0入0汤圆

发表于 2007-2-10 19:36:29 | 显示全部楼层
写得太棒了,真的不错。小弟近期正在弄这个。谢谢你提供了很好的东西。

出0入0汤圆

发表于 2007-3-21 09:29:17 | 显示全部楼层
发就发了,还把注释都去掉了……哎……!

出0入0汤圆

发表于 2007-3-21 10:32:29 | 显示全部楼层
楼主的程序已经很清晰,还要注释什么。

出0入0汤圆

发表于 2007-3-21 10:46:25 | 显示全部楼层
cal_crc函数里的crc^=0xa001;a001是从那里来的,为什么偏偏是它,请指教一下

出0入0汤圆

发表于 2007-3-21 14:05:13 | 显示全部楼层
终于明白了一点,LZ的程序还没有严格按照ModBus的协议做(不是说楼主不厉害哦)比如

33楼说的send_data[1]=0x11; //异常码:是否应该返回receive_data[1]+0x80

说的有道理,但是要确保receive_data[1]的高7位为0,

还有add=add*2-2;应该是自己定义的协议吧,

不知道理解的对不

出0入0汤圆

发表于 2007-3-21 14:20:42 | 显示全部楼层
还有data_act函数里面for(i=1;i<num_recieve;i++)

      send_data[1]=recieve_data[1];    这句不知道LZ是什么意思

是笔误还是,按LZ的意思应该是把收到的全部退还给host,请高手指点

出0入84汤圆

发表于 2007-3-21 14:24:26 | 显示全部楼层
没做完,超时没处理

出0入0汤圆

发表于 2007-5-16 13:27:45 | 显示全部楼层
非常感谢例程,看后受益颇多,也完成了自己的项目.谢谢!

出0入0汤圆

 楼主| 发表于 2007-5-16 15:14:16 | 显示全部楼层
精益求精,不断完善

出0入0汤圆

发表于 2007-5-16 15:58:10 | 显示全部楼层
恭喜了,也很感谢楼主.

出0入0汤圆

发表于 2007-7-20 11:58:49 | 显示全部楼层
小章,能不能当面请教点问题,我的qq83310093

有部分函数不知道什么功能,许多变量也看不明白什么含义

希望你看到贴子后加我聊聊

我以前用别人的51改过一个di的modbus的协议,avr不太熟悉.

希望给予帮助

谢谢

出0入0汤圆

发表于 2007-7-23 10:23:00 | 显示全部楼层
在MODBUS文件中,RTU中没有规定3.5个字节的精确定时,他仅仅是要求在祯头和祯尾空闲的时间是最少3.5字节的时间



这个还是不懂



感觉你在利用      if(num_stop>3)   实现的



你回答别人说是波特率设置的,波特率设置的部分没写



希望详细说明下

出0入0汤圆

发表于 2007-8-10 19:31:47 | 显示全部楼层
我想把这个程序直接拿来用 还要做哪些工作?加上以下语句就可以了吗?

还要另外编写一个定时器程序吗?

#include <avr/io.h>

#include<interrupt.h>

#include<math.h>



int num_send;           //这些是对程序中没有定义变量的定义

num_recieve=0;

int send_up=0;

int flag_send;

int num_stop;

int address=11;

int recieve_data[20];

int send_data[200];



UCR=0x18;              //UART RXD TXD使能

UBRR=71;              //9600bps 11.0592MHz

variable_data[50]={12,20,30,40,59,55,55,333,33,33666,77}

出0入0汤圆

发表于 2007-8-11 08:44:52 | 显示全部楼层
"send_data[1]=recieve_data[1]; "

这是MODBUS协议要求的,回传时,先是地址,再命令,再数据块.这是命令,即功能码.

出0入0汤圆

发表于 2007-11-26 15:41:03 | 显示全部楼层
请大家指教一下,那add=add*2-2 到底为什么这么计算啊~

出0入0汤圆

发表于 2007-12-14 14:52:00 | 显示全部楼层
支持一下,不过楼主你是怎样判断一个数据侦的开始的呢?
这部分程序应该很重要吧

出0入0汤圆

发表于 2008-11-25 10:18:42 | 显示全部楼层
记号~~

出0入0汤圆

发表于 2008-11-26 10:25:58 | 显示全部楼层
弱弱的问一句,记号~~什么意思,呵呵,原谅我是新手~~~

出0入0汤圆

发表于 2008-11-26 12:07:23 | 显示全部楼层
原来可以做记号~~~

出0入0汤圆

发表于 2008-12-11 10:24:17 | 显示全部楼层
很好!

出0入0汤圆

发表于 2008-12-25 22:44:22 | 显示全部楼层
也来做个记号

出0入0汤圆

发表于 2008-12-26 08:49:18 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-12-27 14:44:53 | 显示全部楼层
太好了,需要中

出0入0汤圆

发表于 2008-12-28 19:19:22 | 显示全部楼层
有电路图吗?发上来学习学习

出0入0汤圆

发表于 2009-1-15 16:58:19 | 显示全部楼层
MARK

出0入10汤圆

发表于 2009-1-15 17:51:49 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-3-7 09:29:48 | 显示全部楼层
有个问题啊:线圈是什么啊,看到很多人modbus程序中写了什么读取线圈。
我现在正在做这个 用一个单片机和触摸屏通信 但是很困或 不知道咋入手。难受
有做个这个的朋友吗?给点指导意见
我qq261529672

出0入0汤圆

发表于 2009-3-10 00:59:48 | 显示全部楼层
简直是太经典了,测试MODBUS,终于成功,谢谢前辈指导,不过返回值第4个好象有点不符合MODBUS协议规范,协议规定第3个是返回寄存器数,从第4个开始为数据值,

出0入0汤圆

发表于 2009-3-17 15:11:02 | 显示全部楼层
不错

出0入0汤圆

发表于 2009-3-18 18:54:27 | 显示全部楼层
可读性比较差,我贴一个网上比较流行的,并且可读性非常好的MODBUS源代码吧!
 (1)为了加快发送采用了:数据空中断
 (2)为了保证最后一个字节能够发送到上位机采用了:发送完成中断和

#include <iom128v.h>
#include <macros.h>
#define _USART1_H
#include "DMS2000.h"

const UCHAR auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};

const UCHAR auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};

BOOL volatile USART1_send_mark = FALSE;
UCHAR volatile USART1_sendPosi = 0;
SHORT volatile USART1_receCount = 0;
UCHAR volatile USART1_receTimeOut = 0;
UCHAR volatile USART1_checkoutError = 0;
UCHAR volatile USART1_sendCount = 0;
UCHAR USART1_ch_type = 0;
UCHAR USART1_set_number = 0;
UCHAR USART1_send_buffer[MSCOMM_BUFFER_LENGTH];
UCHAR USART1_mscomm_buffer[MSCOMM_BUFFER_LENGTH];

USHORT CRC16(UCHAR *puchMsg, USHORT usDataLen)
{
        UCHAR uchCRCHi = 0xFF;
        UCHAR uchCRCLo = 0xFF;
        ULONG uIndex;

        while (usDataLen--)
        {
                uIndex = uchCRCHi ^ *puchMsg++;
                uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
                uchCRCLo = auchCRCLo[uIndex];
        }
        return (uchCRCHi << 8 | uchCRCLo);
}


void USART1_Init(SHORT MSCOMM_baud)
{
        UCHAR me_STOP = (UCHAR)(MSCOMM_baud & 0x01);
        UCHAR me_UPM =  (UCHAR)(MSCOMM_baud & 0x06) >> 0x01;
        UCHAR me_Baud = (UCHAR)(MSCOMM_baud & 0x38) >> 0x03;

        UCSR1B = 0x00;
        UCSR1A = 0x00;
        UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);
        switch (me_STOP)
        {
                case 0:
                        UCSR1C |= (0 << USBS1);
                        break;
                case 1:
                        UCSR1C |= (1 << USBS1);
                        break;
        }
        switch (me_UPM)
        {
                 case 0:
                case 1:
                        UCSR1C |= ((0 << UPM11) | ( 0 << UPM10));
                        break;               
                case 2:
                        UCSR1C |= ((1 << UPM11) | ( 0 << UPM10));
                        break;
                case 3:
                        UCSR1C |= ((1 << UPM11) | ( 1 << UPM10));
                        break;
        }
        switch (me_Baud)
        {
                case 0:
                        UBRR1L = 0x3F;       
                        UBRR1H = 0x02;                                       
                        break;
                case 1:       
                        UBRR1L = 0x1F;       
                        UBRR1H = 0x01;
                        break;
                case 2:       
                        UBRR1L = 0x8F;
                        UBRR1H = 0x00;
                        break;
                case 3:       
                        UBRR1L = 0x47;
                        UBRR1H = 0x00;
                        break;
                case 4:
                        UBRR1L = 0x23;
                        UBRR1H = 0x00;
                        break;
                case 5:       
                        UBRR1L = 0x11;
                        UBRR1H = 0x00;
                        break;
                case 6:
                        UBRR1L = 0x0B;
                        UBRR1H = 0x00;
                        break;
                default:
                        UBRR1L = 0x05;
                        UBRR1H = 0x00;
                        break;
        }
        UCSR1B = (1 << RXEN1) | (1 << RXCIE1) | (1 << TXEN1);
}


BOOL USART1_CoilRegistersAddr(SHORT startAddr,SHORT registerAmount)
{
        if (registerAmount >= 1 && registerAmount <= 2000)
        {
                if (startAddr >= 0 && startAddr <= 4)
                {
                        if ((startAddr + registerAmount - 1) <= 4)
                                return (TRUE);
                }
        }
        return (FALSE);
}


void USART1_GetCoilVal(SHORT *tempData,SHORT tempAddr)
{
        switch (tempAddr)
        {
                case 0:
                        *tempData = 0;
                        break;
        }
}


void USART1_SetCoilVal(SHORT OnOff,SHORT tempAddr)
{
}


BOOL USART1_DiscreteRegistersAddr(SHORT startAddr,SHORT registerAmount)
{
        if (registerAmount >= 1 && registerAmount <= 2000)
        {
                if (startAddr >= 0 && startAddr <= 7)
                {
                        if ((startAddr + registerAmount - 1) <= 7)
                                return (TRUE);
                }
        }
        return (FALSE);
}


void USART1_GetDiscreteVal(SHORT *tempData,SHORT tempAddr)
{
        switch (tempAddr)
        {
                case 0:
                        *tempData = 0;
                        break;
        }
}


BOOL USART1_InputRegisterAddr(SHORT startAddr,SHORT registerAmount)
{
        if (registerAmount >= 1 && registerAmount <= 125)
        {
                if (startAddr >= 0 && startAddr <= 7)
                {
                        if ((startAddr + registerAmount - 1) <= 7)
                                return (TRUE);
                }
        }
        return (FALSE);
}


void USART1_GetInputRegisterVal(SHORT *tempData,SHORT tempAddr)
{       
        switch (tempAddr)
        {
                case 0:
                        *tempData = 0;
                        break;
        }
}


BOOL USART1_HoldingRegisterAddr(SHORT startAddr,SHORT registerAmount,UCHAR *set_number)
{
        if (registerAmount >= 1 && registerAmount <= 125)
        {
                if (startAddr >= 0 && startAddr < BUFFER_LENGTH)
                {
                        if ((startAddr + registerAmount - 1) < BUFFER_LENGTH)
                        {
                                *set_number = startAddr + 1;
                                return (TRUE);
                        }
                }
        }
        return (FALSE);
}



void USART1_GetHoldingRegisterVal(SHORT *tempData,UCHAR set_number)
{

}


BOOL USART1_SetHoldingRegisterVal(SHORT tempData,SHORT tempAddr)
{
        return (FALSE);
}


void USART1_Time_Proc(void)
{
        if (USART1_receTimeOut > 0)
        {
                USART1_receTimeOut--;
                if (USART1_receTimeOut == 0 && USART1_receCount > 0)
                {
                        USART1_receCount = 0;
                        USART1_checkoutError = 0;
                        if (!USART1_send_mark)
                                RS485_RECIVE();
                }
        }
}


void USART1_Begin_Send(void)
{
        RS485_SEND();
        NOP();                                                //        --------|       
        NOP();                                                //                        |
        NOP();                                                //                        |-----------等待总线释放
        NOP();                                                //                        |
        NOP();                                                //        --------|
        NOP();                                                //        --------|       
        NOP();                                                //                        |
        NOP();                                                //                        |-----------等待总线释放
        NOP();                                                //                        |
        NOP();                                                //        --------|
        USART1_send_mark = TRUE;
        USART1_sendPosi = 0;
        UCSR1B |= BIT(5);
}


void USART1_MODBUS_Error(UCHAR error_code)
{
        USHORT crcData;

        USART1_send_buffer[0] = USART1_mscomm_buffer[0];
        USART1_send_buffer[1] = USART1_mscomm_buffer[1] | 0x80;
        USART1_send_buffer[2] = error_code;
        crcData = CRC16(USART1_send_buffer,3);
        USART1_send_buffer[3] = crcData >> 8;
        USART1_send_buffer[4] = crcData & 0xff;
        USART1_sendCount = 5;
        USART1_Begin_Send();
}


void USART1_ReadCoilRegisters(void)
{
        UCHAR i,k;
        UCHAR byteCount;
        SHORT registerAmount;
        SHORT startAddr;
        SHORT tempAddr;
        SHORT tempData;
        USHORT crcData;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2] << 8) + (SHORT)USART1_mscomm_buffer[3];
        registerAmount = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_CoilRegistersAddr(startAddr,registerAmount))
        {
                tempAddr = startAddr;
                byteCount = registerAmount >> 0x03;
                if (registerAmount & 0x07)
                        byteCount++;
                for (k = 0 ; k < byteCount ; k++)
                {
                        USART1_send_buffer[k + 3] = 0;
                        for (i = 0 ; i < 8 ; i++)
                        {
                                USART1_GetCoilVal(&tempData,tempAddr++);
                                USART1_send_buffer[k + 3] |= (tempData << i);
                                if (tempAddr >= startAddr + registerAmount)
                                        break;
                        }
                }
                USART1_send_buffer[0] = USART1_mscomm_buffer[0];
                USART1_send_buffer[1] = USART1_mscomm_buffer[1];
                USART1_send_buffer[2] = byteCount;
                byteCount += 3;
                crcData = CRC16(USART1_send_buffer,byteCount);
                USART1_send_buffer[byteCount] = crcData >> 8;
                byteCount++;                                                       
                USART1_send_buffer[byteCount] = crcData & 0xff;
                USART1_sendCount = byteCount + 1;
                USART1_Begin_Send();
        }
        else
                USART1_MODBUS_Error(2);
}



void USART1_ReadDiscreteRegisters(void)
{
        UCHAR i,k;
        UCHAR byteCount;
        SHORT registerAmount;
        SHORT startAddr;
        SHORT tempAddr;
        SHORT tempData;
        USHORT crcData;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2] << 8) + (SHORT)USART1_mscomm_buffer[3];
        registerAmount = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_DiscreteRegistersAddr(startAddr,registerAmount))
        {
                tempAddr = startAddr;
                byteCount = registerAmount >> 0x03;
                if (registerAmount & 0x07)
                        byteCount++;
                for (k = 0 ; k < byteCount ; k++)
                {
                        USART1_send_buffer[k + 3] = 0;
                        for (i = 0 ; i < 8 ; i++)
                        {
                                USART1_GetDiscreteVal(&tempData,tempAddr++);
                                USART1_send_buffer[k + 3] |= (tempData << i);
                                if (tempAddr >= startAddr + registerAmount)
                                        break;
                        }
                }
                USART1_send_buffer[0] = USART1_mscomm_buffer[0];
                USART1_send_buffer[1] = USART1_mscomm_buffer[1];
                USART1_send_buffer[2] = byteCount;
                byteCount += 3;
                crcData = CRC16(USART1_send_buffer,byteCount);
                USART1_send_buffer[byteCount] = crcData >> 8;
                byteCount++;                                                       
                USART1_send_buffer[byteCount] = crcData & 0xff;
                USART1_sendCount = byteCount + 1;
                USART1_Begin_Send();
        }
        else
                USART1_MODBUS_Error(2);
}


void USART1_ReadHoldingRegisters(void)
{
        UCHAR i;
        SHORT startAddr;
        SHORT registerAmount;
        SHORT byteCount;
        SHORT tempData;       
        USHORT crcData;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3];
        registerAmount = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_HoldingRegisterAddr(startAddr,registerAmount,&USART1_set_number))
        {
                byteCount = registerAmount << 0x01;
                for (i = 0 ; i < registerAmount ; i++)
                {
                        USART1_GetHoldingRegisterVal(&tempData,USART1_set_number++);
                        USART1_send_buffer[2*i+3] = tempData >> 8;
                        USART1_send_buffer[2*i+4] = tempData & 0xff;
                }                       
                USART1_send_buffer[0] = USART1_mscomm_buffer[0];
                USART1_send_buffer[1] = USART1_mscomm_buffer[1];
                USART1_send_buffer[2] = byteCount;
                byteCount += 3;
                crcData = CRC16(USART1_send_buffer,byteCount);
                USART1_send_buffer[byteCount] = crcData >> 8;
                byteCount++;
                USART1_send_buffer[byteCount] = crcData & 0xff;
                USART1_sendCount = byteCount + 1;
                USART1_Begin_Send();
        }
        else
                USART1_MODBUS_Error(2);
}


void USART1_ReadInputRegisters(void)
{
        UCHAR i;
        SHORT startAddr;
        SHORT tempAddr;
        SHORT registerAmount;
        SHORT byteCount;
        SHORT tempData;       
        USHORT crcData;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3];
        registerAmount = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_InputRegisterAddr(startAddr,registerAmount))
        {
                tempAddr = startAddr;
                byteCount = registerAmount << 0x01;
                for (i = 0 ; i < registerAmount ; i++)
                {
                        USART1_GetInputRegisterVal(&tempData,tempAddr++);
                        USART1_send_buffer[2*i+3] = tempData >> 8;
                        USART1_send_buffer[2*i+4] = tempData & 0xff;
                }               
                USART1_send_buffer[0] = USART1_mscomm_buffer[0];
                USART1_send_buffer[1] = USART1_mscomm_buffer[1];
                USART1_send_buffer[2] = byteCount;
                byteCount += 3;
                crcData = CRC16(USART1_send_buffer,byteCount);
                USART1_send_buffer[byteCount] = crcData >> 8;
                byteCount++;
                USART1_send_buffer[byteCount] = crcData & 0xff;
                USART1_sendCount = byteCount + 1;
                USART1_Begin_Send();
        }
        else
                USART1_MODBUS_Error(2);
}


void USART1_ForceSingleCoil(void)
{
        UCHAR i;
        SHORT OnOff;
        SHORT startAddr;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2] << 8) + (SHORT)USART1_mscomm_buffer[3];
        if (USART1_CoilRegistersAddr(startAddr,1))
        {
                OnOff = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5];
                switch (OnOff)
                {
                        case 0x00:
                                USART1_SetCoilVal(0,startAddr);
                                break;
                        case 0xFF:
                                USART1_SetCoilVal(1,startAddr);
                                break;
                }
                if (USART1_mscomm_buffer[0] == module_addr)
                {
                        for (i = 0 ; i < 8 ; i++)
                                USART1_send_buffer = USART1_mscomm_buffer;
                        USART1_sendCount = 8;
                        USART1_Begin_Send();
                }
        }
        else if (USART1_mscomm_buffer[0] == module_addr)
                USART1_MODBUS_Error(2);
}


void USART1_PresetSingleHoldingRegister(void)
{
        UCHAR i;
        SHORT startAddr;
        SHORT tempData;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3];
        tempData = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_HoldingRegisterAddr(startAddr,1,&USART1_set_number))
        {
                if (USART1_mscomm_buffer[0] == module_addr)
                {
                        for (i = 0 ; i < 8 ; i++)
                                USART1_send_buffer = USART1_mscomm_buffer;
                        USART1_sendCount = 8;
                        USART1_Begin_Send();
                }
                if (USART1_SetHoldingRegisterVal(tempData,startAddr))
                {
                        QUEUE_In_CRC16();
                        EEPROM_START();
                }
        }
        else if (USART1_mscomm_buffer[0] == module_addr)
                USART1_MODBUS_Error(2);
}


void USART1_ForceMultipleCoil(void)
{
        UCHAR i,k;
        UCHAR byteCount;
        SHORT registerAmount;
        SHORT startAddr;
        SHORT tempAddr;
        SHORT OnOff;
        USHORT crcData;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3];
        registerAmount = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_CoilRegistersAddr(startAddr,registerAmount))
        {
                tempAddr = startAddr;
                byteCount = (SHORT)USART1_mscomm_buffer[6];
                if (USART1_mscomm_buffer[0] == module_addr)
                {
                        for (i = 0 ; i < 6 ; i++)
                                USART1_send_buffer = USART1_mscomm_buffer;
                        crcData = CRC16(USART1_send_buffer,6);
                        USART1_send_buffer[6] = crcData >> 8;
                        USART1_send_buffer[7] = crcData & 0xff;
                        USART1_sendCount = 8;
                        USART1_Begin_Send();
                }
                for (k = 0 ; k < byteCount ; k++)
                {
                        for (i = 0 ; i < 8 ; i++)
                        {
                                OnOff = USART1_mscomm_buffer[k+7] >> i;
                                if (OnOff & 0x01)
                                        USART1_SetCoilVal(1,tempAddr++);
                                else
                                        USART1_SetCoilVal(0,tempAddr++);
                                if (tempAddr >= startAddr + registerAmount)
                                        break;
                        }
                }
        }
        else if (USART1_mscomm_buffer[0] == module_addr)
                USART1_MODBUS_Error(2);
}


void USART1_PresetMultipleHoldingRegisters(void)
{
        UCHAR i;
        SHORT registerAmount;
        SHORT startAddr;
        SHORT tempData;
        USHORT crcData;
        BOOL Enable = FALSE;
       
        startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3];
        registerAmount = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];
        if (USART1_HoldingRegisterAddr(startAddr,registerAmount,&USART1_set_number))
        {
                if (USART1_mscomm_buffer[0] == module_addr)
                {
                        for (i = 0 ; i < 6 ; i++)
                                USART1_send_buffer = USART1_mscomm_buffer;
                        crcData = CRC16(USART1_send_buffer,6);
                        USART1_send_buffer[6] = crcData >> 8;
                        USART1_send_buffer[7] = crcData & 0xff;
                        USART1_sendCount = 8;
                        USART1_Begin_Send();
                }
                for (i = 0 ; i < registerAmount ; i++)
                {
                        tempData = (SHORT)(USART1_mscomm_buffer[i*2+7]<<8) + (SHORT)USART1_mscomm_buffer[i*2+8];
                        if (USART1_SetHoldingRegisterVal(tempData,startAddr++))
                                Enable = TRUE;
                }               
                if (Enable)
                {
                        QUEUE_In_CRC16();
                        EEPROM_START();
                }
        }
        else
                USART1_MODBUS_Error(2);
}


void USART1_Modbus_Analyze(void)
{
        SHORT tempData;
        USHORT crcData;
       
        if (USART1_receCount > 5)
        {
                switch (USART1_mscomm_buffer[1])
                {
                        case 1:
                                if (USART1_receCount >= 8)
                                {
                                        UCSR1B &= ~BIT(7);
                                        if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0)
                                        {
                                                crcData = CRC16(USART1_mscomm_buffer,6);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7])
                                                        USART1_ReadCoilRegisters();
                                        }
                                        USART1_receCount = 0;
                                        USART1_checkoutError = 0;
                                        UCSR1B |= BIT(7);
                                }
                                break;
                        case 2:
                                if (USART1_receCount >= 8)
                                {
                                        UCSR1B &= ~BIT(7);
                                        if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0)
                                        {
                                                crcData = CRC16(USART1_mscomm_buffer,6);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7])
                                                        USART1_ReadDiscreteRegisters();
                                        }
                                        USART1_receCount = 0;
                                        USART1_checkoutError = 0;
                                        UCSR1B |= BIT(7);
                                }
                                break;
                        case 3:
                                if (USART1_receCount >= 8)
                                {
                                        UCSR1B &= ~BIT(7);
                                        if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0)
                                        {
                                                crcData = CRC16(USART1_mscomm_buffer,6);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7])
                                                        USART1_ReadHoldingRegisters();
                                        }
                                        USART1_receCount = 0;
                                        USART1_checkoutError = 0;
                                        UCSR1B |= BIT(7);
                                }
                                break;
                        case 4:
                                if (USART1_receCount >= 8)
                                {
                                        UCSR1B &= ~BIT(7);
                                        if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0)
                                        {
                                                crcData = CRC16(USART1_mscomm_buffer,6);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7])
                                                        USART1_ReadInputRegisters();
                                        }
                                        USART1_receCount = 0;
                                        USART1_checkoutError = 0;
                                        UCSR1B |= BIT(7);
                                }
                                break;
                        case 5:
                                if (USART1_receCount >= 8)
                                {
                                        UCSR1B &= ~BIT(7);
                                        if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkoutError == 0)
                                        {
                                                crcData = CRC16(USART1_mscomm_buffer,6);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7])
                                                        USART1_ForceSingleCoil();
                                        }
                                        USART1_receCount = 0;
                                        USART1_checkoutError = 0;
                                        UCSR1B |= BIT(7);
                                }
                                break;
                        case 6:
                                if (USART1_receCount >= 8)
                                {
                                        UCSR1B &= ~BIT(7);
                                        if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkoutError == 0)
                                        {
                                                crcData = CRC16(USART1_mscomm_buffer,6);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7])
                                                        USART1_PresetSingleHoldingRegister();
                                        }
                                        USART1_receCount = 0;
                                        USART1_checkoutError = 0;       
                                        UCSR1B |= BIT(7);                                                                                       
                                }
                                break;
                        case 15:
                                if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkoutError == 0)
                                {
                                        tempData = (SHORT)(USART1_mscomm_buffer[6]);
                                        tempData += 9;
                                        if (USART1_receCount >= tempData && USART1_receCount < MSCOMM_BUFFER_LENGTH)
                                        {
                                                UCSR1B &= ~BIT(7);
                                                crcData = CRC16(USART1_mscomm_buffer,tempData - 2);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[tempData - 2] << 8) + (USHORT)USART1_mscomm_buffer[tempData - 1])
                                                        USART1_ForceMultipleCoil();
                                                USART1_receCount = 0;
                                                USART1_checkoutError = 0;
                                                UCSR1B |= BIT(7);
                                        }
                                }
                                break;
                        case 16:
                                if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkoutError == 0)
                                {
                                        tempData = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];
                                        tempData <<= 0x01;
                                        tempData += 9;
                                        if (USART1_receCount >= tempData && USART1_receCount < MSCOMM_BUFFER_LENGTH)
                                        {
                                                UCSR1B &= ~BIT(7);
                                                crcData = CRC16(USART1_mscomm_buffer,tempData - 2);
                                                if (crcData == (USHORT)(USART1_mscomm_buffer[tempData - 2] << 8) + (USHORT)USART1_mscomm_buffer[tempData - 1])
                                                        USART1_PresetMultipleHoldingRegisters();
                                                USART1_receCount = 0;
                                                USART1_checkoutError = 0;
                                                UCSR1B |= BIT(7);
                                        }
                                }
                                break;
                }
        }
}



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                        可靠地判断帧结束,防止通信停滞
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//          利用单独的软件定时器,来判断一帧接收报文结束,可以防止若报文接收不完整,该帧通信任务无法结束而影响下一帧的接收。
//由于一帧报文中字节与字节之间的时间间隔和帧与帧之间的时间间隔相比要小得多,因此每当接收一个新字节,就启动软件定时器
//开始计时,定时器的时间设定为帧与帧的最小时间间隔。波特率不同,该时间间隔也不同。
//          (1).若不到预定的时间内又接收到下一个字节,则说明一帧报文未结束,定时器重新计时;若定时器顺利计数到预定时间,就
//会触发相应的中断号,在该定时器中断子程序中设定帧结束标志字节,表明一帧报文接收完毕。
//          (2).当主程序内检测到一帧报文接收完毕后,会通过核查从方地址及循环冗余校验字节是否正确来判断该帧的有效性。若确定
//接收到的是一帧发送给已方的正确报文,则会根据报文内的功能码对该帧命令进行相应的处理,并准备发送帧。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma interrupt_handler USART1_RI_ISR:iv_USART1_RX
void USART1_RI_ISR(void)
{
        UCHAR ch;
        UCHAR status;

        status = UCSR1A;
        ch = UDR1;
        if (USART1_receCount < MSCOMM_BUFFER_LENGTH)
                USART1_mscomm_buffer[USART1_receCount++] = ch;
        else
                USART1_receCount = 0;
        if (status & 0x1c)
                USART1_checkoutError = 2;
        USART1_receTimeOut = 3;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//由于USART1通讯模式=RS232,因此发送完最后一个字节后,无需允许《发送完成中断》,只在在RS485时才会。因为需要确认最后
//一个字节发送出去后,才能将总线置为接收状态。否则,如果不使用《发送完成中断》,而在《数据空中断》中判断如果是发送
//最后一个字节时,立即置总线为接收状态,会导致最后一个字节无法回送给上位机,导致上位机接收不到最后一个字节。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma interrupt_handler USART1_UDRE_ISR:iv_USART1_UDRE
void USART1_UDRE_ISR(void)
{
        UDR1 = USART1_send_buffer[USART1_sendPosi++];
        if (USART1_sendPosi >= USART1_sendCount)
        {
                UCSR1B &= ~BIT(5);
                UCSR1B |= BIT(6);
        }
}


#pragma interrupt_handler USART1_TX_ISR:iv_USART1_TX
void USART1_TX_ISR(void)
{
        USART1_checkoutError = 0;
        USART1_receCount = 0;
        RS485_RECIVE();
        USART1_send_mark = FALSE;       
}

出0入0汤圆

发表于 2009-11-6 22:50:47 | 显示全部楼层
这里这么多的高手啊,有不有人能帮帮我~~~加我我Q475495645

出0入0汤圆

发表于 2009-11-15 21:20:31 | 显示全部楼层
,mark

出0入0汤圆

发表于 2009-11-16 16:29:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-11-16 22:52:40 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-2 09:33:50 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2009-12-2 09:38:48 | 显示全部楼层
MARK!

出0入0汤圆

发表于 2009-12-2 09:39:16 | 显示全部楼层
MARK!

出0入0汤圆

发表于 2009-12-2 10:19:01 | 显示全部楼层
好东西要mark

出0入0汤圆

发表于 2009-12-4 12:30:29 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-8 12:25:42 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-8 16:50:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-8 17:00:17 | 显示全部楼层
做个标记,顺便鼓励共享。

出0入0汤圆

发表于 2009-12-14 10:37:53 | 显示全部楼层
好东西

出0入0汤圆

发表于 2010-1-7 00:44:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-1-12 12:52:19 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-1-14 15:06:49 | 显示全部楼层
签名,以后慢慢看

出0入0汤圆

发表于 2010-1-29 12:50:24 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-1-30 09:16:30 | 显示全部楼层
请问有谁有完整的MODBUS的程序,麻烦请上传一份,我很需要,谢谢啦.

出0入0汤圆

发表于 2010-2-3 07:38:01 | 显示全部楼层

出0入0汤圆

发表于 2010-2-3 08:47:04 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-2-3 09:12:59 | 显示全部楼层
回复【楼主位】zhzzh18 小章
-----------------------------------------------------------------------

参考

出0入0汤圆

发表于 2010-2-4 13:57:14 | 显示全部楼层
xue xi

出0入0汤圆

发表于 2010-2-16 23:28:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-2-17 08:38:33 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-2-17 16:46:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-2-17 20:31:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-3 22:20:26 | 显示全部楼层
记号 M16的modbus

出0入0汤圆

发表于 2010-3-4 07:39:10 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-4 09:30:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-4 09:55:52 | 显示全部楼层
MODBUS 我当时做的时候用的方法很笨,这个看了比我的好很多

出0入0汤圆

发表于 2010-3-16 23:47:27 | 显示全部楼层
JIHAO
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-13 09:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表