📄 f340_modbus.c
字号:
//-----------------------------------------------------------------------------
// F340_modbus.c Modbus Master
//-----------------------------------------------------------------------------
//
// Program Description:
//
// 完成Modbus协议的部分功能:
// 功能码 功能描述 可用数量
//-------------------------------------------
// 01 读取线圈状态(多位)
// 02 读取输入状态(多位) 共128
//-------------------------------------------
// 03 读取保持寄存器(多字)
// 04 读取输入寄存器(多字) 共16
//-------------------------------------------
// 05 强置单线圈,支持广播方式
// 06 预置单寄存器,支持广播方式
//-------------------------------------------
// 08 回送诊断(原帧回传)
//-------------------------------------------
// 15 强置多线圈 共128
// 16 预置多寄存器 共16
//-------------------------------------------
// Target: C8051F340
// Tool chain: Keil C51 7.10
// Command Line: None
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <c8051f340.h> // SFR declarations
#include <compiler_defs.h>
#include <modbus.h>
#include <crc.h>
//-----------------------------------------------------------------------------
// Global Constants
//-----------------------------------------------------------------------------
#define SYSCLK 48000000 // Internal oscillator frequency in Hz
U8 xdata SetCoil[5][4]; //位地址5*32
U16 xdata SetReg[5][16]; //字地址5*16
U16 xdata SetReg0;
extern U8 menu_brChange; //波特率改变寄存器:0-5
sbit b485Send = P3^2; //485 发送接收控制
bit bMB_idle; //=0:Modbus空闲;=1:Modbus占用
U8 xdata sendBuf[64],receBuf[64]; //发送接收缓冲区
U8 checkoutError; // ==2 偶校验错
U8 receTimeOut; //接收超时:开始接收后规定时间内未收到数据,已收数据无效
U8 MB_BroadTimer; //广播计时器:广播发送数据后,产生固定延时,再回到空闲
U16 MB_TimeOut; //Modbus超时:发送数据后规定时间内无响应,产生94号错误
U8 MB_ErrorCode; //错误代码:01:功能码错;02:地址错;03:数据个数错;
// 92:CRC错;93:响应格式错;94:无响应.
U8 MB_TestEcho; //诊断结果回应
U8 MB_c15done; //code15功能 =S:发送指令,=15:完成发送,=0:功能完成
bit bMB_setup; //MB设置:0:工作状态,1:设置状态;由通讯设置采单改变
U8 MB_SendNum; //发送指令序号:工作状态使用的指令序号,完成发送后+1
extern U8 menu_comm0_addr[6]; //通讯地址定义
extern U8 menu_comm0_test; //通讯测试地址
extern U8 menu_brChange; //波特率改变寄存器:0-5
extern U8 SignalSet; //信号设置:高4位:清零;低4位:极性 FRAM 11
U8 localAddr ; //本机地址
U8 sendCount; //发送字节个数
U8 receCount; //接收到的字节个数
U8 sendPosi; //发送位置
extern U8 menu_alarm_set[4]; //报警设置 数组 FRAM 284-287(4)
extern U8 FM_alarming[5]; //报警状态:0x00:无报警,0x0f:警告,0xff:报警
// 0:重量,1:幅度,2:高度,3:角度,4:力矩
U8 MB_SetAlarm; //从机报警设置
//-----------------------------------------------------------------------------
// UART0_ISR
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// 串行中断程序:8-O-1
//
//-----------------------------------------------------------------------------
void UART0_ISR(void) interrupt 4
{
if(TI0)
{
TI0 = 0;
if(sendPosi < sendCount)
{
sendPosi++;
ACC = sendBuf[sendPosi];
TB80 = P; //加上校验位
SBUF0 = sendBuf[sendPosi];
}
else
{
b485Send = 0; //发送完后将485置于接收状态
receCount = 0; //清接收地址偏移寄存器
checkoutError = 0; //偶校验清零
if(sendBuf[0]==0) MB_BroadTimer=120; //广播计时
else MB_TimeOut=1000; //Modbus超时计时
}
}
else if(RI0)
{
RI0 = 0;
receTimeOut =0x40; //通讯超时值
receBuf[receCount] = SBUF0;
ACC = receBuf[receCount];
if(P != RB80)checkoutError = 2; //偶校验出错
receCount++; //接收地址偏移寄存器加1
receCount &= 0x3f; //最多一次只能接收64个字节
}
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure the UART0 using Timer1, for 9600 and 偶校验.
//-----------------------------------------------------------------------------
void UART0_Init (void)
{
SCON0 = 0xd0; // SCON0: 9-bit variable bit rate
// level of STOP bit is ignored
// RX enabled
// ninth bits 偶校验
// clear RI0 and TI0 bits
TH1 = -(SYSCLK/9600/2/48);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10
CKCON |= 0x02;
TL1 = TH1; // init Timer1
TMOD &= ~0xf0; // TMOD: timer 1 in 8-bit autoreload
TMOD |= 0x20;
TR1 = 1; // START Timer1
ES0 = 1; // Enable UART0 interrupts
SetReg0=0; // SetReg0:0:9600;
menu_brChange=0;
}
//-----------------------------------------------------------------------------
// BaudRateChange
//
// Return Value : None
// Parameters : None
//
// 运行中改变波特率
//
// SetReg[0]:0:9600;1:4800;2:14400;3:19200;4:115200;5:230400
// SetReg[0]由Modbus主控设备设置,主机必须同时改变波特率
//-----------------------------------------------------------------------------
void BaudRateChange (void)
{
static U16 NoChange;
if (SetReg0 != NoChange && bMB_idle == 0)//只在SetReg[0]改变与空闲时执行
{
switch(SetReg0)
{
case 0: CKCON &= ~0x0b; CKCON |= 0x02;TH1 = -(SYSCLK/9600/2/48);break; //9600
case 1: CKCON &= ~0x0b; CKCON |= 0x02;TH1 = -(SYSCLK/4800/2/48);break; //4800
case 2: CKCON &= ~0x0b; TH1 = -139; break; //-(SYSCLK/14400/2/12); //14400
case 3: CKCON &= ~0x0b; TH1 = -(SYSCLK/19200/2/12); break; //19200
case 4: CKCON |= 0x08; TH1 = -(SYSCLK/115200/2); break; //115200
case 5: CKCON |= 0x08; TH1 = -(SYSCLK/230400/2); break; //230400
default:break;
}
NoChange = SetReg0;
}
}
//-----------------------------------------------------------------------------
// CRC16
//-----------------------------------------------------------------------------
U16 crc16(U8 *puchMsg, U16 usDataLen)
{
U8 uchCRCHi = 0xFF ; //高CRC 字节初始化
U8 uchCRCLo = 0xFF ; //低CRC 字节初始化
U32 uIndex ; //CRC循环中的索引
while (usDataLen--) //传输消息缓冲区
{
uIndex = uchCRCHi ^ *puchMsg++ ; //计算CRC
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
uchCRCLo = auchCRCLo[uIndex] ;
}
return (uchCRCHi << 8 | uchCRCLo) ;
}
//-----------------------------------------------------------------------------
// MB_DataProc_step 数据处理
//-----------------------------------------------------------------------------
void MB_DataProc_step(void)
{
if(MB_c15done==15){SignalSet=(char)SetReg[0][11];MB_c15done=0;} //信号设置完成
}
//-----------------------------------------------------------------------------
// Modbus_CommandSend
//
// Modbus
//
// Parameters :addr地址:00广播,01采样,02行走,03变幅,04回转,05起升
// func功能码:01读取多线圈,03读取多寄存器,06设置单寄存器,08诊断
// num :func 01,03:元件个数 func06,08:数据内容
// Return Value :none
//
//-----------------------------------------------------------------------------
void Modbus_CommandSend(unsigned char addr,func,num)
{
UU16 crcData;
sendBuf[0]=addr; //从机地址
sendBuf[1]=func; //功能码:
sendBuf[2]=0;sendBuf[3]=0; //起始地址
sendBuf[4]=0;sendBuf[5]=num; //元件个数
crcData.U16 = crc16(sendBuf,6); //CRC
sendBuf[6]=crcData.U8[MSB]; //CRC高字节
sendBuf[7]=crcData.U8[LSB]; //CRC低字节
sendCount = 8; //发送字节数
beginSend(); //开始发送
}
//-----------------------------------------------------------------------------
// Modbus_DataSend
//
// Modbus
//
// Parameters :addr地址:00广播,01采样
// func功能码:15设置多线圈(16),16设置多寄存器(1word)
// Saddr:数据起始地址(word)
// dat :数据内容(word)
// Return Value :none
//
//-----------------------------------------------------------------------------
void Modbus_DataSend(unsigned char addr,func,unsigned int Saddr,dat)
{
UU16 crcData;
sendBuf[0]=addr; //从机地址
sendBuf[1]=func; //功能码:
sendBuf[2]=Saddr>>8;sendBuf[3]=(char)Saddr; //起始地址
sendBuf[4]=0;sendBuf[5]=16; //元件个数
sendBuf[6]=2; //字节个数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -