从SOD到OOD(MotorMCU模块)

本文详细介绍了电机设备与MCU之间通过UART通信的实现,包括数据结构的封装,如MCU2FPGACommand和FPGA2MCUCommand,以及相关操作集的定义。在数据处理中,使用了标志变量fresh和action进行同步。此外,还展示了如何通过解析命令块执行相应操作,如设置电机速度和获取设备状态。
摘要由CSDN通过智能技术生成

这个模块主要提供对外部设备的控制。这里是电机设备。
电机设备和MCU的通信,通过UART完成。
对这个控制模块的封装,一方面是数据,一方面是操作集。
这里关注几个关键点。
先来看数据的封装

class MotorMcu
{
public:
	struct UartLiteDev* uart_;
	SystemManager* sys_;

	...
};

首先,定义索引类的成员变量。
这里面,由于需要使用UART进行操作,所以需要关联一个UART结构体对象,这里没有使用内嵌方式,因为UART是整板的资源,所以使用了索引关联的方式。
这里,由于MotorMCU的对象,是system manager对象的一个成员对象,而且system manager具有最大化的索引范围,所以,这里以索引关联的方式,关联了一个上级system manager对象,形成了源端引用。

然后,定义复杂结构的成员变量,

class MotorMcu
{
public:
	struct MCU2FPGACommand mcu_cmd_;
	...
};

这里面,内嵌了一个MCU2FPGACommand结构体。这个结构体将命令块封装成结构体。配套的,需要为这个结构体设计相应的操作集。

struct MCU2FPGACommand
{
	struct MCU80msCommand mcu80ms_cmd;
	struct MCUTestCommand mcutest_cmd;
	struct MCUIrisCommand mcuiris_cmd;
};

void mcu2fpga_cmd_init(struct MCU2FPGACommand* cmd);
void mcu2fpga_cmd_parse(struct MCU2FPGACommand* mcu_cmd);
void mcu2fpga_cmd_demux(struct RingBuffer* ring, struct MCU2FPGACommand* mcu_cmd);

这里面又是由三个结构体对象构成。分别定义为

struct MCU80msCommand
{
	int fresh;
	u8 data[13];

	int action;
	u16 zoom_motor_value;
	u16 focus_motor_value;
	u8 zoom_limit;
	u8 focus_limit;
	u8 optics_fog_close_limit;
	u8 optics_fog_open_limit;
};

void mcu80ms_cmd_parse(struct MCU80msCommand* mcu80ms_cmd);

struct MCUTestCommand
{
	int fresh;
	u8 data[10];

	int action;
	u8 filter_ok;
	u8 iris_ok;
	u8 zoom_ok;
	u8 focus_ok;
};

void mcutest_cmd_parse(struct MCUTestCommand* mcutest_cmd);


struct MCUIrisCommand
{
	int fresh;
	u8 data[10];

	int action;
	u8 iris_limit_mode;
};

void mcuiris_cmd_parse(struct MCUIrisCommand* mcuiris_cmd);

另一个需要通信的命令块,也要封装成结构体,及其对应的操作集,

struct FPGA2MCUCommand
{
	u8 data[19];
	int len;
};

void fpga2mcu_cmd_init(struct FPGA2MCUCommand* cmd);
void fpga2mcu_set_zoom_field(struct FPGA2MCUCommand* cmd, u8 zoom_mode, u8 zoom_speed);
void fpga2mcu_set_focus_field(struct FPGA2MCUCommand* cmd, u8 focus_mode, u8 focus_speed);
void fpga2mcu_set_filter_field(struct FPGA2MCUCommand* cmd, u8 filter_mode, u8 filter_speed);
void fpga2mcu_set_fov_value(struct FPGA2MCUCommand* cmd, u16 fov_value);
void fpga2mcu_set_focus_value(struct FPGA2MCUCommand* cmd, u16 focus_value);
void fpga2mcu_set_iris_field(struct FPGA2MCUCommand* cmd, u8 iris_mode);
void fpga2mcu_cmd_calc_crc(struct FPGA2MCUCommand* cmd);

定义完了命令块,之后需要定义常量参数,
在C语言中,通常使用宏来定义常量,
在C++中,可以用const的方式来定义,这样封装性和可读性更好,说明这些常量是隶属于某个类的。如果用宏来定义,则是属于全局的。这样,不可避免的需要定义超长的名字,以避免和其他位置的同名常量发生命名冲突。

class MotorMcu
{
public:
	...
	//固定参数
	const float max_optics_focus = 275;
	const float min_optics_focus = 27.5;
	const float max_optics_fov = 42;
	const float min_optics_fov = 4.2;
	const u32 min_focus_value = 30000;
	const u32 max_focus_value = 60000;
	const u32 min_zoom_value = 3000;//3000
	const u32 max_zoom_value = 30000;//30000
	
	...
};

定义完了常量后,需要定义特定用途的基本类型成员变量(非结构体对象)。

class MotorMcu
{
public:
	...
	
	//mcu反馈
	u16 zoom_motor_value_;//0.1mm
	u16 focus_motor_value_;//16384~65536
	u8 zoom_limit_;//变倍到达指定位置
	u8 focus_limit_;//调焦到达指定位置
	u8 optics_fog_close_limit_;//光学透雾关到位
	u8 optics_fog_open_limit_;//光学透雾开到位
	u8 focus_direct_mode_;

	u8 filter_ok_;
	u8 iris_ok_;
	u8 zoom_ok_;
	u8 focus_ok_;

	u8 iris_limit_mode_;

封装好了数据,就要封装相关的操作集。
+++++++++++++++++++++++++++++++++++++++++++++++++++
1)构建函数,

MotorMcu::MotorMcu(struct UartLiteDev* uart, SystemManager* sys) : uart_(uart), sys_(sys), focus_direct_mode_(0)
{
	mcu2fpga_cmd_init(&mcu_cmd_);
}

2)SET系列

void MotorMcu::set_zoom_up(int speed)
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_zoom_field(&cmd, 1, (u8)speed);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_zoom_down(int speed)
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_zoom_field(&cmd, 2, (u8)speed);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_zoom_value(int speed, int value)
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_zoom_field(&cmd, 3, (u8)speed);
	fpga2mcu_set_fov_value(&cmd, (u16)value);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_focus_far(int speed)
{
	plog("set_focus_far: %d\r\n", speed);

	u8 focus_mode = (focus_direct_mode_ == 0) ? 1 : 2;

	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_focus_field(&cmd, focus_mode, (u8)speed);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_focus_near(int speed)
{
	plog("set_focus_near: %d\r\n", speed);

	u8 focus_mode = (focus_direct_mode_ != 0) ? 1 : 2;

	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_focus_field(&cmd, focus_mode, (u8)speed);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_focus_value(int speed, int value)
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_focus_field(&cmd, 3, (u8)speed);
	fpga2mcu_set_focus_value(&cmd, value);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_filter_light(int speed)
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_filter_field(&cmd, 1, (u8)speed);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_filter_ir(int speed)
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_filter_field(&cmd, 2, (u8)speed);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_motor_stop()
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}

void MotorMcu::set_motor_selftest()
{
	struct FPGA2MCUCommand cmd;
	fpga2mcu_cmd_init(&cmd);
	fpga2mcu_set_iris_field(&cmd, 4);
	fpga2mcu_cmd_calc_crc(&cmd);
	uart_lite_send(uart_, cmd.data, cmd.len);
}


可以看出,这几个函数的作用,就是填充命令块,然后通过串口将命令块发送出去。

3)GET系列

u32 MotorMcu::get_optics_focus() {
		return zoom_motor_value_;
	}

int MotorMcu::get_optics_focus_state() {
	u32 now_focus = zoom_motor_value_;
	u32 almost_min_focus = min_zoom_value * 110 / 100;
	u32 almost_max_focus = max_zoom_value * 90 / 100;
	if (now_focus < almost_min_focus) {
		return 0;
	} else if (now_focus < almost_max_focus) {
		return 1;
	} else {
		return 2;
	}
}

可以看出,这几个函数的作用,就是获取成员变量值,或者根据成员变量值经过计算后,返回相应的状态值。

4)ACTION系列

void MotorMcu::mcu2fpga_cmd_action(struct MCU2FPGACommand* mcu_cmd)
{
	struct MCU80msCommand* mcu80ms_cmd = &mcu_cmd->mcu80ms_cmd;
	struct MCUTestCommand* mcutest_cmd = &mcu_cmd->mcutest_cmd;
	struct MCUIrisCommand* mcuiris_cmd = &mcu_cmd->mcuiris_cmd;
	
	mcu80ms_cmd_action(mcu80ms_cmd);
	mcutest_cmd_action(mcutest_cmd);
	mcuiris_cmd_action(mcuiris_cmd);
}

void MotorMcu::mcu80ms_cmd_action(struct MCU80msCommand* mcu80ms_cmd)
{
	if (!mcu80ms_cmd->action)
		return;
	mcu80ms_cmd->action = 0;

	zoom_motor_value_ = mcu80ms_cmd->zoom_motor_value;
	focus_motor_value_ = mcu80ms_cmd->focus_motor_value;
	zoom_limit_ = mcu80ms_cmd->zoom_limit;
	focus_limit_ = mcu80ms_cmd->focus_limit;
	optics_fog_close_limit_ = mcu80ms_cmd->optics_fog_close_limit;
	optics_fog_open_limit_ = mcu80ms_cmd->optics_fog_open_limit;
}

void MotorMcu::mcutest_cmd_action(struct MCUTestCommand* mcutest_cmd)
{
	if (!mcutest_cmd->action)
		return;
	mcutest_cmd->action = 0;

	filter_ok_ = mcutest_cmd->filter_ok;
	iris_ok_ = mcutest_cmd->iris_ok;
	zoom_ok_ = mcutest_cmd->zoom_ok;
	focus_ok_ = mcutest_cmd->focus_ok;
}

void MotorMcu::mcuiris_cmd_action(struct MCUIrisCommand* mcuiris_cmd)
{
	if (!mcuiris_cmd->action)
		return;
	mcuiris_cmd->action = 0;

	iris_limit_mode_ = mcuiris_cmd->iris_limit_mode;
}

可以看出,这几个函数的作用,就是从命令块中取出数据,并赋值给对应的成员变量。

5)DEMUX,功能级函数

void MotorMcu::demux(struct RingBuffer* ring, struct MCU2FPGACommand* mcu_cmd)
{
	unsigned char temp;
	unsigned char buff[35];
	struct MCU80msCommand* mcu80ms_cmd = &mcu_cmd->mcu80ms_cmd;
	struct MCUTestCommand* mcutest_cmd = &mcu_cmd->mcutest_cmd;
	struct MCUIrisCommand* mcuiris_cmd = &mcu_cmd->mcuiris_cmd;

	unsigned char* pdata = (unsigned char*)&buff[0];

	int timeout = 1000;
	u32 start_time = sys_->get_timestamp();
	while (ring_buffer_valid_len(ring) >= 10)
	{
		u32 end_time = sys_->get_timestamp();
		int dlt_time = (end_time > start_time) ? (end_time - start_time) : (start_time - end_time);
		if (dlt_time > timeout) {
			ring_buffer_pop(ring, &temp);
			break;
		}

		ring_buffer_get_value(ring, 0, &buff[0]);
		ring_buffer_get_value(ring, 1, &buff[1]);
		ring_buffer_get_value(ring, 2, &buff[2]);
		ring_buffer_get_value(ring, 3, &buff[3]);
		ring_buffer_get_value(ring, 4, &buff[4]);
		ring_buffer_get_value(ring, 5, &buff[5]);

		if ((pdata[0] == 0x66) && (pdata[1] == 0xAA))
		{
			if (pdata[5] == 0x02)
			{
				if (ring_buffer_valid_len(ring) >= 13)
				{
					for (int i = 0; i < 13; i++)
					{
						ring_buffer_pop(ring, &mcu80ms_cmd->data[i]);
					}
					mcu80ms_cmd->fresh = 1;
					break;
				}

			}
			else if (pdata[5] == 0x03)
			{
				for (int i = 0; i < 10; i++)
				{
					ring_buffer_pop(ring, &mcutest_cmd->data[i]);
				}
				mcutest_cmd->fresh = 1;
				break;
			}
			else if (pdata[5] == 0x04)
			{
				for (int i = 0; i < 10; i++)
				{
					ring_buffer_pop(ring, &mcuiris_cmd->data[i]);
				}
				mcuiris_cmd->fresh = 1;
				break;
			}
			else
			{
				ring_buffer_pop(ring, &temp);
			}
		}
		else
		{
			ring_buffer_pop(ring, &temp);
		}
	}
}

通过直接操作UART接收的FIFO,进行命令块的数据提取。

6)接收处理,业务级函数

void MotorMcu::recv_loop()
{
	//解析mcu的反馈信息
	demux(&uart_->recv_buff, &mcu_cmd_);
	mcu2fpga_cmd_parse(&mcu_cmd_);
	//执行mcu的反馈
	mcu2fpga_cmd_action(&mcu_cmd_);
}

首先从FIFO中提取数据到mcu_cmd_结构体对象中,
然后解析mcu_cmd,
然后根据解析后的mcu_cmd,执行action.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
补充:
对定义的结构体对象,定义的对应的操作集,是全局的。
1)MCUCommand

void mcu2fpga_cmd_init(struct MCU2FPGACommand* cmd)
{
	memset(cmd, 0, sizeof(struct MCU2FPGACommand));
}

void mcu2fpga_cmd_parse(struct MCU2FPGACommand* mcu_cmd)
{
	struct MCU80msCommand* mcu80ms_cmd = &mcu_cmd->mcu80ms_cmd;
	struct MCUTestCommand* mcutest_cmd = &mcu_cmd->mcutest_cmd;
	struct MCUIrisCommand* mcuiris_cmd = &mcu_cmd->mcuiris_cmd;
	
	mcu80ms_cmd_parse(mcu80ms_cmd);
	mcutest_cmd_parse(mcutest_cmd);
	mcuiris_cmd_parse(mcuiris_cmd);
}

void mcu80ms_cmd_parse(struct MCU80msCommand* mcu80ms_cmd)
{
	int ret;
	if (!mcu80ms_cmd->fresh)
		return;

	mcu80ms_cmd->fresh = 0;
	mcu80ms_cmd->action = 0;

	ret = check_xor_crc(&mcu80ms_cmd->data[2], 9, mcu80ms_cmd->data[11]);
	if (ret < 0)
		return;

	unsigned char* pdata = (unsigned char*)&mcu80ms_cmd->data[0];

	mcu80ms_cmd->action = 1;

	mcu80ms_cmd->zoom_motor_value = (((unsigned short)pdata[7]) << 8) + ((unsigned short)pdata[6]);
	mcu80ms_cmd->focus_motor_value = (((unsigned short)pdata[8]) << 8) + ((unsigned short)pdata[9]);
	mcu80ms_cmd->zoom_limit = pdata[10] & 0x1;
	mcu80ms_cmd->focus_limit = (pdata[10] >> 1) & 0x1;
	mcu80ms_cmd->optics_fog_close_limit = (pdata[10] >> 2) & 0x1;
	mcu80ms_cmd->optics_fog_open_limit = (pdata[10] >> 3) & 0x1;
}

void mcutest_cmd_parse(struct MCUTestCommand* mcutest_cmd)
{
	int ret;
	if (!mcutest_cmd->fresh)
		return;

	mcutest_cmd->fresh = 0;
	mcutest_cmd->action = 0;

	ret = check_xor_crc(&mcutest_cmd->data[2], 6, mcutest_cmd->data[8]);
	if (ret < 0)
		return;

	unsigned char* pdata = (unsigned char*)&mcutest_cmd->data[0];

	mcutest_cmd->action = 1;

	mcutest_cmd->filter_ok = pdata[7] & 0x1;
	mcutest_cmd->iris_ok = (pdata[7] >> 1) & 0x1;
	mcutest_cmd->zoom_ok = (pdata[7] >> 2) & 0x1;
	mcutest_cmd->focus_ok = (pdata[7] >> 3) & 0x1;
}

void mcuiris_cmd_parse(struct MCUIrisCommand* mcuiris_cmd)
{
	int ret;
	if (!mcuiris_cmd->fresh)
		return;

	mcuiris_cmd->fresh = 0;
	mcuiris_cmd->action = 0;

	ret = check_xor_crc(&mcuiris_cmd->data[2], 6, mcuiris_cmd->data[8]);
	if (ret < 0)
		return;

	unsigned char* pdata = (unsigned char*)&mcuiris_cmd->data[0];

	mcuiris_cmd->action = 1;

	mcuiris_cmd->iris_limit_mode = pdata[7];
}

2)FPGA2MCUCommad

void fpga2mcu_cmd_init(struct FPGA2MCUCommand* cmd)
{
	memset(cmd->data, 0, sizeof(cmd->data));
	cmd->data[0] = 0x55;
	cmd->data[1] = 0xAA;
	cmd->data[2] = 0x02;
	cmd->data[3] = 0x0D;
	cmd->data[4] = 0x8F;
	cmd->data[5] = 0x0B;
	cmd->data[18] = 0xF0;
	cmd->len = 19;
}

void fpga2mcu_set_zoom_field(struct FPGA2MCUCommand* cmd, u8 zoom_mode, u8 zoom_speed)
{
	cmd->data[6] = zoom_mode;
	cmd->data[7] = zoom_speed;
}

void fpga2mcu_set_focus_field(struct FPGA2MCUCommand* cmd, u8 focus_mode, u8 focus_speed)
{
	cmd->data[8] = focus_mode;
	cmd->data[9] = focus_speed;
}

void fpga2mcu_set_filter_field(struct FPGA2MCUCommand* cmd, u8 filter_mode, u8 filter_speed)
{
	cmd->data[10] = filter_mode;
	cmd->data[11] = filter_speed;
}

void fpga2mcu_set_fov_value(struct FPGA2MCUCommand* cmd, u16 fov_value)
{
	cmd->data[12] = (fov_value >> 8) & 0xff;
	cmd->data[13] = fov_value & 0xff;
}

void fpga2mcu_set_focus_value(struct FPGA2MCUCommand* cmd, u16 focus_value)
{
	cmd->data[14] = (focus_value >> 8) & 0xff;
	cmd->data[15] = focus_value & 0xff;
}

void fpga2mcu_set_iris_field(struct FPGA2MCUCommand* cmd, u8 iris_mode)
{
	cmd->data[16] = iris_mode;
}

void fpga2mcu_cmd_calc_crc(struct FPGA2MCUCommand* cmd)
{
	cmd->data[17] = calc_xor_crc(&cmd->data[2], 15);
}

++++++++++++++++++++++++++++++++++++++++++++++++++
这几个结构体中,使用了共享变量,用于各个函数之间的通信和同步。
这里使用的是标志变量,flag。
这里面,使用了两个flag,
fresh,action。

在parse函数中,会检查fresh的状态,决定是否执行后续代码,如果可以执行后续代码,则清除fresh的状态。这是一个原始的PV通信方式。
parse函数对fresh执行P操作,同步在fresh的状态上。
在parse函数中,会设置action的状态,从而使得其他的函数能够检查action的状态,然后决定是否执行。
parse函数对action执行V操作,是同步在action的状态上的函数,能够得以执行。

void mcuiris_cmd_parse(struct MCUIrisCommand* mcuiris_cmd)
{
	int ret;
	if (!mcuiris_cmd->fresh)
		return;
	mcuiris_cmd->fresh = 0;
	...
	mcuiris_cmd->action = 0;
	...
	mcuiris_cmd->action = 1;
	...
}

在action函数中,会检查action的状态,决定是否执行后续代码,如果可以执行后续代码,则清除action的状态。这是一个原始的PV通信方式。
action函数对action执行P操作,同步在fresh的状态上。

void MotorMcu::mcuiris_cmd_action(struct MCUIrisCommand* mcuiris_cmd)
{
	if (!mcuiris_cmd->action)
		return;
	mcuiris_cmd->action = 0;
	
	...
}

至此,我们看到,对于action标志,有函数执行V操作,作为上游同步者,也有函数执行P操作,作为下游同步者。
但是,对于fresh表示,有函数执行P操作,作为下游同步者,那么哪个函数执行V操作,作为上游同步者?
答案是demux。

void MotorMcu::demux(struct RingBuffer* ring, struct MCU2FPGACommand* mcu_cmd)
{
	...
	while (ring_buffer_valid_len(ring) >= 10)
	{
		if ((pdata[0] == 0x66) && (pdata[1] == 0xAA))
		{
			if (pdata[5] == 0x02)
			{
				if (ring_buffer_valid_len(ring) >= 13)
				{
					...
					mcu80ms_cmd->fresh = 1;
					break;
				}

			}
			else if (pdata[5] == 0x03)
			{
				...
				mcutest_cmd->fresh = 1;
				break;
			}
			else if (pdata[5] == 0x04)
			{
				...
				mcuiris_cmd->fresh = 1;
				break;
			}
			...
		}
		...
	}
}

可以看到,demux中会设置fresh的值为1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值