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