51单片机实战教程(34 线缆摇摆测试机设计)

本文将讲解51单片机在线缆摇摆测试机中的应用,包含单片机程序及人机界面程序设计,将以本人以前做过的一个案子为例来做讲解。

公司外购一款线缆,进料检验时,需要做摇摆测试,以判定品质是否合格。公司当时没有摇摆测试机,也曾外让采购外购,但因价格比较高,体积比较大,且不太适合该线缆的测试而搁浅,最后决定自制。 

如果你以前没接触过线缆制造,也许对摇摆测试不是很了解,这里我就做些简单的介绍。我们常用的软线缆,如USB、HDMI、VGA线缆等。在使用过程中会受到弯曲,多次弯曲后可会能发生:外皮开裂,芯线断裂,连接器脱落、SR脱落、脱焊等问题。为将避免这些问题,需要在产品推向市场前做测试,看是否会发生这些问题,以便做针对性改善。通常的测试方法是:将线缆一端夹在一个轴为水平,可以正反旋转的转盘上;另一端悬挂指定质量的砝码;转盘在电机的带动下,按一定的速度与角度,反复正反转动规定的次数。由于测试时看起来是在摇摆,所以称它为摇摆测试,这个测试机也就是摇摆测试机。英文说法是“Cable flex test”,如HDMI标准中列出了“Cable flex”测试项,并指定了测试方法,如下:

51单片机实战教程(34 线缆摇摆测试机设计)

设计方案确定  在明白了摇摆测试后,讲一下摇摆测试机的设计方案。这个摇摆测试机,搞得很简单。主要执行机构就是一个带减速器的57步进电机与固定在减速器输出轴上的样品装夹转盘。电机安装在一个铝型材的机架上。如下图:

51单片机实战教程(34 线缆摇摆测试机设计)

电控部分:供电电源用的是24V/10A 的开关电源,步进驱动器是MC542G,控制采用STC IAP5W4K61S4单片机为主控的控制板,人机界面用的是7吋触摸(TJC8048K070_011R)。开关电源,步进驱动器,主板,及触摸屏一并装入一个仪表箱中,仪表箱由商家按图开孔。做好后的控制仪表箱如下图示:

51单片机实战教程(34 线缆摇摆测试机设计)

 人机界面设计  这个人机界面比较简单就两个页面,一个是主界面,如下:

51单片机实战教程(34 线缆摇摆测试机设计)

 另一个是输入键盘,如下:

51单片机实战教程(34 线缆摇摆测试机设计)

主界面上控件只有两种,一种是文本控件与按钮控件。点击文本控件,即可弹出输入键盘页面实现输入设置,主页面背景使用色是PS做的图片。图片另存为一张图片在按钮部位做成不同的颜色,工作按钮按下切图。如下:

51单片机实战教程(34 线缆摇摆测试机设计)

51单片机实战教程(34 线缆摇摆测试机设计)

在主界面添加了三个变量,如下:

51单片机实战教程(34 线缆摇摆测试机设计)

 前两个为数值型,最后一个为字符串。下面看一下t0~t4按下事件代码,t0按下事件代码如下:

mstrlen.val=3
kflag.val=0
printh A0
page keybdB0

t1按下事件代码如下:

mstrlen.val=3
kflag.val=1
printh A0
page keybdB0

 t2按下事件代码如下:

mstrlen.val=3
kflag.val=2
printh A0
page keybdB0

t3按下事件代码如下:

mstrlen.val=4
kflag.val=3
printh A0
page keybdB0

t4按下事件代码如下:

mstrlen.val=4
kflag.val=3
printh A0
page keybdB0

再看一下 主界面的按钮b0~b3,按下事件代码,b0按下事件代码如下:

mparameter.txt=t0.txt
mparameter.txt=mparameter.txt+t1.txt+t2.txt+t3.txt+t4.txt
printh A1

b1按下事件代码如下:

printh A2

b2按下事件代码如下:

printh A3

b3按下事件代码如下:

printh A4

再看一下键盘页面,键盘页面也是由两种控件组成,分别为文本控件与按钮控件,文本控件有两个

t0与show,t0用做背景,show用作输入显示。先看一下数字按牛的弹起事件代码(按下事件代码为空,没有按下事件代码),b1的弹起事件代码如下:

printh A0
strlen show.txt,sys0
if(sys0<page0.mstrlen.val)
{
  show.txt=show.txt+"1"
}

b2的弹起事件代码如下:

printh A0
strlen show.txt,sys0
if(sys0<page0.mstrlen.val)
{
  show.txt=show.txt+"2"
}

其他数字键的按钮的弹起事件代码,类似不再一一列举。

b10按钮(-)的作用是Back键的作用,弹起事件代码如下:

printh A0
show.txt=show.txt-1

b200按钮(DEL)的弹起事件代码如下:

printh A0
show.txt=""

b210按钮(OK)的弹起事件代码如下:

printh A0
if(page0.kflag.val==0)
{
  strlen show.txt,sys0
  if(sys0<page0.mstrlen.val)
  {
    page0.t0.txt="000"
    page0.t0.txt=page0.t0.txt-sys0
    page0.t0.txt=page0.t0.txt+show.txt
  }else
  {
    page0.t0.txt=show.txt
  }
}else if(page0.kflag.val==1)
{
  strlen show.txt,sys0
  if(sys0<page0.mstrlen.val)
  {
    page0.t1.txt="000"
    page0.t1.txt=page0.t1.txt-sys0
    page0.t1.txt=page0.t1.txt+show.txt
  }else
  {
    strlen show.txt,sys0
    if(sys0<page0.mstrlen.val)
    {
      page0.t1.txt="000"
      page0.t1.txt=page0.t1.txt-sys0
      page0.t1.txt=page0.t1.txt+show.txt
    }else
    {
      page0.t1.txt=show.txt
    }
  }
}else if(page0.kflag.val==2)
{
  strlen show.txt,sys0
  if(sys0<page0.mstrlen.val)
  {
    page0.t2.txt="000"
    page0.t2.txt=page0.t2.txt-sys0
    page0.t2.txt=page0.t2.txt+show.txt
  }else
  {
    page0.t2.txt=show.txt
  }
}else if(page0.kflag.val==3)
{
  strlen show.txt,sys0
  if(sys0<page0.mstrlen.val)
  {
    page0.t3.txt="0000"
    page0.t3.txt=page0.t3.txt-sys0
    page0.t3.txt=page0.t3.txt+show.txt
  }else
  {
    page0.t3.txt=show.txt
  }
}else if(page0.kflag.val==4)
{
  strlen show.txt,sys0
  if(sys0<page0.mstrlen.val)
  {
    page0.t4.txt="0000"
    page0.t4.txt=page0.t4.txt-sys0
    page0.t4.txt=page0.t4.txt+show.txt
  }else
  {
    page0.t4.txt=show.txt
  }
}
page page0

以上代码中 带printh 行才是与当片机通信的代码行。printh A0是向单片机发送0xA0(让单片机控制蜂鸣器,发出按键音),输入键盘上,除了printh A0,没有其他带printh的代码行。主界面上,按下确定按钮(b0),打包设置参数到mparameter.txt,并发送0xA1(更新设置数据指令);按下开始测试按钮(b1),发送0xA2(开始测试指令);按下暂停测试按钮(b2),发送0xA3(暂停测试指令);按下测试停止按钮(b3),发送0xA4(停止测试指令)。

单片机程序设计  单片机通过PWM模块发送占空比为50%的PWM脉冲给步进驱动器做步进脉冲,单片机Timer 0 做计数器,对脉冲进行计数,以控制反复摆动角度及换向时机。通过外部中断侦测可能出现线缆芯线断裂及电阻异常。单片机与触控屏通过Uart1 实现串口通信。

端口定义 代码如下:

#ifndef __MYPORT_H__
#define __MYPORT_H__

#include "stc15w4k.h"
#include "stc15w4kgpio.h"

#define MONITOR_PORT P2

sbit BUZZER = P4^7;					//buzzer control bit
sbit INT0_IN = P3^2;        //INT0 input pin, sample wire  broken detect
sbit puslePin = P4^4;
sbit motorEnable = P4^3;
sbit motorDirection = P4^2;


sbit T0_In = P3^4;					//T0 input pin for pusle counting
sbit RxD_2 = P3^6;						 //Usart1 RxD
sbit TxD_2 = P3^7;						 //Usart1 TxD

#endif

主程序头文件  main.h代码如下:

#ifndef __MAIN_H__
#define __MAIN_H__

#include "myport.h"
#include "stcpwm.h"
#include "stc15w4kgpio.h"
#include "stctimer.h"
#include "stcuart.h"
#include "delay.h"

Timer_TypeDef mTimerStruct;
//extern ui32 const FOSC; 
ui32 const FOSC = 30000000L; 
ui16 code Vbg_ROM _at_ 0xf3f7; //IAP15W4K61S4
volatile ui8 receiveDataFlag = 0;
volatile ui8 mRdata = 0;
volatile ui8 reFlag = 0;
ui32 const motorsetp = 12800; //64*200 ui16 PAngle = 90;
volatile ui16 nAngle = 90;
volatile ui16 PAngle = 90;
volatile ui32 pPusle = 2000;
volatile ui32 nPusle = 2000;
volatile ui8 mstr[18] = "";
volatile ui8 mstr1[5] ="";
volatile ui8 mstr2[10] ="";                                     
volatile ui8 mNbits = 0;
volatile ui16 speed = 60;
volatile ui32 pusleFr = 1600;
volatile ui32 targetConts = 500;
volatile ui16 rCounts = 0;
volatile ui8 runFalg = 0;
volatile ui8 cycleFlag = 1;
volatile ui8 finishFlag = 0;
volatile ui8 suspendFlag = 0;
volatile ui8 initData = 0;
ui8 const GRATION = 1;
ui8 const CALRaTIO = 5;


//UART1_TYPDEF mUART1_Struct;



//**************************************************
void SoundBuzzer();

//*******************************************************
void SendQuMark(); //send half double quotation mark

//***************************
void SendEndMark(); //Send end mark

#endif

主程序 main.c 代码如下:

//*****************************************************
void Usart1_Routine(void) interrupt 4
{
	if(!receiveDataFlag)
	{
		if(RI)
		{
			RI=0;
			mRdata = SBUF;
			reFlag = 1;
		}
	}
}
//End of Usart1_Routine

//*****************************************************
void Timer0Int() interrupt 1
{
	++cycleFlag;
	PWMCR &= 0x7F; //PWM disable
	switch(cycleFlag)
	{
		case 1:
			rCounts++;
			TR0 = 0;
			TL0 = 65536 - pPusle;
			TH0 = (65536 - pPusle) >> 8;
			TR0 = 1;
			break;	
		case 2:
			motorDirection = !motorDirection;
			TR0 = 0;
			TL0 = 65536 - pPusle;
			TH0 = (65536 - pPusle) >> 8;
			TR0 = 1;
			break;
		case 3:
			TR0 = 0;
			TL0 = 65536 - nPusle;
			TH0 = (65536 - nPusle) >> 8;
			TR0 = 1;
			break;
		case 4:
			motorDirection = !motorDirection;
			cycleFlag = 0;
			TR0 = 0;
			TL0 = 65536 - nPusle;
			TH0 = (65536 - nPusle) >> 8;
			TR0 = 1;
			break;
	}
	if(rCounts >= targetConts)
	{
		//runFalg = 0;
		finishFlag = 1;
		TR0 = 0;
	}
	else
		PWMCR |= 0x80; //PWM enable
}
//End of Timer0_Routine() interrupt 1

//*****************************************************
void Timer1Int() interrupt 3
{
	PWMCR &= 0x7F; //PWM disable
	TR1 = 0;
	SoundBuzzer();
}

void main()
{
	GPIOInit(0xFF, 0xFF,BI_IO);
	P0 =0xFF;
	P1 =0xFF;
	P2 =0xFF;
	P3 =0xFF;
	P4 =0xFF;
	P5 =0xFF;
	P6 =0xFF;
	P7 =0xFF;
	//**************************************
	EA = 1;
	
	GPIOInit(GPIO_P4, GPIO_PIN4, PP_OUT); //init P4.4 PP_OUT
	P_SW2 |= 1 << 7; //visit extend SRF enable

	Usart1Mode(0x01); //8bits variable baud rate
	Usart1MulComDisable(); //multip machine communitate disable
	Usart1ReceiveEnable();
	UsartBaudRateDouble(0); //without double baud rate
	Usart1BaudTimer(1);//selsct baud rate timer2
	Usart1BaudRateFreDivDis();
	Usart1Pin(0x01);//P3.6/RxD_2, P3.7/TxD_2
	GPIOInit(GPIO_P3, GPIO_PIN7, PP_OUT); //push_pull out
	Usart1IntEnable();//Usart1 interrupt enable
	Usart1BaudRate(9600);//configure Usart1 baud rate 9600
	PS = 1;
	Usart1ResetTi();//set TI to 0
	Usart1ResetRi();//set TI to 0
	TIMER_T2Start();//Timer2 start
	
	Timer_Initstruct(&mTimerStruct);
	mTimerStruct.nTimer = timer0;
	mTimerStruct.mWorkMode = _load16bit;
	mTimerStruct.CountEnable = 1; //work as counter
	mTimerStruct.IntEnable = 1;   //int enable
	Timer_Init(&mTimerStruct);

	SoundBuzzer();
	Delay100xms(5,8);
	SoundBuzzer();
	Delay100xms(5,8);
	SoundBuzzer();
	Delay100xms(5,8);
	motorEnable = 1;
	
	while(1)
	{
		if(reFlag)
		{
			reFlag = 0;
			switch(mRdata)
			{
				case 0xA0:
					SoundBuzzer();
					break;
				case 0xA1: //parameter configure ok
					if(!runFalg)
					{
						SoundBuzzer();
						//Delay10xms(2,8);
						
						memset(mstr,0, strlen(mstr));
						receiveDataFlag = 1;
						mNbits = 0;
						UART1_SendString("prints page0.mparameter.txt,0");
						SendEndMark();
						RI = 0;
						while(mNbits < 17)
						{
							while(!RI);
							RI = 0;
							mstr[mNbits] = SBUF;
							mNbits++;
						}
						receiveDataFlag = 0;
						mNbits = 0;
						UART1_SendString("page0.t7.txt=");
						SendQuMark();
						UART1_SendString(mstr);
						SendQuMark();
						SendEndMark();
						Delay100xms(10,8);
						
						
						//memset(mstr1, 0, strlen(mstr1));
						StringSub(mstr1, mstr, 0, 3);
						PAngle = atol(mstr1);
						UART1_SendString("page0.t0.txt=");
						SendQuMark();
						UART1_SendString(mstr1);
						SendQuMark();
						SendEndMark();
						
						//memset(mstr1, 0, strlen(mstr1));
						StringSub(mstr1, mstr, 3, 3);
						nAngle = atol(mstr1);
						UART1_SendString("page0.t1.txt=");
						SendQuMark();
						UART1_SendString(mstr1);
						SendQuMark();
						SendEndMark();
						
						
						//memset(mstr1, 0, strlen(mstr1));
						StringSub(mstr1, mstr, 6, 3);
						speed = atol(mstr1);
						UART1_SendString("page0.t2.txt=");
						SendQuMark();
						UART1_SendString(mstr1);
						SendQuMark();
						SendEndMark();
						
						//memset(mstr1, 0, strlen(mstr1));
						StringSub(mstr1, mstr, 14, 4);
						targetConts = atol(mstr1);
						UART1_SendString("page0.t4.txt=");
						SendQuMark();
						UART1_SendString(mstr1);
						SendQuMark();
						SendEndMark();
						
						
						pusleFr = (f32)motorsetp * speed /10800 * GRATION * (PAngle + nAngle);  //360*60/2=10800
						
						pPusle = (f32)motorsetp * PAngle * GRATION * CALRaTIO/ 720; 
						nPusle = (f32)motorsetp * nAngle * GRATION * CALRaTIO/ 720;
						
						LongtoString(pPusle,mstr2); //nAngle
						UART1_SendString("page0.t7.txt=");
						SendQuMark();
						UART1_SendString(mstr2);
						SendQuMark();
						SendEndMark();
						Delay100xms(10,8);
						
						LongtoString(nPusle,mstr2); //nAngle
						UART1_SendString("page0.t7.txt=");
						SendQuMark();
						UART1_SendString(mstr2);
						SendQuMark();
						SendEndMark();
						Delay100xms(10,8);
						
						UART1_SendString("page0.t7.txt=\"\"");
						SendEndMark();
					}
					
					
					
					break;
				case 0xA2: //start test
					SoundBuzzer();
					if(!runFalg)
					{
						runFalg = 1;
						initData = MONITOR_PORT;
						
						motorDirection = 1;
						//init timer0
						TF0 = 0;
						TR0 = 0;
						TL0 = 65536 - pPusle;
						TH0 = (65536 - pPusle) >> 8;
						TIMER_T0Start();
						motorEnable = 1;
						PWM_Out(PWM_CH4, pusleFr, 0, O2);
					}
					else 
					{
						if(suspendFlag)
						{
							PWMCR |= 0x80; //PWM enable
							suspendFlag = 0;
						}
						if(finishFlag == 1)
							runFalg = 0;
					}
					break;
				case 0xA3: //suspend test
					SoundBuzzer();
					PWMCR &= 0x7F; //PWM disable
					suspendFlag = 1;
					break;
				case 0xA4: //stop test
					SoundBuzzer();
					PWMCR &= 0x7F; //PWM disable
					TR0 = 0;
					suspendFlag = 0;
					finishFlag = 0;
					runFalg = 0;
					rCounts = 0;
					cycleFlag = 1;
					
					LongtoString(rCounts,mstr2); //nAngle
					UART1_SendString("page0.t6.txt=");
					SendQuMark();
					UART1_SendString(mstr2);
					SendQuMark();
					SendEndMark();
					break;
			}
			mRdata = 0;
		}
		if(runFalg)
		{
			if(initData <= MONITOR_PORT)
			{
				UART1_SendString("page0.t5.txt=");
				SendQuMark();
				UART1_SendString("测试中");
				SendQuMark();
			  SendEndMark();
				
				LongtoString(rCounts,mstr2); //nAngle
				UART1_SendString("page0.t6.txt=");
				SendQuMark();
				UART1_SendString(mstr2);
				SendQuMark();
			  SendEndMark();
			}
			else //Test Fail
			{
				PWMCR &= 0x7F; //PWM disable
				runFalg = 0;
				finishFlag = 2;
			}
			if(suspendFlag)
			{
				UART1_SendString("page0.t5.txt=");
				SendQuMark();
				UART1_SendString("暂停中");
				SendQuMark();
			  SendEndMark();
			}
		}
		else
		{
			switch(finishFlag)
			{
				case 0:
					UART1_SendString("page0.t5.txt=");
					SendQuMark();
					UART1_SendString("空闲");
					SendQuMark();
					SendEndMark();
					break;
				case 1:
					UART1_SendString("page0.t5.txt=");
					SendQuMark();
					UART1_SendString("测试完成,Pass!");
					SendQuMark();
					SendEndMark();
					break;
				case 2:
					UART1_SendString("page0.t5.txt=");
					SendQuMark();
					UART1_SendString("测试失败,Fail!");
					SendQuMark();
					SendEndMark();
					UART1_SendString("page0.t5.bco=63488");
					SendEndMark();
					break;
			}
		}
	}
}

//****************************************************/
void SoundBuzzer()
{
	BUZZER = 0;
	Delay100xms(3,8);
	BUZZER = 1;
}
//End of SoundBuzzer()

//*******************************************************
void SendQuMark() //send half double quotation mark
{
	ES = 0;
	Usart1SendByte(34);
	ES = 1;
}
//End of Usart1BaudRate(ui32 myBaudRate)

//***************************
void SendEndMark() //Send end mark
{
	ES = 0;
	Usart1SendByte(0xFF);
	Usart1SendByte(0xFF);
	Usart1SendByte(0xFF);
	ES = 1;
}
//End of SendEndMark()

上面代码中省去了,测试中线缆异常的处理代码。机器的运行效果如下图:

51单片机实战教程(34 线缆摇摆测试机设计)

上一篇:一个非常适合IT团队的在线API文档!


下一篇:aspose.word 替换图片