单片机modbus下位机程序怎么编写

单片机modbus下位机程序怎么编写,第1张

这个是MODBUS控制电磁阀的一个程序。其中还有AD采集的部分。对CRC校验用查表的方法。至于怎样把校验的结果拆分成高低位字节,再发送,看程序吧。

#include"reg51.h"

#include"intrins.h"

#define uchar unsigned char

#define uint unsigned int

#define Pressure P0

////////////////

/////////////////////

uchar addr

uchar  Pressure_updata

uchar  Pressure_lowdata

/////////////////

sbit    Dcf_open=P1^0//电磁阀开启

sbit    Dcf_close=P1^1//电磁阀关闭

bit   dr

bit   Dcf_state=1

bit   Halfsecond=0

bit   Onesecond=0

//////////////////////////////

sbit   Mydress_set=P2^5

sbit    P_uplimite =P2^6

sbit   P_lowlimite=P2^7

sbit   Stor=P3^2

sbit    myint=P3^3

sbit   ADC_wr     =P3^6

sbit   ADC_rd     =P3^7

sbit   xuantong   =P1^7

sbit   addrset=P1^2

sbit   upset=P1^3

sbit   lowset=P1^4

/////////////////////////

uchar code   Myreturnstateopen[3] ={0x01,0x01,0x00}

uchar code   Myreturnstateclose[3]={0x01,0x01,0x01}

uchar code   Myreturnopen[3] ={0x01,0x01,0x10}

uchar code   Myreturnclose[3]={0x01,0x01,0x20}

uchar receive_count=0

uchar mysend[6],aq[8]

uchar Adc_value

unsigned  long   Mycount=0

uchar jishi=0 //定时一秒计数

uint crc=0,myaw=0

uint crc16(unsigned char *puchMsg, unsigned int usDataLen)

bit  yifasong=0

void Beginsend( uchar Me )

bit check_modbus()

void Open_dcf()

void Close_dcf()

void timer0()

void uart_init(void)

void delay(uint z)

void Read_adc()

void  Tosend()

/////////

/*************延时*****************/

void delay(uint z)

{

  uchar y

while(z--)

for(y=113y>0y--)

}

/************串口初始化*****************/

void uart_init(void)   interrupt 4    using 1

{

if(RI)

           {  

                  aq[receive_count]=SBUF

    RI=0

receive_count++

if(0==receive_count%8)

{

yifasong=0

receive_count=0

}

                       

                    RI=0

              }

}

/**************定时器0初始化**************/

void timer0()  interrupt 1    using 1

{

 TH0=0x4b

TL0=0x63

jishi++

if (0==jishi%10) {

 Halfsecond=1

aq[0]=0aq[1]=0aq[2]=0aq[3]=0aq[4]=0aq[5]=0aq[6]=0aq[7]=0receive_count=0

}

   

}  

void Read_adc()

{  

  ADC_rd=1

   ADC_wr=1

   _nop_()

    _nop_()

   _nop_()

   _nop_()

   myint=1

   P0=0xff       

ADC_wr=0

    _nop_()

   _nop_()

   _nop_()

   _nop_()

       ADC_wr=1                       

while( myint==1)   

      ADC_rd=0                   

     _nop_()

     _nop_()

     _nop_()

    _nop_()

    _nop_()

   

    Adc_value=P0                  //读出的数据赋与addate

    ADC_rd=1

}

void Open_dcf()

{

 Dcf_open=0   delay(1200)Dcf_open=1 Dcf_state=1

}

void Close_dcf()

{

 Dcf_close=0  delay(1200)Dcf_close=1Dcf_state=0

}

void Read_Pressure()  

{  

   Read_adc()  

if (Dcf_state)

   {

     if((Adc_value<Pressure_lowdata)|| (Adc_value>Pressure_updata))

         {

              delay(1200)

                    if((Adc_value<Pressure_lowdata)|| (Adc_value>Pressure_updata)) {   Close_dcf()}

           }

      else

          {                 }

    }

 

else

  {

    if((Adc_value>Pressure_lowdata)&&(Adc_value<Pressure_updata))

       {        delay(1200)

                    if((Adc_value>Pressure_lowdata)&&(Adc_value<Pressure_updata))   {  Open_dcf()}

  }

  else        

   }

}

void initialize()

{

TMOD=0x20

SCON=0x50//串口通讯方式1

TH1=0xfd//波特率9600

TL1=0xfd

TH0=0x4b

TL0=0x63

TI=0//发送中断标志位清零

RI=0//接收中断标志位清零

Mydress_set=1P_lowlimite=1P_uplimite=1xuantong=1

Mydress_set=0delay(20)addrset=1delay(20)addr=P0

delay(20)

addrset=0Mydress_set=1delay(200)P0=0xff

P_lowlimite=0delay(20)lowset=1delay(20)Pressure_lowdata=P0

delay(20)

lowset=0P_lowlimite=1P0=0xff           

 P_uplimite=0delay(20)upset=1Pressure_updata=P0delay(20)upset=0P_uplimite=1P0=0xff

 xuantong=0

}

void main(void)

{

IE=0x92

   TR0=1TR1=1

        // WDTRST=0x1E

           // WDTRST=0xE1//初始化看门狗

   

       initialize()

 

       Stor=0

for()  { // WDTRST=0x1E

            //WDTRST=0xE1//喂狗指令

 if (Halfsecond==1)  {

                    Halfsecond=0

                     Read_Pressure()

      }

      //够一秒开始转换

if(receive_count==0&&(yifasong==0))

              {   Stor=0 

  dr= check_modbus()

                       if (dr&&addr==aq[0])

                         {                     if(aq[1]==0x05)

                                                   

                                                            switch ( aq[3])

                                                              {

                                           case  0x00     :    

                                                               

                 if(!Dcf_state)      Open_dcf()

              Beginsend(0)           break

                                                             case  0x01     :                                                                

                                                             

                                                            if(Dcf_state)      Close_dcf()

                                                     

                                                          Beginsend(1)         

                                                               break

                             

                                                                 default  :            

                                          }

             

                                    else if(aq[1]==0x01)

                                                   

                      {

                 if(Dcf_state)

{   Beginsend(2)

                                                                           }

                        else  

                 

                                                                      {   Beginsend(3) 

                                                                            }

                          }

                                  else

                }

                     else

           

               }

       }    

}

void Beginsend(uchar Me )

{

uchar i

ES=0Stor=1

TI=0

mysend[0]=addr

switch(Me)

{

case 0:

       { for(i=1i<4i++)

              {

 

              mysend[i] =  Myreturnopen[i-1]

               }

i=0

}break

case 1:

{for(i=1i<4i++)

              {

 

              mysend[i] =   Myreturnclose[i-1]

               } i=0}break

case 2:

     {   for(i=1i<4i++)

              {

 

              mysend[i] = Myreturnstateopen[i-1]

               } i=0}break

case 3:

{for(i=1i<4i++)

              {

 

               mysend[i] =  Myreturnstateclose[i-1]

}i=0}break

default : }

myaw=crc16(mysend,4)

mysend[4] =myaw&0x00ff

mysend[5] =(myaw>>8)&0x00ff

for(i=0i<6i++)

      {

   

    SBUF=mysend[i]

   

while(TI!=1)

TI=0

       }

Stor=0

ES=1

yifasong=1

}

bit check_modbus()

{

uchar m,n  

 

crc=crc16(aq,6)

 m=crcn=crc>>8&0x00ff

if(aq[6]==m&&aq[7]==n)

return    1

else

return    0

}

uint crc16(uchar *puchMsg, uint usDataLen)

{

uchar uchCRCHi = 0xFF //* 高CRC字节初始化

uchar uchCRCLo = 0xFF //* 低CRC 字节初始化

unsigned long uIndex // CRC循环中的索引

while (usDataLen--) // 传输消息缓冲区

{

uIndex = uchCRCHi ^ *puchMsg++ // 计算CRC

uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex]

uchCRCLo = auchCRCLo[uIndex]

}

return (uchCRCHi  | uchCRCLo<<8)

}

/***********************CRC校验*************************/

// CRC 高位字节值表

上位机组态软件的IO驱动若提供modbus协议,则其变量地址直接使用modbus协议的地址就可以了。modbus协议的地址格式主要是四种类型:0xxxx(线圈,DO类型)、1xxxx(触点,DI类型)、3xxxx(输入寄存器,AI类型)和4xxxx(保持寄存器,AO类型)。

下位机ARM stm32若程序是自己开发,需要程序中定义上述modbus协议的4种地址的数据区,再把4种地址数据区与ARM stm32的IO口建立映射关系,如:

DI口数据===(MOV、COPY指令)===>1xxxx数据区,

AI口数据===(MOV、COPY指令)===>3xxxx数据区,

0xxxx数据区===(MOV、COPY指令)===>DO口,

4xxxx数据区===(MOV、COPY指令)===>AO口。

这4种地址的数据,需在主程序中实时、动态地刷新。

当然,需要在通信子程序中实现modbus协议的事务 *** 作,即接收到modbus的数据帧后,根据功能码及地址,相应地处理modbus协议的4种地址区的数据。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12204336.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存