STM32-modbus rtu 之从机程序
以前移植过freemodbus,这次是自己重新写,只实现保持寄存器的读写。
一、串口
这部分跟上一篇文章主机程序一样,DMA接收,直接发送。
二、错误反馈
/*
发送 错误反馈
*/
void mb_sentACK( u8 cm,u8 err)
{
u16 temp;
serialTXbuf_st.buf[0] = local_addr;
serialTXbuf_st.buf[1] = cm+0x80;
serialTXbuf_st.buf[2] = err;
temp=usMBCRC16( serialTXbuf_st.buf, 3 );
serialTXbuf_st.buf[3] = temp; //低
serialTXbuf_st.buf[4] = temp>>8;
}
错误码为命令F+0X80
三、对 F=0X03的反馈
/*
回应 读保持寄存器,命令0X03
*/
void mb_sentfor_readHoldingReg(const _mbdata_st mbd)
{
u16 temp;
u8 len = mbd.len*2+5;
serialTXbuf_st.buf[0] = local_addr;
serialTXbuf_st.buf[1] = 0x03;
serialTXbuf_st.buf[2] = mbd.len*2;
/*用户数据*/
for(temp=0;temp< (len-5)/2;temp++)
{
serialTXbuf_st.buf[3+temp*2] = mbd.buf[mbd.start+temp] >>8;
serialTXbuf_st.buf[4+temp*2] = mbd.buf[mbd.start+temp] ;
}
temp=usMBCRC16( serialTXbuf_st.buf, len-2 );
serialTXbuf_st.buf[len-2] = temp; //低
serialTXbuf_st.buf[len-1] = temp>>8;
myUSART_Sendarr( USART1, serialTXbuf_st.buf , len) ;
while( (USART1->SR&0X40)==0 ); //等待发送完成
}
四、对F=0X10的反馈
/*
回应 写保持寄存器,命令0X10
*/
void mb_sentfor_writeHoldingReg( _mbdata_st *pmb)
{
u16 temp;
u8 i;
temp=usMBCRC16( serialRXbuf_st.buf, 6 );
serialTXbuf_st.buf[0]=temp;
serialTXbuf_st.buf[1]=temp>>8;
//发送8字节反馈
myUSART_Sendarr( USART1, serialRXbuf_st.buf , 6) ; //前6字节
myUSART_Sendarr( USART1, serialTXbuf_st.buf , 2) ; //CRC
//修改保持寄存器
for(i=0;i< pmb->len ;i++)
{
pmb->buf [ pmb->start +i] = (u16)(serialRXbuf_st.buf[i*2+7]<<8 ) + serialRXbuf_st.buf[i*2+8];
}
while( (USART1->SR&0X40)==0 ){}; //等待发送完成
}
五、接收处理
/*帧检测*/
u8 frm_cheak(_serialbuf_st *rx, _mbfrm_st *pfrm)
{
u16 t,len;
if( rx->len < 4 ) return res_ERR1;
len=rx->len;
rx->len = 0 ;
pfrm->addr=rx->buf[0];
if( pfrm->addr != local_addr ) return res_ERR2;
pfrm->crc= (u16)(rx->buf[ len-1]<<8) + (rx->buf[ len-2]) ;
t= usMBCRC16( rx->buf, len-2 );
if( pfrm->crc != t ) return res_ERR3;
pfrm->cmd=rx->buf[1];
pfrm->start=( u16)(rx->buf[2] <<8 ) + rx->buf[3] ;
pfrm->rlen= ( u16)(rx->buf[4] <<8 ) + rx->buf[5] ;
if( pfrm->start > 0x7d) return res_ERR4;//超出地址
if( pfrm->rlen + pfrm->start > 0x7d) return res_ERR5;//超出长度
return res_OK;
}
//接收
u8 smb_recvHoldingReg( _mbdata_st *pmb )
{
u8 rel;
u16 temp ;
_mbfrm_st frm;
rel=frm_cheak( &serialRXbuf_st , &frm);
if( rel == res_OK)
{
mb_setMODRXorTX(0);//转为发送模式
//延时,给主机准备时间
delay_ms(10);
pmb->len = frm.rlen;
pmb->start = frm.start;
switch( frm.cmd)
{
case 0x03://读寄存器
mb_sentfor_readHoldingReg( *pmb );
break ;
case 0x10://写寄存器
mb_sentfor_writeHoldingReg( pmb);
break ;
}
mb_setMODRXorTX(0);//转为接收模式
}
else
if(rel == res_ERR3)
{
mb_sentACK( frm.cmd , rel) ;
}
return rel;
}
/*主循环调用*/
void mb_poll()
{
smb_recvHoldingReg( &HoldingReg_st ) ;
}
在主循环里调用mb_poll()函数即可。
六、验证
将STM32的串口与电脑连接,打开PC端软件MODBUS POLL ,设置好参数,OK,如下图
F=0X03
F=0X10