Modbus是一种比较常用的工业通讯协议(协议也可以称为约定),它对传输介质的要求并不高,基本上可用实现通讯链接就可以(rs232、rs485、网线等电器通讯均可),这可能也是它比较常用的原因之一,重要的是这个协议它是免费的而且也是一个普遍认可的协议,所有学习一下还是有必要的。
学习modbus(以下简称MB)之前需要搞清楚一个概念“协议”,协议到底是什么呢?
说到协议一般来说大家应该都听说过TCP/IP这个网络协议,tcp/ip是一个大型网络协议相对来说是比较复杂的,但是并不代表协议就是一个复杂的东西。
协议其实就是一种约定。
例如:甲方跟乙方约定好,当乙方接到甲方的信息aa时,乙方给甲方寄出一个东西并回复一个信息bb,这就是协议的模型,协议就是双方都能按照规定来进行交流和执行。
下面以单片机通讯做一简单的协议
协议:1、规定数据格式: 帧头-0x3e 地址 指令 数据 帧尾-0x3f,这个是通讯双方的通讯数据包格式。
2、规定功能指令:A–控制电机正转 B–控制电机反转 C–电机停止转动。
当单片机接收到数据:0x3e 0x01 A 03 0x3f 根据以上规定的协议,接收到这帧数据之后单片机将会执行正转3圈的动作,这就是一个简单的协议。
对协议有一个初步的理解之后,再看看modbus协议。
一、Modbus简介
Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。
此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
ModBus是一种主从问询式的通讯方式,由主机(或者client)发起询问从机接收到问询之后响应主机服务。
二、传输方式与数据帧格式
MB有两种传输模式:ASCII或RTU
ASCII消息帧格式
使用ASCII模式,消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)。
RTU消息帧格式
这两个传输模式的区别:
1、数据帧的格式不同,ASCII模式下有帧头、帧尾而RTU模式下是没有帧头和帧尾的,RTU模式下数据帧的第一个数据就是地址。
2、数据校验的方式不一样,ASCII模式使用的是LRC校验 ,RTU使用的是crc校验
3、数据的表示方式不同,ASCII使用一个ASCII字符表示一位十六进制数,RTU模式下是用4bit二进制表示一位16进制数,因此RTU模式的数据帧长度是要小于ASCII模式的,所有RTU模式的传输速率大于ASCII模式。
以上是关于modbus协议的一个简介,详细介绍网上很多这里就不多讲了,具体内容了解可以看Modbus协议中文版(GB),和Modbus协议详解这个博客。
modbu功能处理c文件
#include "modbus.h"
#include "usart.h"
#include "modbus_timer.h"
#include "modbus_crc.h"
MODBUS modbus;
u16 DataReg[30] ={0}; //¶¨Òå30¸ö16λµÄ¼Ä´æÆ÷
u8 OX[20]; //¶¨ÒåÊä³öÏßȦ±äÁ¿
void modbus_err_response(u8 cmd, u8 err)
{
u16 crc;
u8 i=0;
modbus.tx_buf[i++] = modbus.local_addr;//±¾»úµØÖ·
modbus.tx_buf[i++] = cmd|0x80; //·µ»Ø¹¦ÄÜÂë=¹¦ÄÜÂë+0x80
modbus.tx_buf[i++] = err;
crc = Modbus_CRC16(modbus.tx_buf,i); //¼ÆËãCRC
modbus.tx_buf[i++] = crc/256;
modbus.tx_buf[i++] = crc%256;
Modbus_Uart_Send(modbus.tx_buf,i);
}
// Modbus³õʼ»¯º¯Êý
void Modbus_Init(void)
{
u8 i;
modbus.local_addr = 0x01; //É豸µØַΪ0x01
modbus.rx_flag = 0;
Modbus_Uart_Init(9600);
Modbus_TIM_Init();
for(i=0;i<30;i++) DataReg[i]=i;
for(i=0;i<20;i++) OX[i]=i;
}
//Modbus 1ºÅ¹¦ÄÜÂ뺯Êý£¬¶ÁÏßȦ״̬
void Modbus_Fun1(void)
{
u16 ox_addr,ox_cnt,crc;
u8 i,j;
ox_addr = modbus.rx_buf[2]*256+modbus.rx_buf[3];
ox_cnt = modbus.rx_buf[4]*256+modbus.rx_buf[5];
if(ox_cnt<1 || ox_cnt>0x7d0) //ÅжÏÏßȦ¸öÊýÊÇ·ñÔڹ涨ÇøÓòÄÚ£¬Èç¹û²»ÔÚ·¶Î§ÄÚÔò·µ»ØÒì³£3
{
modbus_err_response(modbus.rx_buf[1],ERROR_2);
return;
}
if( ox_addr>1600)
{
modbus_err_response(modbus.rx_buf[1],ERROR_3);
return;
}
i=0;
modbus.tx_buf[i++] = modbus.local_addr; //·¢Ëͱ¾»úµØÖ·
modbus.tx_buf[i++] = 0x01; //¹¦ÄÜÂë
if(ox_cnt%8 != 0) //Åж϶ÁÈ¡ÏßȦ¸öÊýÊÇ·ñÊÇ8µÄÕûÊý±¶£¬Èç¹û²»ÊÇ8µÄÕûÊý±¶Ôò·µ»Øox_cnt/8+1¸ö×Ö½ÚÊý¾Ý
{
modbus.tx_buf[i++] = (u8)(ox_cnt/8)+1; //·µ»Øox_cnt/8+1×Ö½ÚÊý¾Ý
if(ox_addr%8) //ÅжϵØÖ·ÊÇ·ñÊÇ8µÄÕûÊý±¶£¬Ò»¸öu8µÄ±äÁ¿´æ´¢8¸öÏßȦµÄ¿ª¹ØÖµ£¬Èç¹û²»ÊÇÕûÊý±¶ÔòÐèÒªÒÆλÀ´½øÐÐλѰַ
{
for(j=0;j<ox_cnt/8;j++)
{
modbus.tx_buf[i++]=(OX[ox_addr/8+j]>>(ox_addr%8))|(OX[ox_addr/8+j+1]<<(8-ox_addr%8)); //¶ÁÈ¡ÏßȦ¿ª¹ØÖµ
}
modbus.tx_buf[i++]=((OX[ox_addr/8+j]>>(ox_addr%8))|(OX[ox_addr/8+j+1]<<(8-ox_addr%8)))&(0xff>>(8-ox_cnt%8));
}
else //ÈôÊÇÕûÊý±¶Ôò°´×Ö½ÚÑ°Ö·¼È¿É£¬´ÓOX[20]ÖжÁÈ¡Õû¸ö±äÁ¿·µ»Ø¼´¿É
{
for(j=0;j<(ox_cnt/8);j++)
{
modbus.tx_buf[i++]=OX[ox_addr/8+j];
}
modbus.tx_buf[i++] = OX[ox_addr/8+j] & (0xff>>(8-ox_cnt%8));
}
}
else //¶ÁÈ¡¸öÊýÕýºÃÊÇ8µÄÕûÊý±¶Ôò·µ»Øox_cnt/8¸ö×Ö½ÚµÄÊý¾Ý
{
modbus.tx_buf[i++] = ox_cnt/8;
if(ox_addr%8 != 0)
{
for(j=0;j<ox_cnt/8;j++)
{
modbus.tx_buf[i++]=(OX[ox_addr/8+j]>>(ox_addr%8))|(OX[ox_addr/8+j+1]<<(8-ox_addr%8));
}
}
else
{
for(j=0;j<(ox_cnt/8);j++)
{
modbus.tx_buf[i++]=OX[ox_addr/8+j];
}
}
}
crc = Modbus_CRC16(modbus.tx_buf,i); //¼ÆËãCRC
modbus.tx_buf[i++] = crc/256;
modbus.tx_buf[i++] = crc%256;
Modbus_Uart_Send(modbus.tx_buf,i);
}
// Modbus 3ºÅ¹¦ÄÜÂ뺯Êý£¬¶Á¼Ä´æÆ÷Êý¾Ý
void Modbus_Func3()
{
u16 Reg_addr,Reg_cnt,crc;
u8 i,j;
Reg_addr = modbus.rx_buf[2]*256+modbus.rx_buf[3];//»ñÈ¡±»¶Á¼Ä´æÆ÷µÄµØÖ·
Reg_cnt = modbus.rx_buf[4]*256+modbus.rx_buf[5];//»ñÈ¡¶ÁÈ¡¼Ä´æÆ÷µÄ¸öÊý
if(Reg_cnt<1 || Reg_cnt>0x7d0) //ÅжÏÏßȦ¸öÊýÊÇ·ñÔڹ涨ÇøÓòÄÚ£¬Èç¹û²»ÔÚ·¶Î§ÄÚÔò·µ»ØÒì³£3
{
modbus_err_response(modbus.rx_buf[1],ERROR_3);
return;
}
if(Reg_addr>30) //Òì³£Åжϣ¬Èô¼Ä´æÆ÷µØÖ·²»ºÏ·¨Ôò·µ»ØÒì³£2
{
modbus_err_response(modbus.rx_buf[1],ERROR_2);
return;
}
//·µ»ØÓ¦´ðÊý¾Ý°ü
i = 0;
modbus.tx_buf[i++] = modbus.local_addr; //·¢Ëͱ¾»úµØÖ·
modbus.tx_buf[i++] = 0x03; //¹¦ÄÜÂð
modbus.tx_buf[i++] = ((Reg_cnt*2)%256); //·µ»ØÊý¾Ý³¤¶È
for(j=0;j<Reg_cnt;j++) //·µ»ØÊý¾Ý
{
modbus.tx_buf[i++] = DataReg[Reg_addr+j]/256;
modbus.tx_buf[i++] = DataReg[Reg_addr+j]%256;
}
crc = Modbus_CRC16(modbus.tx_buf,i); //¼ÆËãCRC
modbus.tx_buf[i++] = crc/256;
modbus.tx_buf[i++] = crc%256;
// ·¢ËÍÊý¾Ý
Modbus_Uart_Send(modbus.tx_buf,i);
}
void Modbus_Func5(void)
{
u16 ox_addr,val,crc;
u8 i=0;
ox_addr = modbus.rx_buf[2]*256+modbus.rx_buf[3]; //µØÖ·
val=modbus.rx_buf[4]*256+modbus.rx_buf[5]; //дÈëÖµ£¬0xff00ÏßȦдON,0x0000ÏßȦдÈëOFF
if(val != 0 && val != 0xff00) //ÅжÏÏßȦ¸öÊýÊÇ·ñÔڹ涨ÇøÓòÄÚ£¬Èç¹û²»ÔÚ·¶Î§ÄÚÔò·µ»ØÒì³£3
{
modbus_err_response(modbus.rx_buf[1],ERROR_3);
return;
}
if(ox_addr> 1600)
{
modbus_err_response(modbus.rx_buf[1],ERROR_2);
return;
}
if(val == 0xff00)
OX[ox_addr/8] |= 1<<(ox_addr%8);
else
OX[ox_addr/8] &= ~(1<<(ox_addr%8));
//ÏìÓ¦
modbus.tx_buf[i++]=modbus.local_addr;//±¾»úµØÖ·
modbus.tx_buf[i++]=0x05; //¹¦ÄÜÂë
modbus.tx_buf[i++]=ox_addr/256;
modbus.tx_buf[i++]=ox_addr%256;
modbus.tx_buf[i++]=val/256;
modbus.tx_buf[i++]=val%256;
crc=Modbus_CRC16(modbus.tx_buf,i);
modbus.tx_buf[i++]=crc/256;
modbus.tx_buf[i++]=crc%256;
Modbus_Uart_Send(modbus.tx_buf,i); //ÏòÖ÷»ú·¢ËÍÊý¾Ý
}
// Modbus 6ºÅ¹¦Äܺ¯Êý£¬Ö÷»úдÈë¼Ä´æÆ÷Öµ
void Modbus_Func6()
{
u16 Reg_addr,val,crc;
u8 i=0;
Reg_addr=modbus.rx_buf[2]*256+modbus.rx_buf[3]; //»ñÈ¡±»Ð´¼Ä´æÆ÷µØÖ·
val=modbus.rx_buf[4]*256+modbus.rx_buf[5]; //Ð޸ĺóµÄÖµ
if(val>0xffff) //ÅжÏÏßȦ¸öÊýÊÇ·ñÔڹ涨ÇøÓòÄÚ£¬Èç¹û²»ÔÚ·¶Î§ÄÚÔò·µ»ØÒì³£3
{
modbus_err_response(modbus.rx_buf[1],ERROR_3);
return;
}
if( Reg_addr> 30)
{
modbus_err_response(modbus.rx_buf[1],ERROR_2);
return;
}
DataReg[Reg_addr]=val; //Ð޸ı¾É豸¼Ä´æÆ÷Öµ
//ÏìÓ¦Ö÷»ú
modbus.tx_buf[i++]=modbus.local_addr;//±¾»úµØÖ·
modbus.tx_buf[i++]=0x06; //¹¦ÄÜÂë
modbus.tx_buf[i++]=Reg_addr/256;
modbus.tx_buf[i++]=Reg_addr%256;
modbus.tx_buf[i++]=val/256;
modbus.tx_buf[i++]=val%256;
crc=Modbus_CRC16(modbus.tx_buf,i);
modbus.tx_buf[i++]=crc/256;
modbus.tx_buf[i++]=crc%256;
Modbus_Uart_Send(modbus.tx_buf,i);
}
// Modbus´¦Àíº¯Êý
void Modbus_Msg_Handle()
{
u16 crc,rccrc;
u8 i;
if(modbus.rx_flag == 0) //ûÊÕµ½Êý¾Ý°ü
{
return;
}
if(modbus.rx_buf[0] == modbus.local_addr)
{
crc = Modbus_CRC16(&modbus.rx_buf[0],modbus.rx_count-2); //¼ÆËãÊý¾Ý°üCRC
rccrc = modbus.rx_buf[modbus.rx_count-2]*256+modbus.rx_buf[modbus.rx_count-1];//¶ÁÈ¡CRC
if(crc == rccrc)
{
if(modbus.rx_buf[1]<20)
{
switch(modbus.rx_buf[1]) //¸ù¾Ý¹¦ÄÜÂëÑ¡ÔñÖ´ÐгÌÐò
{
case 1:
Modbus_Fun1();
break;
case 2:
break;
case 3:
Modbus_Func3();
break;
case 4:
break;
case 5:
Modbus_Func5();
break;
case 6:
Modbus_Func6();
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
default:
break;
}
}
//¹¦ÄÜÂ볬³ö¹æ¶¨·¶Î§·µ»ØÒì³£Âë01
else
{
modbus.tx_buf[i++] = modbus.local_addr; //±¾»úµØÖ·
modbus.tx_buf[i++] = modbus.rx_buf[1]|0x80; //·µ»Ø¹¦ÄÜÂë=¹¦ÄÜÂë+0x80
modbus.tx_buf[i++] = ERROR_1;
Modbus_Uart_Send(modbus.tx_buf,i);
return;
}
}
}
modbus.rx_count = 0;
modbus.rx_flag = 0;
}
modbus_crc.c文件
#include "modbus_crc.h"
u8 const auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
u8 const auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
u16 Modbus_CRC16( u8 *puchMsg, u16 DataLen )
{
u8 uchCRCHi = 0xFF ; //crc¸ß×Ö½Ú³õʼ»¯
u8 uchCRCLo = 0xFF ; // CRCµÍ×Ö½Ú³õʼ»¯
unsigned long uIndex ; // crcÑ»·Ë÷Òý
while ( DataLen-- ) //
{
uIndex = uchCRCHi ^ *puchMsg++ ; //
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
uchCRCLo = auchCRCLo[uIndex] ;
}
return ( uchCRCHi << 8 | uchCRCLo ) ;
}
modbus_timer.c文件
#include "modbus_timer.h"
#include "sys.h"
#include "modbus.h"
#include "led.h"
void Modbus_TIM_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(Modbus_Time_Clock , ENABLE);
//¶¨Ê±Æ÷3²ÎÊýÅäÖÃ
TIM_TimeBaseStructure.TIM_Period = Modbus_Time_arr;
TIM_TimeBaseStructure.TIM_Prescaler = Modbus_Time_psc;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up ;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;
TIM_TimeBaseInit(Modbus_Timer, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //¶¨Ê±Æ÷3¸üÐÂÖжÏʹÄÜ
//³õʼ»¯¶¨Ê±Æ÷3µÄÖжÏÏòÁ¿
NVIC_InitStructure.NVIC_IRQChannel = Modbus_Time_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_SetCounter(Modbus_Timer,0);
TIM_Cmd(Modbus_Timer,DISABLE); //ʹÄܶ¨Ê±Æ÷3
}
void Modbus_TIM_IRQHandler(void)
{
if (TIM_GetITStatus(Modbus_Timer, TIM_IT_Update) != RESET) //²úÉúʼþÖжÏ
{
TIM_ClearITPendingBit(Modbus_Timer, TIM_IT_Update); //Çå³ý¶¨Ê±Æ÷Öжϱê¼Ç
modbus.rx_flag = 1; //¼ä¸ô8msδ½ÓÊÕµ½Êý¾Ý±íʾһ֡Êý¾Ý½ÓÊÕÍê³É£¬½ÓÊÕÍê³É±ê¼ÇÖÃ1
TIM_Cmd(Modbus_Timer,DISABLE); //¶¨Ê±Æ÷½ûÓÃ
LED0 = !LED0;
}
}
usart.c文件
#include "sys.h"
#include "usart.h"
#include "modbus.h"
#include "modbus_timer.h"
#if 1
#pragma import(__use_no_semihosting)
//±ê×¼¿âÐèÒªµÄÖ§³Öº¯Êý
struct __FILE
{
int handle;
};
FILE __stdout;
//¶¨Òå_sys_exit()ÒÔ±ÜÃâʹÓðëÖ÷»úģʽ
_sys_exit(int x)
{
x = x;
}
//Öض¨Òåfputcº¯Êý
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//Ñ»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï
USART1->DR = (u8) ch;
return ch;
}
#endif
void UART1_TX(u8 dat)
{
while((USART1->SR&0X40)==0);
USART1->DR = dat;
}
void Modbus_Uart_Send(u8 *dat ,u8 cnt)
{
u8 i;
for(i=0;i<cnt;i++)
{
UART1_TX(dat[i]);
}
}
void Modbus_Uart_Init(u32 bound)
{
//GPIO¶Ë¿ÚÉèÖÃ
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //ʹÄÜUSART1£¬GPIOAʱÖÓ
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
//USART1_RX GPIOA.10³õʼ»¯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.10
//Usart1 NVIC ÅäÖÃ
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//ÇÀÕ¼ÓÅÏȼ¶1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //×ÓÓÅÏȼ¶0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀʹÄÜ
NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
//USART ³õʼ»¯ÉèÖÃ
USART_InitStructure.USART_BaudRate = bound;//´®¿Ú²¨ÌØÂÊ
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæżУÑéλ
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê½
USART_Init(USART1, &USART_InitStructure); //³õʼ»¯´®¿Ú1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
USART_Cmd(USART1, ENABLE); //ʹÄÜ´®¿Ú1
}
void USART1_IRQHandler(void) //´®¿Ú1ÖжϷþÎñ³ÌÐò
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //½ÓÊÕÖжÏ(½ÓÊÕµ½µÄÊý¾Ý±ØÐëÊÇ0x0d 0x0a½áβ)
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //Çå³ý½ÓÊÕÖжϱêÖ¾
Res =USART_ReceiveData(USART1); //¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý
if( modbus.rx_flag==1)
{
return ;
}
TIM_SetCounter(Modbus_Timer,0); //Çå³ý¶¨Ê±Æ÷¼ÆÊý
TIM_Cmd(Modbus_Timer, ENABLE); //¿ªÆô¶¨Ê±Æ÷
modbus.rx_buf[modbus.rx_count++] = Res;
}
}
实测可用:
modbus调试助手测试
modscan32测试:
1、读线圈:
2、读保持寄存器:
以上几个.c文件基本上实现了modbus协议功能,但是注释复制过来之后显示有问题(应该是编码格式的问题),如果有需要的话可以下载源文件modbus资源,资源包里面有modbus协议RTU模式源代码(STM32keil工程文件)以及modbus调试助手、modbus协议详细文档(英文版)。