最近做了个实验,用STM32做从机接收主机发送过来的数据包(也是基于mobus协议),而后从机将一些数据发送给主机。
首先呢还是介绍下modbus协议。其实modbus协议你不需要了解太多。既然是要使用,那么你只需要明白一点,modbus协议就是在你要发送的数据的基础上,在数据前面加上一个帧头,数据后面加一个帧尾。嗯,是不是还是有点迷?举个例子吧。
所以主机会发过来一帧数据:01 03 00 6B 00 03 17 74(这个01是我假设主机的地址,这个域名的作用就是用来判断是否是主机发送过来的数据。因为通信过程可能因为各种原因而导致主机发送过来的数据异常,故而我们从机接收到数据之后会先对数据进行分析主机发过来的数据是否正常,正常从机再发送数据过去,异常则不对这帧数据进行响应即从机不发数据。17 74是根据01 03 00 6B 00 03计算出来的CRC校验值。)
当从机接收到这串数据,并且判断数据正常则发送一帧数据到主机:02 03 06 02 2B 00 00 00 64 11 8A(同样的02是我假设的这个从机的地址,需注意的是咱们假设自己的从机地址不要与主机的地址相同。)在这帧数据中帧头就是02 03 06,11 8A是根据02 03 06 02 2B 00 00 00 64计算出来的CRC 校验值也是帧尾。
(提供一个在线计算CRC校验值的网站:http://www.ip33.com/crc.html)
那么问题来了。。。程序中我们怎么去计算CRC校验值呢???这个嘛 ,下方我会贴上整个实验的例程,其中CRC.c中h函数unsigned int GetCRC16(unsigned char *ptr, unsigned char len)我们只需要调用这个函数就可以算出CRC校验值了。有兴趣的也可以去额外了解下CRC校验具体是怎么实现的。
整个实验例程如下:
main.c:
#include "stm32f10x.h"
#include "bsp_485.h"
#include "bsp_led.h"
#include "crc16.h"
/*描述:硬件:RS485接口 协议:Modbus RTU
*功能:采用DMA方式发送数据,中断方式接收数据。
*注: 接收到指令之后,判断是否是相应指令而进行DMA数据发送。
*/
/*DMA:开启DMA,DMA发送完一帧数据后产生发送完成中断,
* 在DMA发送完成中断中,开启USART接收中断(字节)
* 在USART接收中断中保存接收到的数据。
*注: 本程序额外开启了USART空闲中断,在空闲中断中将
* USART接收中断中接收到的数据发送至串口调试助手显示
* 并开启DMA请求
*/
extern uint8_t u3Temp;
extern uint16_t uart3_p;
extern uint16_t ReceivedUsart3Flag,tempU3,uart3_RXbuff[];
extern uint8_t SendU3Buff[SENDU3BUFF_SIZE];
uint16_t len,iU3;
uint8_t u2_Temp;
char *pbuf;
void SendUsart3Buff(void);
void SendU3DatatoDebug(void);
void load_U3_SendBuff(void);
int main(void)
{
load_U3_SendBuff();
LED_GPIO_Config();
USART3_Config();
while(1)
{
}
}
/*Description:调试通信程序专用,用于将接收到的数据再发送到串口调试助手显示*/
void SendU3DatatoDebug()
{
for(uart3_p= 1; uart3_p <= u3Temp; uart3_p++)
{
Usart_SendByte(USART3,uart3_RXbuff[uart3_p]);
}
uart3_p = 1;
RS485_RX_EN();
ReceivedUsart3Flag = 0;
}
/*将USART3需要发送的数据存放在SendU3Buff[]中*/
void load_U3_SendBuff()
{
uint16_t CRCtemp;
SendU3Buff[0]=0x01;//ID
SendU3Buff[1]=0x03;//功能码
SendU3Buff[2]=0x0C;//内容数据字节数
/*填充将要发送的数据(两个字节为一个寄存器的值)*/
SendU3Buff[3]=0x00; //数据1(slave地址0,网站上地址40001)
SendU3Buff[4]=0x64;
SendU3Buff[5]=0x00;//数据2(slave地址1,网站上地址40002)
SendU3Buff[6]=0x96;
SendU3Buff[7]=0x00;//数据3
SendU3Buff[8]=0xC8;
SendU3Buff[9]=0x00; //4
SendU3Buff[10]=0xFA;
SendU3Buff[11]=0x01;//5页面未添加该数据
SendU3Buff[12]=0x2B;
SendU3Buff[13]=0x01;//6
SendU3Buff[14]=0x