modbus有的人自己移植lib modbus,有人自己移植freemodbus ,日后博主会依次为大家做实验,去用上述两种方法实现,本次先分享自己写的modbus,话不多说上代码。
先是写出串口接收中断部分的代码。
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
extern uint8_t buff1[100]; //接收的数据包
extern int buff1stat; //接收数据包当前位
extern uint8_t RxByte; //中断接收暂存位置
extern int RE4851_flag; //接收结束标志符
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1); //中断启动使能标识
/* USER CODE BEGIN USART1_IRQn 1 */
buff1[buff1stat]=RxByte; //将暂存内容放入接收数据包
buff1stat++; //数据包位置后移1位
HAL_UART_Receive_IT(&huart1,&RxByte,1); //重新启动接收中断,等待下一位数据到来
if(buff1[1]==0x03) //判断功能码,功能码位0x30则为读寄存器,请求数据包应为8位
{
if(buff1stat==8) //数据到8位接收结束符置1,清除接收数据包当前位
{
buff1stat=0;
RE4851_flag=1;
}
}
if(buff1[1]==0x10) //判断功能码,功能码位0x30则为读寄存器,请求数据包应为9+Code Length位
{
if(buff1[6]!=0x00) //当Code Length位不为0 且数据到9+Code Length位时,接收结束符置1,清除接收数据包当前位
{
if(buff1stat==9+buff1[6])
{
buff1stat=0;
RE4851_flag=1;
}
}
}
/* USER CODE END USART1_IRQn 1 */
}
接下来将解析上述结束数据的每一位数据
void modbus_onebit(char a)
{
switch (e.stat)
{
case 0: // SLAVE ID
// slave_id=DeviceAddr;
// if (a == slave_id)
e.stat = 1;
break;
case 1:
if(a==0x03)
e.stat = 2;
if(a==0x10)
e.stat=12;
break;
case 2:
addr[cnt] = a;
cnt++;
e.stat = 3;
break;
case 3:
addr[cnt] = a;
cnt++;
if (cnt > 3)
{
cnt = 0;
startaddr= addr[1];
bufflen= addr[3];
e.stat = 4;
}
break;
case 4:
e.stat = 5;
break;
case 5:
if(n==bufflen)
e.stat = 100;
break;
case 6:
e.stat = 6;
break;
case 7:
e.stat = -1;
break;
case 8:
e.stat = 100;
break;
/********D′è??à????′??÷********/
case 12:
addr[cnt]=a;
cnt++;
if(cnt>4)
{
cnt=0;
startaddr= addr[1];
bufflen= addr[4];
e.stat = 13; //×a′?íê±?
}
break;
case 13:
if(n==bufflen)
e.stat = 100;
break;
}
}
接下来分析接收到的功能码
void ReadHoldRegister(uint8_t buffIN[100],uint8_t buffOUT[100])
{
int i,j;
e.stat = 0;
for (i = 0; i < 10; i++)
{
modbus_onebit(buffIN[i]);
if (e.stat == 100)
{
}
if (e.stat == 0)
{
}
if (e.stat == 1)
{
buffOUT[i]= buffIN[i];
}
if (e.stat == -1)
{
}
if (e.stat == 2)
{
buffOUT[i] = buffIN[i];
}
if (e.stat == 3)
{
}
if (e.stat == 4)
{
buffOUT[2] = bufflen*2;
}
if (e.stat == 5)
{
for (j = 0,n=0; j < bufflen * 2; j= j + 2,n++)
{
buffOUT[3 + j] = (DB_R[n+startaddr] >> 8) & 0x00FF;
buffOUT[3 + j+1] = DB_R[n+startaddr]& 0x00FF;
}
}
if (e.stat == 12)
{
buffOUT[i] = buffIN[i];
}
if (e.stat == 13)
{
for (j = 0,n=0; j < bufflen; j= j + 2,n++)
{
DB_R[n+startaddr]=(buffIN[7 + j] << 8)+buffIN[7 + j + 1];
}
}
}
if(buffIN[1]==0x03)
CrcCheck(buffOUT,3+bufflen*2);
else if(buffIN[1]==0x10)
CrcCheck(buffOUT,6);
}
上述CRC本次采用的是计算法而非查表法。
void CrcCheck(unsigned char *buf,int len)
{
unsigned short crc = 0xFFFF;
unsigned char i,j=0;
while(j < len)
{
crc ^= buf[j];
for(i = 0; i < 8; i++)
{
if(crc & 0x01)
{
crc >>= 1;
crc ^= 0xA001;
}
else
crc >>= 1;
}
j++;
}
buf[j] = crc % 0x100;
buf[j+1]=crc / 0x100;
}
主函数的定义,以及使用方法如下:
主函数初始化内容
DB_R[0] = 0x0102;
DB_R[1] = 0x0204;
DB_R[2] = 0x0306;
DB_R[3] = 0x0408;
int count;
主循环填写内容:
if(RE4851_flag==1)
{ RE4851_flag=0;
DB_R[0] = 待检测数据;
DB_R[1] = 待检测数据;
DB_R[2] = 待检测数据;
DB_R[3] = 待检测数据;
ReadHoldRegister(buff1,buff2); //上面写的函数,不懂的滑上去看
if((buff1[1]==0x03)&&(buff1[0]==slave_id)) //判断功能码,0x03为读寄
存器,发送5+2*length位,不懂为什么的的滑回前面去看
{
buff1[1]=0;buff1[0]=0;
RS485_ControlPin_High;
for(count=0;count<5+buff1[5]*2;count++)
HAL_UART_Transmit(&huart1, &buff2[count],1,0xFFFF);
RS485_ControlPin_Low;
}
}
串口接受之前定义的内容:
u8 slave_id=1; // 从机地址,可设 ,一般存储在flash中
uint16_t DB_R[100];
MB e;
int cnt,n,bufflen,startaddr;
uint8_t addr[100];
串口接收.h文件中定义内容:
extern u8 slave_id;
typedef struct
{
int stat; //Modbus解析位置定义
}MB;
void CrcCheck(unsigned char *buf,int len);
void ReadHoldRegister(unsigned char *buff1,unsigned char *buff2);
void modbus_onebit(char a);
void ReadHoldRegister(uint8_t buffIN[100],uint8_t buffOUT[100]);
以上内容即可解析出modbus,待检测数据放入要读的数据,即可通过主机读取通讯的数据。
以上为一版modbus协议,但是上述在线上挂载好多设备时不安全啊。没有定时器去处理接收时间的判断,而接下来这个接收加发送就灰常nB,只需要处理中断就可以,以下为C代码。
#include "main.h"
#include "Uart2.h"
UART_HandleTypeDef huart2;
u8 UART2_ReceiveBuffer[20];
u8 UART2_WriteBuffer[20];
u8 UART2_ReceiveState;
u16 UART2_CRC_Result;
u8 Uart2_res[10];
u8 UART2_ReceiveDataLength;
u8 Usart2_Receivebiginflag;
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
UART2_ReceiveDataLength = 0;
Usart2_Receivebiginflag = false;
PC_RS485_ControlPin_Low ;
HAL_UART_Receive_IT(&huart2, (uint8_t *)Uart2_res, 1);
}
void Uart2_Send_Byte(u8 SendData)
{
HAL_UART_Transmit(&huart2, (uint8_t *)&SendData,1,200);
}
void Uart2_Send_DuoByte(u8 *SendDataBuffer, u8 SendDataLength)
{
u8 i;
PC_RS485_ControlPin_High ;
for(i=0; i<SendDataLength;i++)
{
Uart2_Send_Byte(SendDataBuffer[i]);
}
PC_RS485_ControlPin_Low;
}
u8 uart_chongfu=0,jieshou_zuhoubit=0;
u8 Uart1JieShouDataTimerRunFlag= 0;
void USART2_IRQHandler(void)
{
u8 res;
u16 Read_Start_Address;
u16 Read_Register_Length;
HAL_UART_IRQHandler(&huart2);
HAL_UART_Receive_IT(&huart2, (u8 *)Uart2_res, 1);
res = Uart2_res[0];
// //接收地址
//if((((unsigned char)STM32valuet.Usart2_address == res)||(0x01 == res)||(0x02 == res))&&( 0 == UART2_ReceiveDataLength)) //兼容老款何佳 BEE-M-300/500程序
if((((unsigned char)STM32valuet.Usart2_address == res))&&( 0 == UART2_ReceiveDataLength)) //兼容老款何佳 BEE-M-300/500程序
{
Usart2_Receivebiginflag = True;
Uart1JieShouDataTimerRunFlag = true;
}
if(True == Usart2_Receivebiginflag)
{
UART2_ReceiveBuffer[UART2_ReceiveDataLength] = res;
if ((uart_chongfu==1)&&((UART2_ReceiveBuffer[UART2_ReceiveDataLength]==4)||(UART2_ReceiveBuffer[UART2_ReceiveDataLength]==3)))
{
UART2_ReceiveDataLength=1;uart_chongfu=0;
UART2_ReceiveBuffer[UART2_ReceiveDataLength] = res;
}
if(UART2_ReceiveBuffer[UART2_ReceiveDataLength]==STM32valuet.Usart2_address)
uart_chongfu=1;
else
uart_chongfu=0;
UART2_ReceiveDataLength++;
if(2 == UART2_ReceiveDataLength)
{
if((0x03 == UART2_ReceiveBuffer[1])||(0x06 == UART2_ReceiveBuffer[1])||(0x04 == UART2_ReceiveBuffer[1])) //兼容04命令
;
else
{
UART2_ReceiveDataLength = 0;
Usart2_Receivebiginflag = false;
Uart1JieShouDataTimerRunFlag = false;
}
}
if(UART2_ReceiveBuffer[7]==STM32valuet.Usart2_address)
jieshou_zuhoubit=1;
else
jieshou_zuhoubit=0;
if(8 <= UART2_ReceiveDataLength) // 数据长度为8
{
UART2_CRC_Result = crc16(UART2_ReceiveBuffer, 6);
if((UART2_ReceiveBuffer[6] == (u8)(UART2_CRC_Result/256))&&(UART2_ReceiveBuffer[7] == (u8)(UART2_CRC_Result%256))) // 判断数据传输校验
{
UART2_ReceiveDataLength=0;
Uart1JieShouDataTimerRunFlag = false;
Read_Start_Address=((u16)UART2_ReceiveBuffer[2]*256 + (u16)UART2_ReceiveBuffer[3]);
Read_Register_Length = ((u16)UART2_ReceiveBuffer[4]*256 + (u16)UART2_ReceiveBuffer[5]);
if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x02)&&(Read_Register_Length==2)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
{
UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
UART2_WriteBuffer[2] = Read_Register_Length*2;
UART2_WriteBuffer[3] = (u8)((u16)STM32valuet.Display_O2/256);
UART2_WriteBuffer[4] = (u8)((u16)STM32valuet.Display_O2%256);
UART2_WriteBuffer[5] = (u8)((u16)Usart1.Send_CO/256);
UART2_WriteBuffer[6] = (u8)((u16)Usart1.Send_CO%256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
}
// STM32valuet.Flash_Data_Buff[2] = Usart1.Send_O2;
// STM32valuet.Flash_Data_Buff[3] = Usart1.Send_CO;
if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x02)&&(Read_Register_Length==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
{
UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
UART2_WriteBuffer[2] = Read_Register_Length*2;
UART2_WriteBuffer[3] = (u8)((u16)STM32valuet.Display_O2/256);
UART2_WriteBuffer[4] = (u8)((u16)STM32valuet.Display_O2%256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
}
if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x03)&&(Read_Register_Length==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
{
UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
UART2_WriteBuffer[2] = Read_Register_Length*2;
UART2_WriteBuffer[3] = (u8)((u16)Usart1.Send_CO/256);
UART2_WriteBuffer[4] = (u8)((u16)Usart1.Send_CO%256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
}
if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x04)&&(Read_Register_Length==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
{
UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
UART2_WriteBuffer[2] = Read_Register_Length*2;
UART2_WriteBuffer[3] = (u8)((u16)HIT10_Temperature/256);
UART2_WriteBuffer[4] = (u8)((u16)HIT10_Temperature%256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
}
if((0x04 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
{
UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
UART2_WriteBuffer[2] =Read_Register_Length*2;
if(0x01 == UART2_ReceiveBuffer[0])
{
UART2_WriteBuffer[3] = (u8)((u16)STM32valuet.Display_O2/256);
UART2_WriteBuffer[4] = (u8)((u16)STM32valuet.Display_O2%256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
}
else if(0x02 == UART2_ReceiveBuffer[0])
{
UART2_WriteBuffer[3] = (u8)((u16)Usart1.Send_CO/256);
UART2_WriteBuffer[4] = (u8)((u16)Usart1.Send_CO%256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] = (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
}
}
if(0x06 == UART2_ReceiveBuffer[1]) //代表写寄存器
{
if(1006 == UART2_ReceiveBuffer[2]*256 + UART2_ReceiveBuffer[3])
{
STM32valuet.Usart2_address = (u16)UART2_ReceiveBuffer[4]*256 + (u16)UART2_ReceiveBuffer[5];
Uart2_Send_DuoByte(UART2_ReceiveBuffer,8);
Writedatatoeeprom();
}
}
} UART2_ReceiveDataLength=jieshou_zuhoubit;
if(UART2_ReceiveDataLength==0)Usart2_Receivebiginflag = false;
}
}
}
以上为手搓modbus的另一种方式,目前测试过10台设备挂机都可以正常测试。已经算是手搓modbus协议的完美作品了。 处理了其他从机的干扰。