STC单片机ModbusMaster主机实现

本文介绍了一种Modbus主机的实现方法,包括关键接口的设计与功能码的具体实现。通过移植到不同平台,实现了Modbus协议中多种功能码的支持,如读取线圈状态、读取保持寄存器等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

modbus主机支持01 02 03 04 05 06 0F 10功能码
移植时主要实现几下几个接口,可自行更改

/*********************************************************************************************************
 *接口1 串口发送数据
*********************************************************************************************************/
void MbSendBytes(unsigned char *buff,unsigned short length)
{
	int i = 0;
	P04 = 1;
	vTaskDelay(1);
	for ( i = 0; i < length; i++)
	{
        S4BUF = buff[i];
        while(!S4TI);
		CLR_TI4();
	}
	vTaskDelay(3);
	P04 = 0;
}
/*********************************************************************************************************
 *接口2 延时函数,操作系统可用vTaskDelay,裸机可直接delay_ms,如果裸机异步方式要修改MbWriteWaitCheckRxData函数,
 *让其不阻塞
*********************************************************************************************************/
void MbSleep(unsigned short ms)
{
	vTaskDelay(ms);
}
/*********************************************************************************************************
 *接口3 初始化函数,用来初始化串口
*********************************************************************************************************/
void ModbusMasterInit(void)
{
	Serial4Init(9600);
}
/*********************************************************************************************************
 *接口4  串口接收一个字节,以下是stc单片机例程
*********************************************************************************************************/
void UART4_ISR_Handler (void) interrupt UART4_VECTOR
{
	if(S4RI)
	{
		CLR_RI4();
        MbRecvByte(S4BUF);
	}
}

例程读取如下,读取从机1,从地址0开始的10个寄存器数据

short reg[10];
if(MbReadDiscreteInputs(1,0,10,&reg[0]) == MB_OK)
{
	//返回MB_OK代表读取成功,返回其他值证明数据有错误
}

只有返回MB_OK,reg数组中的值才会更改
其实现原理比较简单,不讲解直接贴所有代码
modbusmaster.c文件

#include "modbusMaster.h"
#include "modbusmaster.h"
#include "system_init.h"
#include "freertos.h"
#include "task.h"
#define MODBUS_FRAME_MAX_LEN   255                               //modbus最大帧长度
#define MbGetBytes(num,index)     ((num >> (index << 3)))        //获取第index字节
#define MbGetBits(byte,index)     ((byte >> (index)))            //获取第inde位
unsigned char            xdata   _modbusTxBuff[MODBUS_FRAME_MAX_LEN];
volatile unsigned char   xdata   _modbusRxLock = 0;
unsigned char            xdata   _modbusTxLen;
unsigned char            xdata   _modbusRxBuff[MODBUS_FRAME_MAX_LEN];
volatile unsigned char   xdata   _modbusRxLen;
unsigned char            xdata   _slaveId;
unsigned char            xdata   _cmd;
const unsigned short crc_table[256] = {
    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
};

void MbRecvByte(unsigned char byte);


/*********************************************************************************************************
 *接口1 串口发送数据
*********************************************************************************************************/
void MbSendBytes(unsigned char *buff,unsigned short length)
{
	int i = 0;
	P04 = 1;
	vTaskDelay(1);
	for ( i = 0; i < length; i++)
	{
        S4BUF = buff[i];
        while(!S4TI);
		CLR_TI4();
	}
	vTaskDelay(3);
	P04 = 0;
}
/*********************************************************************************************************
 *接口2 延时函数,操作系统可用vTaskDelay,裸机可直接delay_ms,如果裸机异步方式要修改MbWriteWaitCheckRxData函数,
 *让其不阻塞
*********************************************************************************************************/
void MbSleep(unsigned short ms)
{
	vTaskDelay(ms);
}
/*********************************************************************************************************
 *接口3 初始化函数,用来初始化串口
*********************************************************************************************************/
void ModbusMasterInit(void)
{
	Serial4Init(9600);
}
/*********************************************************************************************************
 *接口4  串口接收一个字节,以下是stc单片机例程
*********************************************************************************************************/
void UART4_ISR_Handler (void) interrupt UART4_VECTOR
{
	if(S4RI)
	{
		CLR_RI4();
        MbRecvByte(S4BUF);
	}
}
/*********************************************************************************************************
 *接收一字节,放在串口接收中断接收,如果采用空闲接收可直接改写
*********************************************************************************************************/
void MbRecvByte(unsigned char byte)
{
	if(_modbusRxLock == 0 && _modbusRxLen < MODBUS_FRAME_MAX_LEN)
	{
		_modbusRxBuff[_modbusRxLen++] = byte; 
	}
}
/*********************************************************************************************************
 *获取缓冲区线圈值,注意char一个字节代表一位,这要方便读写
*********************************************************************************************************/

void MbGetResponeBits(char *coils,unsigned char index,unsigned short count)
{
	int readBytesCount = 0;
	short i = 0,j = 0,tmp = 0,idx = 0;
	readBytesCount = count >> 3;
	if((count % 8) > 0)
	{
		readBytesCount++;
	}
	for ( i = 0; i < readBytesCount; i++)
	{
		tmp = count - (i << 3);
		for ( j = 0; j < 8 && j < tmp; j++)
		{
			coils[idx++] = (_modbusRxBuff[i + index] >> j) & 0x01;	
		}
	}
}

/*********************************************************************************************************
 * crc16
*********************************************************************************************************/
unsigned short crc16_update(unsigned char *ptr, int len)
{
    unsigned short crc = 0xFFFF;
    
    while(len--) 
    {
        crc = (crc >> 8) ^ crc_table[(crc ^ *ptr++) & 0xff];
    }
    
    return (crc);
}
/*********************************************************************************************************
 * 获取缓冲区16进制数
*********************************************************************************************************/
void MbGetResponeInt16(short *reg,unsigned char index,unsigned short count)
{
	int idx = 0, i = 0;
	for(idx = 0;idx < count;idx++)
	{
		reg[idx] = (short)((_modbusRxBuff[i + index] << 8) + _modbusRxBuff[i + 1 + index]);
		i += 2; 
	}
}
/*********************************************************************************************************
 * 写入字符,等待接收,并且校验
*********************************************************************************************************/
static unsigned char MbWriteWaitCheckRxData(unsigned char*buff,unsigned short length,unsigned short timeout)
{
    short tryTimes = MB_RX_TRY_TIMS;
	unsigned short lastCount = 0;
	unsigned short crc;
	_cmd = buff[1];
	_slaveId = buff[0];
	crc = crc16_update(buff,length);
	buff[length++] = MbGetBytes(crc,0);
	buff[length++] = MbGetBytes(crc,1);
	while(tryTimes > 0)
	{
		_modbusRxLock = 0;
		_modbusRxLen = 0;
		MbSendBytes(buff,length);
		timeout = 5000;
		lastCount = 0;
		//接收数据
		while((long)timeout > 0)
		{
			MbSleep(50);
			timeout -= 50;
			if(_modbusRxLen > 0 && lastCount == 0)
			{
				lastCount = _modbusRxLen;
			}
			else if(lastCount > 0 && lastCount != _modbusRxLen )
			{
				lastCount = _modbusRxLen;
			}
			else if(lastCount > 0 && lastCount == _modbusRxLen)
			{
				_modbusRxLock = 1;
				tryTimes = -1;
				break;
			}
		}
		tryTimes--;
	}
	if(tryTimes == 0)
	{
		return MB_CRC_ERR;
	}
	//crc校验
	if(crc16_update(_modbusRxBuff,_modbusRxLen) != 0)
	{
		return MB_CRC_ERR;
	}
	//是不是错误码
	if(_modbusRxBuff[1] == (_cmd | 0x80))
	{
		return _modbusRxBuff[2];
	}
	//是不是从几号不一致
	if(_modbusRxBuff[0] != _slaveId)
	{
		return MB_ILLEGAL_SLAVE;
	}
	//是否不是功能
	switch(_cmd)
	{
		case 0x01:
		break;
		case 0x02:
		break;
		case 0x03:
		break;
		case 0x04:
		break;
		case 0x05:
		break;
		case 0x06:
		break;
		case 0x0F:
		break;
		case 0x10:
		break;
		case 0x0b:
		break;
		case 0x0c:
		break;
		case 0x0d:
		break;
		case 0x0e:
		break;	
		case 0x0a:
		break;
		default:
		return MB_ILLEGAL_FUNC;
		break;
	}
	return MB_OK;
}

/*********************************************************************************************************
 * 0x01
*********************************************************************************************************/
unsigned char MbReadCoils(unsigned char slave,unsigned short adress,unsigned short count,unsigned char *coils)
{
	int idx = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x01;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(count,1);
	_modbusTxBuff[idx++] = MbGetBytes(count,0);
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	if(ret == MB_OK)
	{
		MbGetResponeBits(coils,3,count);
	}
	return ret;
}
/*********************************************************************************************************
 * 0x02
*********************************************************************************************************/
unsigned char MbReadDiscreteInputs(unsigned char slave,unsigned short adress,unsigned short count,unsigned char *coils)
{
	int idx = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x02;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(count,1);
	_modbusTxBuff[idx++] = MbGetBytes(count,0);
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	if(ret == MB_OK)
	{
		MbGetResponeBits(coils,3,count);
	}
	return ret;
}
/*********************************************************************************************************
 * 0x03
*********************************************************************************************************/
unsigned char MbReadHoldingRegisters(unsigned char slave,unsigned short adress,unsigned short count,short *reg)
{
	int idx = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x03;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(count,1);
	_modbusTxBuff[idx++] = MbGetBytes(count,0);
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	if(ret == MB_OK)
	{
		MbGetResponeInt16(reg,3,count);
	}
	return ret;
}
/*********************************************************************************************************
 * 0x04
*********************************************************************************************************/
unsigned char MbReadInputRegisters(unsigned char slave,unsigned short adress,unsigned short count,short *reg)
{
	int idx = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x04;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(count,1);
	_modbusTxBuff[idx++] = MbGetBytes(count,0);
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	if(ret == MB_OK)
	{
		MbGetResponeInt16(reg,3,count);
	}
	return ret;
}
/*********************************************************************************************************
 * 0x05
*********************************************************************************************************/
unsigned char MbWriteSingleCoil(unsigned char slave,unsigned short adress,unsigned short value)
{
	int idx = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x05;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(value,1);
	_modbusTxBuff[idx++] = MbGetBytes(value,0);
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	return ret;
}
/*********************************************************************************************************
 * 0x06
*********************************************************************************************************/
unsigned char MbWriteSingleRegister(unsigned char slave,unsigned short adress,unsigned short value)
{
	int idx = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x06;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(value,1);
	_modbusTxBuff[idx++] = MbGetBytes(value,0);
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	return ret;
}
int dbu;
/*********************************************************************************************************
 * 0x0F
*********************************************************************************************************/
unsigned char MbWriteMultipleCoils(unsigned char slave,unsigned short adress,unsigned short count,unsigned char* coils)
{
	int idx = 0,i = 0,j = 0,tmp = 0,k = 0;
	unsigned char ret = 0;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x0F;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(count,1);
	_modbusTxBuff[idx++] = MbGetBytes(count,0);
	ret = count >> 3;
	if((count % 8) > 0)
	{
		ret++;
	}
	_modbusTxBuff[idx++] = (unsigned char)(ret);
	for ( i = 0; i < ret; i++)
	{
		tmp = count - (i << 3);
		_modbusTxBuff[idx] = 0;
		for(j = 0; j < 8 && j < tmp;j++)
		{
			_modbusTxBuff[idx] |= ((coils[k++] & 0x01) << (j));
		}
		idx++;
	}
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	return ret;
}
/*********************************************************************************************************
 * 0x10
*********************************************************************************************************/
unsigned char MbWriteMultipleRegisters(unsigned char slave,unsigned short adress,unsigned short count,unsigned short* value)
{
	int idx = 0,i = 0;
	unsigned char ret;
	_modbusTxBuff[idx++] = slave;
	_modbusTxBuff[idx++] = 0x10;
	_modbusTxBuff[idx++] = MbGetBytes(adress,1);
	_modbusTxBuff[idx++] = MbGetBytes(adress,0);
	_modbusTxBuff[idx++] = MbGetBytes(count,1);
	_modbusTxBuff[idx++] = MbGetBytes(count,0);
	_modbusTxBuff[idx++] = (unsigned char)((count << 1) % 0xFF);
	for ( i = 0; i < count; i++)
	{
		_modbusTxBuff[idx++] = MbGetBytes(value[i],1);
		_modbusTxBuff[idx++] = MbGetBytes(value[i],0);
	}
	ret = MbWriteWaitCheckRxData(_modbusTxBuff,idx,MB_RX_TIMEOUT);
	return ret;
}

modbusmaster.h文件

#ifndef _MB_H
#define _MB_H

#define	MB_ILLEGAL_SLAVE     -1
#define	MB_OK 				 0
#define	MB_TIMEOUT 			 5
#define	MB_ILLEGAL_FUNC 	 1
#define	MB_ILLEGAL_ADDRESS 	 2
#define	MB_ILLEGAL_DATA 	 3
#define	MB_SLAVE_FAULT 		 4
#define	MB_SLAVE_BUSY 		 6
#define	MB_CRC_ERR 			 8

#define MB_RX_TIMEOUT        5000  //设置超时时间
#define MB_RX_TRY_TIMS       5     //尝试几次
/*********************************************************************************************************
 * init
*********************************************************************************************************/
void ModbusMasterInit(void);
void MbSendBytes(unsigned char *buff,unsigned short length);
/*********************************************************************************************************
 * 0x01
*********************************************************************************************************/
unsigned char MbReadCoils(unsigned char slave,unsigned short adress,unsigned short count,unsigned char *coils);
/*********************************************************************************************************
 * 0x02
*********************************************************************************************************/
unsigned char MbReadDiscreteInputs(unsigned char slave,unsigned short adress,unsigned short count,unsigned char *coils);
/*********************************************************************************************************
 * 0x03
*********************************************************************************************************/
unsigned char MbReadHoldingRegisters(unsigned char slave,unsigned short adress,unsigned short count,short *reg);
/*********************************************************************************************************
 * 0x04
*********************************************************************************************************/
unsigned char MbReadInputRegisters(unsigned char slave,unsigned short adress,unsigned short count,short *reg);
/*********************************************************************************************************
 * 0x05
*********************************************************************************************************/
unsigned char MbWriteSingleCoil(unsigned char slave,unsigned short adress,unsigned short value);
/*********************************************************************************************************
 * 0x06
*********************************************************************************************************/
unsigned char MbWriteSingleRegister(unsigned char slave,unsigned short adress,unsigned short value);
/*********************************************************************************************************
 * 0x0F
*********************************************************************************************************/
unsigned char MbWriteMultipleCoils(unsigned char slave,unsigned short adress,unsigned short count,unsigned char* coils);
/*********************************************************************************************************
 * 0x10
*********************************************************************************************************/
unsigned char MbWriteMultipleRegisters(unsigned char slave,unsigned short adress,unsigned short count,unsigned short* value);
#endif
#define LED_PIN P1_6 #define STEP_A_PIN P3_5 #define STEP_B_PIN P3_4 #define STEP_C_PIN P3_3 #define STEP_D_PIN P3_2 #define RS_485_PIN P5_4 #define BUTTON_PIN P1_7 #define LIMIT_UP_PIN P3_7 #define LIMIT_DOWN_PIN P3_6 #define ModBus_Master_UART UART_1 #include <STC8HX.h> uint32 sys_clk = 33000000;//设置PWM、定时器、串口、EEPROM频率参数 #include "mylib/MB_Master.h" void MotorControl(); void ButtonScan(); void ProcessButton(); void CheckLimits(); // 全局变量 volatile SystemState gSystemState = SYS_STATE_INIT; // 系统状态 volatile MotorState gMotorState = MOTOR_STATE_STOP; // 电机状态 volatile unsigned char gStepIndex = 0; // 步进序列索引 volatile unsigned int gCurrentPosition = 0; // 当前位置 volatile unsigned int gTargetPosition = 0; // 目标位置 volatile unsigned int gStepDelay = 5; // 步进延时(ms) volatile unsigned int gSystemTimer = 0; // 系统计时器 volatile unsigned int gButtonTimer = 0; // 按钮计时器 volatile unsigned char gButtonPressCount = 0; // 按钮按下次数 volatile bit gButtonState = 0; // 按钮状态 volatile bit gButtonLastState = 0; // 按钮上次状态 volatile unsigned char gModbusAddress = 0x01; // Modbus地址 volatile unsigned int gStroke = 1000; // 行程步数 volatile unsigned int gDecelDistance = 50; // 减速距离 // 系统状态定义 typedef enum { SYS_STATE_INIT = 0, // 初始化状态 SYS_STATE_IDLE = 1, // 空闲状态 SYS_STATE_WORK = 2, // 工作状态 SYS_STATE_CONFIG = 3, // 配置状态 SYS_STATE_TEST = 4, // 测试状态 SYS_STATE_ERROR = 5, // 错误状态 } SystemState; // 函数声明 void SystemInit(void); void MotorControl(void); void ButtonScan(void); void ProcessButton(void); void ModbusPoll(void); void SavePositionToEeprom(void); void LoadPositionFromEeprom(void); void MoveToTarget(void); void CheckLimits(void); void SetLedState(unsigned char state, unsigned int blinkRate); while(1) { ButtonScan(); // 扫描按钮 ProcessButton(); // 处理按钮事件 CheckLimits(); // 检查限位开关 ModbusPoll(); // 处理Modbus通信 // 根据系统状态执行不同操作 switch(gSystemState) { case SYS_STATE_INIT: // 初始化状态,等待到达上限位 if(gMotorState == MOTOR_STATE_STOP && LIMIT_UP_PIN == 0) { gSystemState = SYS_STATE_IDLE; gCurrentPosition = 0; SavePositionToEeprom(); SetLedState(0, 0); // LED常亮表示就绪 } /*步进电机控制 */ void MotorControl(){ static unsigned int stepTimer = 0; if(gMotorState != MOTOR_STATE_STOP){ if(gSystemTimer - stepTimer > gStepDelay){ stepTimer = gSystemTimer if(gCurrentPosition > gTargetPosition && gCurrentPosition - gTargetPosition < gDecelDistance){ gStepDelay = 10; // 减速 } else{ if(gCurrentPosition < gTargetPosition && gTargetPosition - gCurrentPosition < gDecelDistance){ gStepDelay = 10; // 减速 } else{ gStepDelay = 5; // 正常速度 } } } if(gMotorState == MOTOR_STATE_FWD){ gStepIndex = (gStepIndex + 1) % 8; gCurrentPosition++; P3 = (P3 & 0xE0) | stepTable[gStepIndex];// 正转控制 } else{ gStepIndex = (gStepIndex + 7) % 8; gCurrentPosition--; P3 = (P3 & 0xE0) | stepTable[gStepIndex];// 反转控制 } if((gMotorState == MOTOR_STATE_FWD && gCurrentPosition >= gTargetPosition) || (gMotorState == MOTOR_STATE_REV && gCurrentPosition <= gTargetPosition)){ gMotorState = MOTOR_STATE_STOP; P1 = (P1 & 0xE0); // 关闭所有步进相 SavePositionToEeprom(); } } } /*按钮扫描 */ void ButtonScan(){ static unsigned int debounceTimer = 0; if(gSystemTimer - debounceTimer > 20){ debounceTimer = gSystemTimer; gButtonLastState = gButtonState; gButtonState = BUTTON_PIN; if(gButtonState == 0 && gButtonLastState == 1){ gButtonPressCount++; gButtonTimer = gSystemTimer; } if(gButtonState == 0 && gSystemTimer - gButtonTimer > 3000){ // 长按3秒,恢复出厂设置 gButtonPressCount = 0; } } } /* 处理按钮事件 */ void ProcessButton(){ if(gButtonPressCount > 0 && gSystemTimer - gButtonTimer > 500){ switch(gButtonPressCount) { case 1: // 短按1次 - 切换工作/自动配置模式 if(gSystemState == SYS_STATE_WORK) { gSystemState = SYS_STATE_CONFIG; SetLedState(1, 1000); // LED慢闪表示配置模式 } else { gSystemState = SYS_STATE_WORK; SetLedState(0, 0); // LED常亮表示工作模式 } break; case 2: // 短按2次 - 进入测试模式 gSystemState = SYS_STATE_TEST; SetLedState(1, 300); // LED中速闪烁表示测试模式 break; case 3: // 短按3次 - 电机正转(向上) if(gSystemState == SYS_STATE_WORK || gSystemState == SYS_STATE_TEST) { if(gMotorState == MOTOR_STATE_STOP) { gTargetPosition = 0; // 目标是上限位 gMotorState = MOTOR_STATE_FWD; } else if(gMotorState == MOTOR_STATE_FWD) { gMotorState = MOTOR_STATE_STOP; } } break; case 4: // 短按4次 - 电机反转(向下) if(gSystemState == SYS_STATE_WORK || gSystemState == SYS_STATE_TEST) { if(gMotorState == MOTOR_STATE_STOP) { gTargetPosition = gStroke; // 目标是下限位 gMotorState = MOTOR_STATE_REV; } else if(gMotorState == MOTOR_STATE_REV) { gMotorState = MOTOR_STATE_STOP; } } break; } gButtonPressCount = 0; } } // 定时器0中断服务函数 (系统时基) void Timer0_ISR(void) interrupt 1 { // 重新加载初值 TH0 = 0xFC; TL0 = 0x66; gSystemTimer++; // 系统计时器递增 MotorControl(); // 步进电机控制 } // 保存位置到EEPROM void SavePositionToEeprom(void) { // EEPROM写入代码 // 此处省略具体实现 } // 从EEPROM加载位置 void LoadPositionFromEeprom(void) { // EEPROM读取代码 // 此处省略具体实现 } // Modbus轮询处理 void ModbusPoll(void) { // Modbus通信处理代码 // 此处省略具体实现 } /*/检查限位开关 */ void CheckLimits(){ if(LIMIT_UP_PIN == 0 && gMotorState == MOTOR_STATE_FWD){ gCurrentPosition = 0; gMotorState = MOTOR_STATE_STOP; P3 = (P3 & 0xE0); // 关闭所有步进相 SavePositionToEeprom(); } if(LIMIT_DOWN_PIN == 0 && gMotorState == MOTOR_STATE_REV){ gCurrentPosition = gStroke; gMotorState = MOTOR_STATE_STOP; P3 = (P3 & 0xE0); // 关闭所有步进相 SavePositionToEeprom(); } } // 设置LED状态 void SetLedState(unsigned char blink, unsigned int blinkRate) { static unsigned int ledTimer = 0; static bit ledState = 0; if(blink) { if(gSystemTimer - ledTimer > blinkRate) { ledTimer = gSystemTimer; ledState = !ledState; LED_PIN = ledState; } } else { LED_PIN = 0; // 常亮 } } // 主函数 void main(void) { SystemInit(); // 系统初始化 // 初始化位置到上限位 gSystemState = SYS_STATE_INIT; SetLedState(1, 500); // LED快闪表示初始化 // 读取保存的位置 LoadPositionFromEeprom(); // 移动到上限位 gTargetPosition = 0; gMotorState = MOTOR_STATE_FWD; // 主循环 while(1) { ButtonScan(); // 扫描按钮 ProcessButton(); // 处理按钮事件 CheckLimits(); // 检查限位开关 ModbusPoll(); // 处理Modbus通信 // 根据系统状态执行不同操作 switch(gSystemState) { case SYS_STATE_INIT: // 初始化状态,等待到达上限位 if(gMotorState == MOTOR_STATE_STOP && LIMIT_UP_PIN == 0) { gSystemState = SYS_STATE_IDLE; gCurrentPosition = 0; SavePositionToEeprom(); SetLedState(0, 0); // LED常亮表示就绪 } break; case SYS_STATE_WORK: // 工作状态,处理位置控制 MoveToTarget(); break; case SYS_STATE_CONFIG: // 配置状态,处理自动地址分配 // 此处省略自动地址分配逻辑 break; case SYS_STATE_TEST: // 测试状态,处理电机测试 break; case SYS_STATE_ERROR: // 错误状态,闪烁LED报警 SetLedState(1, 200); break; } // 延时一小段时间 _nop_(); _nop_(); } } void setup() { P3M1&=~0x20;P3M0|=0x20;//推挽输出 P3M1&=~0x10;P3M0|=0x10;//推挽输出 P3M1&=~0x08;P3M0|=0x08;//推挽输出 P3M1&=~0x04;P3M0|=0x04;//推挽输出 P5M1&=~0x10;P5M0|=0x10;//推挽输出 P3M1|=0x80;P3M0&=~0x80;//高阻输入 P3M1|=0x40;P3M0&=~0x40;//高阻输入 P3 = 0x00; //步进电机初始为0 LED_PIN = 0; //LED初始熄灭 TMOD = 0xF0; TH0 = 0xFC; TL0 = 0x66; EA = 1; // 控制总中断 ET0 = 1; // 控制定时器中断 TR0 = 1;// 定时器0开始计时 } void loop() { MBMasterInit(UART_1, UART1_RX_P30, UART1_TX_P31, 9600, TIM_1, MB_M_PAR_NONE); } void main(void) { setup(); while(1){ loop(); } } 根据以上代码加一个自动配置模式,以及不使用modbus分配地址,通过有没有接收到信号来分配地址,做一个3次检测防止误检测;检测到信号后第一个设备分配地址为1,后面设备地址依次加1;如果没有检测到信号能发出一个值来代表等待分配地址,超过检测3次没有检测到信号则是强制给第一个设备分配为1,后面设备地址依次加1,一直分配设备结束为止,以及加上一个步进电机运动过程中能够手动按下刹车,按键只有程序中出现的一个,以现有的功能加上上述文字描述的功能
最新发布
06-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值